xref: /freebsd/contrib/wpa/src/tls/tlsv1_client.c (revision f05cddf940dbfc5b657f5e9beb9de2c31e509e5b)
139beb93cSSam Leffler /*
2*f05cddf9SRui Paulo  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
3*f05cddf9SRui Paulo  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5*f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6*f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "crypto/sha1.h"
13e28a4053SRui Paulo #include "crypto/tls.h"
1439beb93cSSam Leffler #include "tlsv1_common.h"
1539beb93cSSam Leffler #include "tlsv1_record.h"
1639beb93cSSam Leffler #include "tlsv1_client.h"
1739beb93cSSam Leffler #include "tlsv1_client_i.h"
1839beb93cSSam Leffler 
1939beb93cSSam Leffler /* TODO:
2039beb93cSSam Leffler  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
2139beb93cSSam Leffler  */
2239beb93cSSam Leffler 
2339beb93cSSam Leffler 
2439beb93cSSam Leffler void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
2539beb93cSSam Leffler {
2639beb93cSSam Leffler 	conn->alert_level = level;
2739beb93cSSam Leffler 	conn->alert_description = description;
2839beb93cSSam Leffler }
2939beb93cSSam Leffler 
3039beb93cSSam Leffler 
3139beb93cSSam Leffler void tlsv1_client_free_dh(struct tlsv1_client *conn)
3239beb93cSSam Leffler {
3339beb93cSSam Leffler 	os_free(conn->dh_p);
3439beb93cSSam Leffler 	os_free(conn->dh_g);
3539beb93cSSam Leffler 	os_free(conn->dh_ys);
3639beb93cSSam Leffler 	conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
3739beb93cSSam Leffler }
3839beb93cSSam Leffler 
3939beb93cSSam Leffler 
4039beb93cSSam Leffler int tls_derive_pre_master_secret(u8 *pre_master_secret)
4139beb93cSSam Leffler {
4239beb93cSSam Leffler 	WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
4339beb93cSSam Leffler 	if (os_get_random(pre_master_secret + 2,
4439beb93cSSam Leffler 			  TLS_PRE_MASTER_SECRET_LEN - 2))
4539beb93cSSam Leffler 		return -1;
4639beb93cSSam Leffler 	return 0;
4739beb93cSSam Leffler }
4839beb93cSSam Leffler 
4939beb93cSSam Leffler 
5039beb93cSSam Leffler int tls_derive_keys(struct tlsv1_client *conn,
5139beb93cSSam Leffler 		    const u8 *pre_master_secret, size_t pre_master_secret_len)
5239beb93cSSam Leffler {
5339beb93cSSam Leffler 	u8 seed[2 * TLS_RANDOM_LEN];
5439beb93cSSam Leffler 	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
5539beb93cSSam Leffler 	u8 *pos;
5639beb93cSSam Leffler 	size_t key_block_len;
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 	if (pre_master_secret) {
5939beb93cSSam Leffler 		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
6039beb93cSSam Leffler 				pre_master_secret, pre_master_secret_len);
6139beb93cSSam Leffler 		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
6239beb93cSSam Leffler 		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
6339beb93cSSam Leffler 			  TLS_RANDOM_LEN);
64*f05cddf9SRui Paulo 		if (tls_prf(conn->rl.tls_version,
65*f05cddf9SRui Paulo 			    pre_master_secret, pre_master_secret_len,
6639beb93cSSam Leffler 			    "master secret", seed, 2 * TLS_RANDOM_LEN,
6739beb93cSSam Leffler 			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
6839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
6939beb93cSSam Leffler 				   "master_secret");
7039beb93cSSam Leffler 			return -1;
7139beb93cSSam Leffler 		}
7239beb93cSSam Leffler 		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
7339beb93cSSam Leffler 				conn->master_secret, TLS_MASTER_SECRET_LEN);
7439beb93cSSam Leffler 	}
7539beb93cSSam Leffler 
7639beb93cSSam Leffler 	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
7739beb93cSSam Leffler 	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
78*f05cddf9SRui Paulo 	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
79*f05cddf9SRui Paulo 	if (conn->rl.tls_version == TLS_VERSION_1)
80*f05cddf9SRui Paulo 		key_block_len += 2 * conn->rl.iv_size;
81*f05cddf9SRui Paulo 	if (tls_prf(conn->rl.tls_version,
82*f05cddf9SRui Paulo 		    conn->master_secret, TLS_MASTER_SECRET_LEN,
8339beb93cSSam Leffler 		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
8439beb93cSSam Leffler 		    key_block, key_block_len)) {
8539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
8639beb93cSSam Leffler 		return -1;
8739beb93cSSam Leffler 	}
8839beb93cSSam Leffler 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
8939beb93cSSam Leffler 			key_block, key_block_len);
9039beb93cSSam Leffler 
9139beb93cSSam Leffler 	pos = key_block;
9239beb93cSSam Leffler 
9339beb93cSSam Leffler 	/* client_write_MAC_secret */
9439beb93cSSam Leffler 	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
9539beb93cSSam Leffler 	pos += conn->rl.hash_size;
9639beb93cSSam Leffler 	/* server_write_MAC_secret */
9739beb93cSSam Leffler 	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
9839beb93cSSam Leffler 	pos += conn->rl.hash_size;
9939beb93cSSam Leffler 
10039beb93cSSam Leffler 	/* client_write_key */
10139beb93cSSam Leffler 	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
10239beb93cSSam Leffler 	pos += conn->rl.key_material_len;
10339beb93cSSam Leffler 	/* server_write_key */
10439beb93cSSam Leffler 	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
10539beb93cSSam Leffler 	pos += conn->rl.key_material_len;
10639beb93cSSam Leffler 
107*f05cddf9SRui Paulo 	if (conn->rl.tls_version == TLS_VERSION_1) {
10839beb93cSSam Leffler 		/* client_write_IV */
10939beb93cSSam Leffler 		os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
11039beb93cSSam Leffler 		pos += conn->rl.iv_size;
11139beb93cSSam Leffler 		/* server_write_IV */
11239beb93cSSam Leffler 		os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
11339beb93cSSam Leffler 		pos += conn->rl.iv_size;
114*f05cddf9SRui Paulo 	} else {
115*f05cddf9SRui Paulo 		/*
116*f05cddf9SRui Paulo 		 * Use IV field to set the mask value for TLS v1.1. A fixed
117*f05cddf9SRui Paulo 		 * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
118*f05cddf9SRui Paulo 		 * Cipher option 2a.
119*f05cddf9SRui Paulo 		 */
120*f05cddf9SRui Paulo 		os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
121*f05cddf9SRui Paulo 	}
12239beb93cSSam Leffler 
12339beb93cSSam Leffler 	return 0;
12439beb93cSSam Leffler }
12539beb93cSSam Leffler 
12639beb93cSSam Leffler 
12739beb93cSSam Leffler /**
12839beb93cSSam Leffler  * tlsv1_client_handshake - Process TLS handshake
12939beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
13039beb93cSSam Leffler  * @in_data: Input data from TLS peer
13139beb93cSSam Leffler  * @in_len: Input data length
13239beb93cSSam Leffler  * @out_len: Length of the output buffer.
13339beb93cSSam Leffler  * @appl_data: Pointer to application data pointer, or %NULL if dropped
13439beb93cSSam Leffler  * @appl_data_len: Pointer to variable that is set to appl_data length
135*f05cddf9SRui Paulo  * @need_more_data: Set to 1 if more data would be needed to complete
136*f05cddf9SRui Paulo  *	processing
13739beb93cSSam Leffler  * Returns: Pointer to output data, %NULL on failure
13839beb93cSSam Leffler  */
13939beb93cSSam Leffler u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
14039beb93cSSam Leffler 			    const u8 *in_data, size_t in_len,
14139beb93cSSam Leffler 			    size_t *out_len, u8 **appl_data,
142*f05cddf9SRui Paulo 			    size_t *appl_data_len, int *need_more_data)
14339beb93cSSam Leffler {
14439beb93cSSam Leffler 	const u8 *pos, *end;
145*f05cddf9SRui Paulo 	u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
14639beb93cSSam Leffler 	size_t in_msg_len;
14739beb93cSSam Leffler 	int no_appl_data;
148*f05cddf9SRui Paulo 	int used;
149*f05cddf9SRui Paulo 
150*f05cddf9SRui Paulo 	if (need_more_data)
151*f05cddf9SRui Paulo 		*need_more_data = 0;
15239beb93cSSam Leffler 
15339beb93cSSam Leffler 	if (conn->state == CLIENT_HELLO) {
15439beb93cSSam Leffler 		if (in_len)
15539beb93cSSam Leffler 			return NULL;
15639beb93cSSam Leffler 		return tls_send_client_hello(conn, out_len);
15739beb93cSSam Leffler 	}
15839beb93cSSam Leffler 
159*f05cddf9SRui Paulo 	if (conn->partial_input) {
160*f05cddf9SRui Paulo 		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
161*f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
162*f05cddf9SRui Paulo 				   "memory for pending record");
163*f05cddf9SRui Paulo 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
164*f05cddf9SRui Paulo 				  TLS_ALERT_INTERNAL_ERROR);
165*f05cddf9SRui Paulo 			goto failed;
166*f05cddf9SRui Paulo 		}
167*f05cddf9SRui Paulo 		wpabuf_put_data(conn->partial_input, in_data, in_len);
168*f05cddf9SRui Paulo 		in_data = wpabuf_head(conn->partial_input);
169*f05cddf9SRui Paulo 		in_len = wpabuf_len(conn->partial_input);
170*f05cddf9SRui Paulo 	}
171*f05cddf9SRui Paulo 
17239beb93cSSam Leffler 	if (in_data == NULL || in_len == 0)
17339beb93cSSam Leffler 		return NULL;
17439beb93cSSam Leffler 
17539beb93cSSam Leffler 	pos = in_data;
17639beb93cSSam Leffler 	end = in_data + in_len;
17739beb93cSSam Leffler 	in_msg = os_malloc(in_len);
17839beb93cSSam Leffler 	if (in_msg == NULL)
17939beb93cSSam Leffler 		return NULL;
18039beb93cSSam Leffler 
18139beb93cSSam Leffler 	/* Each received packet may include multiple records */
18239beb93cSSam Leffler 	while (pos < end) {
18339beb93cSSam Leffler 		in_msg_len = in_len;
184*f05cddf9SRui Paulo 		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
185*f05cddf9SRui Paulo 					    in_msg, &in_msg_len, &alert);
186*f05cddf9SRui Paulo 		if (used < 0) {
18739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
18839beb93cSSam Leffler 				   "record failed");
18939beb93cSSam Leffler 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
19039beb93cSSam Leffler 			goto failed;
19139beb93cSSam Leffler 		}
192*f05cddf9SRui Paulo 		if (used == 0) {
193*f05cddf9SRui Paulo 			struct wpabuf *partial;
194*f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
195*f05cddf9SRui Paulo 			partial = wpabuf_alloc_copy(pos, end - pos);
196*f05cddf9SRui Paulo 			wpabuf_free(conn->partial_input);
197*f05cddf9SRui Paulo 			conn->partial_input = partial;
198*f05cddf9SRui Paulo 			if (conn->partial_input == NULL) {
199*f05cddf9SRui Paulo 				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
200*f05cddf9SRui Paulo 					   "allocate memory for pending "
201*f05cddf9SRui Paulo 					   "record");
202*f05cddf9SRui Paulo 				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
203*f05cddf9SRui Paulo 					  TLS_ALERT_INTERNAL_ERROR);
204*f05cddf9SRui Paulo 				goto failed;
205*f05cddf9SRui Paulo 			}
206*f05cddf9SRui Paulo 			os_free(in_msg);
207*f05cddf9SRui Paulo 			if (need_more_data)
208*f05cddf9SRui Paulo 				*need_more_data = 1;
209*f05cddf9SRui Paulo 			return NULL;
210*f05cddf9SRui Paulo 		}
21139beb93cSSam Leffler 		ct = pos[0];
21239beb93cSSam Leffler 
21339beb93cSSam Leffler 		in_pos = in_msg;
21439beb93cSSam Leffler 		in_end = in_msg + in_msg_len;
21539beb93cSSam Leffler 
21639beb93cSSam Leffler 		/* Each received record may include multiple messages of the
21739beb93cSSam Leffler 		 * same ContentType. */
21839beb93cSSam Leffler 		while (in_pos < in_end) {
21939beb93cSSam Leffler 			in_msg_len = in_end - in_pos;
22039beb93cSSam Leffler 			if (tlsv1_client_process_handshake(conn, ct, in_pos,
22139beb93cSSam Leffler 							   &in_msg_len,
22239beb93cSSam Leffler 							   appl_data,
22339beb93cSSam Leffler 							   appl_data_len) < 0)
22439beb93cSSam Leffler 				goto failed;
22539beb93cSSam Leffler 			in_pos += in_msg_len;
22639beb93cSSam Leffler 		}
22739beb93cSSam Leffler 
228*f05cddf9SRui Paulo 		pos += used;
22939beb93cSSam Leffler 	}
23039beb93cSSam Leffler 
23139beb93cSSam Leffler 	os_free(in_msg);
23239beb93cSSam Leffler 	in_msg = NULL;
23339beb93cSSam Leffler 
23439beb93cSSam Leffler 	no_appl_data = appl_data == NULL || *appl_data == NULL;
23539beb93cSSam Leffler 	msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
23639beb93cSSam Leffler 
23739beb93cSSam Leffler failed:
23839beb93cSSam Leffler 	os_free(in_msg);
23939beb93cSSam Leffler 	if (conn->alert_level) {
240*f05cddf9SRui Paulo 		wpabuf_free(conn->partial_input);
241*f05cddf9SRui Paulo 		conn->partial_input = NULL;
24239beb93cSSam Leffler 		conn->state = FAILED;
24339beb93cSSam Leffler 		os_free(msg);
24439beb93cSSam Leffler 		msg = tlsv1_client_send_alert(conn, conn->alert_level,
24539beb93cSSam Leffler 					      conn->alert_description,
24639beb93cSSam Leffler 					      out_len);
24739beb93cSSam Leffler 	} else if (msg == NULL) {
24839beb93cSSam Leffler 		msg = os_zalloc(1);
24939beb93cSSam Leffler 		*out_len = 0;
25039beb93cSSam Leffler 	}
25139beb93cSSam Leffler 
252*f05cddf9SRui Paulo 	if (need_more_data == NULL || !(*need_more_data)) {
253*f05cddf9SRui Paulo 		wpabuf_free(conn->partial_input);
254*f05cddf9SRui Paulo 		conn->partial_input = NULL;
255*f05cddf9SRui Paulo 	}
256*f05cddf9SRui Paulo 
25739beb93cSSam Leffler 	return msg;
25839beb93cSSam Leffler }
25939beb93cSSam Leffler 
26039beb93cSSam Leffler 
26139beb93cSSam Leffler /**
26239beb93cSSam Leffler  * tlsv1_client_encrypt - Encrypt data into TLS tunnel
26339beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
26439beb93cSSam Leffler  * @in_data: Pointer to plaintext data to be encrypted
26539beb93cSSam Leffler  * @in_len: Input buffer length
26639beb93cSSam Leffler  * @out_data: Pointer to output buffer (encrypted TLS data)
26739beb93cSSam Leffler  * @out_len: Maximum out_data length
26839beb93cSSam Leffler  * Returns: Number of bytes written to out_data, -1 on failure
26939beb93cSSam Leffler  *
27039beb93cSSam Leffler  * This function is used after TLS handshake has been completed successfully to
27139beb93cSSam Leffler  * send data in the encrypted tunnel.
27239beb93cSSam Leffler  */
27339beb93cSSam Leffler int tlsv1_client_encrypt(struct tlsv1_client *conn,
27439beb93cSSam Leffler 			 const u8 *in_data, size_t in_len,
27539beb93cSSam Leffler 			 u8 *out_data, size_t out_len)
27639beb93cSSam Leffler {
27739beb93cSSam Leffler 	size_t rlen;
27839beb93cSSam Leffler 
27939beb93cSSam Leffler 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
28039beb93cSSam Leffler 			in_data, in_len);
28139beb93cSSam Leffler 
28239beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
283*f05cddf9SRui Paulo 			      out_data, out_len, in_data, in_len, &rlen) < 0) {
28439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
28539beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
28639beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
28739beb93cSSam Leffler 		return -1;
28839beb93cSSam Leffler 	}
28939beb93cSSam Leffler 
29039beb93cSSam Leffler 	return rlen;
29139beb93cSSam Leffler }
29239beb93cSSam Leffler 
29339beb93cSSam Leffler 
29439beb93cSSam Leffler /**
29539beb93cSSam Leffler  * tlsv1_client_decrypt - Decrypt data from TLS tunnel
29639beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
29739beb93cSSam Leffler  * @in_data: Pointer to input buffer (encrypted TLS data)
29839beb93cSSam Leffler  * @in_len: Input buffer length
299*f05cddf9SRui Paulo  * @need_more_data: Set to 1 if more data would be needed to complete
300*f05cddf9SRui Paulo  *	processing
301*f05cddf9SRui Paulo  * Returns: Decrypted data or %NULL on failure
30239beb93cSSam Leffler  *
30339beb93cSSam Leffler  * This function is used after TLS handshake has been completed successfully to
30439beb93cSSam Leffler  * receive data from the encrypted tunnel.
30539beb93cSSam Leffler  */
306*f05cddf9SRui Paulo struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
30739beb93cSSam Leffler 				     const u8 *in_data, size_t in_len,
308*f05cddf9SRui Paulo 				     int *need_more_data)
30939beb93cSSam Leffler {
31039beb93cSSam Leffler 	const u8 *in_end, *pos;
311*f05cddf9SRui Paulo 	int used;
312*f05cddf9SRui Paulo 	u8 alert, *out_pos, ct;
31339beb93cSSam Leffler 	size_t olen;
314*f05cddf9SRui Paulo 	struct wpabuf *buf = NULL;
315*f05cddf9SRui Paulo 
316*f05cddf9SRui Paulo 	if (need_more_data)
317*f05cddf9SRui Paulo 		*need_more_data = 0;
318*f05cddf9SRui Paulo 
319*f05cddf9SRui Paulo 	if (conn->partial_input) {
320*f05cddf9SRui Paulo 		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
321*f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
322*f05cddf9SRui Paulo 				   "memory for pending record");
323*f05cddf9SRui Paulo 			alert = TLS_ALERT_INTERNAL_ERROR;
324*f05cddf9SRui Paulo 			goto fail;
325*f05cddf9SRui Paulo 		}
326*f05cddf9SRui Paulo 		wpabuf_put_data(conn->partial_input, in_data, in_len);
327*f05cddf9SRui Paulo 		in_data = wpabuf_head(conn->partial_input);
328*f05cddf9SRui Paulo 		in_len = wpabuf_len(conn->partial_input);
329*f05cddf9SRui Paulo 	}
33039beb93cSSam Leffler 
33139beb93cSSam Leffler 	pos = in_data;
33239beb93cSSam Leffler 	in_end = in_data + in_len;
33339beb93cSSam Leffler 
33439beb93cSSam Leffler 	while (pos < in_end) {
335*f05cddf9SRui Paulo 		ct = pos[0];
336*f05cddf9SRui Paulo 		if (wpabuf_resize(&buf, in_end - pos) < 0) {
337*f05cddf9SRui Paulo 			alert = TLS_ALERT_INTERNAL_ERROR;
338*f05cddf9SRui Paulo 			goto fail;
33939beb93cSSam Leffler 		}
340*f05cddf9SRui Paulo 		out_pos = wpabuf_put(buf, 0);
341*f05cddf9SRui Paulo 		olen = wpabuf_tailroom(buf);
342*f05cddf9SRui Paulo 		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
34339beb93cSSam Leffler 					    out_pos, &olen, &alert);
344*f05cddf9SRui Paulo 		if (used < 0) {
34539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
34639beb93cSSam Leffler 				   "failed");
347*f05cddf9SRui Paulo 			goto fail;
348*f05cddf9SRui Paulo 		}
349*f05cddf9SRui Paulo 		if (used == 0) {
350*f05cddf9SRui Paulo 			struct wpabuf *partial;
351*f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
352*f05cddf9SRui Paulo 			partial = wpabuf_alloc_copy(pos, in_end - pos);
353*f05cddf9SRui Paulo 			wpabuf_free(conn->partial_input);
354*f05cddf9SRui Paulo 			conn->partial_input = partial;
355*f05cddf9SRui Paulo 			if (conn->partial_input == NULL) {
356*f05cddf9SRui Paulo 				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
357*f05cddf9SRui Paulo 					   "allocate memory for pending "
358*f05cddf9SRui Paulo 					   "record");
359*f05cddf9SRui Paulo 				alert = TLS_ALERT_INTERNAL_ERROR;
360*f05cddf9SRui Paulo 				goto fail;
361*f05cddf9SRui Paulo 			}
362*f05cddf9SRui Paulo 			if (need_more_data)
363*f05cddf9SRui Paulo 				*need_more_data = 1;
364*f05cddf9SRui Paulo 			return buf;
365*f05cddf9SRui Paulo 		}
366*f05cddf9SRui Paulo 
367*f05cddf9SRui Paulo 		if (ct == TLS_CONTENT_TYPE_ALERT) {
368*f05cddf9SRui Paulo 			if (olen < 2) {
369*f05cddf9SRui Paulo 				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
370*f05cddf9SRui Paulo 					   "underflow");
371*f05cddf9SRui Paulo 				alert = TLS_ALERT_DECODE_ERROR;
372*f05cddf9SRui Paulo 				goto fail;
373*f05cddf9SRui Paulo 			}
374*f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
375*f05cddf9SRui Paulo 				   out_pos[0], out_pos[1]);
376*f05cddf9SRui Paulo 			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
377*f05cddf9SRui Paulo 				/* Continue processing */
378*f05cddf9SRui Paulo 				pos += used;
379*f05cddf9SRui Paulo 				continue;
380*f05cddf9SRui Paulo 			}
381*f05cddf9SRui Paulo 
382*f05cddf9SRui Paulo 			alert = out_pos[1];
383*f05cddf9SRui Paulo 			goto fail;
384*f05cddf9SRui Paulo 		}
385*f05cddf9SRui Paulo 
386*f05cddf9SRui Paulo 		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
387*f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
388*f05cddf9SRui Paulo 				   "0x%x when decrypting application data",
389*f05cddf9SRui Paulo 				   pos[0]);
390*f05cddf9SRui Paulo 			alert = TLS_ALERT_UNEXPECTED_MESSAGE;
391*f05cddf9SRui Paulo 			goto fail;
392*f05cddf9SRui Paulo 		}
393*f05cddf9SRui Paulo 
394*f05cddf9SRui Paulo 		wpabuf_put(buf, olen);
395*f05cddf9SRui Paulo 
396*f05cddf9SRui Paulo 		pos += used;
397*f05cddf9SRui Paulo 	}
398*f05cddf9SRui Paulo 
399*f05cddf9SRui Paulo 	wpabuf_free(conn->partial_input);
400*f05cddf9SRui Paulo 	conn->partial_input = NULL;
401*f05cddf9SRui Paulo 	return buf;
402*f05cddf9SRui Paulo 
403*f05cddf9SRui Paulo fail:
404*f05cddf9SRui Paulo 	wpabuf_free(buf);
405*f05cddf9SRui Paulo 	wpabuf_free(conn->partial_input);
406*f05cddf9SRui Paulo 	conn->partial_input = NULL;
40739beb93cSSam Leffler 	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
408*f05cddf9SRui Paulo 	return NULL;
40939beb93cSSam Leffler }
41039beb93cSSam Leffler 
41139beb93cSSam Leffler 
41239beb93cSSam Leffler /**
41339beb93cSSam Leffler  * tlsv1_client_global_init - Initialize TLSv1 client
41439beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
41539beb93cSSam Leffler  *
41639beb93cSSam Leffler  * This function must be called before using any other TLSv1 client functions.
41739beb93cSSam Leffler  */
41839beb93cSSam Leffler int tlsv1_client_global_init(void)
41939beb93cSSam Leffler {
42039beb93cSSam Leffler 	return crypto_global_init();
42139beb93cSSam Leffler }
42239beb93cSSam Leffler 
42339beb93cSSam Leffler 
42439beb93cSSam Leffler /**
42539beb93cSSam Leffler  * tlsv1_client_global_deinit - Deinitialize TLSv1 client
42639beb93cSSam Leffler  *
42739beb93cSSam Leffler  * This function can be used to deinitialize the TLSv1 client that was
42839beb93cSSam Leffler  * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
42939beb93cSSam Leffler  * can be called after this before calling tlsv1_client_global_init() again.
43039beb93cSSam Leffler  */
43139beb93cSSam Leffler void tlsv1_client_global_deinit(void)
43239beb93cSSam Leffler {
43339beb93cSSam Leffler 	crypto_global_deinit();
43439beb93cSSam Leffler }
43539beb93cSSam Leffler 
43639beb93cSSam Leffler 
43739beb93cSSam Leffler /**
43839beb93cSSam Leffler  * tlsv1_client_init - Initialize TLSv1 client connection
43939beb93cSSam Leffler  * Returns: Pointer to TLSv1 client connection data or %NULL on failure
44039beb93cSSam Leffler  */
44139beb93cSSam Leffler struct tlsv1_client * tlsv1_client_init(void)
44239beb93cSSam Leffler {
44339beb93cSSam Leffler 	struct tlsv1_client *conn;
44439beb93cSSam Leffler 	size_t count;
44539beb93cSSam Leffler 	u16 *suites;
44639beb93cSSam Leffler 
44739beb93cSSam Leffler 	conn = os_zalloc(sizeof(*conn));
44839beb93cSSam Leffler 	if (conn == NULL)
44939beb93cSSam Leffler 		return NULL;
45039beb93cSSam Leffler 
45139beb93cSSam Leffler 	conn->state = CLIENT_HELLO;
45239beb93cSSam Leffler 
45339beb93cSSam Leffler 	if (tls_verify_hash_init(&conn->verify) < 0) {
45439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
45539beb93cSSam Leffler 			   "hash");
45639beb93cSSam Leffler 		os_free(conn);
45739beb93cSSam Leffler 		return NULL;
45839beb93cSSam Leffler 	}
45939beb93cSSam Leffler 
46039beb93cSSam Leffler 	count = 0;
46139beb93cSSam Leffler 	suites = conn->cipher_suites;
462*f05cddf9SRui Paulo 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
46339beb93cSSam Leffler 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
464*f05cddf9SRui Paulo 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
46539beb93cSSam Leffler 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
46639beb93cSSam Leffler 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
46739beb93cSSam Leffler 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
46839beb93cSSam Leffler 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
46939beb93cSSam Leffler 	conn->num_cipher_suites = count;
47039beb93cSSam Leffler 
471*f05cddf9SRui Paulo 	conn->rl.tls_version = TLS_VERSION;
472*f05cddf9SRui Paulo 
47339beb93cSSam Leffler 	return conn;
47439beb93cSSam Leffler }
47539beb93cSSam Leffler 
47639beb93cSSam Leffler 
47739beb93cSSam Leffler /**
47839beb93cSSam Leffler  * tlsv1_client_deinit - Deinitialize TLSv1 client connection
47939beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
48039beb93cSSam Leffler  */
48139beb93cSSam Leffler void tlsv1_client_deinit(struct tlsv1_client *conn)
48239beb93cSSam Leffler {
48339beb93cSSam Leffler 	crypto_public_key_free(conn->server_rsa_key);
48439beb93cSSam Leffler 	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
48539beb93cSSam Leffler 	tlsv1_record_change_write_cipher(&conn->rl);
48639beb93cSSam Leffler 	tlsv1_record_change_read_cipher(&conn->rl);
48739beb93cSSam Leffler 	tls_verify_hash_free(&conn->verify);
48839beb93cSSam Leffler 	os_free(conn->client_hello_ext);
48939beb93cSSam Leffler 	tlsv1_client_free_dh(conn);
49039beb93cSSam Leffler 	tlsv1_cred_free(conn->cred);
491*f05cddf9SRui Paulo 	wpabuf_free(conn->partial_input);
49239beb93cSSam Leffler 	os_free(conn);
49339beb93cSSam Leffler }
49439beb93cSSam Leffler 
49539beb93cSSam Leffler 
49639beb93cSSam Leffler /**
49739beb93cSSam Leffler  * tlsv1_client_established - Check whether connection has been established
49839beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
49939beb93cSSam Leffler  * Returns: 1 if connection is established, 0 if not
50039beb93cSSam Leffler  */
50139beb93cSSam Leffler int tlsv1_client_established(struct tlsv1_client *conn)
50239beb93cSSam Leffler {
50339beb93cSSam Leffler 	return conn->state == ESTABLISHED;
50439beb93cSSam Leffler }
50539beb93cSSam Leffler 
50639beb93cSSam Leffler 
50739beb93cSSam Leffler /**
50839beb93cSSam Leffler  * tlsv1_client_prf - Use TLS-PRF to derive keying material
50939beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
51039beb93cSSam Leffler  * @label: Label (e.g., description of the key) for PRF
51139beb93cSSam Leffler  * @server_random_first: seed is 0 = client_random|server_random,
51239beb93cSSam Leffler  * 1 = server_random|client_random
51339beb93cSSam Leffler  * @out: Buffer for output data from TLS-PRF
51439beb93cSSam Leffler  * @out_len: Length of the output buffer
51539beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
51639beb93cSSam Leffler  */
51739beb93cSSam Leffler int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
51839beb93cSSam Leffler 		     int server_random_first, u8 *out, size_t out_len)
51939beb93cSSam Leffler {
52039beb93cSSam Leffler 	u8 seed[2 * TLS_RANDOM_LEN];
52139beb93cSSam Leffler 
52239beb93cSSam Leffler 	if (conn->state != ESTABLISHED)
52339beb93cSSam Leffler 		return -1;
52439beb93cSSam Leffler 
52539beb93cSSam Leffler 	if (server_random_first) {
52639beb93cSSam Leffler 		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
52739beb93cSSam Leffler 		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
52839beb93cSSam Leffler 			  TLS_RANDOM_LEN);
52939beb93cSSam Leffler 	} else {
53039beb93cSSam Leffler 		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
53139beb93cSSam Leffler 		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
53239beb93cSSam Leffler 			  TLS_RANDOM_LEN);
53339beb93cSSam Leffler 	}
53439beb93cSSam Leffler 
535*f05cddf9SRui Paulo 	return tls_prf(conn->rl.tls_version,
536*f05cddf9SRui Paulo 		       conn->master_secret, TLS_MASTER_SECRET_LEN,
53739beb93cSSam Leffler 		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
53839beb93cSSam Leffler }
53939beb93cSSam Leffler 
54039beb93cSSam Leffler 
54139beb93cSSam Leffler /**
54239beb93cSSam Leffler  * tlsv1_client_get_cipher - Get current cipher name
54339beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
54439beb93cSSam Leffler  * @buf: Buffer for the cipher name
54539beb93cSSam Leffler  * @buflen: buf size
54639beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
54739beb93cSSam Leffler  *
54839beb93cSSam Leffler  * Get the name of the currently used cipher.
54939beb93cSSam Leffler  */
55039beb93cSSam Leffler int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
55139beb93cSSam Leffler 			    size_t buflen)
55239beb93cSSam Leffler {
55339beb93cSSam Leffler 	char *cipher;
55439beb93cSSam Leffler 
55539beb93cSSam Leffler 	switch (conn->rl.cipher_suite) {
55639beb93cSSam Leffler 	case TLS_RSA_WITH_RC4_128_MD5:
55739beb93cSSam Leffler 		cipher = "RC4-MD5";
55839beb93cSSam Leffler 		break;
55939beb93cSSam Leffler 	case TLS_RSA_WITH_RC4_128_SHA:
56039beb93cSSam Leffler 		cipher = "RC4-SHA";
56139beb93cSSam Leffler 		break;
56239beb93cSSam Leffler 	case TLS_RSA_WITH_DES_CBC_SHA:
56339beb93cSSam Leffler 		cipher = "DES-CBC-SHA";
56439beb93cSSam Leffler 		break;
56539beb93cSSam Leffler 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
56639beb93cSSam Leffler 		cipher = "DES-CBC3-SHA";
56739beb93cSSam Leffler 		break;
568*f05cddf9SRui Paulo 	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
569*f05cddf9SRui Paulo 		cipher = "ADH-AES-128-SHA256";
570*f05cddf9SRui Paulo 		break;
57139beb93cSSam Leffler 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
57239beb93cSSam Leffler 		cipher = "ADH-AES-128-SHA";
57339beb93cSSam Leffler 		break;
57439beb93cSSam Leffler 	case TLS_RSA_WITH_AES_256_CBC_SHA:
57539beb93cSSam Leffler 		cipher = "AES-256-SHA";
57639beb93cSSam Leffler 		break;
577*f05cddf9SRui Paulo 	case TLS_RSA_WITH_AES_256_CBC_SHA256:
578*f05cddf9SRui Paulo 		cipher = "AES-256-SHA256";
579*f05cddf9SRui Paulo 		break;
58039beb93cSSam Leffler 	case TLS_RSA_WITH_AES_128_CBC_SHA:
58139beb93cSSam Leffler 		cipher = "AES-128-SHA";
58239beb93cSSam Leffler 		break;
583*f05cddf9SRui Paulo 	case TLS_RSA_WITH_AES_128_CBC_SHA256:
584*f05cddf9SRui Paulo 		cipher = "AES-128-SHA256";
585*f05cddf9SRui Paulo 		break;
58639beb93cSSam Leffler 	default:
58739beb93cSSam Leffler 		return -1;
58839beb93cSSam Leffler 	}
58939beb93cSSam Leffler 
59039beb93cSSam Leffler 	if (os_strlcpy(buf, cipher, buflen) >= buflen)
59139beb93cSSam Leffler 		return -1;
59239beb93cSSam Leffler 	return 0;
59339beb93cSSam Leffler }
59439beb93cSSam Leffler 
59539beb93cSSam Leffler 
59639beb93cSSam Leffler /**
59739beb93cSSam Leffler  * tlsv1_client_shutdown - Shutdown TLS connection
59839beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
59939beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
60039beb93cSSam Leffler  */
60139beb93cSSam Leffler int tlsv1_client_shutdown(struct tlsv1_client *conn)
60239beb93cSSam Leffler {
60339beb93cSSam Leffler 	conn->state = CLIENT_HELLO;
60439beb93cSSam Leffler 
60539beb93cSSam Leffler 	if (tls_verify_hash_init(&conn->verify) < 0) {
60639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
60739beb93cSSam Leffler 			   "hash");
60839beb93cSSam Leffler 		return -1;
60939beb93cSSam Leffler 	}
61039beb93cSSam Leffler 
61139beb93cSSam Leffler 	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
61239beb93cSSam Leffler 	tlsv1_record_change_write_cipher(&conn->rl);
61339beb93cSSam Leffler 	tlsv1_record_change_read_cipher(&conn->rl);
61439beb93cSSam Leffler 
61539beb93cSSam Leffler 	conn->certificate_requested = 0;
61639beb93cSSam Leffler 	crypto_public_key_free(conn->server_rsa_key);
61739beb93cSSam Leffler 	conn->server_rsa_key = NULL;
61839beb93cSSam Leffler 	conn->session_resumed = 0;
61939beb93cSSam Leffler 
62039beb93cSSam Leffler 	return 0;
62139beb93cSSam Leffler }
62239beb93cSSam Leffler 
62339beb93cSSam Leffler 
62439beb93cSSam Leffler /**
62539beb93cSSam Leffler  * tlsv1_client_resumed - Was session resumption used
62639beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
62739beb93cSSam Leffler  * Returns: 1 if current session used session resumption, 0 if not
62839beb93cSSam Leffler  */
62939beb93cSSam Leffler int tlsv1_client_resumed(struct tlsv1_client *conn)
63039beb93cSSam Leffler {
63139beb93cSSam Leffler 	return !!conn->session_resumed;
63239beb93cSSam Leffler }
63339beb93cSSam Leffler 
63439beb93cSSam Leffler 
63539beb93cSSam Leffler /**
63639beb93cSSam Leffler  * tlsv1_client_hello_ext - Set TLS extension for ClientHello
63739beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
63839beb93cSSam Leffler  * @ext_type: Extension type
63939beb93cSSam Leffler  * @data: Extension payload (%NULL to remove extension)
64039beb93cSSam Leffler  * @data_len: Extension payload length
64139beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
64239beb93cSSam Leffler  */
64339beb93cSSam Leffler int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
64439beb93cSSam Leffler 			   const u8 *data, size_t data_len)
64539beb93cSSam Leffler {
64639beb93cSSam Leffler 	u8 *pos;
64739beb93cSSam Leffler 
64839beb93cSSam Leffler 	conn->session_ticket_included = 0;
64939beb93cSSam Leffler 	os_free(conn->client_hello_ext);
65039beb93cSSam Leffler 	conn->client_hello_ext = NULL;
65139beb93cSSam Leffler 	conn->client_hello_ext_len = 0;
65239beb93cSSam Leffler 
65339beb93cSSam Leffler 	if (data == NULL || data_len == 0)
65439beb93cSSam Leffler 		return 0;
65539beb93cSSam Leffler 
65639beb93cSSam Leffler 	pos = conn->client_hello_ext = os_malloc(6 + data_len);
65739beb93cSSam Leffler 	if (pos == NULL)
65839beb93cSSam Leffler 		return -1;
65939beb93cSSam Leffler 
66039beb93cSSam Leffler 	WPA_PUT_BE16(pos, 4 + data_len);
66139beb93cSSam Leffler 	pos += 2;
66239beb93cSSam Leffler 	WPA_PUT_BE16(pos, ext_type);
66339beb93cSSam Leffler 	pos += 2;
66439beb93cSSam Leffler 	WPA_PUT_BE16(pos, data_len);
66539beb93cSSam Leffler 	pos += 2;
66639beb93cSSam Leffler 	os_memcpy(pos, data, data_len);
66739beb93cSSam Leffler 	conn->client_hello_ext_len = 6 + data_len;
66839beb93cSSam Leffler 
66939beb93cSSam Leffler 	if (ext_type == TLS_EXT_PAC_OPAQUE) {
67039beb93cSSam Leffler 		conn->session_ticket_included = 1;
67139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
67239beb93cSSam Leffler 	}
67339beb93cSSam Leffler 
67439beb93cSSam Leffler 	return 0;
67539beb93cSSam Leffler }
67639beb93cSSam Leffler 
67739beb93cSSam Leffler 
67839beb93cSSam Leffler /**
67939beb93cSSam Leffler  * tlsv1_client_get_keys - Get master key and random data from TLS connection
68039beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
68139beb93cSSam Leffler  * @keys: Structure of key/random data (filled on success)
68239beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
68339beb93cSSam Leffler  */
68439beb93cSSam Leffler int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
68539beb93cSSam Leffler {
68639beb93cSSam Leffler 	os_memset(keys, 0, sizeof(*keys));
68739beb93cSSam Leffler 	if (conn->state == CLIENT_HELLO)
68839beb93cSSam Leffler 		return -1;
68939beb93cSSam Leffler 
69039beb93cSSam Leffler 	keys->client_random = conn->client_random;
69139beb93cSSam Leffler 	keys->client_random_len = TLS_RANDOM_LEN;
69239beb93cSSam Leffler 
69339beb93cSSam Leffler 	if (conn->state != SERVER_HELLO) {
69439beb93cSSam Leffler 		keys->server_random = conn->server_random;
69539beb93cSSam Leffler 		keys->server_random_len = TLS_RANDOM_LEN;
69639beb93cSSam Leffler 		keys->master_key = conn->master_secret;
69739beb93cSSam Leffler 		keys->master_key_len = TLS_MASTER_SECRET_LEN;
69839beb93cSSam Leffler 	}
69939beb93cSSam Leffler 
70039beb93cSSam Leffler 	return 0;
70139beb93cSSam Leffler }
70239beb93cSSam Leffler 
70339beb93cSSam Leffler 
70439beb93cSSam Leffler /**
70539beb93cSSam Leffler  * tlsv1_client_get_keyblock_size - Get TLS key_block size
70639beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
70739beb93cSSam Leffler  * Returns: Size of the key_block for the negotiated cipher suite or -1 on
70839beb93cSSam Leffler  * failure
70939beb93cSSam Leffler  */
71039beb93cSSam Leffler int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
71139beb93cSSam Leffler {
71239beb93cSSam Leffler 	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
71339beb93cSSam Leffler 		return -1;
71439beb93cSSam Leffler 
71539beb93cSSam Leffler 	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
71639beb93cSSam Leffler 		    conn->rl.iv_size);
71739beb93cSSam Leffler }
71839beb93cSSam Leffler 
71939beb93cSSam Leffler 
72039beb93cSSam Leffler /**
72139beb93cSSam Leffler  * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
72239beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
72339beb93cSSam Leffler  * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
72439beb93cSSam Leffler  * (TLS_CIPHER_*).
72539beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
72639beb93cSSam Leffler  */
72739beb93cSSam Leffler int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
72839beb93cSSam Leffler {
72939beb93cSSam Leffler 	size_t count;
73039beb93cSSam Leffler 	u16 *suites;
73139beb93cSSam Leffler 
73239beb93cSSam Leffler 	/* TODO: implement proper configuration of cipher suites */
73339beb93cSSam Leffler 	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
73439beb93cSSam Leffler 		count = 0;
73539beb93cSSam Leffler 		suites = conn->cipher_suites;
736*f05cddf9SRui Paulo 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
73739beb93cSSam Leffler 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
738*f05cddf9SRui Paulo 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
73939beb93cSSam Leffler 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
74039beb93cSSam Leffler 		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
74139beb93cSSam Leffler 		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
74239beb93cSSam Leffler 		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
7433157ba21SRui Paulo 
7443157ba21SRui Paulo 		/*
7453157ba21SRui Paulo 		 * Cisco AP (at least 350 and 1200 series) local authentication
7463157ba21SRui Paulo 		 * server does not know how to search cipher suites from the
7473157ba21SRui Paulo 		 * list and seem to require that the last entry in the list is
7483157ba21SRui Paulo 		 * the one that it wants to use. However, TLS specification
7493157ba21SRui Paulo 		 * requires the list to be in the client preference order. As a
7503157ba21SRui Paulo 		 * workaround, add anon-DH AES-128-SHA1 again at the end of the
7513157ba21SRui Paulo 		 * list to allow the Cisco code to find it.
7523157ba21SRui Paulo 		 */
7533157ba21SRui Paulo 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
75439beb93cSSam Leffler 		conn->num_cipher_suites = count;
75539beb93cSSam Leffler 	}
75639beb93cSSam Leffler 
75739beb93cSSam Leffler 	return 0;
75839beb93cSSam Leffler }
75939beb93cSSam Leffler 
76039beb93cSSam Leffler 
76139beb93cSSam Leffler /**
76239beb93cSSam Leffler  * tlsv1_client_set_cred - Set client credentials
76339beb93cSSam Leffler  * @conn: TLSv1 client connection data from tlsv1_client_init()
76439beb93cSSam Leffler  * @cred: Credentials from tlsv1_cred_alloc()
76539beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
76639beb93cSSam Leffler  *
76739beb93cSSam Leffler  * On success, the client takes ownership of the credentials block and caller
76839beb93cSSam Leffler  * must not free it. On failure, caller is responsible for freeing the
76939beb93cSSam Leffler  * credential block.
77039beb93cSSam Leffler  */
77139beb93cSSam Leffler int tlsv1_client_set_cred(struct tlsv1_client *conn,
77239beb93cSSam Leffler 			  struct tlsv1_credentials *cred)
77339beb93cSSam Leffler {
77439beb93cSSam Leffler 	tlsv1_cred_free(conn->cred);
77539beb93cSSam Leffler 	conn->cred = cred;
77639beb93cSSam Leffler 	return 0;
77739beb93cSSam Leffler }
77839beb93cSSam Leffler 
77939beb93cSSam Leffler 
780*f05cddf9SRui Paulo void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
781*f05cddf9SRui Paulo {
782*f05cddf9SRui Paulo 	conn->disable_time_checks = !enabled;
783*f05cddf9SRui Paulo }
784*f05cddf9SRui Paulo 
785*f05cddf9SRui Paulo 
78639beb93cSSam Leffler void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
78739beb93cSSam Leffler 					tlsv1_client_session_ticket_cb cb,
78839beb93cSSam Leffler 					void *ctx)
78939beb93cSSam Leffler {
79039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
79139beb93cSSam Leffler 		   cb, ctx);
79239beb93cSSam Leffler 	conn->session_ticket_cb = cb;
79339beb93cSSam Leffler 	conn->session_ticket_cb_ctx = ctx;
79439beb93cSSam Leffler }
795