2 * TLSv1 client (RFC 2246)
3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
20 #include "tlsv1_common.h"
21 #include "tlsv1_record.h"
22 #include "tlsv1_client.h"
23 #include "tlsv1_client_i.h"
26 * Support for a message fragmented across several records (RFC 2246, 6.2.1)
30 void tls_alert(struct tlsv1_client
*conn
, u8 level
, u8 description
)
32 conn
->alert_level
= level
;
33 conn
->alert_description
= description
;
37 void tlsv1_client_free_dh(struct tlsv1_client
*conn
)
42 conn
->dh_p
= conn
->dh_g
= conn
->dh_ys
= NULL
;
46 int tls_derive_pre_master_secret(u8
*pre_master_secret
)
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))
56 int tls_derive_keys(struct tlsv1_client
*conn
,
57 const u8
*pre_master_secret
, size_t pre_master_secret_len
)
59 u8 seed
[2 * TLS_RANDOM_LEN
];
60 u8 key_block
[TLS_MAX_KEY_BLOCK_LEN
];
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
,
70 if (tls_prf(pre_master_secret
, pre_master_secret_len
,
71 "master secret", seed
, 2 * TLS_RANDOM_LEN
,
72 conn
->master_secret
, TLS_MASTER_SECRET_LEN
)) {
73 wpa_printf(MSG_DEBUG
, "TLSv1: Failed to derive "
77 wpa_hexdump_key(MSG_MSGDUMP
, "TLSv1: master_secret",
78 conn
->master_secret
, TLS_MASTER_SECRET_LEN
);
81 os_memcpy(seed
, conn
->server_random
, TLS_RANDOM_LEN
);
82 os_memcpy(seed
+ TLS_RANDOM_LEN
, conn
->client_random
, TLS_RANDOM_LEN
);
83 key_block_len
= 2 * (conn
->rl
.hash_size
+ conn
->rl
.key_material_len
+
85 if (tls_prf(conn
->master_secret
, TLS_MASTER_SECRET_LEN
,
86 "key expansion", seed
, 2 * TLS_RANDOM_LEN
,
87 key_block
, key_block_len
)) {
88 wpa_printf(MSG_DEBUG
, "TLSv1: Failed to derive key_block");
91 wpa_hexdump_key(MSG_MSGDUMP
, "TLSv1: key_block",
92 key_block
, key_block_len
);
96 /* client_write_MAC_secret */
97 os_memcpy(conn
->rl
.write_mac_secret
, pos
, conn
->rl
.hash_size
);
98 pos
+= conn
->rl
.hash_size
;
99 /* server_write_MAC_secret */
100 os_memcpy(conn
->rl
.read_mac_secret
, pos
, conn
->rl
.hash_size
);
101 pos
+= conn
->rl
.hash_size
;
103 /* client_write_key */
104 os_memcpy(conn
->rl
.write_key
, pos
, conn
->rl
.key_material_len
);
105 pos
+= conn
->rl
.key_material_len
;
106 /* server_write_key */
107 os_memcpy(conn
->rl
.read_key
, pos
, conn
->rl
.key_material_len
);
108 pos
+= conn
->rl
.key_material_len
;
110 /* client_write_IV */
111 os_memcpy(conn
->rl
.write_iv
, pos
, conn
->rl
.iv_size
);
112 pos
+= conn
->rl
.iv_size
;
113 /* server_write_IV */
114 os_memcpy(conn
->rl
.read_iv
, pos
, conn
->rl
.iv_size
);
115 pos
+= conn
->rl
.iv_size
;
122 * tlsv1_client_handshake - Process TLS handshake
123 * @conn: TLSv1 client connection data from tlsv1_client_init()
124 * @in_data: Input data from TLS peer
125 * @in_len: Input data length
126 * @out_len: Length of the output buffer.
127 * Returns: Pointer to output data, %NULL on failure
129 u8
* tlsv1_client_handshake(struct tlsv1_client
*conn
,
130 const u8
*in_data
, size_t in_len
,
131 size_t *out_len
, u8
**appl_data
,
132 size_t *appl_data_len
)
135 u8
*msg
= NULL
, *in_msg
, *in_pos
, *in_end
, alert
, ct
;
139 if (conn
->state
== CLIENT_HELLO
) {
142 return tls_send_client_hello(conn
, out_len
);
145 if (in_data
== NULL
|| in_len
== 0)
149 end
= in_data
+ in_len
;
150 in_msg
= os_malloc(in_len
);
154 /* Each received packet may include multiple records */
157 if (tlsv1_record_receive(&conn
->rl
, pos
, end
- pos
,
158 in_msg
, &in_msg_len
, &alert
)) {
159 wpa_printf(MSG_DEBUG
, "TLSv1: Processing received "
161 tls_alert(conn
, TLS_ALERT_LEVEL_FATAL
, alert
);
167 in_end
= in_msg
+ in_msg_len
;
169 /* Each received record may include multiple messages of the
170 * same ContentType. */
171 while (in_pos
< in_end
) {
172 in_msg_len
= in_end
- in_pos
;
173 if (tlsv1_client_process_handshake(conn
, ct
, in_pos
,
178 in_pos
+= in_msg_len
;
181 pos
+= TLS_RECORD_HEADER_LEN
+ WPA_GET_BE16(pos
+ 3);
187 no_appl_data
= appl_data
== NULL
|| *appl_data
== NULL
;
188 msg
= tlsv1_client_handshake_write(conn
, out_len
, no_appl_data
);
192 if (conn
->alert_level
) {
193 conn
->state
= FAILED
;
195 msg
= tlsv1_client_send_alert(conn
, conn
->alert_level
,
196 conn
->alert_description
,
198 } else if (msg
== NULL
) {
208 * tlsv1_client_encrypt - Encrypt data into TLS tunnel
209 * @conn: TLSv1 client connection data from tlsv1_client_init()
210 * @in_data: Pointer to plaintext data to be encrypted
211 * @in_len: Input buffer length
212 * @out_data: Pointer to output buffer (encrypted TLS data)
213 * @out_len: Maximum out_data length
214 * Returns: Number of bytes written to out_data, -1 on failure
216 * This function is used after TLS handshake has been completed successfully to
217 * send data in the encrypted tunnel.
219 int tlsv1_client_encrypt(struct tlsv1_client
*conn
,
220 const u8
*in_data
, size_t in_len
,
221 u8
*out_data
, size_t out_len
)
225 wpa_hexdump_key(MSG_MSGDUMP
, "TLSv1: Plaintext AppData",
228 os_memcpy(out_data
+ TLS_RECORD_HEADER_LEN
, in_data
, in_len
);
230 if (tlsv1_record_send(&conn
->rl
, TLS_CONTENT_TYPE_APPLICATION_DATA
,
231 out_data
, out_len
, in_len
, &rlen
) < 0) {
232 wpa_printf(MSG_DEBUG
, "TLSv1: Failed to create a record");
233 tls_alert(conn
, TLS_ALERT_LEVEL_FATAL
,
234 TLS_ALERT_INTERNAL_ERROR
);
243 * tlsv1_client_decrypt - Decrypt data from TLS tunnel
244 * @conn: TLSv1 client connection data from tlsv1_client_init()
245 * @in_data: Pointer to input buffer (encrypted TLS data)
246 * @in_len: Input buffer length
247 * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
248 * @out_len: Maximum out_data length
249 * Returns: Number of bytes written to out_data, -1 on failure
251 * This function is used after TLS handshake has been completed successfully to
252 * receive data from the encrypted tunnel.
254 int tlsv1_client_decrypt(struct tlsv1_client
*conn
,
255 const u8
*in_data
, size_t in_len
,
256 u8
*out_data
, size_t out_len
)
258 const u8
*in_end
, *pos
;
260 u8 alert
, *out_end
, *out_pos
;
264 in_end
= in_data
+ in_len
;
266 out_end
= out_data
+ out_len
;
268 while (pos
< in_end
) {
269 if (pos
[0] != TLS_CONTENT_TYPE_APPLICATION_DATA
) {
270 wpa_printf(MSG_DEBUG
, "TLSv1: Unexpected content type "
272 tls_alert(conn
, TLS_ALERT_LEVEL_FATAL
,
273 TLS_ALERT_UNEXPECTED_MESSAGE
);
277 olen
= out_end
- out_pos
;
278 res
= tlsv1_record_receive(&conn
->rl
, pos
, in_end
- pos
,
279 out_pos
, &olen
, &alert
);
281 wpa_printf(MSG_DEBUG
, "TLSv1: Record layer processing "
283 tls_alert(conn
, TLS_ALERT_LEVEL_FATAL
, alert
);
287 if (out_pos
> out_end
) {
288 wpa_printf(MSG_DEBUG
, "TLSv1: Buffer not large enough "
289 "for processing the received record");
290 tls_alert(conn
, TLS_ALERT_LEVEL_FATAL
,
291 TLS_ALERT_INTERNAL_ERROR
);
295 pos
+= TLS_RECORD_HEADER_LEN
+ WPA_GET_BE16(pos
+ 3);
298 return out_pos
- out_data
;
303 * tlsv1_client_global_init - Initialize TLSv1 client
304 * Returns: 0 on success, -1 on failure
306 * This function must be called before using any other TLSv1 client functions.
308 int tlsv1_client_global_init(void)
310 return crypto_global_init();
315 * tlsv1_client_global_deinit - Deinitialize TLSv1 client
317 * This function can be used to deinitialize the TLSv1 client that was
318 * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
319 * can be called after this before calling tlsv1_client_global_init() again.
321 void tlsv1_client_global_deinit(void)
323 crypto_global_deinit();
328 * tlsv1_client_init - Initialize TLSv1 client connection
329 * Returns: Pointer to TLSv1 client connection data or %NULL on failure
331 struct tlsv1_client
* tlsv1_client_init(void)
333 struct tlsv1_client
*conn
;
337 conn
= os_zalloc(sizeof(*conn
));
341 conn
->state
= CLIENT_HELLO
;
343 if (tls_verify_hash_init(&conn
->verify
) < 0) {
344 wpa_printf(MSG_DEBUG
, "TLSv1: Failed to initialize verify "
351 suites
= conn
->cipher_suites
;
352 #ifndef CONFIG_CRYPTO_INTERNAL
353 suites
[count
++] = TLS_RSA_WITH_AES_256_CBC_SHA
;
354 #endif /* CONFIG_CRYPTO_INTERNAL */
355 suites
[count
++] = TLS_RSA_WITH_AES_128_CBC_SHA
;
356 suites
[count
++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA
;
357 suites
[count
++] = TLS_RSA_WITH_RC4_128_SHA
;
358 suites
[count
++] = TLS_RSA_WITH_RC4_128_MD5
;
359 conn
->num_cipher_suites
= count
;
366 * tlsv1_client_deinit - Deinitialize TLSv1 client connection
367 * @conn: TLSv1 client connection data from tlsv1_client_init()
369 void tlsv1_client_deinit(struct tlsv1_client
*conn
)
371 crypto_public_key_free(conn
->server_rsa_key
);
372 tlsv1_record_set_cipher_suite(&conn
->rl
, TLS_NULL_WITH_NULL_NULL
);
373 tlsv1_record_change_write_cipher(&conn
->rl
);
374 tlsv1_record_change_read_cipher(&conn
->rl
);
375 tls_verify_hash_free(&conn
->verify
);
376 os_free(conn
->client_hello_ext
);
377 tlsv1_client_free_dh(conn
);
378 tlsv1_cred_free(conn
->cred
);
384 * tlsv1_client_established - Check whether connection has been established
385 * @conn: TLSv1 client connection data from tlsv1_client_init()
386 * Returns: 1 if connection is established, 0 if not
388 int tlsv1_client_established(struct tlsv1_client
*conn
)
390 return conn
->state
== ESTABLISHED
;
395 * tlsv1_client_prf - Use TLS-PRF to derive keying material
396 * @conn: TLSv1 client connection data from tlsv1_client_init()
397 * @label: Label (e.g., description of the key) for PRF
398 * @server_random_first: seed is 0 = client_random|server_random,
399 * 1 = server_random|client_random
400 * @out: Buffer for output data from TLS-PRF
401 * @out_len: Length of the output buffer
402 * Returns: 0 on success, -1 on failure
404 int tlsv1_client_prf(struct tlsv1_client
*conn
, const char *label
,
405 int server_random_first
, u8
*out
, size_t out_len
)
407 u8 seed
[2 * TLS_RANDOM_LEN
];
409 if (conn
->state
!= ESTABLISHED
)
412 if (server_random_first
) {
413 os_memcpy(seed
, conn
->server_random
, TLS_RANDOM_LEN
);
414 os_memcpy(seed
+ TLS_RANDOM_LEN
, conn
->client_random
,
417 os_memcpy(seed
, conn
->client_random
, TLS_RANDOM_LEN
);
418 os_memcpy(seed
+ TLS_RANDOM_LEN
, conn
->server_random
,
422 return tls_prf(conn
->master_secret
, TLS_MASTER_SECRET_LEN
,
423 label
, seed
, 2 * TLS_RANDOM_LEN
, out
, out_len
);
428 * tlsv1_client_get_cipher - Get current cipher name
429 * @conn: TLSv1 client connection data from tlsv1_client_init()
430 * @buf: Buffer for the cipher name
432 * Returns: 0 on success, -1 on failure
434 * Get the name of the currently used cipher.
436 int tlsv1_client_get_cipher(struct tlsv1_client
*conn
, char *buf
,
441 switch (conn
->rl
.cipher_suite
) {
442 case TLS_RSA_WITH_RC4_128_MD5
:
445 case TLS_RSA_WITH_RC4_128_SHA
:
448 case TLS_RSA_WITH_DES_CBC_SHA
:
449 cipher
= "DES-CBC-SHA";
451 case TLS_RSA_WITH_3DES_EDE_CBC_SHA
:
452 cipher
= "DES-CBC3-SHA";
454 case TLS_DH_anon_WITH_AES_128_CBC_SHA
:
455 cipher
= "ADH-AES-128-SHA";
457 case TLS_RSA_WITH_AES_256_CBC_SHA
:
458 cipher
= "AES-256-SHA";
460 case TLS_RSA_WITH_AES_128_CBC_SHA
:
461 cipher
= "AES-128-SHA";
467 if (os_strlcpy(buf
, cipher
, buflen
) >= buflen
)
474 * tlsv1_client_shutdown - Shutdown TLS connection
475 * @conn: TLSv1 client connection data from tlsv1_client_init()
476 * Returns: 0 on success, -1 on failure
478 int tlsv1_client_shutdown(struct tlsv1_client
*conn
)
480 conn
->state
= CLIENT_HELLO
;
482 if (tls_verify_hash_init(&conn
->verify
) < 0) {
483 wpa_printf(MSG_DEBUG
, "TLSv1: Failed to re-initialize verify "
488 tlsv1_record_set_cipher_suite(&conn
->rl
, TLS_NULL_WITH_NULL_NULL
);
489 tlsv1_record_change_write_cipher(&conn
->rl
);
490 tlsv1_record_change_read_cipher(&conn
->rl
);
492 conn
->certificate_requested
= 0;
493 crypto_public_key_free(conn
->server_rsa_key
);
494 conn
->server_rsa_key
= NULL
;
495 conn
->session_resumed
= 0;
502 * tlsv1_client_resumed - Was session resumption used
503 * @conn: TLSv1 client connection data from tlsv1_client_init()
504 * Returns: 1 if current session used session resumption, 0 if not
506 int tlsv1_client_resumed(struct tlsv1_client
*conn
)
508 return !!conn
->session_resumed
;
513 * tlsv1_client_hello_ext - Set TLS extension for ClientHello
514 * @conn: TLSv1 client connection data from tlsv1_client_init()
515 * @ext_type: Extension type
516 * @data: Extension payload (%NULL to remove extension)
517 * @data_len: Extension payload length
518 * Returns: 0 on success, -1 on failure
520 int tlsv1_client_hello_ext(struct tlsv1_client
*conn
, int ext_type
,
521 const u8
*data
, size_t data_len
)
525 conn
->session_ticket_included
= 0;
526 os_free(conn
->client_hello_ext
);
527 conn
->client_hello_ext
= NULL
;
528 conn
->client_hello_ext_len
= 0;
530 if (data
== NULL
|| data_len
== 0)
533 pos
= conn
->client_hello_ext
= os_malloc(6 + data_len
);
537 WPA_PUT_BE16(pos
, 4 + data_len
);
539 WPA_PUT_BE16(pos
, ext_type
);
541 WPA_PUT_BE16(pos
, data_len
);
543 os_memcpy(pos
, data
, data_len
);
544 conn
->client_hello_ext_len
= 6 + data_len
;
546 if (ext_type
== TLS_EXT_PAC_OPAQUE
) {
547 conn
->session_ticket_included
= 1;
548 wpa_printf(MSG_DEBUG
, "TLSv1: Using session ticket");
556 * tlsv1_client_get_keys - Get master key and random data from TLS connection
557 * @conn: TLSv1 client connection data from tlsv1_client_init()
558 * @keys: Structure of key/random data (filled on success)
559 * Returns: 0 on success, -1 on failure
561 int tlsv1_client_get_keys(struct tlsv1_client
*conn
, struct tls_keys
*keys
)
563 os_memset(keys
, 0, sizeof(*keys
));
564 if (conn
->state
== CLIENT_HELLO
)
567 keys
->client_random
= conn
->client_random
;
568 keys
->client_random_len
= TLS_RANDOM_LEN
;
570 if (conn
->state
!= SERVER_HELLO
) {
571 keys
->server_random
= conn
->server_random
;
572 keys
->server_random_len
= TLS_RANDOM_LEN
;
573 keys
->master_key
= conn
->master_secret
;
574 keys
->master_key_len
= TLS_MASTER_SECRET_LEN
;
582 * tlsv1_client_get_keyblock_size - Get TLS key_block size
583 * @conn: TLSv1 client connection data from tlsv1_client_init()
584 * Returns: Size of the key_block for the negotiated cipher suite or -1 on
587 int tlsv1_client_get_keyblock_size(struct tlsv1_client
*conn
)
589 if (conn
->state
== CLIENT_HELLO
|| conn
->state
== SERVER_HELLO
)
592 return 2 * (conn
->rl
.hash_size
+ conn
->rl
.key_material_len
+
598 * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
599 * @conn: TLSv1 client connection data from tlsv1_client_init()
600 * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
602 * Returns: 0 on success, -1 on failure
604 int tlsv1_client_set_cipher_list(struct tlsv1_client
*conn
, u8
*ciphers
)
610 /* TODO: implement proper configuration of cipher suites */
611 if (ciphers
[0] == TLS_CIPHER_ANON_DH_AES128_SHA
) {
613 suites
= conn
->cipher_suites
;
614 #ifndef CONFIG_CRYPTO_INTERNAL
615 suites
[count
++] = TLS_DH_anon_WITH_AES_256_CBC_SHA
;
616 #endif /* CONFIG_CRYPTO_INTERNAL */
617 suites
[count
++] = TLS_DH_anon_WITH_AES_128_CBC_SHA
;
618 suites
[count
++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA
;
619 suites
[count
++] = TLS_DH_anon_WITH_RC4_128_MD5
;
620 suites
[count
++] = TLS_DH_anon_WITH_DES_CBC_SHA
;
621 conn
->num_cipher_suites
= count
;
627 #endif /* EAP_FAST */
632 * tlsv1_client_set_cred - Set client credentials
633 * @conn: TLSv1 client connection data from tlsv1_client_init()
634 * @cred: Credentials from tlsv1_cred_alloc()
635 * Returns: 0 on success, -1 on failure
637 * On success, the client takes ownership of the credentials block and caller
638 * must not free it. On failure, caller is responsible for freeing the
641 int tlsv1_client_set_cred(struct tlsv1_client
*conn
,
642 struct tlsv1_credentials
*cred
)
644 tlsv1_cred_free(conn
->cred
);
650 void tlsv1_client_set_session_ticket_cb(struct tlsv1_client
*conn
,
651 tlsv1_client_session_ticket_cb cb
,
654 wpa_printf(MSG_DEBUG
, "TLSv1: SessionTicket callback set %p (ctx %p)",
656 conn
->session_ticket_cb
= cb
;
657 conn
->session_ticket_cb_ctx
= ctx
;