tlsv1_record.c
Go to the documentation of this file.
00001 /*
00002  * TLSv1 Record Protocol
00003  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "crypto/md5.h"
00019 #include "crypto/sha1.h"
00020 #include "tlsv1_common.h"
00021 #include "tlsv1_record.h"
00022 
00023 
00035 int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
00036                                   u16 cipher_suite)
00037 {
00038         const struct tls_cipher_suite *suite;
00039         const struct tls_cipher_data *data;
00040 
00041         wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
00042                    cipher_suite);
00043         rl->cipher_suite = cipher_suite;
00044 
00045         suite = tls_get_cipher_suite(cipher_suite);
00046         if (suite == NULL)
00047                 return -1;
00048 
00049         if (suite->hash == TLS_HASH_MD5) {
00050                 rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
00051                 rl->hash_size = MD5_MAC_LEN;
00052         } else if (suite->hash == TLS_HASH_SHA) {
00053                 rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
00054                 rl->hash_size = SHA1_MAC_LEN;
00055         }
00056 
00057         data = tls_get_cipher_data(suite->cipher);
00058         if (data == NULL)
00059                 return -1;
00060 
00061         rl->key_material_len = data->key_material;
00062         rl->iv_size = data->block_size;
00063         rl->cipher_alg = data->alg;
00064 
00065         return 0;
00066 }
00067 
00068 
00077 int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
00078 {
00079         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
00080                    "0x%04x", rl->cipher_suite);
00081         rl->write_cipher_suite = rl->cipher_suite;
00082         os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
00083 
00084         if (rl->write_cbc) {
00085                 crypto_cipher_deinit(rl->write_cbc);
00086                 rl->write_cbc = NULL;
00087         }
00088         if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
00089                 rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
00090                                                    rl->write_iv, rl->write_key,
00091                                                    rl->key_material_len);
00092                 if (rl->write_cbc == NULL) {
00093                         wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
00094                                    "cipher");
00095                         return -1;
00096                 }
00097         }
00098 
00099         return 0;
00100 }
00101 
00102 
00111 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
00112 {
00113         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
00114                    "0x%04x", rl->cipher_suite);
00115         rl->read_cipher_suite = rl->cipher_suite;
00116         os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
00117 
00118         if (rl->read_cbc) {
00119                 crypto_cipher_deinit(rl->read_cbc);
00120                 rl->read_cbc = NULL;
00121         }
00122         if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
00123                 rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
00124                                                   rl->read_iv, rl->read_key,
00125                                                   rl->key_material_len);
00126                 if (rl->read_cbc == NULL) {
00127                         wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
00128                                    "cipher");
00129                         return -1;
00130                 }
00131         }
00132 
00133         return 0;
00134 }
00135 
00136 
00152 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
00153                       size_t buf_size, size_t payload_len, size_t *out_len)
00154 {
00155         u8 *pos, *ct_start, *length, *payload;
00156         struct crypto_hash *hmac;
00157         size_t clen;
00158 
00159         pos = buf;
00160         /* ContentType type */
00161         ct_start = pos;
00162         *pos++ = content_type;
00163         /* ProtocolVersion version */
00164         WPA_PUT_BE16(pos, TLS_VERSION);
00165         pos += 2;
00166         /* uint16 length */
00167         length = pos;
00168         WPA_PUT_BE16(length, payload_len);
00169         pos += 2;
00170 
00171         /* opaque fragment[TLSPlaintext.length] */
00172         payload = pos;
00173         pos += payload_len;
00174 
00175         if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
00176                 hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
00177                                         rl->hash_size);
00178                 if (hmac == NULL) {
00179                         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
00180                                    "to initialize HMAC");
00181                         return -1;
00182                 }
00183                 crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
00184                 /* type + version + length + fragment */
00185                 crypto_hash_update(hmac, ct_start, pos - ct_start);
00186                 clen = buf + buf_size - pos;
00187                 if (clen < rl->hash_size) {
00188                         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
00189                                    "enough room for MAC");
00190                         crypto_hash_finish(hmac, NULL, NULL);
00191                         return -1;
00192                 }
00193 
00194                 if (crypto_hash_finish(hmac, pos, &clen) < 0) {
00195                         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
00196                                    "to calculate HMAC");
00197                         return -1;
00198                 }
00199                 wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
00200                             pos, clen);
00201                 pos += clen;
00202                 if (rl->iv_size) {
00203                         size_t len = pos - payload;
00204                         size_t pad;
00205                         pad = (len + 1) % rl->iv_size;
00206                         if (pad)
00207                                 pad = rl->iv_size - pad;
00208                         if (pos + pad + 1 > buf + buf_size) {
00209                                 wpa_printf(MSG_DEBUG, "TLSv1: No room for "
00210                                            "block cipher padding");
00211                                 return -1;
00212                         }
00213                         os_memset(pos, pad, pad + 1);
00214                         pos += pad + 1;
00215                 }
00216 
00217                 if (crypto_cipher_encrypt(rl->write_cbc, payload,
00218                                           payload, pos - payload) < 0)
00219                         return -1;
00220         }
00221 
00222         WPA_PUT_BE16(length, pos - length - 2);
00223         inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
00224 
00225         *out_len = pos - buf;
00226 
00227         return 0;
00228 }
00229 
00230 
00245 int tlsv1_record_receive(struct tlsv1_record_layer *rl,
00246                          const u8 *in_data, size_t in_len,
00247                          u8 *out_data, size_t *out_len, u8 *alert)
00248 {
00249         size_t i, rlen, hlen;
00250         u8 padlen;
00251         struct crypto_hash *hmac;
00252         u8 len[2], hash[100];
00253 
00254         wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
00255                     in_data, in_len);
00256 
00257         if (in_len < TLS_RECORD_HEADER_LEN) {
00258                 wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
00259                            (unsigned long) in_len);
00260                 *alert = TLS_ALERT_DECODE_ERROR;
00261                 return -1;
00262         }
00263 
00264         wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
00265                    "length %d", in_data[0], in_data[1], in_data[2],
00266                    WPA_GET_BE16(in_data + 3));
00267 
00268         if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
00269             in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
00270             in_data[0] != TLS_CONTENT_TYPE_ALERT &&
00271             in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
00272                 wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
00273                            in_data[0]);
00274                 *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
00275                 return -1;
00276         }
00277 
00278         if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
00279                 wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
00280                            "%d.%d", in_data[1], in_data[2]);
00281                 *alert = TLS_ALERT_PROTOCOL_VERSION;
00282                 return -1;
00283         }
00284 
00285         rlen = WPA_GET_BE16(in_data + 3);
00286 
00287         /* TLSCiphertext must not be more than 2^14+2048 bytes */
00288         if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
00289                 wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
00290                            (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
00291                 *alert = TLS_ALERT_RECORD_OVERFLOW;
00292                 return -1;
00293         }
00294 
00295         in_data += TLS_RECORD_HEADER_LEN;
00296         in_len -= TLS_RECORD_HEADER_LEN;
00297 
00298         if (rlen > in_len) {
00299                 wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
00300                            "(rlen=%lu > in_len=%lu)",
00301                            (unsigned long) rlen, (unsigned long) in_len);
00302                 *alert = TLS_ALERT_DECODE_ERROR;
00303                 return -1;
00304         }
00305 
00306         in_len = rlen;
00307 
00308         if (*out_len < in_len) {
00309                 wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
00310                            "processing received record");
00311                 *alert = TLS_ALERT_INTERNAL_ERROR;
00312                 return -1;
00313         }
00314 
00315         os_memcpy(out_data, in_data, in_len);
00316         *out_len = in_len;
00317 
00318         if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
00319                 if (crypto_cipher_decrypt(rl->read_cbc, out_data,
00320                                           out_data, in_len) < 0) {
00321                         *alert = TLS_ALERT_DECRYPTION_FAILED;
00322                         return -1;
00323                 }
00324                 if (rl->iv_size) {
00325                         if (in_len == 0) {
00326                                 wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
00327                                            " (no pad)");
00328                                 *alert = TLS_ALERT_DECODE_ERROR;
00329                                 return -1;
00330                         }
00331                         padlen = out_data[in_len - 1];
00332                         if (padlen >= in_len) {
00333                                 wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
00334                                            "length (%u, in_len=%lu) in "
00335                                            "received record",
00336                                            padlen, (unsigned long) in_len);
00337                                 *alert = TLS_ALERT_DECRYPTION_FAILED;
00338                                 return -1;
00339                         }
00340                         for (i = in_len - padlen; i < in_len; i++) {
00341                                 if (out_data[i] != padlen) {
00342                                         wpa_hexdump(MSG_DEBUG,
00343                                                     "TLSv1: Invalid pad in "
00344                                                     "received record",
00345                                                     out_data + in_len - padlen,
00346                                                     padlen);
00347                                         *alert = TLS_ALERT_DECRYPTION_FAILED;
00348                                         return -1;
00349                                 }
00350                         }
00351 
00352                         *out_len -= padlen + 1;
00353                 }
00354 
00355                 wpa_hexdump(MSG_MSGDUMP,
00356                             "TLSv1: Record Layer - Decrypted data",
00357                             out_data, in_len);
00358 
00359                 if (*out_len < rl->hash_size) {
00360                         wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
00361                                    "hash value");
00362                         *alert = TLS_ALERT_INTERNAL_ERROR;
00363                         return -1;
00364                 }
00365 
00366                 *out_len -= rl->hash_size;
00367 
00368                 hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
00369                                         rl->hash_size);
00370                 if (hmac == NULL) {
00371                         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
00372                                    "to initialize HMAC");
00373                         *alert = TLS_ALERT_INTERNAL_ERROR;
00374                         return -1;
00375                 }
00376 
00377                 crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
00378                 /* type + version + length + fragment */
00379                 crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
00380                 WPA_PUT_BE16(len, *out_len);
00381                 crypto_hash_update(hmac, len, 2);
00382                 crypto_hash_update(hmac, out_data, *out_len);
00383                 hlen = sizeof(hash);
00384                 if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
00385                         wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
00386                                    "to calculate HMAC");
00387                         return -1;
00388                 }
00389                 if (hlen != rl->hash_size ||
00390                     os_memcmp(hash, out_data + *out_len, hlen) != 0) {
00391                         wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
00392                                    "received message");
00393                         *alert = TLS_ALERT_BAD_RECORD_MAC;
00394                         return -1;
00395                 }
00396         }
00397 
00398         /* TLSCompressed must not be more than 2^14+1024 bytes */
00399         if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
00400                 wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
00401                            (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
00402                 *alert = TLS_ALERT_RECORD_OVERFLOW;
00403                 return -1;
00404         }
00405 
00406         inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
00407 
00408         return 0;
00409 }


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:25:14