• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * TLSv1 Record Protocol
3  * Copyright (c) 2006-2007, Jouni Malinen <j@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  */
tlsv1_record_set_cipher_suite(struct tlsv1_record_layer * rl,u16 cipher_suite)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  */
tlsv1_record_change_write_cipher(struct tlsv1_record_layer * rl)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  */
tlsv1_record_change_read_cipher(struct tlsv1_record_layer * rl)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  */
tlsv1_record_send(struct tlsv1_record_layer * rl,u8 content_type,u8 * buf,size_t buf_size,size_t payload_len,size_t * out_len)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  */
tlsv1_record_receive(struct tlsv1_record_layer * rl,const u8 * in_data,size_t in_len,u8 * out_data,size_t * out_len,u8 * alert)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