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