Home | History | Annotate | Download | only in tls
      1 /*
      2  * TLSv1 Record Protocol
      3  * Copyright (c) 2006-2007, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "crypto/md5.h"
     19 #include "crypto/sha1.h"
     20 #include "tlsv1_common.h"
     21 #include "tlsv1_record.h"
     22 
     23 
     24 /**
     25  * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
     26  * @rl: Pointer to TLS record layer data
     27  * @cipher_suite: New cipher suite
     28  * Returns: 0 on success, -1 on failure
     29  *
     30  * This function is used to prepare TLS record layer for cipher suite change.
     31  * tlsv1_record_change_write_cipher() and
     32  * tlsv1_record_change_read_cipher() functions can then be used to change the
     33  * currently used ciphers.
     34  */
     35 int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
     36 				  u16 cipher_suite)
     37 {
     38 	const struct tls_cipher_suite *suite;
     39 	const struct tls_cipher_data *data;
     40 
     41 	wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
     42 		   cipher_suite);
     43 	rl->cipher_suite = cipher_suite;
     44 
     45 	suite = tls_get_cipher_suite(cipher_suite);
     46 	if (suite == NULL)
     47 		return -1;
     48 
     49 	if (suite->hash == TLS_HASH_MD5) {
     50 		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
     51 		rl->hash_size = MD5_MAC_LEN;
     52 	} else if (suite->hash == TLS_HASH_SHA) {
     53 		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
     54 		rl->hash_size = SHA1_MAC_LEN;
     55 	}
     56 
     57 	data = tls_get_cipher_data(suite->cipher);
     58 	if (data == NULL)
     59 		return -1;
     60 
     61 	rl->key_material_len = data->key_material;
     62 	rl->iv_size = data->block_size;
     63 	rl->cipher_alg = data->alg;
     64 
     65 	return 0;
     66 }
     67 
     68 
     69 /**
     70  * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
     71  * @rl: Pointer to TLS record layer data
     72  * Returns: 0 on success (cipher changed), -1 on failure
     73  *
     74  * This function changes TLS record layer to use the new cipher suite
     75  * configured with tlsv1_record_set_cipher_suite() for writing.
     76  */
     77 int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
     78 {
     79 	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
     80 		   "0x%04x", rl->cipher_suite);
     81 	rl->write_cipher_suite = rl->cipher_suite;
     82 	os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
     83 
     84 	if (rl->write_cbc) {
     85 		crypto_cipher_deinit(rl->write_cbc);
     86 		rl->write_cbc = NULL;
     87 	}
     88 	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
     89 		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
     90 						   rl->write_iv, rl->write_key,
     91 						   rl->key_material_len);
     92 		if (rl->write_cbc == NULL) {
     93 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
     94 				   "cipher");
     95 			return -1;
     96 		}
     97 	}
     98 
     99 	return 0;
    100 }
    101 
    102 
    103 /**
    104  * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
    105  * @rl: Pointer to TLS record layer data
    106  * Returns: 0 on success (cipher changed), -1 on failure
    107  *
    108  * This function changes TLS record layer to use the new cipher suite
    109  * configured with tlsv1_record_set_cipher_suite() for reading.
    110  */
    111 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
    112 {
    113 	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
    114 		   "0x%04x", rl->cipher_suite);
    115 	rl->read_cipher_suite = rl->cipher_suite;
    116 	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
    117 
    118 	if (rl->read_cbc) {
    119 		crypto_cipher_deinit(rl->read_cbc);
    120 		rl->read_cbc = NULL;
    121 	}
    122 	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
    123 		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
    124 						  rl->read_iv, rl->read_key,
    125 						  rl->key_material_len);
    126 		if (rl->read_cbc == NULL) {
    127 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
    128 				   "cipher");
    129 			return -1;
    130 		}
    131 	}
    132 
    133 	return 0;
    134 }
    135 
    136 
    137 /**
    138  * tlsv1_record_send - TLS record layer: Send a message
    139  * @rl: Pointer to TLS record layer data
    140  * @content_type: Content type (TLS_CONTENT_TYPE_*)
    141  * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
    142  * beginning for record layer to fill in; payload filled in after this and
    143  * extra space in the end for HMAC).
    144  * @buf_size: Maximum buf size
    145  * @payload_len: Length of the payload
    146  * @out_len: Buffer for returning the used buf length
    147  * Returns: 0 on success, -1 on failure
    148  *
    149  * This function fills in the TLS record layer header, adds HMAC, and encrypts
    150  * the data using the current write cipher.
    151  */
    152 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
    153 		      size_t buf_size, size_t payload_len, size_t *out_len)
    154 {
    155 	u8 *pos, *ct_start, *length, *payload;
    156 	struct crypto_hash *hmac;
    157 	size_t clen;
    158 
    159 	pos = buf;
    160 	/* ContentType type */
    161 	ct_start = pos;
    162 	*pos++ = content_type;
    163 	/* ProtocolVersion version */
    164 	WPA_PUT_BE16(pos, TLS_VERSION);
    165 	pos += 2;
    166 	/* uint16 length */
    167 	length = pos;
    168 	WPA_PUT_BE16(length, payload_len);
    169 	pos += 2;
    170 
    171 	/* opaque fragment[TLSPlaintext.length] */
    172 	payload = pos;
    173 	pos += payload_len;
    174 
    175 	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
    176 		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
    177 					rl->hash_size);
    178 		if (hmac == NULL) {
    179 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
    180 				   "to initialize HMAC");
    181 			return -1;
    182 		}
    183 		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
    184 		/* type + version + length + fragment */
    185 		crypto_hash_update(hmac, ct_start, pos - ct_start);
    186 		clen = buf + buf_size - pos;
    187 		if (clen < rl->hash_size) {
    188 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
    189 				   "enough room for MAC");
    190 			crypto_hash_finish(hmac, NULL, NULL);
    191 			return -1;
    192 		}
    193 
    194 		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
    195 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
    196 				   "to calculate HMAC");
    197 			return -1;
    198 		}
    199 		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
    200 			    pos, clen);
    201 		pos += clen;
    202 		if (rl->iv_size) {
    203 			size_t len = pos - payload;
    204 			size_t pad;
    205 			pad = (len + 1) % rl->iv_size;
    206 			if (pad)
    207 				pad = rl->iv_size - pad;
    208 			if (pos + pad + 1 > buf + buf_size) {
    209 				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
    210 					   "block cipher padding");
    211 				return -1;
    212 			}
    213 			os_memset(pos, pad, pad + 1);
    214 			pos += pad + 1;
    215 		}
    216 
    217 		if (crypto_cipher_encrypt(rl->write_cbc, payload,
    218 					  payload, pos - payload) < 0)
    219 			return -1;
    220 	}
    221 
    222 	WPA_PUT_BE16(length, pos - length - 2);
    223 	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
    224 
    225 	*out_len = pos - buf;
    226 
    227 	return 0;
    228 }
    229 
    230 
    231 /**
    232  * tlsv1_record_receive - TLS record layer: Process a received message
    233  * @rl: Pointer to TLS record layer data
    234  * @in_data: Received data
    235  * @in_len: Length of the received data
    236  * @out_data: Buffer for output data (must be at least as long as in_data)
    237  * @out_len: Set to maximum out_data length by caller; used to return the
    238  * length of the used data
    239  * @alert: Buffer for returning an alert value on failure
    240  * Returns: 0 on success, -1 on failure
    241  *
    242  * This function decrypts the received message, verifies HMAC and TLS record
    243  * layer header.
    244  */
    245 int tlsv1_record_receive(struct tlsv1_record_layer *rl,
    246 			 const u8 *in_data, size_t in_len,
    247 			 u8 *out_data, size_t *out_len, u8 *alert)
    248 {
    249 	size_t i, rlen, hlen;
    250 	u8 padlen;
    251 	struct crypto_hash *hmac;
    252 	u8 len[2], hash[100];
    253 
    254 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
    255 		    in_data, in_len);
    256 
    257 	if (in_len < TLS_RECORD_HEADER_LEN) {
    258 		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
    259 			   (unsigned long) in_len);
    260 		*alert = TLS_ALERT_DECODE_ERROR;
    261 		return -1;
    262 	}
    263 
    264 	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
    265 		   "length %d", in_data[0], in_data[1], in_data[2],
    266 		   WPA_GET_BE16(in_data + 3));
    267 
    268 	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
    269 	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
    270 	    in_data[0] != TLS_CONTENT_TYPE_ALERT &&
    271 	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
    272 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
    273 			   in_data[0]);
    274 		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
    275 		return -1;
    276 	}
    277 
    278 	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
    279 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
    280 			   "%d.%d", in_data[1], in_data[2]);
    281 		*alert = TLS_ALERT_PROTOCOL_VERSION;
    282 		return -1;
    283 	}
    284 
    285 	rlen = WPA_GET_BE16(in_data + 3);
    286 
    287 	/* TLSCiphertext must not be more than 2^14+2048 bytes */
    288 	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
    289 		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
    290 			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
    291 		*alert = TLS_ALERT_RECORD_OVERFLOW;
    292 		return -1;
    293 	}
    294 
    295 	in_data += TLS_RECORD_HEADER_LEN;
    296 	in_len -= TLS_RECORD_HEADER_LEN;
    297 
    298 	if (rlen > in_len) {
    299 		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
    300 			   "(rlen=%lu > in_len=%lu)",
    301 			   (unsigned long) rlen, (unsigned long) in_len);
    302 		*alert = TLS_ALERT_DECODE_ERROR;
    303 		return -1;
    304 	}
    305 
    306 	in_len = rlen;
    307 
    308 	if (*out_len < in_len) {
    309 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
    310 			   "processing received record");
    311 		*alert = TLS_ALERT_INTERNAL_ERROR;
    312 		return -1;
    313 	}
    314 
    315 	os_memcpy(out_data, in_data, in_len);
    316 	*out_len = in_len;
    317 
    318 	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
    319 		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
    320 					  out_data, in_len) < 0) {
    321 			*alert = TLS_ALERT_DECRYPTION_FAILED;
    322 			return -1;
    323 		}
    324 		if (rl->iv_size) {
    325 			if (in_len == 0) {
    326 				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
    327 					   " (no pad)");
    328 				*alert = TLS_ALERT_DECODE_ERROR;
    329 				return -1;
    330 			}
    331 			padlen = out_data[in_len - 1];
    332 			if (padlen >= in_len) {
    333 				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
    334 					   "length (%u, in_len=%lu) in "
    335 					   "received record",
    336 					   padlen, (unsigned long) in_len);
    337 				*alert = TLS_ALERT_DECRYPTION_FAILED;
    338 				return -1;
    339 			}
    340 			for (i = in_len - padlen; i < in_len; i++) {
    341 				if (out_data[i] != padlen) {
    342 					wpa_hexdump(MSG_DEBUG,
    343 						    "TLSv1: Invalid pad in "
    344 						    "received record",
    345 						    out_data + in_len - padlen,
    346 						    padlen);
    347 					*alert = TLS_ALERT_DECRYPTION_FAILED;
    348 					return -1;
    349 				}
    350 			}
    351 
    352 			*out_len -= padlen + 1;
    353 		}
    354 
    355 		wpa_hexdump(MSG_MSGDUMP,
    356 			    "TLSv1: Record Layer - Decrypted data",
    357 			    out_data, in_len);
    358 
    359 		if (*out_len < rl->hash_size) {
    360 			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
    361 				   "hash value");
    362 			*alert = TLS_ALERT_INTERNAL_ERROR;
    363 			return -1;
    364 		}
    365 
    366 		*out_len -= rl->hash_size;
    367 
    368 		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
    369 					rl->hash_size);
    370 		if (hmac == NULL) {
    371 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
    372 				   "to initialize HMAC");
    373 			*alert = TLS_ALERT_INTERNAL_ERROR;
    374 			return -1;
    375 		}
    376 
    377 		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
    378 		/* type + version + length + fragment */
    379 		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
    380 		WPA_PUT_BE16(len, *out_len);
    381 		crypto_hash_update(hmac, len, 2);
    382 		crypto_hash_update(hmac, out_data, *out_len);
    383 		hlen = sizeof(hash);
    384 		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
    385 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
    386 				   "to calculate HMAC");
    387 			return -1;
    388 		}
    389 		if (hlen != rl->hash_size ||
    390 		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
    391 			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
    392 				   "received message");
    393 			*alert = TLS_ALERT_BAD_RECORD_MAC;
    394 			return -1;
    395 		}
    396 	}
    397 
    398 	/* TLSCompressed must not be more than 2^14+1024 bytes */
    399 	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
    400 		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
    401 			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
    402 		*alert = TLS_ALERT_RECORD_OVERFLOW;
    403 		return -1;
    404 	}
    405 
    406 	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
    407 
    408 	return 0;
    409 }
    410