1189251Ssam/*
2189251Ssam * TLSv1 Record Protocol
3252726Srpaulo * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/md5.h"
13214734Srpaulo#include "crypto/sha1.h"
14252726Srpaulo#include "crypto/sha256.h"
15189251Ssam#include "tlsv1_common.h"
16189251Ssam#include "tlsv1_record.h"
17189251Ssam
18189251Ssam
19189251Ssam/**
20189251Ssam * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
21189251Ssam * @rl: Pointer to TLS record layer data
22189251Ssam * @cipher_suite: New cipher suite
23189251Ssam * Returns: 0 on success, -1 on failure
24189251Ssam *
25189251Ssam * This function is used to prepare TLS record layer for cipher suite change.
26189251Ssam * tlsv1_record_change_write_cipher() and
27189251Ssam * tlsv1_record_change_read_cipher() functions can then be used to change the
28189251Ssam * currently used ciphers.
29189251Ssam */
30189251Ssamint tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
31189251Ssam				  u16 cipher_suite)
32189251Ssam{
33189251Ssam	const struct tls_cipher_suite *suite;
34189251Ssam	const struct tls_cipher_data *data;
35189251Ssam
36189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
37189251Ssam		   cipher_suite);
38189251Ssam	rl->cipher_suite = cipher_suite;
39189251Ssam
40189251Ssam	suite = tls_get_cipher_suite(cipher_suite);
41189251Ssam	if (suite == NULL)
42189251Ssam		return -1;
43189251Ssam
44189251Ssam	if (suite->hash == TLS_HASH_MD5) {
45189251Ssam		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
46189251Ssam		rl->hash_size = MD5_MAC_LEN;
47189251Ssam	} else if (suite->hash == TLS_HASH_SHA) {
48189251Ssam		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
49189251Ssam		rl->hash_size = SHA1_MAC_LEN;
50252726Srpaulo	} else if (suite->hash == TLS_HASH_SHA256) {
51252726Srpaulo		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
52252726Srpaulo		rl->hash_size = SHA256_MAC_LEN;
53189251Ssam	}
54189251Ssam
55189251Ssam	data = tls_get_cipher_data(suite->cipher);
56189251Ssam	if (data == NULL)
57189251Ssam		return -1;
58189251Ssam
59189251Ssam	rl->key_material_len = data->key_material;
60189251Ssam	rl->iv_size = data->block_size;
61189251Ssam	rl->cipher_alg = data->alg;
62189251Ssam
63189251Ssam	return 0;
64189251Ssam}
65189251Ssam
66189251Ssam
67189251Ssam/**
68189251Ssam * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
69189251Ssam * @rl: Pointer to TLS record layer data
70189251Ssam * Returns: 0 on success (cipher changed), -1 on failure
71189251Ssam *
72189251Ssam * This function changes TLS record layer to use the new cipher suite
73189251Ssam * configured with tlsv1_record_set_cipher_suite() for writing.
74189251Ssam */
75189251Ssamint tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
76189251Ssam{
77189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
78189251Ssam		   "0x%04x", rl->cipher_suite);
79189251Ssam	rl->write_cipher_suite = rl->cipher_suite;
80189251Ssam	os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
81189251Ssam
82189251Ssam	if (rl->write_cbc) {
83189251Ssam		crypto_cipher_deinit(rl->write_cbc);
84189251Ssam		rl->write_cbc = NULL;
85189251Ssam	}
86189251Ssam	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
87189251Ssam		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
88189251Ssam						   rl->write_iv, rl->write_key,
89189251Ssam						   rl->key_material_len);
90189251Ssam		if (rl->write_cbc == NULL) {
91189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
92189251Ssam				   "cipher");
93189251Ssam			return -1;
94189251Ssam		}
95189251Ssam	}
96189251Ssam
97189251Ssam	return 0;
98189251Ssam}
99189251Ssam
100189251Ssam
101189251Ssam/**
102189251Ssam * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
103189251Ssam * @rl: Pointer to TLS record layer data
104189251Ssam * Returns: 0 on success (cipher changed), -1 on failure
105189251Ssam *
106189251Ssam * This function changes TLS record layer to use the new cipher suite
107189251Ssam * configured with tlsv1_record_set_cipher_suite() for reading.
108189251Ssam */
109189251Ssamint tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
110189251Ssam{
111189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
112189251Ssam		   "0x%04x", rl->cipher_suite);
113189251Ssam	rl->read_cipher_suite = rl->cipher_suite;
114189251Ssam	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
115189251Ssam
116189251Ssam	if (rl->read_cbc) {
117189251Ssam		crypto_cipher_deinit(rl->read_cbc);
118189251Ssam		rl->read_cbc = NULL;
119189251Ssam	}
120189251Ssam	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
121189251Ssam		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
122189251Ssam						  rl->read_iv, rl->read_key,
123189251Ssam						  rl->key_material_len);
124189251Ssam		if (rl->read_cbc == NULL) {
125189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
126189251Ssam				   "cipher");
127189251Ssam			return -1;
128189251Ssam		}
129189251Ssam	}
130189251Ssam
131189251Ssam	return 0;
132189251Ssam}
133189251Ssam
134189251Ssam
135189251Ssam/**
136189251Ssam * tlsv1_record_send - TLS record layer: Send a message
137189251Ssam * @rl: Pointer to TLS record layer data
138189251Ssam * @content_type: Content type (TLS_CONTENT_TYPE_*)
139252726Srpaulo * @buf: Buffer for the generated TLS message (needs to have extra space for
140252726Srpaulo * header, IV (TLS v1.1), and HMAC)
141189251Ssam * @buf_size: Maximum buf size
142252726Srpaulo * @payload: Payload to be sent
143189251Ssam * @payload_len: Length of the payload
144189251Ssam * @out_len: Buffer for returning the used buf length
145189251Ssam * Returns: 0 on success, -1 on failure
146189251Ssam *
147189251Ssam * This function fills in the TLS record layer header, adds HMAC, and encrypts
148189251Ssam * the data using the current write cipher.
149189251Ssam */
150189251Ssamint tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
151252726Srpaulo		      size_t buf_size, const u8 *payload, size_t payload_len,
152252726Srpaulo		      size_t *out_len)
153189251Ssam{
154252726Srpaulo	u8 *pos, *ct_start, *length, *cpayload;
155189251Ssam	struct crypto_hash *hmac;
156189251Ssam	size_t clen;
157252726Srpaulo	int explicit_iv;
158189251Ssam
159189251Ssam	pos = buf;
160252726Srpaulo	if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
161252726Srpaulo		return -1;
162252726Srpaulo
163189251Ssam	/* ContentType type */
164189251Ssam	ct_start = pos;
165189251Ssam	*pos++ = content_type;
166189251Ssam	/* ProtocolVersion version */
167252726Srpaulo	WPA_PUT_BE16(pos, rl->tls_version);
168189251Ssam	pos += 2;
169189251Ssam	/* uint16 length */
170189251Ssam	length = pos;
171189251Ssam	WPA_PUT_BE16(length, payload_len);
172189251Ssam	pos += 2;
173189251Ssam
174252726Srpaulo	cpayload = pos;
175252726Srpaulo	explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
176252726Srpaulo		rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
177252726Srpaulo	if (explicit_iv) {
178252726Srpaulo		/* opaque IV[Cipherspec.block_length] */
179252726Srpaulo		if (pos + rl->iv_size > buf + buf_size)
180252726Srpaulo			return -1;
181252726Srpaulo
182252726Srpaulo		/*
183252726Srpaulo		 * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
184252726Srpaulo		 * Cipher option 2a.
185252726Srpaulo		 */
186252726Srpaulo
187252726Srpaulo		if (os_get_random(pos, rl->iv_size))
188252726Srpaulo			return -1;
189252726Srpaulo		pos += rl->iv_size;
190252726Srpaulo	}
191252726Srpaulo
192252726Srpaulo	/*
193252726Srpaulo	 * opaque fragment[TLSPlaintext.length]
194252726Srpaulo	 * (opaque content[TLSCompressed.length] in GenericBlockCipher)
195252726Srpaulo	 */
196252726Srpaulo	if (pos + payload_len > buf + buf_size)
197252726Srpaulo		return -1;
198252726Srpaulo	os_memmove(pos, payload, payload_len);
199189251Ssam	pos += payload_len;
200189251Ssam
201189251Ssam	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
202252726Srpaulo		/*
203252726Srpaulo		 * MAC calculated over seq_num + TLSCompressed.type +
204252726Srpaulo		 * TLSCompressed.version + TLSCompressed.length +
205252726Srpaulo		 * TLSCompressed.fragment
206252726Srpaulo		 */
207189251Ssam		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
208189251Ssam					rl->hash_size);
209189251Ssam		if (hmac == NULL) {
210189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
211189251Ssam				   "to initialize HMAC");
212189251Ssam			return -1;
213189251Ssam		}
214189251Ssam		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
215189251Ssam		/* type + version + length + fragment */
216252726Srpaulo		crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
217252726Srpaulo		crypto_hash_update(hmac, payload, payload_len);
218189251Ssam		clen = buf + buf_size - pos;
219189251Ssam		if (clen < rl->hash_size) {
220189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
221189251Ssam				   "enough room for MAC");
222189251Ssam			crypto_hash_finish(hmac, NULL, NULL);
223189251Ssam			return -1;
224189251Ssam		}
225189251Ssam
226189251Ssam		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
227189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
228189251Ssam				   "to calculate HMAC");
229189251Ssam			return -1;
230189251Ssam		}
231189251Ssam		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
232189251Ssam			    pos, clen);
233189251Ssam		pos += clen;
234189251Ssam		if (rl->iv_size) {
235252726Srpaulo			size_t len = pos - cpayload;
236189251Ssam			size_t pad;
237189251Ssam			pad = (len + 1) % rl->iv_size;
238189251Ssam			if (pad)
239189251Ssam				pad = rl->iv_size - pad;
240189251Ssam			if (pos + pad + 1 > buf + buf_size) {
241189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
242189251Ssam					   "block cipher padding");
243189251Ssam				return -1;
244189251Ssam			}
245189251Ssam			os_memset(pos, pad, pad + 1);
246189251Ssam			pos += pad + 1;
247189251Ssam		}
248189251Ssam
249252726Srpaulo		if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
250252726Srpaulo					  cpayload, pos - cpayload) < 0)
251189251Ssam			return -1;
252189251Ssam	}
253189251Ssam
254189251Ssam	WPA_PUT_BE16(length, pos - length - 2);
255189251Ssam	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
256189251Ssam
257189251Ssam	*out_len = pos - buf;
258189251Ssam
259189251Ssam	return 0;
260189251Ssam}
261189251Ssam
262189251Ssam
263189251Ssam/**
264189251Ssam * tlsv1_record_receive - TLS record layer: Process a received message
265189251Ssam * @rl: Pointer to TLS record layer data
266189251Ssam * @in_data: Received data
267189251Ssam * @in_len: Length of the received data
268189251Ssam * @out_data: Buffer for output data (must be at least as long as in_data)
269189251Ssam * @out_len: Set to maximum out_data length by caller; used to return the
270189251Ssam * length of the used data
271189251Ssam * @alert: Buffer for returning an alert value on failure
272252726Srpaulo * Returns: Number of bytes used from in_data on success, 0 if record was not
273252726Srpaulo *	complete (more data needed), or -1 on failure
274189251Ssam *
275189251Ssam * This function decrypts the received message, verifies HMAC and TLS record
276189251Ssam * layer header.
277189251Ssam */
278189251Ssamint tlsv1_record_receive(struct tlsv1_record_layer *rl,
279189251Ssam			 const u8 *in_data, size_t in_len,
280189251Ssam			 u8 *out_data, size_t *out_len, u8 *alert)
281189251Ssam{
282189251Ssam	size_t i, rlen, hlen;
283189251Ssam	u8 padlen;
284189251Ssam	struct crypto_hash *hmac;
285189251Ssam	u8 len[2], hash[100];
286252726Srpaulo	int force_mac_error = 0;
287252726Srpaulo	u8 ct;
288189251Ssam
289189251Ssam	if (in_len < TLS_RECORD_HEADER_LEN) {
290252726Srpaulo		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
291252726Srpaulo			   "need more data",
292189251Ssam			   (unsigned long) in_len);
293252726Srpaulo		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
294252726Srpaulo			    in_data, in_len);
295252726Srpaulo		return 0;
296189251Ssam	}
297189251Ssam
298252726Srpaulo	ct = in_data[0];
299252726Srpaulo	rlen = WPA_GET_BE16(in_data + 3);
300189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
301252726Srpaulo		   "length %d", ct, in_data[1], in_data[2], (int) rlen);
302189251Ssam
303252726Srpaulo	/*
304252726Srpaulo	 * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
305252726Srpaulo	 * protocol version in record layer. As such, accept any {03,xx} value
306252726Srpaulo	 * to remain compatible with existing implementations.
307252726Srpaulo	 */
308252726Srpaulo	if (in_data[1] != 0x03) {
309189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
310252726Srpaulo			   "%u.%u", in_data[1], in_data[2]);
311189251Ssam		*alert = TLS_ALERT_PROTOCOL_VERSION;
312189251Ssam		return -1;
313189251Ssam	}
314189251Ssam
315189251Ssam	/* TLSCiphertext must not be more than 2^14+2048 bytes */
316189251Ssam	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
317189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
318189251Ssam			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
319189251Ssam		*alert = TLS_ALERT_RECORD_OVERFLOW;
320189251Ssam		return -1;
321189251Ssam	}
322189251Ssam
323189251Ssam	in_data += TLS_RECORD_HEADER_LEN;
324189251Ssam	in_len -= TLS_RECORD_HEADER_LEN;
325189251Ssam
326189251Ssam	if (rlen > in_len) {
327189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
328189251Ssam			   "(rlen=%lu > in_len=%lu)",
329189251Ssam			   (unsigned long) rlen, (unsigned long) in_len);
330252726Srpaulo		return 0;
331252726Srpaulo	}
332252726Srpaulo
333252726Srpaulo	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
334252726Srpaulo		    in_data, rlen);
335252726Srpaulo
336252726Srpaulo	if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
337252726Srpaulo	    ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
338252726Srpaulo	    ct != TLS_CONTENT_TYPE_ALERT &&
339252726Srpaulo	    ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
340252726Srpaulo		wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
341252726Srpaulo			   "content type 0x%x", ct);
342252726Srpaulo		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
343189251Ssam		return -1;
344189251Ssam	}
345189251Ssam
346189251Ssam	in_len = rlen;
347189251Ssam
348189251Ssam	if (*out_len < in_len) {
349189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
350189251Ssam			   "processing received record");
351189251Ssam		*alert = TLS_ALERT_INTERNAL_ERROR;
352189251Ssam		return -1;
353189251Ssam	}
354189251Ssam
355189251Ssam	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
356252726Srpaulo		size_t plen;
357252726Srpaulo		if (crypto_cipher_decrypt(rl->read_cbc, in_data,
358189251Ssam					  out_data, in_len) < 0) {
359189251Ssam			*alert = TLS_ALERT_DECRYPTION_FAILED;
360189251Ssam			return -1;
361189251Ssam		}
362252726Srpaulo		plen = in_len;
363252726Srpaulo		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
364252726Srpaulo				"data", out_data, plen);
365252726Srpaulo
366189251Ssam		if (rl->iv_size) {
367252726Srpaulo			/*
368252726Srpaulo			 * TLS v1.0 defines different alert values for various
369252726Srpaulo			 * failures. That may information to aid in attacks, so
370252726Srpaulo			 * use the same bad_record_mac alert regardless of the
371252726Srpaulo			 * issues.
372252726Srpaulo			 *
373252726Srpaulo			 * In addition, instead of returning immediately on
374252726Srpaulo			 * error, run through the MAC check to make timing
375252726Srpaulo			 * attacks more difficult.
376252726Srpaulo			 */
377252726Srpaulo
378252726Srpaulo			if (rl->tls_version >= TLS_VERSION_1_1) {
379252726Srpaulo				/* Remove opaque IV[Cipherspec.block_length] */
380252726Srpaulo				if (plen < rl->iv_size) {
381252726Srpaulo					wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
382252726Srpaulo						   "enough room for IV");
383252726Srpaulo					force_mac_error = 1;
384252726Srpaulo					goto check_mac;
385252726Srpaulo				}
386252726Srpaulo				os_memmove(out_data, out_data + rl->iv_size,
387252726Srpaulo					   plen - rl->iv_size);
388252726Srpaulo				plen -= rl->iv_size;
389252726Srpaulo			}
390252726Srpaulo
391252726Srpaulo			/* Verify and remove padding */
392252726Srpaulo			if (plen == 0) {
393189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
394189251Ssam					   " (no pad)");
395252726Srpaulo				force_mac_error = 1;
396252726Srpaulo				goto check_mac;
397189251Ssam			}
398252726Srpaulo			padlen = out_data[plen - 1];
399252726Srpaulo			if (padlen >= plen) {
400189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
401252726Srpaulo					   "length (%u, plen=%lu) in "
402189251Ssam					   "received record",
403252726Srpaulo					   padlen, (unsigned long) plen);
404252726Srpaulo				force_mac_error = 1;
405252726Srpaulo				goto check_mac;
406189251Ssam			}
407252726Srpaulo			for (i = plen - padlen - 1; i < plen - 1; i++) {
408189251Ssam				if (out_data[i] != padlen) {
409189251Ssam					wpa_hexdump(MSG_DEBUG,
410189251Ssam						    "TLSv1: Invalid pad in "
411189251Ssam						    "received record",
412252726Srpaulo						    out_data + plen - padlen -
413252726Srpaulo						    1, padlen + 1);
414252726Srpaulo					force_mac_error = 1;
415252726Srpaulo					goto check_mac;
416189251Ssam				}
417189251Ssam			}
418189251Ssam
419252726Srpaulo			plen -= padlen + 1;
420252726Srpaulo
421252726Srpaulo			wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
422252726Srpaulo					"Decrypted data with IV and padding "
423252726Srpaulo					"removed", out_data, plen);
424189251Ssam		}
425189251Ssam
426252726Srpaulo	check_mac:
427252726Srpaulo		if (plen < rl->hash_size) {
428189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
429189251Ssam				   "hash value");
430252726Srpaulo			*alert = TLS_ALERT_BAD_RECORD_MAC;
431189251Ssam			return -1;
432189251Ssam		}
433189251Ssam
434252726Srpaulo		plen -= rl->hash_size;
435189251Ssam
436189251Ssam		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
437189251Ssam					rl->hash_size);
438189251Ssam		if (hmac == NULL) {
439189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
440189251Ssam				   "to initialize HMAC");
441189251Ssam			*alert = TLS_ALERT_INTERNAL_ERROR;
442189251Ssam			return -1;
443189251Ssam		}
444189251Ssam
445189251Ssam		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
446189251Ssam		/* type + version + length + fragment */
447189251Ssam		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
448252726Srpaulo		WPA_PUT_BE16(len, plen);
449189251Ssam		crypto_hash_update(hmac, len, 2);
450252726Srpaulo		crypto_hash_update(hmac, out_data, plen);
451189251Ssam		hlen = sizeof(hash);
452189251Ssam		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
453189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
454189251Ssam				   "to calculate HMAC");
455252726Srpaulo			*alert = TLS_ALERT_INTERNAL_ERROR;
456189251Ssam			return -1;
457189251Ssam		}
458189251Ssam		if (hlen != rl->hash_size ||
459252726Srpaulo		    os_memcmp(hash, out_data + plen, hlen) != 0 ||
460252726Srpaulo		    force_mac_error) {
461189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
462252726Srpaulo				   "received message (force_mac_error=%d)",
463252726Srpaulo				   force_mac_error);
464189251Ssam			*alert = TLS_ALERT_BAD_RECORD_MAC;
465189251Ssam			return -1;
466189251Ssam		}
467252726Srpaulo
468252726Srpaulo		*out_len = plen;
469252726Srpaulo	} else {
470252726Srpaulo		os_memcpy(out_data, in_data, in_len);
471252726Srpaulo		*out_len = in_len;
472189251Ssam	}
473189251Ssam
474189251Ssam	/* TLSCompressed must not be more than 2^14+1024 bytes */
475189251Ssam	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
476189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
477189251Ssam			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
478189251Ssam		*alert = TLS_ALERT_RECORD_OVERFLOW;
479189251Ssam		return -1;
480189251Ssam	}
481189251Ssam
482189251Ssam	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
483189251Ssam
484252726Srpaulo	return TLS_RECORD_HEADER_LEN + rlen;
485189251Ssam}
486