xref: /freebsd/contrib/wpa/src/tls/tlsv1_client_write.c (revision 780fb4a2fa9a9aee5ac48a60b790f567c0dc13e9)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * TLSv1 client - write handshake message
3*780fb4a2SCy Schubert  * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui 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/md5.h"
13e28a4053SRui Paulo #include "crypto/sha1.h"
14f05cddf9SRui Paulo #include "crypto/sha256.h"
15e28a4053SRui Paulo #include "crypto/tls.h"
16f05cddf9SRui Paulo #include "crypto/random.h"
1739beb93cSSam Leffler #include "x509v3.h"
1839beb93cSSam Leffler #include "tlsv1_common.h"
1939beb93cSSam Leffler #include "tlsv1_record.h"
2039beb93cSSam Leffler #include "tlsv1_client.h"
2139beb93cSSam Leffler #include "tlsv1_client_i.h"
2239beb93cSSam Leffler 
2339beb93cSSam Leffler 
2439beb93cSSam Leffler static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
2539beb93cSSam Leffler {
2639beb93cSSam Leffler 	size_t len = 0;
2739beb93cSSam Leffler 	struct x509_certificate *cert;
2839beb93cSSam Leffler 
2939beb93cSSam Leffler 	if (conn->cred == NULL)
3039beb93cSSam Leffler 		return 0;
3139beb93cSSam Leffler 
3239beb93cSSam Leffler 	cert = conn->cred->cert;
3339beb93cSSam Leffler 	while (cert) {
3439beb93cSSam Leffler 		len += 3 + cert->cert_len;
3539beb93cSSam Leffler 		if (x509_certificate_self_signed(cert))
3639beb93cSSam Leffler 			break;
3739beb93cSSam Leffler 		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
3839beb93cSSam Leffler 						    &cert->issuer);
3939beb93cSSam Leffler 	}
4039beb93cSSam Leffler 
4139beb93cSSam Leffler 	return len;
4239beb93cSSam Leffler }
4339beb93cSSam Leffler 
4439beb93cSSam Leffler 
4539beb93cSSam Leffler u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
4639beb93cSSam Leffler {
4739beb93cSSam Leffler 	u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
4839beb93cSSam Leffler 	struct os_time now;
4939beb93cSSam Leffler 	size_t len, i;
50*780fb4a2SCy Schubert 	u8 *ext_start;
51*780fb4a2SCy Schubert 	u16 tls_version = TLS_VERSION;
5239beb93cSSam Leffler 
53*780fb4a2SCy Schubert 	/* Pick the highest locally enabled TLS version */
54*780fb4a2SCy Schubert #ifdef CONFIG_TLSV12
55*780fb4a2SCy Schubert 	if ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
56*780fb4a2SCy Schubert 	    tls_version == TLS_VERSION_1_2)
57*780fb4a2SCy Schubert 		tls_version = TLS_VERSION_1_1;
58*780fb4a2SCy Schubert #endif /* CONFIG_TLSV12 */
59*780fb4a2SCy Schubert #ifdef CONFIG_TLSV11
60*780fb4a2SCy Schubert 	if ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
61*780fb4a2SCy Schubert 	    tls_version == TLS_VERSION_1_1)
62*780fb4a2SCy Schubert 		tls_version = TLS_VERSION_1;
63*780fb4a2SCy Schubert #endif /* CONFIG_TLSV11 */
64*780fb4a2SCy Schubert 	if ((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
65*780fb4a2SCy Schubert 	    tls_version == TLS_VERSION_1) {
66*780fb4a2SCy Schubert 		wpa_printf(MSG_INFO, "TLSv1: No TLS version allowed");
67*780fb4a2SCy Schubert 		return NULL;
68*780fb4a2SCy Schubert 	}
69*780fb4a2SCy Schubert 
70*780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello (ver %s)",
71*780fb4a2SCy Schubert 		   tls_version_str(tls_version));
7239beb93cSSam Leffler 	*out_len = 0;
7339beb93cSSam Leffler 
7439beb93cSSam Leffler 	os_get_time(&now);
7539beb93cSSam Leffler 	WPA_PUT_BE32(conn->client_random, now.sec);
76f05cddf9SRui Paulo 	if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
7739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
7839beb93cSSam Leffler 			   "client_random");
7939beb93cSSam Leffler 		return NULL;
8039beb93cSSam Leffler 	}
8139beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
8239beb93cSSam Leffler 		    conn->client_random, TLS_RANDOM_LEN);
8339beb93cSSam Leffler 
84*780fb4a2SCy Schubert 	len = 150 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
8539beb93cSSam Leffler 	hello = os_malloc(len);
8639beb93cSSam Leffler 	if (hello == NULL)
8739beb93cSSam Leffler 		return NULL;
8839beb93cSSam Leffler 	end = hello + len;
8939beb93cSSam Leffler 
9039beb93cSSam Leffler 	rhdr = hello;
9139beb93cSSam Leffler 	pos = rhdr + TLS_RECORD_HEADER_LEN;
9239beb93cSSam Leffler 
9339beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
9439beb93cSSam Leffler 
9539beb93cSSam Leffler 	/* Handshake */
9639beb93cSSam Leffler 	hs_start = pos;
9739beb93cSSam Leffler 	/* HandshakeType msg_type */
9839beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
9939beb93cSSam Leffler 	/* uint24 length (to be filled) */
10039beb93cSSam Leffler 	hs_length = pos;
10139beb93cSSam Leffler 	pos += 3;
10239beb93cSSam Leffler 	/* body - ClientHello */
10339beb93cSSam Leffler 	/* ProtocolVersion client_version */
104*780fb4a2SCy Schubert 	WPA_PUT_BE16(pos, tls_version);
10539beb93cSSam Leffler 	pos += 2;
10639beb93cSSam Leffler 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
10739beb93cSSam Leffler 	os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
10839beb93cSSam Leffler 	pos += TLS_RANDOM_LEN;
10939beb93cSSam Leffler 	/* SessionID session_id */
11039beb93cSSam Leffler 	*pos++ = conn->session_id_len;
11139beb93cSSam Leffler 	os_memcpy(pos, conn->session_id, conn->session_id_len);
11239beb93cSSam Leffler 	pos += conn->session_id_len;
11339beb93cSSam Leffler 	/* CipherSuite cipher_suites<2..2^16-1> */
11439beb93cSSam Leffler 	WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
11539beb93cSSam Leffler 	pos += 2;
11639beb93cSSam Leffler 	for (i = 0; i < conn->num_cipher_suites; i++) {
11739beb93cSSam Leffler 		WPA_PUT_BE16(pos, conn->cipher_suites[i]);
11839beb93cSSam Leffler 		pos += 2;
11939beb93cSSam Leffler 	}
12039beb93cSSam Leffler 	/* CompressionMethod compression_methods<1..2^8-1> */
12139beb93cSSam Leffler 	*pos++ = 1;
12239beb93cSSam Leffler 	*pos++ = TLS_COMPRESSION_NULL;
12339beb93cSSam Leffler 
124*780fb4a2SCy Schubert 	/* Extension */
125*780fb4a2SCy Schubert 	ext_start = pos;
126*780fb4a2SCy Schubert 	pos += 2;
127*780fb4a2SCy Schubert 
128*780fb4a2SCy Schubert #ifdef CONFIG_TLSV12
129*780fb4a2SCy Schubert 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
130*780fb4a2SCy Schubert 		/*
131*780fb4a2SCy Schubert 		 * Add signature_algorithms extension since we support only
132*780fb4a2SCy Schubert 		 * SHA256 (and not the default SHA1) with TLSv1.2.
133*780fb4a2SCy Schubert 		 */
134*780fb4a2SCy Schubert 		/* ExtensionsType extension_type = signature_algorithms(13) */
135*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
136*780fb4a2SCy Schubert 		pos += 2;
137*780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
138*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 8);
139*780fb4a2SCy Schubert 		pos += 2;
140*780fb4a2SCy Schubert 		/* supported_signature_algorithms<2..2^16-2> length */
141*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 6);
142*780fb4a2SCy Schubert 		pos += 2;
143*780fb4a2SCy Schubert 		/* supported_signature_algorithms */
144*780fb4a2SCy Schubert 		*pos++ = TLS_HASH_ALG_SHA512;
145*780fb4a2SCy Schubert 		*pos++ = TLS_SIGN_ALG_RSA;
146*780fb4a2SCy Schubert 		*pos++ = TLS_HASH_ALG_SHA384;
147*780fb4a2SCy Schubert 		*pos++ = TLS_SIGN_ALG_RSA;
148*780fb4a2SCy Schubert 		*pos++ = TLS_HASH_ALG_SHA256;
149*780fb4a2SCy Schubert 		*pos++ = TLS_SIGN_ALG_RSA;
150*780fb4a2SCy Schubert 	}
151*780fb4a2SCy Schubert #endif /* CONFIG_TLSV12 */
152*780fb4a2SCy Schubert 
15339beb93cSSam Leffler 	if (conn->client_hello_ext) {
15439beb93cSSam Leffler 		os_memcpy(pos, conn->client_hello_ext,
15539beb93cSSam Leffler 			  conn->client_hello_ext_len);
15639beb93cSSam Leffler 		pos += conn->client_hello_ext_len;
15739beb93cSSam Leffler 	}
15839beb93cSSam Leffler 
159*780fb4a2SCy Schubert 	if (conn->flags & TLS_CONN_REQUEST_OCSP) {
160*780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
161*780fb4a2SCy Schubert 			   "TLSv1: Add status_request extension for OCSP stapling");
162*780fb4a2SCy Schubert 		/* ExtensionsType extension_type = status_request(5) */
163*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
164*780fb4a2SCy Schubert 		pos += 2;
165*780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
166*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 5);
167*780fb4a2SCy Schubert 		pos += 2;
168*780fb4a2SCy Schubert 
169*780fb4a2SCy Schubert 		/*
170*780fb4a2SCy Schubert 		 * RFC 6066, 8:
171*780fb4a2SCy Schubert 		 * struct {
172*780fb4a2SCy Schubert 		 *     CertificateStatusType status_type;
173*780fb4a2SCy Schubert 		 *     select (status_type) {
174*780fb4a2SCy Schubert 		 *         case ocsp: OCSPStatusRequest;
175*780fb4a2SCy Schubert 		 *     } request;
176*780fb4a2SCy Schubert 		 * } CertificateStatusRequest;
177*780fb4a2SCy Schubert 		 *
178*780fb4a2SCy Schubert 		 * enum { ocsp(1), (255) } CertificateStatusType;
179*780fb4a2SCy Schubert 		 */
180*780fb4a2SCy Schubert 		*pos++ = 1; /* status_type = ocsp(1) */
181*780fb4a2SCy Schubert 
182*780fb4a2SCy Schubert 		/*
183*780fb4a2SCy Schubert 		 * struct {
184*780fb4a2SCy Schubert 		 *     ResponderID responder_id_list<0..2^16-1>;
185*780fb4a2SCy Schubert 		 *     Extensions  request_extensions;
186*780fb4a2SCy Schubert 		 * } OCSPStatusRequest;
187*780fb4a2SCy Schubert 		 *
188*780fb4a2SCy Schubert 		 * opaque ResponderID<1..2^16-1>;
189*780fb4a2SCy Schubert 		 * opaque Extensions<0..2^16-1>;
190*780fb4a2SCy Schubert 		 */
191*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
192*780fb4a2SCy Schubert 		pos += 2;
193*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
194*780fb4a2SCy Schubert 		pos += 2;
195*780fb4a2SCy Schubert 
196*780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
197*780fb4a2SCy Schubert 			   "TLSv1: Add status_request_v2 extension for OCSP stapling");
198*780fb4a2SCy Schubert 		/* ExtensionsType extension_type = status_request_v2(17) */
199*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
200*780fb4a2SCy Schubert 		pos += 2;
201*780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
202*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 7);
203*780fb4a2SCy Schubert 		pos += 2;
204*780fb4a2SCy Schubert 
205*780fb4a2SCy Schubert 		/*
206*780fb4a2SCy Schubert 		 * RFC 6961, 2.2:
207*780fb4a2SCy Schubert 		 * struct {
208*780fb4a2SCy Schubert 		 *     CertificateStatusType status_type;
209*780fb4a2SCy Schubert 		 *     uint16 request_length;
210*780fb4a2SCy Schubert 		 *     select (status_type) {
211*780fb4a2SCy Schubert 		 *         case ocsp: OCSPStatusRequest;
212*780fb4a2SCy Schubert 		 *         case ocsp_multi: OCSPStatusRequest;
213*780fb4a2SCy Schubert 		 *     } request;
214*780fb4a2SCy Schubert 		 * } CertificateStatusRequestItemV2;
215*780fb4a2SCy Schubert 		 *
216*780fb4a2SCy Schubert 		 * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
217*780fb4a2SCy Schubert 		 *
218*780fb4a2SCy Schubert 		 * struct {
219*780fb4a2SCy Schubert 		 * CertificateStatusRequestItemV2
220*780fb4a2SCy Schubert 		 *     certificate_status_req_list<1..2^16-1>;
221*780fb4a2SCy Schubert 		 * } CertificateStatusRequestListV2;
222*780fb4a2SCy Schubert 		 */
223*780fb4a2SCy Schubert 
224*780fb4a2SCy Schubert 		/* certificate_status_req_list<1..2^16-1> */
225*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 5);
226*780fb4a2SCy Schubert 		pos += 2;
227*780fb4a2SCy Schubert 
228*780fb4a2SCy Schubert 		/* CertificateStatusRequestItemV2 */
229*780fb4a2SCy Schubert 		*pos++ = 2; /* status_type = ocsp_multi(2) */
230*780fb4a2SCy Schubert 		/* OCSPStatusRequest as shown above for v1 */
231*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
232*780fb4a2SCy Schubert 		pos += 2;
233*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
234*780fb4a2SCy Schubert 		pos += 2;
235*780fb4a2SCy Schubert 	}
236*780fb4a2SCy Schubert 
237*780fb4a2SCy Schubert 	if (pos == ext_start + 2)
238*780fb4a2SCy Schubert 		pos -= 2; /* no extensions */
239*780fb4a2SCy Schubert 	else
240*780fb4a2SCy Schubert 		WPA_PUT_BE16(ext_start, pos - ext_start - 2);
241*780fb4a2SCy Schubert 
24239beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
24339beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
24439beb93cSSam Leffler 
24539beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
246f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
247f05cddf9SRui Paulo 			      out_len) < 0) {
24839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
24939beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
25039beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
25139beb93cSSam Leffler 		os_free(hello);
25239beb93cSSam Leffler 		return NULL;
25339beb93cSSam Leffler 	}
25439beb93cSSam Leffler 
25539beb93cSSam Leffler 	conn->state = SERVER_HELLO;
25639beb93cSSam Leffler 
25739beb93cSSam Leffler 	return hello;
25839beb93cSSam Leffler }
25939beb93cSSam Leffler 
26039beb93cSSam Leffler 
26139beb93cSSam Leffler static int tls_write_client_certificate(struct tlsv1_client *conn,
26239beb93cSSam Leffler 					u8 **msgpos, u8 *end)
26339beb93cSSam Leffler {
26439beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
26539beb93cSSam Leffler 	size_t rlen;
26639beb93cSSam Leffler 	struct x509_certificate *cert;
26739beb93cSSam Leffler 
26839beb93cSSam Leffler 	pos = *msgpos;
269*780fb4a2SCy Schubert 	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
270*780fb4a2SCy Schubert 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
271*780fb4a2SCy Schubert 			  TLS_ALERT_INTERNAL_ERROR);
272*780fb4a2SCy Schubert 		return -1;
273*780fb4a2SCy Schubert 	}
27439beb93cSSam Leffler 
27539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
27639beb93cSSam Leffler 	rhdr = pos;
27739beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
27839beb93cSSam Leffler 
27939beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
28039beb93cSSam Leffler 
28139beb93cSSam Leffler 	/* Handshake */
28239beb93cSSam Leffler 	hs_start = pos;
28339beb93cSSam Leffler 	/* HandshakeType msg_type */
28439beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
28539beb93cSSam Leffler 	/* uint24 length (to be filled) */
28639beb93cSSam Leffler 	hs_length = pos;
28739beb93cSSam Leffler 	pos += 3;
28839beb93cSSam Leffler 	/* body - Certificate */
28939beb93cSSam Leffler 	/* uint24 length (to be filled) */
29039beb93cSSam Leffler 	cert_start = pos;
29139beb93cSSam Leffler 	pos += 3;
29239beb93cSSam Leffler 	cert = conn->cred ? conn->cred->cert : NULL;
29339beb93cSSam Leffler 	while (cert) {
294*780fb4a2SCy Schubert 		if (3 + cert->cert_len > (size_t) (end - pos)) {
29539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
29639beb93cSSam Leffler 				   "for Certificate (cert_len=%lu left=%lu)",
29739beb93cSSam Leffler 				   (unsigned long) cert->cert_len,
29839beb93cSSam Leffler 				   (unsigned long) (end - pos));
29939beb93cSSam Leffler 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
30039beb93cSSam Leffler 				  TLS_ALERT_INTERNAL_ERROR);
30139beb93cSSam Leffler 			return -1;
30239beb93cSSam Leffler 		}
30339beb93cSSam Leffler 		WPA_PUT_BE24(pos, cert->cert_len);
30439beb93cSSam Leffler 		pos += 3;
30539beb93cSSam Leffler 		os_memcpy(pos, cert->cert_start, cert->cert_len);
30639beb93cSSam Leffler 		pos += cert->cert_len;
30739beb93cSSam Leffler 
30839beb93cSSam Leffler 		if (x509_certificate_self_signed(cert))
30939beb93cSSam Leffler 			break;
31039beb93cSSam Leffler 		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
31139beb93cSSam Leffler 						    &cert->issuer);
31239beb93cSSam Leffler 	}
31339beb93cSSam Leffler 	if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
31439beb93cSSam Leffler 		/*
31539beb93cSSam Leffler 		 * Client was not configured with all the needed certificates
31639beb93cSSam Leffler 		 * to form a full certificate chain. The server may fail to
31739beb93cSSam Leffler 		 * validate the chain unless it is configured with all the
31839beb93cSSam Leffler 		 * missing CA certificates.
31939beb93cSSam Leffler 		 */
32039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
32139beb93cSSam Leffler 			   "not configured - validation may fail");
32239beb93cSSam Leffler 	}
32339beb93cSSam Leffler 	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
32439beb93cSSam Leffler 
32539beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
32639beb93cSSam Leffler 
32739beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
328f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
329f05cddf9SRui Paulo 			      &rlen) < 0) {
33039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
33139beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
33239beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
33339beb93cSSam Leffler 		return -1;
33439beb93cSSam Leffler 	}
33539beb93cSSam Leffler 	pos = rhdr + rlen;
33639beb93cSSam Leffler 
33739beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
33839beb93cSSam Leffler 
33939beb93cSSam Leffler 	*msgpos = pos;
34039beb93cSSam Leffler 
34139beb93cSSam Leffler 	return 0;
34239beb93cSSam Leffler }
34339beb93cSSam Leffler 
34439beb93cSSam Leffler 
3455b9c547cSRui Paulo static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
34639beb93cSSam Leffler {
34739beb93cSSam Leffler 	/* ClientDiffieHellmanPublic */
34839beb93cSSam Leffler 	u8 *csecret, *csecret_start, *dh_yc, *shared;
34939beb93cSSam Leffler 	size_t csecret_len, dh_yc_len, shared_len;
35039beb93cSSam Leffler 
35139beb93cSSam Leffler 	csecret_len = conn->dh_p_len;
35239beb93cSSam Leffler 	csecret = os_malloc(csecret_len);
35339beb93cSSam Leffler 	if (csecret == NULL) {
35439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
35539beb93cSSam Leffler 			   "memory for Yc (Diffie-Hellman)");
35639beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
35739beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
35839beb93cSSam Leffler 		return -1;
35939beb93cSSam Leffler 	}
360f05cddf9SRui Paulo 	if (random_get_bytes(csecret, csecret_len)) {
36139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
36239beb93cSSam Leffler 			   "data for Diffie-Hellman");
36339beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
36439beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
36539beb93cSSam Leffler 		os_free(csecret);
36639beb93cSSam Leffler 		return -1;
36739beb93cSSam Leffler 	}
36839beb93cSSam Leffler 
36939beb93cSSam Leffler 	if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
37039beb93cSSam Leffler 		csecret[0] = 0; /* make sure Yc < p */
37139beb93cSSam Leffler 
37239beb93cSSam Leffler 	csecret_start = csecret;
37339beb93cSSam Leffler 	while (csecret_len > 1 && *csecret_start == 0) {
37439beb93cSSam Leffler 		csecret_start++;
37539beb93cSSam Leffler 		csecret_len--;
37639beb93cSSam Leffler 	}
37739beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
37839beb93cSSam Leffler 			csecret_start, csecret_len);
37939beb93cSSam Leffler 
38039beb93cSSam Leffler 	/* Yc = g^csecret mod p */
38139beb93cSSam Leffler 	dh_yc_len = conn->dh_p_len;
38239beb93cSSam Leffler 	dh_yc = os_malloc(dh_yc_len);
38339beb93cSSam Leffler 	if (dh_yc == NULL) {
38439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
38539beb93cSSam Leffler 			   "memory for Diffie-Hellman");
38639beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
38739beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
38839beb93cSSam Leffler 		os_free(csecret);
38939beb93cSSam Leffler 		return -1;
39039beb93cSSam Leffler 	}
39139beb93cSSam Leffler 	if (crypto_mod_exp(conn->dh_g, conn->dh_g_len,
39239beb93cSSam Leffler 			   csecret_start, csecret_len,
39339beb93cSSam Leffler 			   conn->dh_p, conn->dh_p_len,
39439beb93cSSam Leffler 			   dh_yc, &dh_yc_len)) {
39539beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
39639beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
39739beb93cSSam Leffler 		os_free(csecret);
39839beb93cSSam Leffler 		os_free(dh_yc);
39939beb93cSSam Leffler 		return -1;
40039beb93cSSam Leffler 	}
40139beb93cSSam Leffler 
40239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
40339beb93cSSam Leffler 		    dh_yc, dh_yc_len);
40439beb93cSSam Leffler 
405*780fb4a2SCy Schubert 	if (end - *pos < 2) {
406*780fb4a2SCy Schubert 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
407*780fb4a2SCy Schubert 			  TLS_ALERT_INTERNAL_ERROR);
408*780fb4a2SCy Schubert 		os_free(csecret);
409*780fb4a2SCy Schubert 		os_free(dh_yc);
410*780fb4a2SCy Schubert 		return -1;
411*780fb4a2SCy Schubert 	}
41239beb93cSSam Leffler 	WPA_PUT_BE16(*pos, dh_yc_len);
41339beb93cSSam Leffler 	*pos += 2;
414*780fb4a2SCy Schubert 	if (dh_yc_len > (size_t) (end - *pos)) {
41539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
41639beb93cSSam Leffler 			   "message buffer for Yc");
41739beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
41839beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
41939beb93cSSam Leffler 		os_free(csecret);
42039beb93cSSam Leffler 		os_free(dh_yc);
42139beb93cSSam Leffler 		return -1;
42239beb93cSSam Leffler 	}
42339beb93cSSam Leffler 	os_memcpy(*pos, dh_yc, dh_yc_len);
42439beb93cSSam Leffler 	*pos += dh_yc_len;
42539beb93cSSam Leffler 	os_free(dh_yc);
42639beb93cSSam Leffler 
42739beb93cSSam Leffler 	shared_len = conn->dh_p_len;
42839beb93cSSam Leffler 	shared = os_malloc(shared_len);
42939beb93cSSam Leffler 	if (shared == NULL) {
43039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
43139beb93cSSam Leffler 			   "DH");
43239beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
43339beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
43439beb93cSSam Leffler 		os_free(csecret);
43539beb93cSSam Leffler 		return -1;
43639beb93cSSam Leffler 	}
43739beb93cSSam Leffler 
43839beb93cSSam Leffler 	/* shared = Ys^csecret mod p */
43939beb93cSSam Leffler 	if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
44039beb93cSSam Leffler 			   csecret_start, csecret_len,
44139beb93cSSam Leffler 			   conn->dh_p, conn->dh_p_len,
44239beb93cSSam Leffler 			   shared, &shared_len)) {
44339beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
44439beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
44539beb93cSSam Leffler 		os_free(csecret);
44639beb93cSSam Leffler 		os_free(shared);
44739beb93cSSam Leffler 		return -1;
44839beb93cSSam Leffler 	}
44939beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
45039beb93cSSam Leffler 			shared, shared_len);
45139beb93cSSam Leffler 
45239beb93cSSam Leffler 	os_memset(csecret_start, 0, csecret_len);
45339beb93cSSam Leffler 	os_free(csecret);
45439beb93cSSam Leffler 	if (tls_derive_keys(conn, shared, shared_len)) {
45539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
45639beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
45739beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
45839beb93cSSam Leffler 		os_free(shared);
45939beb93cSSam Leffler 		return -1;
46039beb93cSSam Leffler 	}
46139beb93cSSam Leffler 	os_memset(shared, 0, shared_len);
46239beb93cSSam Leffler 	os_free(shared);
46339beb93cSSam Leffler 	tlsv1_client_free_dh(conn);
46439beb93cSSam Leffler 	return 0;
46539beb93cSSam Leffler }
46639beb93cSSam Leffler 
46739beb93cSSam Leffler 
46839beb93cSSam Leffler static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
46939beb93cSSam Leffler {
47039beb93cSSam Leffler 	u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
47139beb93cSSam Leffler 	size_t clen;
47239beb93cSSam Leffler 	int res;
47339beb93cSSam Leffler 
47439beb93cSSam Leffler 	if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
47539beb93cSSam Leffler 	    tls_derive_keys(conn, pre_master_secret,
47639beb93cSSam Leffler 			    TLS_PRE_MASTER_SECRET_LEN)) {
47739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
47839beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
47939beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
48039beb93cSSam Leffler 		return -1;
48139beb93cSSam Leffler 	}
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 	/* EncryptedPreMasterSecret */
48439beb93cSSam Leffler 	if (conn->server_rsa_key == NULL) {
48539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
48639beb93cSSam Leffler 			   "use for encrypting pre-master secret");
48739beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
48839beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
48939beb93cSSam Leffler 		return -1;
49039beb93cSSam Leffler 	}
49139beb93cSSam Leffler 
49239beb93cSSam Leffler 	/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
49339beb93cSSam Leffler 	*pos += 2;
49439beb93cSSam Leffler 	clen = end - *pos;
49539beb93cSSam Leffler 	res = crypto_public_key_encrypt_pkcs1_v15(
49639beb93cSSam Leffler 		conn->server_rsa_key,
49739beb93cSSam Leffler 		pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
49839beb93cSSam Leffler 		*pos, &clen);
49939beb93cSSam Leffler 	os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
50039beb93cSSam Leffler 	if (res < 0) {
50139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
50239beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
50339beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
50439beb93cSSam Leffler 		return -1;
50539beb93cSSam Leffler 	}
50639beb93cSSam Leffler 	WPA_PUT_BE16(*pos - 2, clen);
50739beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
50839beb93cSSam Leffler 		    *pos, clen);
50939beb93cSSam Leffler 	*pos += clen;
51039beb93cSSam Leffler 
51139beb93cSSam Leffler 	return 0;
51239beb93cSSam Leffler }
51339beb93cSSam Leffler 
51439beb93cSSam Leffler 
51539beb93cSSam Leffler static int tls_write_client_key_exchange(struct tlsv1_client *conn,
51639beb93cSSam Leffler 					 u8 **msgpos, u8 *end)
51739beb93cSSam Leffler {
51839beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length;
51939beb93cSSam Leffler 	size_t rlen;
52039beb93cSSam Leffler 	tls_key_exchange keyx;
52139beb93cSSam Leffler 	const struct tls_cipher_suite *suite;
52239beb93cSSam Leffler 
52339beb93cSSam Leffler 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
52439beb93cSSam Leffler 	if (suite == NULL)
52539beb93cSSam Leffler 		keyx = TLS_KEY_X_NULL;
52639beb93cSSam Leffler 	else
52739beb93cSSam Leffler 		keyx = suite->key_exchange;
52839beb93cSSam Leffler 
52939beb93cSSam Leffler 	pos = *msgpos;
53039beb93cSSam Leffler 
53139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
53239beb93cSSam Leffler 
53339beb93cSSam Leffler 	rhdr = pos;
53439beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
53539beb93cSSam Leffler 
53639beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
53739beb93cSSam Leffler 
53839beb93cSSam Leffler 	/* Handshake */
53939beb93cSSam Leffler 	hs_start = pos;
54039beb93cSSam Leffler 	/* HandshakeType msg_type */
54139beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
54239beb93cSSam Leffler 	/* uint24 length (to be filled) */
54339beb93cSSam Leffler 	hs_length = pos;
54439beb93cSSam Leffler 	pos += 3;
54539beb93cSSam Leffler 	/* body - ClientKeyExchange */
5465b9c547cSRui Paulo 	if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
5475b9c547cSRui Paulo 		if (tlsv1_key_x_dh(conn, &pos, end) < 0)
54839beb93cSSam Leffler 			return -1;
54939beb93cSSam Leffler 	} else {
55039beb93cSSam Leffler 		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
55139beb93cSSam Leffler 			return -1;
55239beb93cSSam Leffler 	}
55339beb93cSSam Leffler 
55439beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
55539beb93cSSam Leffler 
55639beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
557f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
558f05cddf9SRui Paulo 			      &rlen) < 0) {
55939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
56039beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
56139beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
56239beb93cSSam Leffler 		return -1;
56339beb93cSSam Leffler 	}
56439beb93cSSam Leffler 	pos = rhdr + rlen;
56539beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
56639beb93cSSam Leffler 
56739beb93cSSam Leffler 	*msgpos = pos;
56839beb93cSSam Leffler 
56939beb93cSSam Leffler 	return 0;
57039beb93cSSam Leffler }
57139beb93cSSam Leffler 
57239beb93cSSam Leffler 
57339beb93cSSam Leffler static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
57439beb93cSSam Leffler 					       u8 **msgpos, u8 *end)
57539beb93cSSam Leffler {
57639beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
57739beb93cSSam Leffler 	size_t rlen, hlen, clen;
578f05cddf9SRui Paulo 	u8 hash[100], *hpos;
57939beb93cSSam Leffler 
58039beb93cSSam Leffler 	pos = *msgpos;
58139beb93cSSam Leffler 
58239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
58339beb93cSSam Leffler 	rhdr = pos;
58439beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
58539beb93cSSam Leffler 
58639beb93cSSam Leffler 	/* Handshake */
58739beb93cSSam Leffler 	hs_start = pos;
58839beb93cSSam Leffler 	/* HandshakeType msg_type */
58939beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
59039beb93cSSam Leffler 	/* uint24 length (to be filled) */
59139beb93cSSam Leffler 	hs_length = pos;
59239beb93cSSam Leffler 	pos += 3;
59339beb93cSSam Leffler 
59439beb93cSSam Leffler 	/*
59539beb93cSSam Leffler 	 * RFC 2246: 7.4.3 and 7.4.8:
59639beb93cSSam Leffler 	 * Signature signature
59739beb93cSSam Leffler 	 *
59839beb93cSSam Leffler 	 * RSA:
59939beb93cSSam Leffler 	 * digitally-signed struct {
60039beb93cSSam Leffler 	 *     opaque md5_hash[16];
60139beb93cSSam Leffler 	 *     opaque sha_hash[20];
60239beb93cSSam Leffler 	 * };
60339beb93cSSam Leffler 	 *
60439beb93cSSam Leffler 	 * DSA:
60539beb93cSSam Leffler 	 * digitally-signed struct {
60639beb93cSSam Leffler 	 *     opaque sha_hash[20];
60739beb93cSSam Leffler 	 * };
60839beb93cSSam Leffler 	 *
60939beb93cSSam Leffler 	 * The hash values are calculated over all handshake messages sent or
61039beb93cSSam Leffler 	 * received starting at ClientHello up to, but not including, this
61139beb93cSSam Leffler 	 * CertificateVerify message, including the type and length fields of
61239beb93cSSam Leffler 	 * the handshake messages.
61339beb93cSSam Leffler 	 */
61439beb93cSSam Leffler 
61539beb93cSSam Leffler 	hpos = hash;
61639beb93cSSam Leffler 
617f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
618f05cddf9SRui Paulo 	if (conn->rl.tls_version == TLS_VERSION_1_2) {
619f05cddf9SRui Paulo 		hlen = SHA256_MAC_LEN;
620f05cddf9SRui Paulo 		if (conn->verify.sha256_cert == NULL ||
621f05cddf9SRui Paulo 		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
622f05cddf9SRui Paulo 		    0) {
623f05cddf9SRui Paulo 			conn->verify.sha256_cert = NULL;
624f05cddf9SRui Paulo 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
625f05cddf9SRui Paulo 				  TLS_ALERT_INTERNAL_ERROR);
626f05cddf9SRui Paulo 			return -1;
627f05cddf9SRui Paulo 		}
628f05cddf9SRui Paulo 		conn->verify.sha256_cert = NULL;
629f05cddf9SRui Paulo 
630f05cddf9SRui Paulo 		/*
631f05cddf9SRui Paulo 		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
632f05cddf9SRui Paulo 		 *
633f05cddf9SRui Paulo 		 * DigestInfo ::= SEQUENCE {
634f05cddf9SRui Paulo 		 *   digestAlgorithm DigestAlgorithm,
635f05cddf9SRui Paulo 		 *   digest OCTET STRING
636f05cddf9SRui Paulo 		 * }
637f05cddf9SRui Paulo 		 *
638f05cddf9SRui Paulo 		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
639f05cddf9SRui Paulo 		 *
640f05cddf9SRui Paulo 		 * DER encoded DigestInfo for SHA256 per RFC 3447:
641f05cddf9SRui Paulo 		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
642f05cddf9SRui Paulo 		 * H
643f05cddf9SRui Paulo 		 */
644f05cddf9SRui Paulo 		os_memmove(hash + 19, hash, hlen);
645f05cddf9SRui Paulo 		hlen += 19;
646f05cddf9SRui Paulo 		os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
647f05cddf9SRui Paulo 			  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
648f05cddf9SRui Paulo 	} else {
649f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
650f05cddf9SRui Paulo 
65139beb93cSSam Leffler 	hlen = MD5_MAC_LEN;
65239beb93cSSam Leffler 	if (conn->verify.md5_cert == NULL ||
6535b9c547cSRui Paulo 	    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
65439beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
65539beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
65639beb93cSSam Leffler 		conn->verify.md5_cert = NULL;
65739beb93cSSam Leffler 		crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
65839beb93cSSam Leffler 		conn->verify.sha1_cert = NULL;
65939beb93cSSam Leffler 		return -1;
66039beb93cSSam Leffler 	}
66139beb93cSSam Leffler 	hpos += MD5_MAC_LEN;
66239beb93cSSam Leffler 
66339beb93cSSam Leffler 	conn->verify.md5_cert = NULL;
66439beb93cSSam Leffler 	hlen = SHA1_MAC_LEN;
66539beb93cSSam Leffler 	if (conn->verify.sha1_cert == NULL ||
66639beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
66739beb93cSSam Leffler 		conn->verify.sha1_cert = NULL;
66839beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
66939beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
67039beb93cSSam Leffler 		return -1;
67139beb93cSSam Leffler 	}
67239beb93cSSam Leffler 	conn->verify.sha1_cert = NULL;
67339beb93cSSam Leffler 
67439beb93cSSam Leffler 	hlen += MD5_MAC_LEN;
67539beb93cSSam Leffler 
676f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
677f05cddf9SRui Paulo 	}
678f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
679f05cddf9SRui Paulo 
68039beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
68139beb93cSSam Leffler 
682f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
683f05cddf9SRui Paulo 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
684f05cddf9SRui Paulo 		/*
685f05cddf9SRui Paulo 		 * RFC 5246, 4.7:
686f05cddf9SRui Paulo 		 * TLS v1.2 adds explicit indication of the used signature and
687f05cddf9SRui Paulo 		 * hash algorithms.
688f05cddf9SRui Paulo 		 *
689f05cddf9SRui Paulo 		 * struct {
690f05cddf9SRui Paulo 		 *   HashAlgorithm hash;
691f05cddf9SRui Paulo 		 *   SignatureAlgorithm signature;
692f05cddf9SRui Paulo 		 * } SignatureAndHashAlgorithm;
693f05cddf9SRui Paulo 		 */
694f05cddf9SRui Paulo 		*pos++ = TLS_HASH_ALG_SHA256;
695f05cddf9SRui Paulo 		*pos++ = TLS_SIGN_ALG_RSA;
696f05cddf9SRui Paulo 	}
697f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
698f05cddf9SRui Paulo 
69939beb93cSSam Leffler 	/*
70039beb93cSSam Leffler 	 * RFC 2246, 4.7:
70139beb93cSSam Leffler 	 * In digital signing, one-way hash functions are used as input for a
70239beb93cSSam Leffler 	 * signing algorithm. A digitally-signed element is encoded as an
70339beb93cSSam Leffler 	 * opaque vector <0..2^16-1>, where the length is specified by the
70439beb93cSSam Leffler 	 * signing algorithm and key.
70539beb93cSSam Leffler 	 *
70639beb93cSSam Leffler 	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
70739beb93cSSam Leffler 	 * MD5) is signed (encrypted with the private key). It is encoded with
70839beb93cSSam Leffler 	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
70939beb93cSSam Leffler 	 */
71039beb93cSSam Leffler 	signed_start = pos; /* length to be filled */
71139beb93cSSam Leffler 	pos += 2;
71239beb93cSSam Leffler 	clen = end - pos;
71339beb93cSSam Leffler 	if (conn->cred == NULL ||
71439beb93cSSam Leffler 	    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
71539beb93cSSam Leffler 					  pos, &clen) < 0) {
71639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
71739beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
71839beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
71939beb93cSSam Leffler 		return -1;
72039beb93cSSam Leffler 	}
72139beb93cSSam Leffler 	WPA_PUT_BE16(signed_start, clen);
72239beb93cSSam Leffler 
72339beb93cSSam Leffler 	pos += clen;
72439beb93cSSam Leffler 
72539beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
72639beb93cSSam Leffler 
72739beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
728f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
729f05cddf9SRui Paulo 			      &rlen) < 0) {
73039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
73139beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
73239beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
73339beb93cSSam Leffler 		return -1;
73439beb93cSSam Leffler 	}
73539beb93cSSam Leffler 	pos = rhdr + rlen;
73639beb93cSSam Leffler 
73739beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
73839beb93cSSam Leffler 
73939beb93cSSam Leffler 	*msgpos = pos;
74039beb93cSSam Leffler 
74139beb93cSSam Leffler 	return 0;
74239beb93cSSam Leffler }
74339beb93cSSam Leffler 
74439beb93cSSam Leffler 
74539beb93cSSam Leffler static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
74639beb93cSSam Leffler 					       u8 **msgpos, u8 *end)
74739beb93cSSam Leffler {
74839beb93cSSam Leffler 	size_t rlen;
749f05cddf9SRui Paulo 	u8 payload[1];
75039beb93cSSam Leffler 
75139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
752f05cddf9SRui Paulo 
753f05cddf9SRui Paulo 	payload[0] = TLS_CHANGE_CIPHER_SPEC;
754f05cddf9SRui Paulo 
75539beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
756f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, payload, sizeof(payload),
757f05cddf9SRui Paulo 			      &rlen) < 0) {
75839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
75939beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
76039beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
76139beb93cSSam Leffler 		return -1;
76239beb93cSSam Leffler 	}
76339beb93cSSam Leffler 
76439beb93cSSam Leffler 	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
76539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
76639beb93cSSam Leffler 			   "record layer");
76739beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
76839beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
76939beb93cSSam Leffler 		return -1;
77039beb93cSSam Leffler 	}
77139beb93cSSam Leffler 
772f05cddf9SRui Paulo 	*msgpos += rlen;
77339beb93cSSam Leffler 
77439beb93cSSam Leffler 	return 0;
77539beb93cSSam Leffler }
77639beb93cSSam Leffler 
77739beb93cSSam Leffler 
77839beb93cSSam Leffler static int tls_write_client_finished(struct tlsv1_client *conn,
77939beb93cSSam Leffler 				     u8 **msgpos, u8 *end)
78039beb93cSSam Leffler {
781f05cddf9SRui Paulo 	u8 *pos, *hs_start;
78239beb93cSSam Leffler 	size_t rlen, hlen;
783f05cddf9SRui Paulo 	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
78439beb93cSSam Leffler 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
78539beb93cSSam Leffler 
78639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
78739beb93cSSam Leffler 
78839beb93cSSam Leffler 	/* Encrypted Handshake Message: Finished */
78939beb93cSSam Leffler 
790f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
791f05cddf9SRui Paulo 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
792f05cddf9SRui Paulo 		hlen = SHA256_MAC_LEN;
793f05cddf9SRui Paulo 		if (conn->verify.sha256_client == NULL ||
794f05cddf9SRui Paulo 		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
795f05cddf9SRui Paulo 		    < 0) {
796f05cddf9SRui Paulo 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
797f05cddf9SRui Paulo 				  TLS_ALERT_INTERNAL_ERROR);
798f05cddf9SRui Paulo 			conn->verify.sha256_client = NULL;
799f05cddf9SRui Paulo 			return -1;
800f05cddf9SRui Paulo 		}
801f05cddf9SRui Paulo 		conn->verify.sha256_client = NULL;
802f05cddf9SRui Paulo 	} else {
803f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
804f05cddf9SRui Paulo 
80539beb93cSSam Leffler 	hlen = MD5_MAC_LEN;
80639beb93cSSam Leffler 	if (conn->verify.md5_client == NULL ||
80739beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
80839beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
80939beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
81039beb93cSSam Leffler 		conn->verify.md5_client = NULL;
81139beb93cSSam Leffler 		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
81239beb93cSSam Leffler 		conn->verify.sha1_client = NULL;
81339beb93cSSam Leffler 		return -1;
81439beb93cSSam Leffler 	}
81539beb93cSSam Leffler 	conn->verify.md5_client = NULL;
81639beb93cSSam Leffler 	hlen = SHA1_MAC_LEN;
81739beb93cSSam Leffler 	if (conn->verify.sha1_client == NULL ||
81839beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
81939beb93cSSam Leffler 			       &hlen) < 0) {
82039beb93cSSam Leffler 		conn->verify.sha1_client = NULL;
82139beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
82239beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
82339beb93cSSam Leffler 		return -1;
82439beb93cSSam Leffler 	}
82539beb93cSSam Leffler 	conn->verify.sha1_client = NULL;
826f05cddf9SRui Paulo 	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
82739beb93cSSam Leffler 
828f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
829f05cddf9SRui Paulo 	}
830f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
831f05cddf9SRui Paulo 
832f05cddf9SRui Paulo 	if (tls_prf(conn->rl.tls_version,
833f05cddf9SRui Paulo 		    conn->master_secret, TLS_MASTER_SECRET_LEN,
834f05cddf9SRui Paulo 		    "client finished", hash, hlen,
835f05cddf9SRui Paulo 		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
83639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
83739beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
83839beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
83939beb93cSSam Leffler 		return -1;
84039beb93cSSam Leffler 	}
84139beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
842f05cddf9SRui Paulo 			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
84339beb93cSSam Leffler 
84439beb93cSSam Leffler 	/* Handshake */
845f05cddf9SRui Paulo 	pos = hs_start = verify_data;
84639beb93cSSam Leffler 	/* HandshakeType msg_type */
84739beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
848f05cddf9SRui Paulo 	/* uint24 length */
849f05cddf9SRui Paulo 	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
85039beb93cSSam Leffler 	pos += 3;
851f05cddf9SRui Paulo 	pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
85239beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
85339beb93cSSam Leffler 
85439beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
855f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
856f05cddf9SRui Paulo 			      &rlen) < 0) {
85739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
85839beb93cSSam Leffler 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
85939beb93cSSam Leffler 			  TLS_ALERT_INTERNAL_ERROR);
86039beb93cSSam Leffler 		return -1;
86139beb93cSSam Leffler 	}
86239beb93cSSam Leffler 
863f05cddf9SRui Paulo 	*msgpos += rlen;
86439beb93cSSam Leffler 
86539beb93cSSam Leffler 	return 0;
86639beb93cSSam Leffler }
86739beb93cSSam Leffler 
86839beb93cSSam Leffler 
86939beb93cSSam Leffler static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
87039beb93cSSam Leffler 					 size_t *out_len)
87139beb93cSSam Leffler {
87239beb93cSSam Leffler 	u8 *msg, *end, *pos;
87339beb93cSSam Leffler 	size_t msglen;
87439beb93cSSam Leffler 
87539beb93cSSam Leffler 	*out_len = 0;
87639beb93cSSam Leffler 
877f05cddf9SRui Paulo 	msglen = 2000;
87839beb93cSSam Leffler 	if (conn->certificate_requested)
87939beb93cSSam Leffler 		msglen += tls_client_cert_chain_der_len(conn);
88039beb93cSSam Leffler 
88139beb93cSSam Leffler 	msg = os_malloc(msglen);
88239beb93cSSam Leffler 	if (msg == NULL)
88339beb93cSSam Leffler 		return NULL;
88439beb93cSSam Leffler 
88539beb93cSSam Leffler 	pos = msg;
88639beb93cSSam Leffler 	end = msg + msglen;
88739beb93cSSam Leffler 
88839beb93cSSam Leffler 	if (conn->certificate_requested) {
88939beb93cSSam Leffler 		if (tls_write_client_certificate(conn, &pos, end) < 0) {
89039beb93cSSam Leffler 			os_free(msg);
89139beb93cSSam Leffler 			return NULL;
89239beb93cSSam Leffler 		}
89339beb93cSSam Leffler 	}
89439beb93cSSam Leffler 
89539beb93cSSam Leffler 	if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
89639beb93cSSam Leffler 	    (conn->certificate_requested && conn->cred && conn->cred->key &&
89739beb93cSSam Leffler 	     tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
89839beb93cSSam Leffler 	    tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
89939beb93cSSam Leffler 	    tls_write_client_finished(conn, &pos, end) < 0) {
90039beb93cSSam Leffler 		os_free(msg);
90139beb93cSSam Leffler 		return NULL;
90239beb93cSSam Leffler 	}
90339beb93cSSam Leffler 
90439beb93cSSam Leffler 	*out_len = pos - msg;
90539beb93cSSam Leffler 
90639beb93cSSam Leffler 	conn->state = SERVER_CHANGE_CIPHER_SPEC;
90739beb93cSSam Leffler 
90839beb93cSSam Leffler 	return msg;
90939beb93cSSam Leffler }
91039beb93cSSam Leffler 
91139beb93cSSam Leffler 
91239beb93cSSam Leffler static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
91339beb93cSSam Leffler 					size_t *out_len)
91439beb93cSSam Leffler {
91539beb93cSSam Leffler 	u8 *msg, *end, *pos;
91639beb93cSSam Leffler 
91739beb93cSSam Leffler 	*out_len = 0;
91839beb93cSSam Leffler 
91939beb93cSSam Leffler 	msg = os_malloc(1000);
92039beb93cSSam Leffler 	if (msg == NULL)
92139beb93cSSam Leffler 		return NULL;
92239beb93cSSam Leffler 
92339beb93cSSam Leffler 	pos = msg;
92439beb93cSSam Leffler 	end = msg + 1000;
92539beb93cSSam Leffler 
92639beb93cSSam Leffler 	if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
92739beb93cSSam Leffler 	    tls_write_client_finished(conn, &pos, end) < 0) {
92839beb93cSSam Leffler 		os_free(msg);
92939beb93cSSam Leffler 		return NULL;
93039beb93cSSam Leffler 	}
93139beb93cSSam Leffler 
93239beb93cSSam Leffler 	*out_len = pos - msg;
93339beb93cSSam Leffler 
93439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
93539beb93cSSam Leffler 		   "successfully");
936*780fb4a2SCy Schubert 	if (!conn->session_resumed && conn->use_session_ticket)
937*780fb4a2SCy Schubert 		conn->session_resumed = 1;
93839beb93cSSam Leffler 	conn->state = ESTABLISHED;
93939beb93cSSam Leffler 
94039beb93cSSam Leffler 	return msg;
94139beb93cSSam Leffler }
94239beb93cSSam Leffler 
94339beb93cSSam Leffler 
94439beb93cSSam Leffler u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
94539beb93cSSam Leffler 				  int no_appl_data)
94639beb93cSSam Leffler {
94739beb93cSSam Leffler 	switch (conn->state) {
94839beb93cSSam Leffler 	case CLIENT_KEY_EXCHANGE:
94939beb93cSSam Leffler 		return tls_send_client_key_exchange(conn, out_len);
95039beb93cSSam Leffler 	case CHANGE_CIPHER_SPEC:
95139beb93cSSam Leffler 		return tls_send_change_cipher_spec(conn, out_len);
95239beb93cSSam Leffler 	case ACK_FINISHED:
95339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
95439beb93cSSam Leffler 			   "successfully");
95539beb93cSSam Leffler 		conn->state = ESTABLISHED;
95639beb93cSSam Leffler 		*out_len = 0;
95739beb93cSSam Leffler 		if (no_appl_data) {
95839beb93cSSam Leffler 			/* Need to return something to get final TLS ACK. */
95939beb93cSSam Leffler 			return os_malloc(1);
96039beb93cSSam Leffler 		}
96139beb93cSSam Leffler 		return NULL;
96239beb93cSSam Leffler 	default:
96339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
96439beb93cSSam Leffler 			   "generating reply", conn->state);
96539beb93cSSam Leffler 		return NULL;
96639beb93cSSam Leffler 	}
96739beb93cSSam Leffler }
96839beb93cSSam Leffler 
96939beb93cSSam Leffler 
97039beb93cSSam Leffler u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
97139beb93cSSam Leffler 			     u8 description, size_t *out_len)
97239beb93cSSam Leffler {
97339beb93cSSam Leffler 	u8 *alert, *pos, *length;
97439beb93cSSam Leffler 
97539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
97639beb93cSSam Leffler 	*out_len = 0;
97739beb93cSSam Leffler 
97839beb93cSSam Leffler 	alert = os_malloc(10);
97939beb93cSSam Leffler 	if (alert == NULL)
98039beb93cSSam Leffler 		return NULL;
98139beb93cSSam Leffler 
98239beb93cSSam Leffler 	pos = alert;
98339beb93cSSam Leffler 
98439beb93cSSam Leffler 	/* TLSPlaintext */
98539beb93cSSam Leffler 	/* ContentType type */
98639beb93cSSam Leffler 	*pos++ = TLS_CONTENT_TYPE_ALERT;
98739beb93cSSam Leffler 	/* ProtocolVersion version */
988f05cddf9SRui Paulo 	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
989f05cddf9SRui Paulo 		     TLS_VERSION);
99039beb93cSSam Leffler 	pos += 2;
99139beb93cSSam Leffler 	/* uint16 length (to be filled) */
99239beb93cSSam Leffler 	length = pos;
99339beb93cSSam Leffler 	pos += 2;
99439beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
99539beb93cSSam Leffler 
99639beb93cSSam Leffler 	/* Alert */
99739beb93cSSam Leffler 	/* AlertLevel level */
99839beb93cSSam Leffler 	*pos++ = level;
99939beb93cSSam Leffler 	/* AlertDescription description */
100039beb93cSSam Leffler 	*pos++ = description;
100139beb93cSSam Leffler 
100239beb93cSSam Leffler 	WPA_PUT_BE16(length, pos - length - 2);
100339beb93cSSam Leffler 	*out_len = pos - alert;
100439beb93cSSam Leffler 
100539beb93cSSam Leffler 	return alert;
100639beb93cSSam Leffler }
1007