blob: d0da5883591efc2b4f239010f131dbffe8aaadb8 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002 * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07003 * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
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/sha1.h"
19#include "crypto/tls.h"
20#include "tlsv1_common.h"
21#include "tlsv1_record.h"
22#include "tlsv1_client.h"
23#include "tlsv1_client_i.h"
24
25/* TODO:
26 * Support for a message fragmented across several records (RFC 2246, 6.2.1)
27 */
28
29
30void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
31{
32 conn->alert_level = level;
33 conn->alert_description = description;
34}
35
36
37void tlsv1_client_free_dh(struct tlsv1_client *conn)
38{
39 os_free(conn->dh_p);
40 os_free(conn->dh_g);
41 os_free(conn->dh_ys);
42 conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
43}
44
45
46int tls_derive_pre_master_secret(u8 *pre_master_secret)
47{
48 WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
49 if (os_get_random(pre_master_secret + 2,
50 TLS_PRE_MASTER_SECRET_LEN - 2))
51 return -1;
52 return 0;
53}
54
55
56int tls_derive_keys(struct tlsv1_client *conn,
57 const u8 *pre_master_secret, size_t pre_master_secret_len)
58{
59 u8 seed[2 * TLS_RANDOM_LEN];
60 u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
61 u8 *pos;
62 size_t key_block_len;
63
64 if (pre_master_secret) {
65 wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
66 pre_master_secret, pre_master_secret_len);
67 os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
68 os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
69 TLS_RANDOM_LEN);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080070 if (tls_prf(conn->rl.tls_version,
71 pre_master_secret, pre_master_secret_len,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070072 "master secret", seed, 2 * TLS_RANDOM_LEN,
73 conn->master_secret, TLS_MASTER_SECRET_LEN)) {
74 wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
75 "master_secret");
76 return -1;
77 }
78 wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
79 conn->master_secret, TLS_MASTER_SECRET_LEN);
80 }
81
82 os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
83 os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080084 key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
85 if (conn->rl.tls_version == TLS_VERSION_1)
86 key_block_len += 2 * conn->rl.iv_size;
87 if (tls_prf(conn->rl.tls_version,
88 conn->master_secret, TLS_MASTER_SECRET_LEN,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070089 "key expansion", seed, 2 * TLS_RANDOM_LEN,
90 key_block, key_block_len)) {
91 wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
92 return -1;
93 }
94 wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
95 key_block, key_block_len);
96
97 pos = key_block;
98
99 /* client_write_MAC_secret */
100 os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
101 pos += conn->rl.hash_size;
102 /* server_write_MAC_secret */
103 os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
104 pos += conn->rl.hash_size;
105
106 /* client_write_key */
107 os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
108 pos += conn->rl.key_material_len;
109 /* server_write_key */
110 os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
111 pos += conn->rl.key_material_len;
112
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800113 if (conn->rl.tls_version == TLS_VERSION_1) {
114 /* client_write_IV */
115 os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
116 pos += conn->rl.iv_size;
117 /* server_write_IV */
118 os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
119 pos += conn->rl.iv_size;
120 } else {
121 /*
122 * Use IV field to set the mask value for TLS v1.1. A fixed
123 * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
124 * Cipher option 2a.
125 */
126 os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
127 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700128
129 return 0;
130}
131
132
133/**
134 * tlsv1_client_handshake - Process TLS handshake
135 * @conn: TLSv1 client connection data from tlsv1_client_init()
136 * @in_data: Input data from TLS peer
137 * @in_len: Input data length
138 * @out_len: Length of the output buffer.
139 * @appl_data: Pointer to application data pointer, or %NULL if dropped
140 * @appl_data_len: Pointer to variable that is set to appl_data length
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800141 * @need_more_data: Set to 1 if more data would be needed to complete
142 * processing
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700143 * Returns: Pointer to output data, %NULL on failure
144 */
145u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
146 const u8 *in_data, size_t in_len,
147 size_t *out_len, u8 **appl_data,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800148 size_t *appl_data_len, int *need_more_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700149{
150 const u8 *pos, *end;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800151 u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700152 size_t in_msg_len;
153 int no_appl_data;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800154 int used;
155
156 if (need_more_data)
157 *need_more_data = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700158
159 if (conn->state == CLIENT_HELLO) {
160 if (in_len)
161 return NULL;
162 return tls_send_client_hello(conn, out_len);
163 }
164
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800165 if (conn->partial_input) {
166 if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
167 wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
168 "memory for pending record");
169 tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
170 TLS_ALERT_INTERNAL_ERROR);
171 goto failed;
172 }
173 wpabuf_put_data(conn->partial_input, in_data, in_len);
174 in_data = wpabuf_head(conn->partial_input);
175 in_len = wpabuf_len(conn->partial_input);
176 }
177
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700178 if (in_data == NULL || in_len == 0)
179 return NULL;
180
181 pos = in_data;
182 end = in_data + in_len;
183 in_msg = os_malloc(in_len);
184 if (in_msg == NULL)
185 return NULL;
186
187 /* Each received packet may include multiple records */
188 while (pos < end) {
189 in_msg_len = in_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800190 used = tlsv1_record_receive(&conn->rl, pos, end - pos,
191 in_msg, &in_msg_len, &alert);
192 if (used < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700193 wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
194 "record failed");
195 tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
196 goto failed;
197 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800198 if (used == 0) {
199 struct wpabuf *partial;
200 wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
201 partial = wpabuf_alloc_copy(pos, end - pos);
202 wpabuf_free(conn->partial_input);
203 conn->partial_input = partial;
204 if (conn->partial_input == NULL) {
205 wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
206 "allocate memory for pending "
207 "record");
208 tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
209 TLS_ALERT_INTERNAL_ERROR);
210 goto failed;
211 }
212 os_free(in_msg);
213 if (need_more_data)
214 *need_more_data = 1;
215 return NULL;
216 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 ct = pos[0];
218
219 in_pos = in_msg;
220 in_end = in_msg + in_msg_len;
221
222 /* Each received record may include multiple messages of the
223 * same ContentType. */
224 while (in_pos < in_end) {
225 in_msg_len = in_end - in_pos;
226 if (tlsv1_client_process_handshake(conn, ct, in_pos,
227 &in_msg_len,
228 appl_data,
229 appl_data_len) < 0)
230 goto failed;
231 in_pos += in_msg_len;
232 }
233
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800234 pos += used;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700235 }
236
237 os_free(in_msg);
238 in_msg = NULL;
239
240 no_appl_data = appl_data == NULL || *appl_data == NULL;
241 msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
242
243failed:
244 os_free(in_msg);
245 if (conn->alert_level) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800246 wpabuf_free(conn->partial_input);
247 conn->partial_input = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700248 conn->state = FAILED;
249 os_free(msg);
250 msg = tlsv1_client_send_alert(conn, conn->alert_level,
251 conn->alert_description,
252 out_len);
253 } else if (msg == NULL) {
254 msg = os_zalloc(1);
255 *out_len = 0;
256 }
257
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800258 if (need_more_data == NULL || !(*need_more_data)) {
259 wpabuf_free(conn->partial_input);
260 conn->partial_input = NULL;
261 }
262
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700263 return msg;
264}
265
266
267/**
268 * tlsv1_client_encrypt - Encrypt data into TLS tunnel
269 * @conn: TLSv1 client connection data from tlsv1_client_init()
270 * @in_data: Pointer to plaintext data to be encrypted
271 * @in_len: Input buffer length
272 * @out_data: Pointer to output buffer (encrypted TLS data)
273 * @out_len: Maximum out_data length
274 * Returns: Number of bytes written to out_data, -1 on failure
275 *
276 * This function is used after TLS handshake has been completed successfully to
277 * send data in the encrypted tunnel.
278 */
279int tlsv1_client_encrypt(struct tlsv1_client *conn,
280 const u8 *in_data, size_t in_len,
281 u8 *out_data, size_t out_len)
282{
283 size_t rlen;
284
285 wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
286 in_data, in_len);
287
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700288 if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800289 out_data, out_len, in_data, in_len, &rlen) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700290 wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
291 tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
292 TLS_ALERT_INTERNAL_ERROR);
293 return -1;
294 }
295
296 return rlen;
297}
298
299
300/**
301 * tlsv1_client_decrypt - Decrypt data from TLS tunnel
302 * @conn: TLSv1 client connection data from tlsv1_client_init()
303 * @in_data: Pointer to input buffer (encrypted TLS data)
304 * @in_len: Input buffer length
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800305 * @need_more_data: Set to 1 if more data would be needed to complete
306 * processing
307 * Returns: Decrypted data or %NULL on failure
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700308 *
309 * This function is used after TLS handshake has been completed successfully to
310 * receive data from the encrypted tunnel.
311 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800312struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
313 const u8 *in_data, size_t in_len,
314 int *need_more_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700315{
316 const u8 *in_end, *pos;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800317 int used;
318 u8 alert, *out_pos, ct;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700319 size_t olen;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800320 struct wpabuf *buf = NULL;
321
322 if (need_more_data)
323 *need_more_data = 0;
324
325 if (conn->partial_input) {
326 if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
327 wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
328 "memory for pending record");
329 alert = TLS_ALERT_INTERNAL_ERROR;
330 goto fail;
331 }
332 wpabuf_put_data(conn->partial_input, in_data, in_len);
333 in_data = wpabuf_head(conn->partial_input);
334 in_len = wpabuf_len(conn->partial_input);
335 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336
337 pos = in_data;
338 in_end = in_data + in_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700339
340 while (pos < in_end) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800341 ct = pos[0];
342 if (wpabuf_resize(&buf, in_end - pos) < 0) {
343 alert = TLS_ALERT_INTERNAL_ERROR;
344 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700345 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800346 out_pos = wpabuf_put(buf, 0);
347 olen = wpabuf_tailroom(buf);
348 used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
349 out_pos, &olen, &alert);
350 if (used < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700351 wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
352 "failed");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800353 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700354 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800355 if (used == 0) {
356 struct wpabuf *partial;
357 wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
358 partial = wpabuf_alloc_copy(pos, in_end - pos);
359 wpabuf_free(conn->partial_input);
360 conn->partial_input = partial;
361 if (conn->partial_input == NULL) {
362 wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
363 "allocate memory for pending "
364 "record");
365 alert = TLS_ALERT_INTERNAL_ERROR;
366 goto fail;
367 }
368 if (need_more_data)
369 *need_more_data = 1;
370 return buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700371 }
372
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800373 if (ct == TLS_CONTENT_TYPE_ALERT) {
374 if (olen < 2) {
375 wpa_printf(MSG_DEBUG, "TLSv1: Alert "
376 "underflow");
377 alert = TLS_ALERT_DECODE_ERROR;
378 goto fail;
379 }
380 wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
381 out_pos[0], out_pos[1]);
382 if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
383 /* Continue processing */
384 pos += used;
385 continue;
386 }
387
388 alert = out_pos[1];
389 goto fail;
390 }
391
392 if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
393 wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
394 "0x%x when decrypting application data",
395 pos[0]);
396 alert = TLS_ALERT_UNEXPECTED_MESSAGE;
397 goto fail;
398 }
399
400 wpabuf_put(buf, olen);
401
402 pos += used;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700403 }
404
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800405 wpabuf_free(conn->partial_input);
406 conn->partial_input = NULL;
407 return buf;
408
409fail:
410 wpabuf_free(buf);
411 wpabuf_free(conn->partial_input);
412 conn->partial_input = NULL;
413 tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
414 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700415}
416
417
418/**
419 * tlsv1_client_global_init - Initialize TLSv1 client
420 * Returns: 0 on success, -1 on failure
421 *
422 * This function must be called before using any other TLSv1 client functions.
423 */
424int tlsv1_client_global_init(void)
425{
426 return crypto_global_init();
427}
428
429
430/**
431 * tlsv1_client_global_deinit - Deinitialize TLSv1 client
432 *
433 * This function can be used to deinitialize the TLSv1 client that was
434 * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
435 * can be called after this before calling tlsv1_client_global_init() again.
436 */
437void tlsv1_client_global_deinit(void)
438{
439 crypto_global_deinit();
440}
441
442
443/**
444 * tlsv1_client_init - Initialize TLSv1 client connection
445 * Returns: Pointer to TLSv1 client connection data or %NULL on failure
446 */
447struct tlsv1_client * tlsv1_client_init(void)
448{
449 struct tlsv1_client *conn;
450 size_t count;
451 u16 *suites;
452
453 conn = os_zalloc(sizeof(*conn));
454 if (conn == NULL)
455 return NULL;
456
457 conn->state = CLIENT_HELLO;
458
459 if (tls_verify_hash_init(&conn->verify) < 0) {
460 wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
461 "hash");
462 os_free(conn);
463 return NULL;
464 }
465
466 count = 0;
467 suites = conn->cipher_suites;
468#ifndef CONFIG_CRYPTO_INTERNAL
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800469 suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700470 suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
471#endif /* CONFIG_CRYPTO_INTERNAL */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800472 suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700473 suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
474 suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
475 suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
476 suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
477 conn->num_cipher_suites = count;
478
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800479 conn->rl.tls_version = TLS_VERSION;
480
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700481 return conn;
482}
483
484
485/**
486 * tlsv1_client_deinit - Deinitialize TLSv1 client connection
487 * @conn: TLSv1 client connection data from tlsv1_client_init()
488 */
489void tlsv1_client_deinit(struct tlsv1_client *conn)
490{
491 crypto_public_key_free(conn->server_rsa_key);
492 tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
493 tlsv1_record_change_write_cipher(&conn->rl);
494 tlsv1_record_change_read_cipher(&conn->rl);
495 tls_verify_hash_free(&conn->verify);
496 os_free(conn->client_hello_ext);
497 tlsv1_client_free_dh(conn);
498 tlsv1_cred_free(conn->cred);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800499 wpabuf_free(conn->partial_input);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700500 os_free(conn);
501}
502
503
504/**
505 * tlsv1_client_established - Check whether connection has been established
506 * @conn: TLSv1 client connection data from tlsv1_client_init()
507 * Returns: 1 if connection is established, 0 if not
508 */
509int tlsv1_client_established(struct tlsv1_client *conn)
510{
511 return conn->state == ESTABLISHED;
512}
513
514
515/**
516 * tlsv1_client_prf - Use TLS-PRF to derive keying material
517 * @conn: TLSv1 client connection data from tlsv1_client_init()
518 * @label: Label (e.g., description of the key) for PRF
519 * @server_random_first: seed is 0 = client_random|server_random,
520 * 1 = server_random|client_random
521 * @out: Buffer for output data from TLS-PRF
522 * @out_len: Length of the output buffer
523 * Returns: 0 on success, -1 on failure
524 */
525int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
526 int server_random_first, u8 *out, size_t out_len)
527{
528 u8 seed[2 * TLS_RANDOM_LEN];
529
530 if (conn->state != ESTABLISHED)
531 return -1;
532
533 if (server_random_first) {
534 os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
535 os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
536 TLS_RANDOM_LEN);
537 } else {
538 os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
539 os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
540 TLS_RANDOM_LEN);
541 }
542
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800543 return tls_prf(conn->rl.tls_version,
544 conn->master_secret, TLS_MASTER_SECRET_LEN,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700545 label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
546}
547
548
549/**
550 * tlsv1_client_get_cipher - Get current cipher name
551 * @conn: TLSv1 client connection data from tlsv1_client_init()
552 * @buf: Buffer for the cipher name
553 * @buflen: buf size
554 * Returns: 0 on success, -1 on failure
555 *
556 * Get the name of the currently used cipher.
557 */
558int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
559 size_t buflen)
560{
561 char *cipher;
562
563 switch (conn->rl.cipher_suite) {
564 case TLS_RSA_WITH_RC4_128_MD5:
565 cipher = "RC4-MD5";
566 break;
567 case TLS_RSA_WITH_RC4_128_SHA:
568 cipher = "RC4-SHA";
569 break;
570 case TLS_RSA_WITH_DES_CBC_SHA:
571 cipher = "DES-CBC-SHA";
572 break;
573 case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
574 cipher = "DES-CBC3-SHA";
575 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800576 case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
577 cipher = "ADH-AES-128-SHA256";
578 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700579 case TLS_DH_anon_WITH_AES_128_CBC_SHA:
580 cipher = "ADH-AES-128-SHA";
581 break;
582 case TLS_RSA_WITH_AES_256_CBC_SHA:
583 cipher = "AES-256-SHA";
584 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800585 case TLS_RSA_WITH_AES_256_CBC_SHA256:
586 cipher = "AES-256-SHA256";
587 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700588 case TLS_RSA_WITH_AES_128_CBC_SHA:
589 cipher = "AES-128-SHA";
590 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800591 case TLS_RSA_WITH_AES_128_CBC_SHA256:
592 cipher = "AES-128-SHA256";
593 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700594 default:
595 return -1;
596 }
597
598 if (os_strlcpy(buf, cipher, buflen) >= buflen)
599 return -1;
600 return 0;
601}
602
603
604/**
605 * tlsv1_client_shutdown - Shutdown TLS connection
606 * @conn: TLSv1 client connection data from tlsv1_client_init()
607 * Returns: 0 on success, -1 on failure
608 */
609int tlsv1_client_shutdown(struct tlsv1_client *conn)
610{
611 conn->state = CLIENT_HELLO;
612
613 if (tls_verify_hash_init(&conn->verify) < 0) {
614 wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
615 "hash");
616 return -1;
617 }
618
619 tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
620 tlsv1_record_change_write_cipher(&conn->rl);
621 tlsv1_record_change_read_cipher(&conn->rl);
622
623 conn->certificate_requested = 0;
624 crypto_public_key_free(conn->server_rsa_key);
625 conn->server_rsa_key = NULL;
626 conn->session_resumed = 0;
627
628 return 0;
629}
630
631
632/**
633 * tlsv1_client_resumed - Was session resumption used
634 * @conn: TLSv1 client connection data from tlsv1_client_init()
635 * Returns: 1 if current session used session resumption, 0 if not
636 */
637int tlsv1_client_resumed(struct tlsv1_client *conn)
638{
639 return !!conn->session_resumed;
640}
641
642
643/**
644 * tlsv1_client_hello_ext - Set TLS extension for ClientHello
645 * @conn: TLSv1 client connection data from tlsv1_client_init()
646 * @ext_type: Extension type
647 * @data: Extension payload (%NULL to remove extension)
648 * @data_len: Extension payload length
649 * Returns: 0 on success, -1 on failure
650 */
651int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
652 const u8 *data, size_t data_len)
653{
654 u8 *pos;
655
656 conn->session_ticket_included = 0;
657 os_free(conn->client_hello_ext);
658 conn->client_hello_ext = NULL;
659 conn->client_hello_ext_len = 0;
660
661 if (data == NULL || data_len == 0)
662 return 0;
663
664 pos = conn->client_hello_ext = os_malloc(6 + data_len);
665 if (pos == NULL)
666 return -1;
667
668 WPA_PUT_BE16(pos, 4 + data_len);
669 pos += 2;
670 WPA_PUT_BE16(pos, ext_type);
671 pos += 2;
672 WPA_PUT_BE16(pos, data_len);
673 pos += 2;
674 os_memcpy(pos, data, data_len);
675 conn->client_hello_ext_len = 6 + data_len;
676
677 if (ext_type == TLS_EXT_PAC_OPAQUE) {
678 conn->session_ticket_included = 1;
679 wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
680 }
681
682 return 0;
683}
684
685
686/**
687 * tlsv1_client_get_keys - Get master key and random data from TLS connection
688 * @conn: TLSv1 client connection data from tlsv1_client_init()
689 * @keys: Structure of key/random data (filled on success)
690 * Returns: 0 on success, -1 on failure
691 */
692int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
693{
694 os_memset(keys, 0, sizeof(*keys));
695 if (conn->state == CLIENT_HELLO)
696 return -1;
697
698 keys->client_random = conn->client_random;
699 keys->client_random_len = TLS_RANDOM_LEN;
700
701 if (conn->state != SERVER_HELLO) {
702 keys->server_random = conn->server_random;
703 keys->server_random_len = TLS_RANDOM_LEN;
704 keys->master_key = conn->master_secret;
705 keys->master_key_len = TLS_MASTER_SECRET_LEN;
706 }
707
708 return 0;
709}
710
711
712/**
713 * tlsv1_client_get_keyblock_size - Get TLS key_block size
714 * @conn: TLSv1 client connection data from tlsv1_client_init()
715 * Returns: Size of the key_block for the negotiated cipher suite or -1 on
716 * failure
717 */
718int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
719{
720 if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
721 return -1;
722
723 return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
724 conn->rl.iv_size);
725}
726
727
728/**
729 * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
730 * @conn: TLSv1 client connection data from tlsv1_client_init()
731 * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
732 * (TLS_CIPHER_*).
733 * Returns: 0 on success, -1 on failure
734 */
735int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
736{
737 size_t count;
738 u16 *suites;
739
740 /* TODO: implement proper configuration of cipher suites */
741 if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
742 count = 0;
743 suites = conn->cipher_suites;
744#ifndef CONFIG_CRYPTO_INTERNAL
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800745 suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746 suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
747#endif /* CONFIG_CRYPTO_INTERNAL */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800748 suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700749 suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
750 suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
751 suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
752 suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
753
754 /*
755 * Cisco AP (at least 350 and 1200 series) local authentication
756 * server does not know how to search cipher suites from the
757 * list and seem to require that the last entry in the list is
758 * the one that it wants to use. However, TLS specification
759 * requires the list to be in the client preference order. As a
760 * workaround, add anon-DH AES-128-SHA1 again at the end of the
761 * list to allow the Cisco code to find it.
762 */
763 suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
764 conn->num_cipher_suites = count;
765 }
766
767 return 0;
768}
769
770
771/**
772 * tlsv1_client_set_cred - Set client credentials
773 * @conn: TLSv1 client connection data from tlsv1_client_init()
774 * @cred: Credentials from tlsv1_cred_alloc()
775 * Returns: 0 on success, -1 on failure
776 *
777 * On success, the client takes ownership of the credentials block and caller
778 * must not free it. On failure, caller is responsible for freeing the
779 * credential block.
780 */
781int tlsv1_client_set_cred(struct tlsv1_client *conn,
782 struct tlsv1_credentials *cred)
783{
784 tlsv1_cred_free(conn->cred);
785 conn->cred = cred;
786 return 0;
787}
788
789
Dmitry Shmidtc55524a2011-07-07 11:18:38 -0700790void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
791{
792 conn->disable_time_checks = !enabled;
793}
794
795
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700796void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
797 tlsv1_client_session_ticket_cb cb,
798 void *ctx)
799{
800 wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
801 cb, ctx);
802 conn->session_ticket_cb = cb;
803 conn->session_ticket_cb_ctx = ctx;
804}