tlsv1_record.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
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 */
35int 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 */
77int 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 */
111int 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 */
152int 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 */
245int 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