xref: /freebsd/contrib/wpa/src/tls/tlsv1_server_write.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * TLSv1 server - write handshake message
35b9c547cSRui Paulo  * Copyright (c) 2006-2014, 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_server.h"
2139beb93cSSam Leffler #include "tlsv1_server_i.h"
2239beb93cSSam Leffler 
2339beb93cSSam Leffler 
tls_server_cert_chain_der_len(struct tlsv1_server * conn)2439beb93cSSam Leffler static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
2539beb93cSSam Leffler {
2639beb93cSSam Leffler 	size_t len = 0;
2739beb93cSSam Leffler 	struct x509_certificate *cert;
2839beb93cSSam Leffler 
294bc52338SCy Schubert 	cert = conn->cred ? conn->cred->cert : NULL;
3039beb93cSSam Leffler 	while (cert) {
3139beb93cSSam Leffler 		len += 3 + cert->cert_len;
3239beb93cSSam Leffler 		if (x509_certificate_self_signed(cert))
3339beb93cSSam Leffler 			break;
3439beb93cSSam Leffler 		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
3539beb93cSSam Leffler 						    &cert->issuer);
3639beb93cSSam Leffler 	}
3739beb93cSSam Leffler 
3839beb93cSSam Leffler 	return len;
3939beb93cSSam Leffler }
4039beb93cSSam Leffler 
4139beb93cSSam Leffler 
tls_write_server_hello(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)4239beb93cSSam Leffler static int tls_write_server_hello(struct tlsv1_server *conn,
4339beb93cSSam Leffler 				  u8 **msgpos, u8 *end)
4439beb93cSSam Leffler {
45780fb4a2SCy Schubert 	u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
4639beb93cSSam Leffler 	struct os_time now;
4739beb93cSSam Leffler 	size_t rlen;
4839beb93cSSam Leffler 
4939beb93cSSam Leffler 	pos = *msgpos;
5039beb93cSSam Leffler 
515b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ServerHello");
5239beb93cSSam Leffler 	rhdr = pos;
5339beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
5439beb93cSSam Leffler 
5539beb93cSSam Leffler 	os_get_time(&now);
564bc52338SCy Schubert #ifdef TEST_FUZZ
574bc52338SCy Schubert 	now.sec = 0xfffefdfc;
584bc52338SCy Schubert #endif /* TEST_FUZZ */
5939beb93cSSam Leffler 	WPA_PUT_BE32(conn->server_random, now.sec);
60f05cddf9SRui Paulo 	if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
6139beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
6239beb93cSSam Leffler 			   "server_random");
6339beb93cSSam Leffler 		return -1;
6439beb93cSSam Leffler 	}
6539beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
6639beb93cSSam Leffler 		    conn->server_random, TLS_RANDOM_LEN);
6739beb93cSSam Leffler 
6839beb93cSSam Leffler 	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
69f05cddf9SRui Paulo 	if (random_get_bytes(conn->session_id, conn->session_id_len)) {
7039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
7139beb93cSSam Leffler 			   "session_id");
7239beb93cSSam Leffler 		return -1;
7339beb93cSSam Leffler 	}
7439beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
7539beb93cSSam Leffler 		    conn->session_id, conn->session_id_len);
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
7839beb93cSSam Leffler 
7939beb93cSSam Leffler 	/* Handshake */
8039beb93cSSam Leffler 	hs_start = pos;
8139beb93cSSam Leffler 	/* HandshakeType msg_type */
8239beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
8339beb93cSSam Leffler 	/* uint24 length (to be filled) */
8439beb93cSSam Leffler 	hs_length = pos;
8539beb93cSSam Leffler 	pos += 3;
8639beb93cSSam Leffler 	/* body - ServerHello */
8739beb93cSSam Leffler 	/* ProtocolVersion server_version */
88f05cddf9SRui Paulo 	WPA_PUT_BE16(pos, conn->rl.tls_version);
8939beb93cSSam Leffler 	pos += 2;
9039beb93cSSam Leffler 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
9139beb93cSSam Leffler 	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
9239beb93cSSam Leffler 	pos += TLS_RANDOM_LEN;
9339beb93cSSam Leffler 	/* SessionID session_id */
9439beb93cSSam Leffler 	*pos++ = conn->session_id_len;
9539beb93cSSam Leffler 	os_memcpy(pos, conn->session_id, conn->session_id_len);
9639beb93cSSam Leffler 	pos += conn->session_id_len;
9739beb93cSSam Leffler 	/* CipherSuite cipher_suite */
9839beb93cSSam Leffler 	WPA_PUT_BE16(pos, conn->cipher_suite);
9939beb93cSSam Leffler 	pos += 2;
10039beb93cSSam Leffler 	/* CompressionMethod compression_method */
10139beb93cSSam Leffler 	*pos++ = TLS_COMPRESSION_NULL;
10239beb93cSSam Leffler 
103780fb4a2SCy Schubert 	/* Extension */
104780fb4a2SCy Schubert 	ext_start = pos;
105780fb4a2SCy Schubert 	pos += 2;
106780fb4a2SCy Schubert 
107780fb4a2SCy Schubert 	if (conn->status_request) {
108780fb4a2SCy Schubert 		/* Add a status_request extension with empty extension_data */
109780fb4a2SCy Schubert 		/* ExtensionsType extension_type = status_request(5) */
110780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
111780fb4a2SCy Schubert 		pos += 2;
112780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
113780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0);
114780fb4a2SCy Schubert 		pos += 2;
115780fb4a2SCy Schubert 	}
116780fb4a2SCy Schubert 
117780fb4a2SCy Schubert 	if (conn->status_request_v2) {
118780fb4a2SCy Schubert 		/*
119780fb4a2SCy Schubert 		  Add a status_request_v2 extension with empty extension_data
120780fb4a2SCy Schubert 		*/
121780fb4a2SCy Schubert 		/* ExtensionsType extension_type = status_request_v2(17) */
122780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
123780fb4a2SCy Schubert 		pos += 2;
124780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
125780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0);
126780fb4a2SCy Schubert 		pos += 2;
127780fb4a2SCy Schubert 	}
128780fb4a2SCy Schubert 
12939beb93cSSam Leffler 	if (conn->session_ticket && conn->session_ticket_cb) {
13039beb93cSSam Leffler 		int res = conn->session_ticket_cb(
13139beb93cSSam Leffler 			conn->session_ticket_cb_ctx,
13239beb93cSSam Leffler 			conn->session_ticket, conn->session_ticket_len,
13339beb93cSSam Leffler 			conn->client_random, conn->server_random,
13439beb93cSSam Leffler 			conn->master_secret);
13539beb93cSSam Leffler 		if (res < 0) {
1365b9c547cSRui Paulo 			tlsv1_server_log(conn, "SessionTicket callback indicated failure");
13739beb93cSSam Leffler 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
13839beb93cSSam Leffler 					   TLS_ALERT_HANDSHAKE_FAILURE);
13939beb93cSSam Leffler 			return -1;
14039beb93cSSam Leffler 		}
14139beb93cSSam Leffler 		conn->use_session_ticket = res;
14239beb93cSSam Leffler 
14339beb93cSSam Leffler 		if (conn->use_session_ticket) {
14439beb93cSSam Leffler 			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
14539beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
14639beb93cSSam Leffler 					   "derive keys");
14739beb93cSSam Leffler 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
14839beb93cSSam Leffler 						   TLS_ALERT_INTERNAL_ERROR);
14939beb93cSSam Leffler 				return -1;
15039beb93cSSam Leffler 			}
15139beb93cSSam Leffler 		}
15239beb93cSSam Leffler 
15339beb93cSSam Leffler 		/*
15439beb93cSSam Leffler 		 * RFC 4507 specifies that server would include an empty
15539beb93cSSam Leffler 		 * SessionTicket extension in ServerHello and a
15639beb93cSSam Leffler 		 * NewSessionTicket message after the ServerHello. However,
15739beb93cSSam Leffler 		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
15839beb93cSSam Leffler 		 * extension at the moment, does not use such extensions.
15939beb93cSSam Leffler 		 *
16039beb93cSSam Leffler 		 * TODO: Add support for configuring RFC 4507 behavior and make
16139beb93cSSam Leffler 		 * EAP-FAST disable it.
16239beb93cSSam Leffler 		 */
16339beb93cSSam Leffler 	}
16439beb93cSSam Leffler 
165780fb4a2SCy Schubert 	if (pos == ext_start + 2)
166780fb4a2SCy Schubert 		pos -= 2; /* no extensions */
167780fb4a2SCy Schubert 	else
168780fb4a2SCy Schubert 		WPA_PUT_BE16(ext_start, pos - ext_start - 2);
169780fb4a2SCy Schubert 
17039beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
17139beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
17239beb93cSSam Leffler 
17339beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
174f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
175f05cddf9SRui Paulo 			      &rlen) < 0) {
17639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
17739beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
17839beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
17939beb93cSSam Leffler 		return -1;
18039beb93cSSam Leffler 	}
18139beb93cSSam Leffler 	pos = rhdr + rlen;
18239beb93cSSam Leffler 
18339beb93cSSam Leffler 	*msgpos = pos;
18439beb93cSSam Leffler 
18539beb93cSSam Leffler 	return 0;
18639beb93cSSam Leffler }
18739beb93cSSam Leffler 
18839beb93cSSam Leffler 
tls_write_server_certificate(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)18939beb93cSSam Leffler static int tls_write_server_certificate(struct tlsv1_server *conn,
19039beb93cSSam Leffler 					u8 **msgpos, u8 *end)
19139beb93cSSam Leffler {
19239beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
19339beb93cSSam Leffler 	size_t rlen;
19439beb93cSSam Leffler 	struct x509_certificate *cert;
19539beb93cSSam Leffler 	const struct tls_cipher_suite *suite;
19639beb93cSSam Leffler 
19739beb93cSSam Leffler 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
19839beb93cSSam Leffler 	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
19939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
20039beb93cSSam Leffler 			   "using anonymous DH");
20139beb93cSSam Leffler 		return 0;
20239beb93cSSam Leffler 	}
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 	pos = *msgpos;
205780fb4a2SCy Schubert 	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
206780fb4a2SCy Schubert 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
207780fb4a2SCy Schubert 				   TLS_ALERT_INTERNAL_ERROR);
208780fb4a2SCy Schubert 		return -1;
209780fb4a2SCy Schubert 	}
21039beb93cSSam Leffler 
2115b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send Certificate");
21239beb93cSSam Leffler 	rhdr = pos;
21339beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
21439beb93cSSam Leffler 
21539beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
21639beb93cSSam Leffler 
21739beb93cSSam Leffler 	/* Handshake */
21839beb93cSSam Leffler 	hs_start = pos;
21939beb93cSSam Leffler 	/* HandshakeType msg_type */
22039beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
22139beb93cSSam Leffler 	/* uint24 length (to be filled) */
22239beb93cSSam Leffler 	hs_length = pos;
22339beb93cSSam Leffler 	pos += 3;
22439beb93cSSam Leffler 	/* body - Certificate */
22539beb93cSSam Leffler 	/* uint24 length (to be filled) */
22639beb93cSSam Leffler 	cert_start = pos;
22739beb93cSSam Leffler 	pos += 3;
22839beb93cSSam Leffler 	cert = conn->cred->cert;
22939beb93cSSam Leffler 	while (cert) {
230780fb4a2SCy Schubert 		if (3 + cert->cert_len > (size_t) (end - pos)) {
23139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
23239beb93cSSam Leffler 				   "for Certificate (cert_len=%lu left=%lu)",
23339beb93cSSam Leffler 				   (unsigned long) cert->cert_len,
23439beb93cSSam Leffler 				   (unsigned long) (end - pos));
23539beb93cSSam Leffler 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
23639beb93cSSam Leffler 					   TLS_ALERT_INTERNAL_ERROR);
23739beb93cSSam Leffler 			return -1;
23839beb93cSSam Leffler 		}
23939beb93cSSam Leffler 		WPA_PUT_BE24(pos, cert->cert_len);
24039beb93cSSam Leffler 		pos += 3;
24139beb93cSSam Leffler 		os_memcpy(pos, cert->cert_start, cert->cert_len);
24239beb93cSSam Leffler 		pos += cert->cert_len;
24339beb93cSSam Leffler 
24439beb93cSSam Leffler 		if (x509_certificate_self_signed(cert))
24539beb93cSSam Leffler 			break;
24639beb93cSSam Leffler 		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
24739beb93cSSam Leffler 						    &cert->issuer);
24839beb93cSSam Leffler 	}
24939beb93cSSam Leffler 	if (cert == conn->cred->cert || cert == NULL) {
25039beb93cSSam Leffler 		/*
25139beb93cSSam Leffler 		 * Server was not configured with all the needed certificates
25239beb93cSSam Leffler 		 * to form a full certificate chain. The client may fail to
25339beb93cSSam Leffler 		 * validate the chain unless it is configured with all the
25439beb93cSSam Leffler 		 * missing CA certificates.
25539beb93cSSam Leffler 		 */
25639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
25739beb93cSSam Leffler 			   "not configured - validation may fail");
25839beb93cSSam Leffler 	}
25939beb93cSSam Leffler 	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
26039beb93cSSam Leffler 
26139beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
26239beb93cSSam Leffler 
26339beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
264f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
265f05cddf9SRui Paulo 			      &rlen) < 0) {
26639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
26739beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
26839beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
26939beb93cSSam Leffler 		return -1;
27039beb93cSSam Leffler 	}
27139beb93cSSam Leffler 	pos = rhdr + rlen;
27239beb93cSSam Leffler 
27339beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
27439beb93cSSam Leffler 
27539beb93cSSam Leffler 	*msgpos = pos;
27639beb93cSSam Leffler 
27739beb93cSSam Leffler 	return 0;
27839beb93cSSam Leffler }
27939beb93cSSam Leffler 
28039beb93cSSam Leffler 
tls_write_server_certificate_status(struct tlsv1_server * conn,u8 ** msgpos,u8 * end,int ocsp_multi,char * ocsp_resp,size_t ocsp_resp_len)281780fb4a2SCy Schubert static int tls_write_server_certificate_status(struct tlsv1_server *conn,
282780fb4a2SCy Schubert 					       u8 **msgpos, u8 *end,
283780fb4a2SCy Schubert 					       int ocsp_multi,
284780fb4a2SCy Schubert 					       char *ocsp_resp,
285780fb4a2SCy Schubert 					       size_t ocsp_resp_len)
286780fb4a2SCy Schubert {
287780fb4a2SCy Schubert 	u8 *pos, *rhdr, *hs_start, *hs_length;
288780fb4a2SCy Schubert 	size_t rlen;
289780fb4a2SCy Schubert 
290780fb4a2SCy Schubert 	if (!ocsp_resp) {
291780fb4a2SCy Schubert 		 /*
292780fb4a2SCy Schubert 		  * Client did not request certificate status or there is no
293780fb4a2SCy Schubert 		  * matching response cached.
294780fb4a2SCy Schubert 		  */
295780fb4a2SCy Schubert 		return 0;
296780fb4a2SCy Schubert 	}
297780fb4a2SCy Schubert 
298780fb4a2SCy Schubert 	pos = *msgpos;
299780fb4a2SCy Schubert 	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
300780fb4a2SCy Schubert 	    (unsigned int) (end - pos)) {
301780fb4a2SCy Schubert 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
302780fb4a2SCy Schubert 				   TLS_ALERT_INTERNAL_ERROR);
303780fb4a2SCy Schubert 		return -1;
304780fb4a2SCy Schubert 	}
305780fb4a2SCy Schubert 
306780fb4a2SCy Schubert 	tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
307780fb4a2SCy Schubert 	rhdr = pos;
308780fb4a2SCy Schubert 	pos += TLS_RECORD_HEADER_LEN;
309780fb4a2SCy Schubert 
310780fb4a2SCy Schubert 	/* opaque fragment[TLSPlaintext.length] */
311780fb4a2SCy Schubert 
312780fb4a2SCy Schubert 	/* Handshake */
313780fb4a2SCy Schubert 	hs_start = pos;
314780fb4a2SCy Schubert 	/* HandshakeType msg_type */
315780fb4a2SCy Schubert 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
316780fb4a2SCy Schubert 	/* uint24 length (to be filled) */
317780fb4a2SCy Schubert 	hs_length = pos;
318780fb4a2SCy Schubert 	pos += 3;
319780fb4a2SCy Schubert 
320780fb4a2SCy Schubert 	/* body - CertificateStatus
321780fb4a2SCy Schubert 	 *
322780fb4a2SCy Schubert 	 * struct {
323780fb4a2SCy Schubert 	 *     CertificateStatusType status_type;
324780fb4a2SCy Schubert 	 *     select (status_type) {
325780fb4a2SCy Schubert 	 *         case ocsp: OCSPResponse;
326780fb4a2SCy Schubert 	 *         case ocsp_multi: OCSPResponseList;
327780fb4a2SCy Schubert 	 *     } response;
328780fb4a2SCy Schubert 	 * } CertificateStatus;
329780fb4a2SCy Schubert 	 *
330780fb4a2SCy Schubert 	 * opaque OCSPResponse<1..2^24-1>;
331780fb4a2SCy Schubert 	 *
332780fb4a2SCy Schubert 	 * struct {
333780fb4a2SCy Schubert 	 *   OCSPResponse ocsp_response_list<1..2^24-1>;
334780fb4a2SCy Schubert 	 * } OCSPResponseList;
335780fb4a2SCy Schubert 	 */
336780fb4a2SCy Schubert 
337780fb4a2SCy Schubert 	/* CertificateStatusType status_type */
338780fb4a2SCy Schubert 	if (ocsp_multi)
339780fb4a2SCy Schubert 		*pos++ = 2; /* ocsp_multi(2) */
340780fb4a2SCy Schubert 	else
341780fb4a2SCy Schubert 		*pos++ = 1; /* ocsp(1) */
342780fb4a2SCy Schubert 	/* uint24 length of OCSPResponse */
343780fb4a2SCy Schubert 	WPA_PUT_BE24(pos, ocsp_resp_len);
344780fb4a2SCy Schubert 	pos += 3;
345780fb4a2SCy Schubert 	os_memcpy(pos, ocsp_resp, ocsp_resp_len);
346780fb4a2SCy Schubert 	pos += ocsp_resp_len;
347780fb4a2SCy Schubert 
348780fb4a2SCy Schubert 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
349780fb4a2SCy Schubert 
350780fb4a2SCy Schubert 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
351780fb4a2SCy Schubert 			      rhdr, end - rhdr, hs_start, pos - hs_start,
352780fb4a2SCy Schubert 			      &rlen) < 0) {
353780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
354780fb4a2SCy Schubert 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
355780fb4a2SCy Schubert 				   TLS_ALERT_INTERNAL_ERROR);
356780fb4a2SCy Schubert 		return -1;
357780fb4a2SCy Schubert 	}
358780fb4a2SCy Schubert 	pos = rhdr + rlen;
359780fb4a2SCy Schubert 
360780fb4a2SCy Schubert 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
361780fb4a2SCy Schubert 
362780fb4a2SCy Schubert 	*msgpos = pos;
363780fb4a2SCy Schubert 
364780fb4a2SCy Schubert 	return 0;
365780fb4a2SCy Schubert }
366780fb4a2SCy Schubert 
367780fb4a2SCy Schubert 
tls_write_server_key_exchange(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)36839beb93cSSam Leffler static int tls_write_server_key_exchange(struct tlsv1_server *conn,
36939beb93cSSam Leffler 					 u8 **msgpos, u8 *end)
37039beb93cSSam Leffler {
37139beb93cSSam Leffler 	tls_key_exchange keyx;
37239beb93cSSam Leffler 	const struct tls_cipher_suite *suite;
3735b9c547cSRui Paulo 	u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
37439beb93cSSam Leffler 	size_t rlen;
37539beb93cSSam Leffler 	u8 *dh_ys;
37639beb93cSSam Leffler 	size_t dh_ys_len;
3775b9c547cSRui Paulo 	const u8 *dh_p;
3785b9c547cSRui Paulo 	size_t dh_p_len;
37939beb93cSSam Leffler 
38039beb93cSSam Leffler 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
38139beb93cSSam Leffler 	if (suite == NULL)
38239beb93cSSam Leffler 		keyx = TLS_KEY_X_NULL;
38339beb93cSSam Leffler 	else
38439beb93cSSam Leffler 		keyx = suite->key_exchange;
38539beb93cSSam Leffler 
38639beb93cSSam Leffler 	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
38739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
38839beb93cSSam Leffler 		return 0;
38939beb93cSSam Leffler 	}
39039beb93cSSam Leffler 
3915b9c547cSRui Paulo 	if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
39239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
39339beb93cSSam Leffler 			   "supported with key exchange type %d", keyx);
39439beb93cSSam Leffler 		return -1;
39539beb93cSSam Leffler 	}
39639beb93cSSam Leffler 
39739beb93cSSam Leffler 	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
39839beb93cSSam Leffler 	    conn->cred->dh_g == NULL) {
39939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
40039beb93cSSam Leffler 			   "ServerKeyExhcange");
40139beb93cSSam Leffler 		return -1;
40239beb93cSSam Leffler 	}
40339beb93cSSam Leffler 
4045b9c547cSRui Paulo 	tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
4055b9c547cSRui Paulo 
40639beb93cSSam Leffler 	os_free(conn->dh_secret);
4075b9c547cSRui Paulo 	conn->dh_secret_len = dh_p_len;
40839beb93cSSam Leffler 	conn->dh_secret = os_malloc(conn->dh_secret_len);
40939beb93cSSam Leffler 	if (conn->dh_secret == NULL) {
41039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
41139beb93cSSam Leffler 			   "memory for secret (Diffie-Hellman)");
41239beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
41339beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
41439beb93cSSam Leffler 		return -1;
41539beb93cSSam Leffler 	}
416f05cddf9SRui Paulo 	if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) {
41739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
41839beb93cSSam Leffler 			   "data for Diffie-Hellman");
41939beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
42039beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
42139beb93cSSam Leffler 		os_free(conn->dh_secret);
42239beb93cSSam Leffler 		conn->dh_secret = NULL;
42339beb93cSSam Leffler 		return -1;
42439beb93cSSam Leffler 	}
42539beb93cSSam Leffler 
4265b9c547cSRui Paulo 	if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
42739beb93cSSam Leffler 		conn->dh_secret[0] = 0; /* make sure secret < p */
42839beb93cSSam Leffler 
42939beb93cSSam Leffler 	pos = conn->dh_secret;
43039beb93cSSam Leffler 	while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
43139beb93cSSam Leffler 		pos++;
43239beb93cSSam Leffler 	if (pos != conn->dh_secret) {
43339beb93cSSam Leffler 		os_memmove(conn->dh_secret, pos,
43439beb93cSSam Leffler 			   conn->dh_secret_len - (pos - conn->dh_secret));
43539beb93cSSam Leffler 		conn->dh_secret_len -= pos - conn->dh_secret;
43639beb93cSSam Leffler 	}
43739beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
43839beb93cSSam Leffler 			conn->dh_secret, conn->dh_secret_len);
43939beb93cSSam Leffler 
44039beb93cSSam Leffler 	/* Ys = g^secret mod p */
4415b9c547cSRui Paulo 	dh_ys_len = dh_p_len;
44239beb93cSSam Leffler 	dh_ys = os_malloc(dh_ys_len);
44339beb93cSSam Leffler 	if (dh_ys == NULL) {
44439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
44539beb93cSSam Leffler 			   "Diffie-Hellman");
44639beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
44739beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
44839beb93cSSam Leffler 		return -1;
44939beb93cSSam Leffler 	}
45039beb93cSSam Leffler 	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
45139beb93cSSam Leffler 			   conn->dh_secret, conn->dh_secret_len,
4525b9c547cSRui Paulo 			   dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
45339beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
45439beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
45539beb93cSSam Leffler 		os_free(dh_ys);
45639beb93cSSam Leffler 		return -1;
45739beb93cSSam Leffler 	}
45839beb93cSSam Leffler 
45939beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
46039beb93cSSam Leffler 		    dh_ys, dh_ys_len);
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 	/*
46339beb93cSSam Leffler 	 * struct {
46439beb93cSSam Leffler 	 *    select (KeyExchangeAlgorithm) {
46539beb93cSSam Leffler 	 *       case diffie_hellman:
46639beb93cSSam Leffler 	 *          ServerDHParams params;
46739beb93cSSam Leffler 	 *          Signature signed_params;
46839beb93cSSam Leffler 	 *       case rsa:
46939beb93cSSam Leffler 	 *          ServerRSAParams params;
47039beb93cSSam Leffler 	 *          Signature signed_params;
47139beb93cSSam Leffler 	 *    };
47239beb93cSSam Leffler 	 * } ServerKeyExchange;
47339beb93cSSam Leffler 	 *
47439beb93cSSam Leffler 	 * struct {
47539beb93cSSam Leffler 	 *    opaque dh_p<1..2^16-1>;
47639beb93cSSam Leffler 	 *    opaque dh_g<1..2^16-1>;
47739beb93cSSam Leffler 	 *    opaque dh_Ys<1..2^16-1>;
47839beb93cSSam Leffler 	 * } ServerDHParams;
47939beb93cSSam Leffler 	 */
48039beb93cSSam Leffler 
48139beb93cSSam Leffler 	pos = *msgpos;
48239beb93cSSam Leffler 
4835b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ServerKeyExchange");
48439beb93cSSam Leffler 	rhdr = pos;
48539beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
48639beb93cSSam Leffler 
48739beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
48839beb93cSSam Leffler 
48939beb93cSSam Leffler 	/* Handshake */
49039beb93cSSam Leffler 	hs_start = pos;
49139beb93cSSam Leffler 	/* HandshakeType msg_type */
49239beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
49339beb93cSSam Leffler 	/* uint24 length (to be filled) */
49439beb93cSSam Leffler 	hs_length = pos;
49539beb93cSSam Leffler 	pos += 3;
49639beb93cSSam Leffler 
49739beb93cSSam Leffler 	/* body - ServerDHParams */
4985b9c547cSRui Paulo 	server_params = pos;
49939beb93cSSam Leffler 	/* dh_p */
500780fb4a2SCy Schubert 	if (2 + dh_p_len > (size_t) (end - pos)) {
50139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
50239beb93cSSam Leffler 			   "dh_p");
50339beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
50439beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
50539beb93cSSam Leffler 		os_free(dh_ys);
50639beb93cSSam Leffler 		return -1;
50739beb93cSSam Leffler 	}
5085b9c547cSRui Paulo 	WPA_PUT_BE16(pos, dh_p_len);
50939beb93cSSam Leffler 	pos += 2;
5105b9c547cSRui Paulo 	os_memcpy(pos, dh_p, dh_p_len);
5115b9c547cSRui Paulo 	pos += dh_p_len;
51239beb93cSSam Leffler 
51339beb93cSSam Leffler 	/* dh_g */
514780fb4a2SCy Schubert 	if (2 + conn->cred->dh_g_len > (size_t) (end - pos)) {
51539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
51639beb93cSSam Leffler 			   "dh_g");
51739beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
51839beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
51939beb93cSSam Leffler 		os_free(dh_ys);
52039beb93cSSam Leffler 		return -1;
52139beb93cSSam Leffler 	}
52239beb93cSSam Leffler 	WPA_PUT_BE16(pos, conn->cred->dh_g_len);
52339beb93cSSam Leffler 	pos += 2;
52439beb93cSSam Leffler 	os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
52539beb93cSSam Leffler 	pos += conn->cred->dh_g_len;
52639beb93cSSam Leffler 
52739beb93cSSam Leffler 	/* dh_Ys */
528780fb4a2SCy Schubert 	if (2 + dh_ys_len > (size_t) (end - pos)) {
52939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
53039beb93cSSam Leffler 			   "dh_Ys");
53139beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
53239beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
53339beb93cSSam Leffler 		os_free(dh_ys);
53439beb93cSSam Leffler 		return -1;
53539beb93cSSam Leffler 	}
53639beb93cSSam Leffler 	WPA_PUT_BE16(pos, dh_ys_len);
53739beb93cSSam Leffler 	pos += 2;
53839beb93cSSam Leffler 	os_memcpy(pos, dh_ys, dh_ys_len);
53939beb93cSSam Leffler 	pos += dh_ys_len;
54039beb93cSSam Leffler 	os_free(dh_ys);
54139beb93cSSam Leffler 
5425b9c547cSRui Paulo 	/*
5435b9c547cSRui Paulo 	 * select (SignatureAlgorithm)
5445b9c547cSRui Paulo 	 * {   case anonymous: struct { };
5455b9c547cSRui Paulo 	 *     case rsa:
5465b9c547cSRui Paulo 	 *         digitally-signed struct {
5475b9c547cSRui Paulo 	 *             opaque md5_hash[16];
5485b9c547cSRui Paulo 	 *             opaque sha_hash[20];
5495b9c547cSRui Paulo 	 *         };
5505b9c547cSRui Paulo 	 *     case dsa:
5515b9c547cSRui Paulo 	 *         digitally-signed struct {
5525b9c547cSRui Paulo 	 *             opaque sha_hash[20];
5535b9c547cSRui Paulo 	 *         };
5545b9c547cSRui Paulo 	 * } Signature;
5555b9c547cSRui Paulo 	 *
5565b9c547cSRui Paulo 	 * md5_hash
5575b9c547cSRui Paulo 	 *     MD5(ClientHello.random + ServerHello.random + ServerParams);
5585b9c547cSRui Paulo 	 *
5595b9c547cSRui Paulo 	 * sha_hash
5605b9c547cSRui Paulo 	 *     SHA(ClientHello.random + ServerHello.random + ServerParams);
5615b9c547cSRui Paulo 	 */
5625b9c547cSRui Paulo 
5635b9c547cSRui Paulo 	if (keyx == TLS_KEY_X_DHE_RSA) {
5645b9c547cSRui Paulo 		u8 hash[100];
5655b9c547cSRui Paulo 		u8 *signed_start;
5665b9c547cSRui Paulo 		size_t clen;
5675b9c547cSRui Paulo 		int hlen;
5685b9c547cSRui Paulo 
5695b9c547cSRui Paulo 		if (conn->rl.tls_version >= TLS_VERSION_1_2) {
5705b9c547cSRui Paulo #ifdef CONFIG_TLSV12
5715b9c547cSRui Paulo 			hlen = tlsv12_key_x_server_params_hash(
572780fb4a2SCy Schubert 				conn->rl.tls_version, TLS_HASH_ALG_SHA256,
573780fb4a2SCy Schubert 				conn->client_random,
5745b9c547cSRui Paulo 				conn->server_random, server_params,
5755b9c547cSRui Paulo 				pos - server_params, hash + 19);
5765b9c547cSRui Paulo 
5775b9c547cSRui Paulo 			/*
5785b9c547cSRui Paulo 			 * RFC 5246, 4.7:
5795b9c547cSRui Paulo 			 * TLS v1.2 adds explicit indication of the used
5805b9c547cSRui Paulo 			 * signature and hash algorithms.
5815b9c547cSRui Paulo 			 *
5825b9c547cSRui Paulo 			 * struct {
5835b9c547cSRui Paulo 			 *   HashAlgorithm hash;
5845b9c547cSRui Paulo 			 *   SignatureAlgorithm signature;
5855b9c547cSRui Paulo 			 * } SignatureAndHashAlgorithm;
5865b9c547cSRui Paulo 			 */
587780fb4a2SCy Schubert 			if (hlen < 0 || end - pos < 2) {
5885b9c547cSRui Paulo 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
5895b9c547cSRui Paulo 						   TLS_ALERT_INTERNAL_ERROR);
5905b9c547cSRui Paulo 				return -1;
5915b9c547cSRui Paulo 			}
5925b9c547cSRui Paulo 			*pos++ = TLS_HASH_ALG_SHA256;
5935b9c547cSRui Paulo 			*pos++ = TLS_SIGN_ALG_RSA;
5945b9c547cSRui Paulo 
5955b9c547cSRui Paulo 			/*
5965b9c547cSRui Paulo 			 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
5975b9c547cSRui Paulo 			 *
5985b9c547cSRui Paulo 			 * DigestInfo ::= SEQUENCE {
5995b9c547cSRui Paulo 			 *   digestAlgorithm DigestAlgorithm,
6005b9c547cSRui Paulo 			 *   digest OCTET STRING
6015b9c547cSRui Paulo 			 * }
6025b9c547cSRui Paulo 			 *
6035b9c547cSRui Paulo 			 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
6045b9c547cSRui Paulo 			 *
6055b9c547cSRui Paulo 			 * DER encoded DigestInfo for SHA256 per RFC 3447:
6065b9c547cSRui Paulo 			 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
6075b9c547cSRui Paulo 			 * 04 20 || H
6085b9c547cSRui Paulo 			 */
6095b9c547cSRui Paulo 			hlen += 19;
6105b9c547cSRui Paulo 			os_memcpy(hash,
6115b9c547cSRui Paulo 				  "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
6125b9c547cSRui Paulo 				  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
6135b9c547cSRui Paulo 
6145b9c547cSRui Paulo #else /* CONFIG_TLSV12 */
6155b9c547cSRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6165b9c547cSRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
6175b9c547cSRui Paulo 			return -1;
6185b9c547cSRui Paulo #endif /* CONFIG_TLSV12 */
6195b9c547cSRui Paulo 		} else {
6205b9c547cSRui Paulo 			hlen = tls_key_x_server_params_hash(
6215b9c547cSRui Paulo 				conn->rl.tls_version, conn->client_random,
6225b9c547cSRui Paulo 				conn->server_random, server_params,
623*a90b9d01SCy Schubert 				pos - server_params, hash, sizeof(hash));
6245b9c547cSRui Paulo 		}
6255b9c547cSRui Paulo 
6265b9c547cSRui Paulo 		if (hlen < 0) {
6275b9c547cSRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6285b9c547cSRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
6295b9c547cSRui Paulo 			return -1;
6305b9c547cSRui Paulo 		}
6315b9c547cSRui Paulo 
6325b9c547cSRui Paulo 		wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
6335b9c547cSRui Paulo 			    hash, hlen);
6345b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
6355b9c547cSRui Paulo 		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
6365b9c547cSRui Paulo 			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
6375b9c547cSRui Paulo 			hash[hlen - 1] ^= 0x80;
6385b9c547cSRui Paulo 		}
6395b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
6405b9c547cSRui Paulo 
6415b9c547cSRui Paulo 		/*
6425b9c547cSRui Paulo 		 * RFC 2246, 4.7:
6435b9c547cSRui Paulo 		 * In digital signing, one-way hash functions are used as input
6445b9c547cSRui Paulo 		 * for a signing algorithm. A digitally-signed element is
6455b9c547cSRui Paulo 		 * encoded as an opaque vector <0..2^16-1>, where the length is
6465b9c547cSRui Paulo 		 * specified by the signing algorithm and key.
6475b9c547cSRui Paulo 		 *
6485b9c547cSRui Paulo 		 * In RSA signing, a 36-byte structure of two hashes (one SHA
6495b9c547cSRui Paulo 		 * and one MD5) is signed (encrypted with the private key). It
6505b9c547cSRui Paulo 		 * is encoded with PKCS #1 block type 0 or type 1 as described
6515b9c547cSRui Paulo 		 * in [PKCS1].
6525b9c547cSRui Paulo 		 */
6535b9c547cSRui Paulo 		signed_start = pos; /* length to be filled */
6545b9c547cSRui Paulo 		pos += 2;
6555b9c547cSRui Paulo 		clen = end - pos;
6565b9c547cSRui Paulo 		if (conn->cred == NULL ||
6575b9c547cSRui Paulo 		    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
6585b9c547cSRui Paulo 						  pos, &clen) < 0) {
6595b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
6605b9c547cSRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6615b9c547cSRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
6625b9c547cSRui Paulo 			return -1;
6635b9c547cSRui Paulo 		}
6645b9c547cSRui Paulo 		WPA_PUT_BE16(signed_start, clen);
6655b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
6665b9c547cSRui Paulo 		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
6675b9c547cSRui Paulo 			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
6685b9c547cSRui Paulo 			pos[clen - 1] ^= 0x80;
6695b9c547cSRui Paulo 		}
6705b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
6715b9c547cSRui Paulo 
6725b9c547cSRui Paulo 		pos += clen;
6735b9c547cSRui Paulo 	}
6745b9c547cSRui Paulo 
67539beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
67639beb93cSSam Leffler 
67739beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
678f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
679f05cddf9SRui Paulo 			      &rlen) < 0) {
68039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
68139beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
68239beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
68339beb93cSSam Leffler 		return -1;
68439beb93cSSam Leffler 	}
68539beb93cSSam Leffler 	pos = rhdr + rlen;
68639beb93cSSam Leffler 
68739beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
68839beb93cSSam Leffler 
68939beb93cSSam Leffler 	*msgpos = pos;
69039beb93cSSam Leffler 
69139beb93cSSam Leffler 	return 0;
69239beb93cSSam Leffler }
69339beb93cSSam Leffler 
69439beb93cSSam Leffler 
tls_write_server_certificate_request(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)69539beb93cSSam Leffler static int tls_write_server_certificate_request(struct tlsv1_server *conn,
69639beb93cSSam Leffler 						u8 **msgpos, u8 *end)
69739beb93cSSam Leffler {
69839beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length;
69939beb93cSSam Leffler 	size_t rlen;
70039beb93cSSam Leffler 
70139beb93cSSam Leffler 	if (!conn->verify_peer) {
70239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
70339beb93cSSam Leffler 		return 0;
70439beb93cSSam Leffler 	}
70539beb93cSSam Leffler 
70639beb93cSSam Leffler 	pos = *msgpos;
70739beb93cSSam Leffler 
7085b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send CertificateRequest");
70939beb93cSSam Leffler 	rhdr = pos;
71039beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
71139beb93cSSam Leffler 
71239beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
71339beb93cSSam Leffler 
71439beb93cSSam Leffler 	/* Handshake */
71539beb93cSSam Leffler 	hs_start = pos;
71639beb93cSSam Leffler 	/* HandshakeType msg_type */
71739beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
71839beb93cSSam Leffler 	/* uint24 length (to be filled) */
71939beb93cSSam Leffler 	hs_length = pos;
72039beb93cSSam Leffler 	pos += 3;
72139beb93cSSam Leffler 	/* body - CertificateRequest */
72239beb93cSSam Leffler 
72339beb93cSSam Leffler 	/*
72439beb93cSSam Leffler 	 * enum {
72539beb93cSSam Leffler 	 *   rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
72639beb93cSSam Leffler 	 *   (255)
72739beb93cSSam Leffler 	 * } ClientCertificateType;
72839beb93cSSam Leffler 	 * ClientCertificateType certificate_types<1..2^8-1>
72939beb93cSSam Leffler 	 */
73039beb93cSSam Leffler 	*pos++ = 1;
73139beb93cSSam Leffler 	*pos++ = 1; /* rsa_sign */
73239beb93cSSam Leffler 
73339beb93cSSam Leffler 	/*
73439beb93cSSam Leffler 	 * opaque DistinguishedName<1..2^16-1>
73539beb93cSSam Leffler 	 * DistinguishedName certificate_authorities<3..2^16-1>
73639beb93cSSam Leffler 	 */
73739beb93cSSam Leffler 	/* TODO: add support for listing DNs for trusted CAs */
73839beb93cSSam Leffler 	WPA_PUT_BE16(pos, 0);
73939beb93cSSam Leffler 	pos += 2;
74039beb93cSSam Leffler 
74139beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
74239beb93cSSam Leffler 
74339beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
744f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
745f05cddf9SRui Paulo 			      &rlen) < 0) {
74639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
74739beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
74839beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
74939beb93cSSam Leffler 		return -1;
75039beb93cSSam Leffler 	}
75139beb93cSSam Leffler 	pos = rhdr + rlen;
75239beb93cSSam Leffler 
75339beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
75439beb93cSSam Leffler 
75539beb93cSSam Leffler 	*msgpos = pos;
75639beb93cSSam Leffler 
75739beb93cSSam Leffler 	return 0;
75839beb93cSSam Leffler }
75939beb93cSSam Leffler 
76039beb93cSSam Leffler 
tls_write_server_hello_done(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)76139beb93cSSam Leffler static int tls_write_server_hello_done(struct tlsv1_server *conn,
76239beb93cSSam Leffler 				       u8 **msgpos, u8 *end)
76339beb93cSSam Leffler {
764f05cddf9SRui Paulo 	u8 *pos;
76539beb93cSSam Leffler 	size_t rlen;
766f05cddf9SRui Paulo 	u8 payload[4];
76739beb93cSSam Leffler 
7685b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ServerHelloDone");
76939beb93cSSam Leffler 
77039beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
77139beb93cSSam Leffler 
77239beb93cSSam Leffler 	/* Handshake */
773f05cddf9SRui Paulo 	pos = payload;
77439beb93cSSam Leffler 	/* HandshakeType msg_type */
77539beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
776f05cddf9SRui Paulo 	/* uint24 length */
777f05cddf9SRui Paulo 	WPA_PUT_BE24(pos, 0);
77839beb93cSSam Leffler 	pos += 3;
77939beb93cSSam Leffler 	/* body - ServerHelloDone (empty) */
78039beb93cSSam Leffler 
78139beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
782f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, payload, pos - payload,
783f05cddf9SRui Paulo 			      &rlen) < 0) {
78439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
78539beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
78639beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
78739beb93cSSam Leffler 		return -1;
78839beb93cSSam Leffler 	}
78939beb93cSSam Leffler 
790f05cddf9SRui Paulo 	tls_verify_hash_add(&conn->verify, payload, pos - payload);
79139beb93cSSam Leffler 
792f05cddf9SRui Paulo 	*msgpos += rlen;
79339beb93cSSam Leffler 
79439beb93cSSam Leffler 	return 0;
79539beb93cSSam Leffler }
79639beb93cSSam Leffler 
79739beb93cSSam Leffler 
tls_write_server_change_cipher_spec(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)79839beb93cSSam Leffler static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
79939beb93cSSam Leffler 					       u8 **msgpos, u8 *end)
80039beb93cSSam Leffler {
80139beb93cSSam Leffler 	size_t rlen;
802f05cddf9SRui Paulo 	u8 payload[1];
80339beb93cSSam Leffler 
8045b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ChangeCipherSpec");
805f05cddf9SRui Paulo 
806f05cddf9SRui Paulo 	payload[0] = TLS_CHANGE_CIPHER_SPEC;
807f05cddf9SRui Paulo 
80839beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
809f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, payload, sizeof(payload),
810f05cddf9SRui Paulo 			      &rlen) < 0) {
81139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
81239beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
81339beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
81439beb93cSSam Leffler 		return -1;
81539beb93cSSam Leffler 	}
81639beb93cSSam Leffler 
81739beb93cSSam Leffler 	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
81839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
81939beb93cSSam Leffler 			   "record layer");
82039beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
82139beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
82239beb93cSSam Leffler 		return -1;
82339beb93cSSam Leffler 	}
82439beb93cSSam Leffler 
825f05cddf9SRui Paulo 	*msgpos += rlen;
82639beb93cSSam Leffler 
82739beb93cSSam Leffler 	return 0;
82839beb93cSSam Leffler }
82939beb93cSSam Leffler 
83039beb93cSSam Leffler 
tls_write_server_finished(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)83139beb93cSSam Leffler static int tls_write_server_finished(struct tlsv1_server *conn,
83239beb93cSSam Leffler 				     u8 **msgpos, u8 *end)
83339beb93cSSam Leffler {
834f05cddf9SRui Paulo 	u8 *pos, *hs_start;
83539beb93cSSam Leffler 	size_t rlen, hlen;
836f05cddf9SRui Paulo 	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
83739beb93cSSam Leffler 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
83839beb93cSSam Leffler 
83939beb93cSSam Leffler 	pos = *msgpos;
84039beb93cSSam Leffler 
8415b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send Finished");
84239beb93cSSam Leffler 
84339beb93cSSam Leffler 	/* Encrypted Handshake Message: Finished */
84439beb93cSSam Leffler 
845f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
846f05cddf9SRui Paulo 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
847f05cddf9SRui Paulo 		hlen = SHA256_MAC_LEN;
848f05cddf9SRui Paulo 		if (conn->verify.sha256_server == NULL ||
849f05cddf9SRui Paulo 		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
850f05cddf9SRui Paulo 		    < 0) {
851f05cddf9SRui Paulo 			conn->verify.sha256_server = NULL;
852f05cddf9SRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
853f05cddf9SRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
854f05cddf9SRui Paulo 			return -1;
855f05cddf9SRui Paulo 		}
856f05cddf9SRui Paulo 		conn->verify.sha256_server = NULL;
857f05cddf9SRui Paulo 	} else {
858f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
859f05cddf9SRui Paulo 
86039beb93cSSam Leffler 	hlen = MD5_MAC_LEN;
86139beb93cSSam Leffler 	if (conn->verify.md5_server == NULL ||
86239beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
86339beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
86439beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
86539beb93cSSam Leffler 		conn->verify.md5_server = NULL;
86639beb93cSSam Leffler 		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
86739beb93cSSam Leffler 		conn->verify.sha1_server = NULL;
86839beb93cSSam Leffler 		return -1;
86939beb93cSSam Leffler 	}
87039beb93cSSam Leffler 	conn->verify.md5_server = NULL;
87139beb93cSSam Leffler 	hlen = SHA1_MAC_LEN;
87239beb93cSSam Leffler 	if (conn->verify.sha1_server == NULL ||
87339beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
87439beb93cSSam Leffler 			       &hlen) < 0) {
87539beb93cSSam Leffler 		conn->verify.sha1_server = NULL;
87639beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
87739beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
87839beb93cSSam Leffler 		return -1;
87939beb93cSSam Leffler 	}
88039beb93cSSam Leffler 	conn->verify.sha1_server = NULL;
881f05cddf9SRui Paulo 	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
88239beb93cSSam Leffler 
883f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
884f05cddf9SRui Paulo 	}
885f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
886f05cddf9SRui Paulo 
887f05cddf9SRui Paulo 	if (tls_prf(conn->rl.tls_version,
888f05cddf9SRui Paulo 		    conn->master_secret, TLS_MASTER_SECRET_LEN,
889f05cddf9SRui Paulo 		    "server finished", hash, hlen,
890f05cddf9SRui Paulo 		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
89139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
89239beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
89339beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
89439beb93cSSam Leffler 		return -1;
89539beb93cSSam Leffler 	}
89639beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
897f05cddf9SRui Paulo 			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
8985b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
8995b9c547cSRui Paulo 	if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
9005b9c547cSRui Paulo 		tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
9015b9c547cSRui Paulo 		verify_data[1 + 3 + 1] ^= 0x80;
9025b9c547cSRui Paulo 	}
9035b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
90439beb93cSSam Leffler 
90539beb93cSSam Leffler 	/* Handshake */
906f05cddf9SRui Paulo 	pos = hs_start = verify_data;
90739beb93cSSam Leffler 	/* HandshakeType msg_type */
90839beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
909f05cddf9SRui Paulo 	/* uint24 length */
910f05cddf9SRui Paulo 	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
91139beb93cSSam Leffler 	pos += 3;
91239beb93cSSam Leffler 	pos += TLS_VERIFY_DATA_LEN;
91339beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
91439beb93cSSam Leffler 
91539beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
916f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
917f05cddf9SRui Paulo 			      &rlen) < 0) {
91839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
91939beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
92039beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
92139beb93cSSam Leffler 		return -1;
92239beb93cSSam Leffler 	}
92339beb93cSSam Leffler 
924f05cddf9SRui Paulo 	*msgpos += rlen;
92539beb93cSSam Leffler 
92639beb93cSSam Leffler 	return 0;
92739beb93cSSam Leffler }
92839beb93cSSam Leffler 
92939beb93cSSam Leffler 
tls_send_server_hello(struct tlsv1_server * conn,size_t * out_len)93039beb93cSSam Leffler static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
93139beb93cSSam Leffler {
93239beb93cSSam Leffler 	u8 *msg, *end, *pos;
93339beb93cSSam Leffler 	size_t msglen;
934780fb4a2SCy Schubert 	int ocsp_multi = 0;
935780fb4a2SCy Schubert 	char *ocsp_resp = NULL;
936780fb4a2SCy Schubert 	size_t ocsp_resp_len = 0;
93739beb93cSSam Leffler 
93839beb93cSSam Leffler 	*out_len = 0;
93939beb93cSSam Leffler 
940780fb4a2SCy Schubert 	if (conn->status_request_multi &&
941780fb4a2SCy Schubert 	    conn->cred->ocsp_stapling_response_multi) {
942780fb4a2SCy Schubert 		ocsp_resp = os_readfile(
943780fb4a2SCy Schubert 			conn->cred->ocsp_stapling_response_multi,
944780fb4a2SCy Schubert 			&ocsp_resp_len);
945780fb4a2SCy Schubert 		ocsp_multi = 1;
946780fb4a2SCy Schubert 	} else if ((conn->status_request || conn->status_request_v2) &&
947780fb4a2SCy Schubert 		   conn->cred->ocsp_stapling_response) {
948780fb4a2SCy Schubert 		ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
949780fb4a2SCy Schubert 					&ocsp_resp_len);
950780fb4a2SCy Schubert 	}
951780fb4a2SCy Schubert 	if (!ocsp_resp)
952780fb4a2SCy Schubert 		ocsp_resp_len = 0;
953780fb4a2SCy Schubert 
954780fb4a2SCy Schubert 	msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 	msg = os_malloc(msglen);
957780fb4a2SCy Schubert 	if (msg == NULL) {
958780fb4a2SCy Schubert 		os_free(ocsp_resp);
95939beb93cSSam Leffler 		return NULL;
960780fb4a2SCy Schubert 	}
96139beb93cSSam Leffler 
96239beb93cSSam Leffler 	pos = msg;
96339beb93cSSam Leffler 	end = msg + msglen;
96439beb93cSSam Leffler 
96539beb93cSSam Leffler 	if (tls_write_server_hello(conn, &pos, end) < 0) {
96639beb93cSSam Leffler 		os_free(msg);
967780fb4a2SCy Schubert 		os_free(ocsp_resp);
96839beb93cSSam Leffler 		return NULL;
96939beb93cSSam Leffler 	}
97039beb93cSSam Leffler 
97139beb93cSSam Leffler 	if (conn->use_session_ticket) {
972780fb4a2SCy Schubert 		os_free(ocsp_resp);
973780fb4a2SCy Schubert 
97439beb93cSSam Leffler 		/* Abbreviated handshake using session ticket; RFC 4507 */
97539beb93cSSam Leffler 		if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
97639beb93cSSam Leffler 		    tls_write_server_finished(conn, &pos, end) < 0) {
97739beb93cSSam Leffler 			os_free(msg);
97839beb93cSSam Leffler 			return NULL;
97939beb93cSSam Leffler 		}
98039beb93cSSam Leffler 
98139beb93cSSam Leffler 		*out_len = pos - msg;
98239beb93cSSam Leffler 
98339beb93cSSam Leffler 		conn->state = CHANGE_CIPHER_SPEC;
98439beb93cSSam Leffler 
98539beb93cSSam Leffler 		return msg;
98639beb93cSSam Leffler 	}
98739beb93cSSam Leffler 
98839beb93cSSam Leffler 	/* Full handshake */
98939beb93cSSam Leffler 	if (tls_write_server_certificate(conn, &pos, end) < 0 ||
990780fb4a2SCy Schubert 	    tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
991780fb4a2SCy Schubert 						ocsp_resp, ocsp_resp_len) < 0 ||
99239beb93cSSam Leffler 	    tls_write_server_key_exchange(conn, &pos, end) < 0 ||
99339beb93cSSam Leffler 	    tls_write_server_certificate_request(conn, &pos, end) < 0 ||
99439beb93cSSam Leffler 	    tls_write_server_hello_done(conn, &pos, end) < 0) {
99539beb93cSSam Leffler 		os_free(msg);
996780fb4a2SCy Schubert 		os_free(ocsp_resp);
99739beb93cSSam Leffler 		return NULL;
99839beb93cSSam Leffler 	}
999780fb4a2SCy Schubert 	os_free(ocsp_resp);
100039beb93cSSam Leffler 
100139beb93cSSam Leffler 	*out_len = pos - msg;
100239beb93cSSam Leffler 
100339beb93cSSam Leffler 	conn->state = CLIENT_CERTIFICATE;
100439beb93cSSam Leffler 
100539beb93cSSam Leffler 	return msg;
100639beb93cSSam Leffler }
100739beb93cSSam Leffler 
100839beb93cSSam Leffler 
tls_send_change_cipher_spec(struct tlsv1_server * conn,size_t * out_len)100939beb93cSSam Leffler static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
101039beb93cSSam Leffler 					size_t *out_len)
101139beb93cSSam Leffler {
101239beb93cSSam Leffler 	u8 *msg, *end, *pos;
101339beb93cSSam Leffler 
101439beb93cSSam Leffler 	*out_len = 0;
101539beb93cSSam Leffler 
101639beb93cSSam Leffler 	msg = os_malloc(1000);
101739beb93cSSam Leffler 	if (msg == NULL)
101839beb93cSSam Leffler 		return NULL;
101939beb93cSSam Leffler 
102039beb93cSSam Leffler 	pos = msg;
102139beb93cSSam Leffler 	end = msg + 1000;
102239beb93cSSam Leffler 
102339beb93cSSam Leffler 	if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
102439beb93cSSam Leffler 	    tls_write_server_finished(conn, &pos, end) < 0) {
102539beb93cSSam Leffler 		os_free(msg);
102639beb93cSSam Leffler 		return NULL;
102739beb93cSSam Leffler 	}
102839beb93cSSam Leffler 
102939beb93cSSam Leffler 	*out_len = pos - msg;
103039beb93cSSam Leffler 
10315b9c547cSRui Paulo 	tlsv1_server_log(conn, "Handshake completed successfully");
103239beb93cSSam Leffler 	conn->state = ESTABLISHED;
103339beb93cSSam Leffler 
103439beb93cSSam Leffler 	return msg;
103539beb93cSSam Leffler }
103639beb93cSSam Leffler 
103739beb93cSSam Leffler 
tlsv1_server_handshake_write(struct tlsv1_server * conn,size_t * out_len)103839beb93cSSam Leffler u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
103939beb93cSSam Leffler {
104039beb93cSSam Leffler 	switch (conn->state) {
104139beb93cSSam Leffler 	case SERVER_HELLO:
104239beb93cSSam Leffler 		return tls_send_server_hello(conn, out_len);
104339beb93cSSam Leffler 	case SERVER_CHANGE_CIPHER_SPEC:
104439beb93cSSam Leffler 		return tls_send_change_cipher_spec(conn, out_len);
104539beb93cSSam Leffler 	default:
104639beb93cSSam Leffler 		if (conn->state == ESTABLISHED && conn->use_session_ticket) {
104739beb93cSSam Leffler 			/* Abbreviated handshake was already completed. */
104839beb93cSSam Leffler 			return NULL;
104939beb93cSSam Leffler 		}
10505b9c547cSRui Paulo 		tlsv1_server_log(conn, "Unexpected state %d while generating reply",
10515b9c547cSRui Paulo 				 conn->state);
105239beb93cSSam Leffler 		return NULL;
105339beb93cSSam Leffler 	}
105439beb93cSSam Leffler }
105539beb93cSSam Leffler 
105639beb93cSSam Leffler 
tlsv1_server_send_alert(struct tlsv1_server * conn,u8 level,u8 description,size_t * out_len)105739beb93cSSam Leffler u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
105839beb93cSSam Leffler 			     u8 description, size_t *out_len)
105939beb93cSSam Leffler {
106039beb93cSSam Leffler 	u8 *alert, *pos, *length;
106139beb93cSSam Leffler 
10625b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
106339beb93cSSam Leffler 	*out_len = 0;
106439beb93cSSam Leffler 
106539beb93cSSam Leffler 	alert = os_malloc(10);
106639beb93cSSam Leffler 	if (alert == NULL)
106739beb93cSSam Leffler 		return NULL;
106839beb93cSSam Leffler 
106939beb93cSSam Leffler 	pos = alert;
107039beb93cSSam Leffler 
107139beb93cSSam Leffler 	/* TLSPlaintext */
107239beb93cSSam Leffler 	/* ContentType type */
107339beb93cSSam Leffler 	*pos++ = TLS_CONTENT_TYPE_ALERT;
107439beb93cSSam Leffler 	/* ProtocolVersion version */
1075f05cddf9SRui Paulo 	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
1076f05cddf9SRui Paulo 		     TLS_VERSION);
107739beb93cSSam Leffler 	pos += 2;
107839beb93cSSam Leffler 	/* uint16 length (to be filled) */
107939beb93cSSam Leffler 	length = pos;
108039beb93cSSam Leffler 	pos += 2;
108139beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
108239beb93cSSam Leffler 
108339beb93cSSam Leffler 	/* Alert */
108439beb93cSSam Leffler 	/* AlertLevel level */
108539beb93cSSam Leffler 	*pos++ = level;
108639beb93cSSam Leffler 	/* AlertDescription description */
108739beb93cSSam Leffler 	*pos++ = description;
108839beb93cSSam Leffler 
108939beb93cSSam Leffler 	WPA_PUT_BE16(length, pos - length - 2);
109039beb93cSSam Leffler 	*out_len = pos - alert;
109139beb93cSSam Leffler 
109239beb93cSSam Leffler 	return alert;
109339beb93cSSam Leffler }
1094