xref: /freebsd/contrib/wpa/src/tls/tlsv1_server_write.c (revision 780fb4a2fa9a9aee5ac48a60b790f567c0dc13e9)
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 
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 
2939beb93cSSam Leffler 	cert = conn->cred->cert;
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 
4239beb93cSSam Leffler static int tls_write_server_hello(struct tlsv1_server *conn,
4339beb93cSSam Leffler 				  u8 **msgpos, u8 *end)
4439beb93cSSam Leffler {
45*780fb4a2SCy 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);
5639beb93cSSam Leffler 	WPA_PUT_BE32(conn->server_random, now.sec);
57f05cddf9SRui Paulo 	if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
5839beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
5939beb93cSSam Leffler 			   "server_random");
6039beb93cSSam Leffler 		return -1;
6139beb93cSSam Leffler 	}
6239beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
6339beb93cSSam Leffler 		    conn->server_random, TLS_RANDOM_LEN);
6439beb93cSSam Leffler 
6539beb93cSSam Leffler 	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
66f05cddf9SRui Paulo 	if (random_get_bytes(conn->session_id, conn->session_id_len)) {
6739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
6839beb93cSSam Leffler 			   "session_id");
6939beb93cSSam Leffler 		return -1;
7039beb93cSSam Leffler 	}
7139beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
7239beb93cSSam Leffler 		    conn->session_id, conn->session_id_len);
7339beb93cSSam Leffler 
7439beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
7539beb93cSSam Leffler 
7639beb93cSSam Leffler 	/* Handshake */
7739beb93cSSam Leffler 	hs_start = pos;
7839beb93cSSam Leffler 	/* HandshakeType msg_type */
7939beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
8039beb93cSSam Leffler 	/* uint24 length (to be filled) */
8139beb93cSSam Leffler 	hs_length = pos;
8239beb93cSSam Leffler 	pos += 3;
8339beb93cSSam Leffler 	/* body - ServerHello */
8439beb93cSSam Leffler 	/* ProtocolVersion server_version */
85f05cddf9SRui Paulo 	WPA_PUT_BE16(pos, conn->rl.tls_version);
8639beb93cSSam Leffler 	pos += 2;
8739beb93cSSam Leffler 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
8839beb93cSSam Leffler 	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
8939beb93cSSam Leffler 	pos += TLS_RANDOM_LEN;
9039beb93cSSam Leffler 	/* SessionID session_id */
9139beb93cSSam Leffler 	*pos++ = conn->session_id_len;
9239beb93cSSam Leffler 	os_memcpy(pos, conn->session_id, conn->session_id_len);
9339beb93cSSam Leffler 	pos += conn->session_id_len;
9439beb93cSSam Leffler 	/* CipherSuite cipher_suite */
9539beb93cSSam Leffler 	WPA_PUT_BE16(pos, conn->cipher_suite);
9639beb93cSSam Leffler 	pos += 2;
9739beb93cSSam Leffler 	/* CompressionMethod compression_method */
9839beb93cSSam Leffler 	*pos++ = TLS_COMPRESSION_NULL;
9939beb93cSSam Leffler 
100*780fb4a2SCy Schubert 	/* Extension */
101*780fb4a2SCy Schubert 	ext_start = pos;
102*780fb4a2SCy Schubert 	pos += 2;
103*780fb4a2SCy Schubert 
104*780fb4a2SCy Schubert 	if (conn->status_request) {
105*780fb4a2SCy Schubert 		/* Add a status_request extension with empty extension_data */
106*780fb4a2SCy Schubert 		/* ExtensionsType extension_type = status_request(5) */
107*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
108*780fb4a2SCy Schubert 		pos += 2;
109*780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
110*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0);
111*780fb4a2SCy Schubert 		pos += 2;
112*780fb4a2SCy Schubert 	}
113*780fb4a2SCy Schubert 
114*780fb4a2SCy Schubert 	if (conn->status_request_v2) {
115*780fb4a2SCy Schubert 		/*
116*780fb4a2SCy Schubert 		  Add a status_request_v2 extension with empty extension_data
117*780fb4a2SCy Schubert 		*/
118*780fb4a2SCy Schubert 		/* ExtensionsType extension_type = status_request_v2(17) */
119*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
120*780fb4a2SCy Schubert 		pos += 2;
121*780fb4a2SCy Schubert 		/* opaque extension_data<0..2^16-1> length */
122*780fb4a2SCy Schubert 		WPA_PUT_BE16(pos, 0);
123*780fb4a2SCy Schubert 		pos += 2;
124*780fb4a2SCy Schubert 	}
125*780fb4a2SCy Schubert 
12639beb93cSSam Leffler 	if (conn->session_ticket && conn->session_ticket_cb) {
12739beb93cSSam Leffler 		int res = conn->session_ticket_cb(
12839beb93cSSam Leffler 			conn->session_ticket_cb_ctx,
12939beb93cSSam Leffler 			conn->session_ticket, conn->session_ticket_len,
13039beb93cSSam Leffler 			conn->client_random, conn->server_random,
13139beb93cSSam Leffler 			conn->master_secret);
13239beb93cSSam Leffler 		if (res < 0) {
1335b9c547cSRui Paulo 			tlsv1_server_log(conn, "SessionTicket callback indicated failure");
13439beb93cSSam Leffler 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
13539beb93cSSam Leffler 					   TLS_ALERT_HANDSHAKE_FAILURE);
13639beb93cSSam Leffler 			return -1;
13739beb93cSSam Leffler 		}
13839beb93cSSam Leffler 		conn->use_session_ticket = res;
13939beb93cSSam Leffler 
14039beb93cSSam Leffler 		if (conn->use_session_ticket) {
14139beb93cSSam Leffler 			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
14239beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
14339beb93cSSam Leffler 					   "derive keys");
14439beb93cSSam Leffler 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
14539beb93cSSam Leffler 						   TLS_ALERT_INTERNAL_ERROR);
14639beb93cSSam Leffler 				return -1;
14739beb93cSSam Leffler 			}
14839beb93cSSam Leffler 		}
14939beb93cSSam Leffler 
15039beb93cSSam Leffler 		/*
15139beb93cSSam Leffler 		 * RFC 4507 specifies that server would include an empty
15239beb93cSSam Leffler 		 * SessionTicket extension in ServerHello and a
15339beb93cSSam Leffler 		 * NewSessionTicket message after the ServerHello. However,
15439beb93cSSam Leffler 		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
15539beb93cSSam Leffler 		 * extension at the moment, does not use such extensions.
15639beb93cSSam Leffler 		 *
15739beb93cSSam Leffler 		 * TODO: Add support for configuring RFC 4507 behavior and make
15839beb93cSSam Leffler 		 * EAP-FAST disable it.
15939beb93cSSam Leffler 		 */
16039beb93cSSam Leffler 	}
16139beb93cSSam Leffler 
162*780fb4a2SCy Schubert 	if (pos == ext_start + 2)
163*780fb4a2SCy Schubert 		pos -= 2; /* no extensions */
164*780fb4a2SCy Schubert 	else
165*780fb4a2SCy Schubert 		WPA_PUT_BE16(ext_start, pos - ext_start - 2);
166*780fb4a2SCy Schubert 
16739beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
16839beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
16939beb93cSSam Leffler 
17039beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
171f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
172f05cddf9SRui Paulo 			      &rlen) < 0) {
17339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
17439beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
17539beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
17639beb93cSSam Leffler 		return -1;
17739beb93cSSam Leffler 	}
17839beb93cSSam Leffler 	pos = rhdr + rlen;
17939beb93cSSam Leffler 
18039beb93cSSam Leffler 	*msgpos = pos;
18139beb93cSSam Leffler 
18239beb93cSSam Leffler 	return 0;
18339beb93cSSam Leffler }
18439beb93cSSam Leffler 
18539beb93cSSam Leffler 
18639beb93cSSam Leffler static int tls_write_server_certificate(struct tlsv1_server *conn,
18739beb93cSSam Leffler 					u8 **msgpos, u8 *end)
18839beb93cSSam Leffler {
18939beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
19039beb93cSSam Leffler 	size_t rlen;
19139beb93cSSam Leffler 	struct x509_certificate *cert;
19239beb93cSSam Leffler 	const struct tls_cipher_suite *suite;
19339beb93cSSam Leffler 
19439beb93cSSam Leffler 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
19539beb93cSSam Leffler 	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
19639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
19739beb93cSSam Leffler 			   "using anonymous DH");
19839beb93cSSam Leffler 		return 0;
19939beb93cSSam Leffler 	}
20039beb93cSSam Leffler 
20139beb93cSSam Leffler 	pos = *msgpos;
202*780fb4a2SCy Schubert 	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
203*780fb4a2SCy Schubert 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
204*780fb4a2SCy Schubert 				   TLS_ALERT_INTERNAL_ERROR);
205*780fb4a2SCy Schubert 		return -1;
206*780fb4a2SCy Schubert 	}
20739beb93cSSam Leffler 
2085b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send Certificate");
20939beb93cSSam Leffler 	rhdr = pos;
21039beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
21139beb93cSSam Leffler 
21239beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
21339beb93cSSam Leffler 
21439beb93cSSam Leffler 	/* Handshake */
21539beb93cSSam Leffler 	hs_start = pos;
21639beb93cSSam Leffler 	/* HandshakeType msg_type */
21739beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
21839beb93cSSam Leffler 	/* uint24 length (to be filled) */
21939beb93cSSam Leffler 	hs_length = pos;
22039beb93cSSam Leffler 	pos += 3;
22139beb93cSSam Leffler 	/* body - Certificate */
22239beb93cSSam Leffler 	/* uint24 length (to be filled) */
22339beb93cSSam Leffler 	cert_start = pos;
22439beb93cSSam Leffler 	pos += 3;
22539beb93cSSam Leffler 	cert = conn->cred->cert;
22639beb93cSSam Leffler 	while (cert) {
227*780fb4a2SCy Schubert 		if (3 + cert->cert_len > (size_t) (end - pos)) {
22839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
22939beb93cSSam Leffler 				   "for Certificate (cert_len=%lu left=%lu)",
23039beb93cSSam Leffler 				   (unsigned long) cert->cert_len,
23139beb93cSSam Leffler 				   (unsigned long) (end - pos));
23239beb93cSSam Leffler 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
23339beb93cSSam Leffler 					   TLS_ALERT_INTERNAL_ERROR);
23439beb93cSSam Leffler 			return -1;
23539beb93cSSam Leffler 		}
23639beb93cSSam Leffler 		WPA_PUT_BE24(pos, cert->cert_len);
23739beb93cSSam Leffler 		pos += 3;
23839beb93cSSam Leffler 		os_memcpy(pos, cert->cert_start, cert->cert_len);
23939beb93cSSam Leffler 		pos += cert->cert_len;
24039beb93cSSam Leffler 
24139beb93cSSam Leffler 		if (x509_certificate_self_signed(cert))
24239beb93cSSam Leffler 			break;
24339beb93cSSam Leffler 		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
24439beb93cSSam Leffler 						    &cert->issuer);
24539beb93cSSam Leffler 	}
24639beb93cSSam Leffler 	if (cert == conn->cred->cert || cert == NULL) {
24739beb93cSSam Leffler 		/*
24839beb93cSSam Leffler 		 * Server was not configured with all the needed certificates
24939beb93cSSam Leffler 		 * to form a full certificate chain. The client may fail to
25039beb93cSSam Leffler 		 * validate the chain unless it is configured with all the
25139beb93cSSam Leffler 		 * missing CA certificates.
25239beb93cSSam Leffler 		 */
25339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
25439beb93cSSam Leffler 			   "not configured - validation may fail");
25539beb93cSSam Leffler 	}
25639beb93cSSam Leffler 	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
25739beb93cSSam Leffler 
25839beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
25939beb93cSSam Leffler 
26039beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
261f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
262f05cddf9SRui Paulo 			      &rlen) < 0) {
26339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
26439beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
26539beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
26639beb93cSSam Leffler 		return -1;
26739beb93cSSam Leffler 	}
26839beb93cSSam Leffler 	pos = rhdr + rlen;
26939beb93cSSam Leffler 
27039beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
27139beb93cSSam Leffler 
27239beb93cSSam Leffler 	*msgpos = pos;
27339beb93cSSam Leffler 
27439beb93cSSam Leffler 	return 0;
27539beb93cSSam Leffler }
27639beb93cSSam Leffler 
27739beb93cSSam Leffler 
278*780fb4a2SCy Schubert static int tls_write_server_certificate_status(struct tlsv1_server *conn,
279*780fb4a2SCy Schubert 					       u8 **msgpos, u8 *end,
280*780fb4a2SCy Schubert 					       int ocsp_multi,
281*780fb4a2SCy Schubert 					       char *ocsp_resp,
282*780fb4a2SCy Schubert 					       size_t ocsp_resp_len)
283*780fb4a2SCy Schubert {
284*780fb4a2SCy Schubert 	u8 *pos, *rhdr, *hs_start, *hs_length;
285*780fb4a2SCy Schubert 	size_t rlen;
286*780fb4a2SCy Schubert 
287*780fb4a2SCy Schubert 	if (!ocsp_resp) {
288*780fb4a2SCy Schubert 		 /*
289*780fb4a2SCy Schubert 		  * Client did not request certificate status or there is no
290*780fb4a2SCy Schubert 		  * matching response cached.
291*780fb4a2SCy Schubert 		  */
292*780fb4a2SCy Schubert 		return 0;
293*780fb4a2SCy Schubert 	}
294*780fb4a2SCy Schubert 
295*780fb4a2SCy Schubert 	pos = *msgpos;
296*780fb4a2SCy Schubert 	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
297*780fb4a2SCy Schubert 	    (unsigned int) (end - pos)) {
298*780fb4a2SCy Schubert 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
299*780fb4a2SCy Schubert 				   TLS_ALERT_INTERNAL_ERROR);
300*780fb4a2SCy Schubert 		return -1;
301*780fb4a2SCy Schubert 	}
302*780fb4a2SCy Schubert 
303*780fb4a2SCy Schubert 	tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
304*780fb4a2SCy Schubert 	rhdr = pos;
305*780fb4a2SCy Schubert 	pos += TLS_RECORD_HEADER_LEN;
306*780fb4a2SCy Schubert 
307*780fb4a2SCy Schubert 	/* opaque fragment[TLSPlaintext.length] */
308*780fb4a2SCy Schubert 
309*780fb4a2SCy Schubert 	/* Handshake */
310*780fb4a2SCy Schubert 	hs_start = pos;
311*780fb4a2SCy Schubert 	/* HandshakeType msg_type */
312*780fb4a2SCy Schubert 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
313*780fb4a2SCy Schubert 	/* uint24 length (to be filled) */
314*780fb4a2SCy Schubert 	hs_length = pos;
315*780fb4a2SCy Schubert 	pos += 3;
316*780fb4a2SCy Schubert 
317*780fb4a2SCy Schubert 	/* body - CertificateStatus
318*780fb4a2SCy Schubert 	 *
319*780fb4a2SCy Schubert 	 * struct {
320*780fb4a2SCy Schubert 	 *     CertificateStatusType status_type;
321*780fb4a2SCy Schubert 	 *     select (status_type) {
322*780fb4a2SCy Schubert 	 *         case ocsp: OCSPResponse;
323*780fb4a2SCy Schubert 	 *         case ocsp_multi: OCSPResponseList;
324*780fb4a2SCy Schubert 	 *     } response;
325*780fb4a2SCy Schubert 	 * } CertificateStatus;
326*780fb4a2SCy Schubert 	 *
327*780fb4a2SCy Schubert 	 * opaque OCSPResponse<1..2^24-1>;
328*780fb4a2SCy Schubert 	 *
329*780fb4a2SCy Schubert 	 * struct {
330*780fb4a2SCy Schubert 	 *   OCSPResponse ocsp_response_list<1..2^24-1>;
331*780fb4a2SCy Schubert 	 * } OCSPResponseList;
332*780fb4a2SCy Schubert 	 */
333*780fb4a2SCy Schubert 
334*780fb4a2SCy Schubert 	/* CertificateStatusType status_type */
335*780fb4a2SCy Schubert 	if (ocsp_multi)
336*780fb4a2SCy Schubert 		*pos++ = 2; /* ocsp_multi(2) */
337*780fb4a2SCy Schubert 	else
338*780fb4a2SCy Schubert 		*pos++ = 1; /* ocsp(1) */
339*780fb4a2SCy Schubert 	/* uint24 length of OCSPResponse */
340*780fb4a2SCy Schubert 	WPA_PUT_BE24(pos, ocsp_resp_len);
341*780fb4a2SCy Schubert 	pos += 3;
342*780fb4a2SCy Schubert 	os_memcpy(pos, ocsp_resp, ocsp_resp_len);
343*780fb4a2SCy Schubert 	pos += ocsp_resp_len;
344*780fb4a2SCy Schubert 
345*780fb4a2SCy Schubert 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
346*780fb4a2SCy Schubert 
347*780fb4a2SCy Schubert 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
348*780fb4a2SCy Schubert 			      rhdr, end - rhdr, hs_start, pos - hs_start,
349*780fb4a2SCy Schubert 			      &rlen) < 0) {
350*780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
351*780fb4a2SCy Schubert 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
352*780fb4a2SCy Schubert 				   TLS_ALERT_INTERNAL_ERROR);
353*780fb4a2SCy Schubert 		return -1;
354*780fb4a2SCy Schubert 	}
355*780fb4a2SCy Schubert 	pos = rhdr + rlen;
356*780fb4a2SCy Schubert 
357*780fb4a2SCy Schubert 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
358*780fb4a2SCy Schubert 
359*780fb4a2SCy Schubert 	*msgpos = pos;
360*780fb4a2SCy Schubert 
361*780fb4a2SCy Schubert 	return 0;
362*780fb4a2SCy Schubert }
363*780fb4a2SCy Schubert 
364*780fb4a2SCy Schubert 
36539beb93cSSam Leffler static int tls_write_server_key_exchange(struct tlsv1_server *conn,
36639beb93cSSam Leffler 					 u8 **msgpos, u8 *end)
36739beb93cSSam Leffler {
36839beb93cSSam Leffler 	tls_key_exchange keyx;
36939beb93cSSam Leffler 	const struct tls_cipher_suite *suite;
3705b9c547cSRui Paulo 	u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
37139beb93cSSam Leffler 	size_t rlen;
37239beb93cSSam Leffler 	u8 *dh_ys;
37339beb93cSSam Leffler 	size_t dh_ys_len;
3745b9c547cSRui Paulo 	const u8 *dh_p;
3755b9c547cSRui Paulo 	size_t dh_p_len;
37639beb93cSSam Leffler 
37739beb93cSSam Leffler 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
37839beb93cSSam Leffler 	if (suite == NULL)
37939beb93cSSam Leffler 		keyx = TLS_KEY_X_NULL;
38039beb93cSSam Leffler 	else
38139beb93cSSam Leffler 		keyx = suite->key_exchange;
38239beb93cSSam Leffler 
38339beb93cSSam Leffler 	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
38439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
38539beb93cSSam Leffler 		return 0;
38639beb93cSSam Leffler 	}
38739beb93cSSam Leffler 
3885b9c547cSRui Paulo 	if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
38939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
39039beb93cSSam Leffler 			   "supported with key exchange type %d", keyx);
39139beb93cSSam Leffler 		return -1;
39239beb93cSSam Leffler 	}
39339beb93cSSam Leffler 
39439beb93cSSam Leffler 	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
39539beb93cSSam Leffler 	    conn->cred->dh_g == NULL) {
39639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
39739beb93cSSam Leffler 			   "ServerKeyExhcange");
39839beb93cSSam Leffler 		return -1;
39939beb93cSSam Leffler 	}
40039beb93cSSam Leffler 
4015b9c547cSRui Paulo 	tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
4025b9c547cSRui Paulo 
40339beb93cSSam Leffler 	os_free(conn->dh_secret);
4045b9c547cSRui Paulo 	conn->dh_secret_len = dh_p_len;
40539beb93cSSam Leffler 	conn->dh_secret = os_malloc(conn->dh_secret_len);
40639beb93cSSam Leffler 	if (conn->dh_secret == NULL) {
40739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
40839beb93cSSam Leffler 			   "memory for secret (Diffie-Hellman)");
40939beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
41039beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
41139beb93cSSam Leffler 		return -1;
41239beb93cSSam Leffler 	}
413f05cddf9SRui Paulo 	if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) {
41439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
41539beb93cSSam Leffler 			   "data for Diffie-Hellman");
41639beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
41739beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
41839beb93cSSam Leffler 		os_free(conn->dh_secret);
41939beb93cSSam Leffler 		conn->dh_secret = NULL;
42039beb93cSSam Leffler 		return -1;
42139beb93cSSam Leffler 	}
42239beb93cSSam Leffler 
4235b9c547cSRui Paulo 	if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
42439beb93cSSam Leffler 		conn->dh_secret[0] = 0; /* make sure secret < p */
42539beb93cSSam Leffler 
42639beb93cSSam Leffler 	pos = conn->dh_secret;
42739beb93cSSam Leffler 	while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
42839beb93cSSam Leffler 		pos++;
42939beb93cSSam Leffler 	if (pos != conn->dh_secret) {
43039beb93cSSam Leffler 		os_memmove(conn->dh_secret, pos,
43139beb93cSSam Leffler 			   conn->dh_secret_len - (pos - conn->dh_secret));
43239beb93cSSam Leffler 		conn->dh_secret_len -= pos - conn->dh_secret;
43339beb93cSSam Leffler 	}
43439beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
43539beb93cSSam Leffler 			conn->dh_secret, conn->dh_secret_len);
43639beb93cSSam Leffler 
43739beb93cSSam Leffler 	/* Ys = g^secret mod p */
4385b9c547cSRui Paulo 	dh_ys_len = dh_p_len;
43939beb93cSSam Leffler 	dh_ys = os_malloc(dh_ys_len);
44039beb93cSSam Leffler 	if (dh_ys == NULL) {
44139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
44239beb93cSSam Leffler 			   "Diffie-Hellman");
44339beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
44439beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
44539beb93cSSam Leffler 		return -1;
44639beb93cSSam Leffler 	}
44739beb93cSSam Leffler 	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
44839beb93cSSam Leffler 			   conn->dh_secret, conn->dh_secret_len,
4495b9c547cSRui Paulo 			   dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
45039beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
45139beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
45239beb93cSSam Leffler 		os_free(dh_ys);
45339beb93cSSam Leffler 		return -1;
45439beb93cSSam Leffler 	}
45539beb93cSSam Leffler 
45639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
45739beb93cSSam Leffler 		    dh_ys, dh_ys_len);
45839beb93cSSam Leffler 
45939beb93cSSam Leffler 	/*
46039beb93cSSam Leffler 	 * struct {
46139beb93cSSam Leffler 	 *    select (KeyExchangeAlgorithm) {
46239beb93cSSam Leffler 	 *       case diffie_hellman:
46339beb93cSSam Leffler 	 *          ServerDHParams params;
46439beb93cSSam Leffler 	 *          Signature signed_params;
46539beb93cSSam Leffler 	 *       case rsa:
46639beb93cSSam Leffler 	 *          ServerRSAParams params;
46739beb93cSSam Leffler 	 *          Signature signed_params;
46839beb93cSSam Leffler 	 *    };
46939beb93cSSam Leffler 	 * } ServerKeyExchange;
47039beb93cSSam Leffler 	 *
47139beb93cSSam Leffler 	 * struct {
47239beb93cSSam Leffler 	 *    opaque dh_p<1..2^16-1>;
47339beb93cSSam Leffler 	 *    opaque dh_g<1..2^16-1>;
47439beb93cSSam Leffler 	 *    opaque dh_Ys<1..2^16-1>;
47539beb93cSSam Leffler 	 * } ServerDHParams;
47639beb93cSSam Leffler 	 */
47739beb93cSSam Leffler 
47839beb93cSSam Leffler 	pos = *msgpos;
47939beb93cSSam Leffler 
4805b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ServerKeyExchange");
48139beb93cSSam Leffler 	rhdr = pos;
48239beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
48339beb93cSSam Leffler 
48439beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
48539beb93cSSam Leffler 
48639beb93cSSam Leffler 	/* Handshake */
48739beb93cSSam Leffler 	hs_start = pos;
48839beb93cSSam Leffler 	/* HandshakeType msg_type */
48939beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
49039beb93cSSam Leffler 	/* uint24 length (to be filled) */
49139beb93cSSam Leffler 	hs_length = pos;
49239beb93cSSam Leffler 	pos += 3;
49339beb93cSSam Leffler 
49439beb93cSSam Leffler 	/* body - ServerDHParams */
4955b9c547cSRui Paulo 	server_params = pos;
49639beb93cSSam Leffler 	/* dh_p */
497*780fb4a2SCy Schubert 	if (2 + dh_p_len > (size_t) (end - pos)) {
49839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
49939beb93cSSam Leffler 			   "dh_p");
50039beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
50139beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
50239beb93cSSam Leffler 		os_free(dh_ys);
50339beb93cSSam Leffler 		return -1;
50439beb93cSSam Leffler 	}
5055b9c547cSRui Paulo 	WPA_PUT_BE16(pos, dh_p_len);
50639beb93cSSam Leffler 	pos += 2;
5075b9c547cSRui Paulo 	os_memcpy(pos, dh_p, dh_p_len);
5085b9c547cSRui Paulo 	pos += dh_p_len;
50939beb93cSSam Leffler 
51039beb93cSSam Leffler 	/* dh_g */
511*780fb4a2SCy Schubert 	if (2 + conn->cred->dh_g_len > (size_t) (end - pos)) {
51239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
51339beb93cSSam Leffler 			   "dh_g");
51439beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
51539beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
51639beb93cSSam Leffler 		os_free(dh_ys);
51739beb93cSSam Leffler 		return -1;
51839beb93cSSam Leffler 	}
51939beb93cSSam Leffler 	WPA_PUT_BE16(pos, conn->cred->dh_g_len);
52039beb93cSSam Leffler 	pos += 2;
52139beb93cSSam Leffler 	os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
52239beb93cSSam Leffler 	pos += conn->cred->dh_g_len;
52339beb93cSSam Leffler 
52439beb93cSSam Leffler 	/* dh_Ys */
525*780fb4a2SCy Schubert 	if (2 + dh_ys_len > (size_t) (end - pos)) {
52639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
52739beb93cSSam Leffler 			   "dh_Ys");
52839beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
52939beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
53039beb93cSSam Leffler 		os_free(dh_ys);
53139beb93cSSam Leffler 		return -1;
53239beb93cSSam Leffler 	}
53339beb93cSSam Leffler 	WPA_PUT_BE16(pos, dh_ys_len);
53439beb93cSSam Leffler 	pos += 2;
53539beb93cSSam Leffler 	os_memcpy(pos, dh_ys, dh_ys_len);
53639beb93cSSam Leffler 	pos += dh_ys_len;
53739beb93cSSam Leffler 	os_free(dh_ys);
53839beb93cSSam Leffler 
5395b9c547cSRui Paulo 	/*
5405b9c547cSRui Paulo 	 * select (SignatureAlgorithm)
5415b9c547cSRui Paulo 	 * {   case anonymous: struct { };
5425b9c547cSRui Paulo 	 *     case rsa:
5435b9c547cSRui Paulo 	 *         digitally-signed struct {
5445b9c547cSRui Paulo 	 *             opaque md5_hash[16];
5455b9c547cSRui Paulo 	 *             opaque sha_hash[20];
5465b9c547cSRui Paulo 	 *         };
5475b9c547cSRui Paulo 	 *     case dsa:
5485b9c547cSRui Paulo 	 *         digitally-signed struct {
5495b9c547cSRui Paulo 	 *             opaque sha_hash[20];
5505b9c547cSRui Paulo 	 *         };
5515b9c547cSRui Paulo 	 * } Signature;
5525b9c547cSRui Paulo 	 *
5535b9c547cSRui Paulo 	 * md5_hash
5545b9c547cSRui Paulo 	 *     MD5(ClientHello.random + ServerHello.random + ServerParams);
5555b9c547cSRui Paulo 	 *
5565b9c547cSRui Paulo 	 * sha_hash
5575b9c547cSRui Paulo 	 *     SHA(ClientHello.random + ServerHello.random + ServerParams);
5585b9c547cSRui Paulo 	 */
5595b9c547cSRui Paulo 
5605b9c547cSRui Paulo 	if (keyx == TLS_KEY_X_DHE_RSA) {
5615b9c547cSRui Paulo 		u8 hash[100];
5625b9c547cSRui Paulo 		u8 *signed_start;
5635b9c547cSRui Paulo 		size_t clen;
5645b9c547cSRui Paulo 		int hlen;
5655b9c547cSRui Paulo 
5665b9c547cSRui Paulo 		if (conn->rl.tls_version >= TLS_VERSION_1_2) {
5675b9c547cSRui Paulo #ifdef CONFIG_TLSV12
5685b9c547cSRui Paulo 			hlen = tlsv12_key_x_server_params_hash(
569*780fb4a2SCy Schubert 				conn->rl.tls_version, TLS_HASH_ALG_SHA256,
570*780fb4a2SCy Schubert 				conn->client_random,
5715b9c547cSRui Paulo 				conn->server_random, server_params,
5725b9c547cSRui Paulo 				pos - server_params, hash + 19);
5735b9c547cSRui Paulo 
5745b9c547cSRui Paulo 			/*
5755b9c547cSRui Paulo 			 * RFC 5246, 4.7:
5765b9c547cSRui Paulo 			 * TLS v1.2 adds explicit indication of the used
5775b9c547cSRui Paulo 			 * signature and hash algorithms.
5785b9c547cSRui Paulo 			 *
5795b9c547cSRui Paulo 			 * struct {
5805b9c547cSRui Paulo 			 *   HashAlgorithm hash;
5815b9c547cSRui Paulo 			 *   SignatureAlgorithm signature;
5825b9c547cSRui Paulo 			 * } SignatureAndHashAlgorithm;
5835b9c547cSRui Paulo 			 */
584*780fb4a2SCy Schubert 			if (hlen < 0 || end - pos < 2) {
5855b9c547cSRui Paulo 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
5865b9c547cSRui Paulo 						   TLS_ALERT_INTERNAL_ERROR);
5875b9c547cSRui Paulo 				return -1;
5885b9c547cSRui Paulo 			}
5895b9c547cSRui Paulo 			*pos++ = TLS_HASH_ALG_SHA256;
5905b9c547cSRui Paulo 			*pos++ = TLS_SIGN_ALG_RSA;
5915b9c547cSRui Paulo 
5925b9c547cSRui Paulo 			/*
5935b9c547cSRui Paulo 			 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
5945b9c547cSRui Paulo 			 *
5955b9c547cSRui Paulo 			 * DigestInfo ::= SEQUENCE {
5965b9c547cSRui Paulo 			 *   digestAlgorithm DigestAlgorithm,
5975b9c547cSRui Paulo 			 *   digest OCTET STRING
5985b9c547cSRui Paulo 			 * }
5995b9c547cSRui Paulo 			 *
6005b9c547cSRui Paulo 			 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
6015b9c547cSRui Paulo 			 *
6025b9c547cSRui Paulo 			 * DER encoded DigestInfo for SHA256 per RFC 3447:
6035b9c547cSRui Paulo 			 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
6045b9c547cSRui Paulo 			 * 04 20 || H
6055b9c547cSRui Paulo 			 */
6065b9c547cSRui Paulo 			hlen += 19;
6075b9c547cSRui Paulo 			os_memcpy(hash,
6085b9c547cSRui Paulo 				  "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
6095b9c547cSRui Paulo 				  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
6105b9c547cSRui Paulo 
6115b9c547cSRui Paulo #else /* CONFIG_TLSV12 */
6125b9c547cSRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6135b9c547cSRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
6145b9c547cSRui Paulo 			return -1;
6155b9c547cSRui Paulo #endif /* CONFIG_TLSV12 */
6165b9c547cSRui Paulo 		} else {
6175b9c547cSRui Paulo 			hlen = tls_key_x_server_params_hash(
6185b9c547cSRui Paulo 				conn->rl.tls_version, conn->client_random,
6195b9c547cSRui Paulo 				conn->server_random, server_params,
6205b9c547cSRui Paulo 				pos - server_params, hash);
6215b9c547cSRui Paulo 		}
6225b9c547cSRui Paulo 
6235b9c547cSRui Paulo 		if (hlen < 0) {
6245b9c547cSRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6255b9c547cSRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
6265b9c547cSRui Paulo 			return -1;
6275b9c547cSRui Paulo 		}
6285b9c547cSRui Paulo 
6295b9c547cSRui Paulo 		wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
6305b9c547cSRui Paulo 			    hash, hlen);
6315b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
6325b9c547cSRui Paulo 		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
6335b9c547cSRui Paulo 			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
6345b9c547cSRui Paulo 			hash[hlen - 1] ^= 0x80;
6355b9c547cSRui Paulo 		}
6365b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
6375b9c547cSRui Paulo 
6385b9c547cSRui Paulo 		/*
6395b9c547cSRui Paulo 		 * RFC 2246, 4.7:
6405b9c547cSRui Paulo 		 * In digital signing, one-way hash functions are used as input
6415b9c547cSRui Paulo 		 * for a signing algorithm. A digitally-signed element is
6425b9c547cSRui Paulo 		 * encoded as an opaque vector <0..2^16-1>, where the length is
6435b9c547cSRui Paulo 		 * specified by the signing algorithm and key.
6445b9c547cSRui Paulo 		 *
6455b9c547cSRui Paulo 		 * In RSA signing, a 36-byte structure of two hashes (one SHA
6465b9c547cSRui Paulo 		 * and one MD5) is signed (encrypted with the private key). It
6475b9c547cSRui Paulo 		 * is encoded with PKCS #1 block type 0 or type 1 as described
6485b9c547cSRui Paulo 		 * in [PKCS1].
6495b9c547cSRui Paulo 		 */
6505b9c547cSRui Paulo 		signed_start = pos; /* length to be filled */
6515b9c547cSRui Paulo 		pos += 2;
6525b9c547cSRui Paulo 		clen = end - pos;
6535b9c547cSRui Paulo 		if (conn->cred == NULL ||
6545b9c547cSRui Paulo 		    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
6555b9c547cSRui Paulo 						  pos, &clen) < 0) {
6565b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
6575b9c547cSRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6585b9c547cSRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
6595b9c547cSRui Paulo 			return -1;
6605b9c547cSRui Paulo 		}
6615b9c547cSRui Paulo 		WPA_PUT_BE16(signed_start, clen);
6625b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
6635b9c547cSRui Paulo 		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
6645b9c547cSRui Paulo 			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
6655b9c547cSRui Paulo 			pos[clen - 1] ^= 0x80;
6665b9c547cSRui Paulo 		}
6675b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
6685b9c547cSRui Paulo 
6695b9c547cSRui Paulo 		pos += clen;
6705b9c547cSRui Paulo 	}
6715b9c547cSRui Paulo 
67239beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
67339beb93cSSam Leffler 
67439beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
675f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
676f05cddf9SRui Paulo 			      &rlen) < 0) {
67739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
67839beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
67939beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
68039beb93cSSam Leffler 		return -1;
68139beb93cSSam Leffler 	}
68239beb93cSSam Leffler 	pos = rhdr + rlen;
68339beb93cSSam Leffler 
68439beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
68539beb93cSSam Leffler 
68639beb93cSSam Leffler 	*msgpos = pos;
68739beb93cSSam Leffler 
68839beb93cSSam Leffler 	return 0;
68939beb93cSSam Leffler }
69039beb93cSSam Leffler 
69139beb93cSSam Leffler 
69239beb93cSSam Leffler static int tls_write_server_certificate_request(struct tlsv1_server *conn,
69339beb93cSSam Leffler 						u8 **msgpos, u8 *end)
69439beb93cSSam Leffler {
69539beb93cSSam Leffler 	u8 *pos, *rhdr, *hs_start, *hs_length;
69639beb93cSSam Leffler 	size_t rlen;
69739beb93cSSam Leffler 
69839beb93cSSam Leffler 	if (!conn->verify_peer) {
69939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
70039beb93cSSam Leffler 		return 0;
70139beb93cSSam Leffler 	}
70239beb93cSSam Leffler 
70339beb93cSSam Leffler 	pos = *msgpos;
70439beb93cSSam Leffler 
7055b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send CertificateRequest");
70639beb93cSSam Leffler 	rhdr = pos;
70739beb93cSSam Leffler 	pos += TLS_RECORD_HEADER_LEN;
70839beb93cSSam Leffler 
70939beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
71039beb93cSSam Leffler 
71139beb93cSSam Leffler 	/* Handshake */
71239beb93cSSam Leffler 	hs_start = pos;
71339beb93cSSam Leffler 	/* HandshakeType msg_type */
71439beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
71539beb93cSSam Leffler 	/* uint24 length (to be filled) */
71639beb93cSSam Leffler 	hs_length = pos;
71739beb93cSSam Leffler 	pos += 3;
71839beb93cSSam Leffler 	/* body - CertificateRequest */
71939beb93cSSam Leffler 
72039beb93cSSam Leffler 	/*
72139beb93cSSam Leffler 	 * enum {
72239beb93cSSam Leffler 	 *   rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
72339beb93cSSam Leffler 	 *   (255)
72439beb93cSSam Leffler 	 * } ClientCertificateType;
72539beb93cSSam Leffler 	 * ClientCertificateType certificate_types<1..2^8-1>
72639beb93cSSam Leffler 	 */
72739beb93cSSam Leffler 	*pos++ = 1;
72839beb93cSSam Leffler 	*pos++ = 1; /* rsa_sign */
72939beb93cSSam Leffler 
73039beb93cSSam Leffler 	/*
73139beb93cSSam Leffler 	 * opaque DistinguishedName<1..2^16-1>
73239beb93cSSam Leffler 	 * DistinguishedName certificate_authorities<3..2^16-1>
73339beb93cSSam Leffler 	 */
73439beb93cSSam Leffler 	/* TODO: add support for listing DNs for trusted CAs */
73539beb93cSSam Leffler 	WPA_PUT_BE16(pos, 0);
73639beb93cSSam Leffler 	pos += 2;
73739beb93cSSam Leffler 
73839beb93cSSam Leffler 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
73939beb93cSSam Leffler 
74039beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
741f05cddf9SRui Paulo 			      rhdr, end - rhdr, hs_start, pos - hs_start,
742f05cddf9SRui Paulo 			      &rlen) < 0) {
74339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
74439beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
74539beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
74639beb93cSSam Leffler 		return -1;
74739beb93cSSam Leffler 	}
74839beb93cSSam Leffler 	pos = rhdr + rlen;
74939beb93cSSam Leffler 
75039beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
75139beb93cSSam Leffler 
75239beb93cSSam Leffler 	*msgpos = pos;
75339beb93cSSam Leffler 
75439beb93cSSam Leffler 	return 0;
75539beb93cSSam Leffler }
75639beb93cSSam Leffler 
75739beb93cSSam Leffler 
75839beb93cSSam Leffler static int tls_write_server_hello_done(struct tlsv1_server *conn,
75939beb93cSSam Leffler 				       u8 **msgpos, u8 *end)
76039beb93cSSam Leffler {
761f05cddf9SRui Paulo 	u8 *pos;
76239beb93cSSam Leffler 	size_t rlen;
763f05cddf9SRui Paulo 	u8 payload[4];
76439beb93cSSam Leffler 
7655b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ServerHelloDone");
76639beb93cSSam Leffler 
76739beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
76839beb93cSSam Leffler 
76939beb93cSSam Leffler 	/* Handshake */
770f05cddf9SRui Paulo 	pos = payload;
77139beb93cSSam Leffler 	/* HandshakeType msg_type */
77239beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
773f05cddf9SRui Paulo 	/* uint24 length */
774f05cddf9SRui Paulo 	WPA_PUT_BE24(pos, 0);
77539beb93cSSam Leffler 	pos += 3;
77639beb93cSSam Leffler 	/* body - ServerHelloDone (empty) */
77739beb93cSSam Leffler 
77839beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
779f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, payload, pos - payload,
780f05cddf9SRui Paulo 			      &rlen) < 0) {
78139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
78239beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
78339beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
78439beb93cSSam Leffler 		return -1;
78539beb93cSSam Leffler 	}
78639beb93cSSam Leffler 
787f05cddf9SRui Paulo 	tls_verify_hash_add(&conn->verify, payload, pos - payload);
78839beb93cSSam Leffler 
789f05cddf9SRui Paulo 	*msgpos += rlen;
79039beb93cSSam Leffler 
79139beb93cSSam Leffler 	return 0;
79239beb93cSSam Leffler }
79339beb93cSSam Leffler 
79439beb93cSSam Leffler 
79539beb93cSSam Leffler static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
79639beb93cSSam Leffler 					       u8 **msgpos, u8 *end)
79739beb93cSSam Leffler {
79839beb93cSSam Leffler 	size_t rlen;
799f05cddf9SRui Paulo 	u8 payload[1];
80039beb93cSSam Leffler 
8015b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send ChangeCipherSpec");
802f05cddf9SRui Paulo 
803f05cddf9SRui Paulo 	payload[0] = TLS_CHANGE_CIPHER_SPEC;
804f05cddf9SRui Paulo 
80539beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
806f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, payload, sizeof(payload),
807f05cddf9SRui Paulo 			      &rlen) < 0) {
80839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
80939beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
81039beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
81139beb93cSSam Leffler 		return -1;
81239beb93cSSam Leffler 	}
81339beb93cSSam Leffler 
81439beb93cSSam Leffler 	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
81539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
81639beb93cSSam Leffler 			   "record layer");
81739beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
81839beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
81939beb93cSSam Leffler 		return -1;
82039beb93cSSam Leffler 	}
82139beb93cSSam Leffler 
822f05cddf9SRui Paulo 	*msgpos += rlen;
82339beb93cSSam Leffler 
82439beb93cSSam Leffler 	return 0;
82539beb93cSSam Leffler }
82639beb93cSSam Leffler 
82739beb93cSSam Leffler 
82839beb93cSSam Leffler static int tls_write_server_finished(struct tlsv1_server *conn,
82939beb93cSSam Leffler 				     u8 **msgpos, u8 *end)
83039beb93cSSam Leffler {
831f05cddf9SRui Paulo 	u8 *pos, *hs_start;
83239beb93cSSam Leffler 	size_t rlen, hlen;
833f05cddf9SRui Paulo 	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
83439beb93cSSam Leffler 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
83539beb93cSSam Leffler 
83639beb93cSSam Leffler 	pos = *msgpos;
83739beb93cSSam Leffler 
8385b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send Finished");
83939beb93cSSam Leffler 
84039beb93cSSam Leffler 	/* Encrypted Handshake Message: Finished */
84139beb93cSSam Leffler 
842f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
843f05cddf9SRui Paulo 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
844f05cddf9SRui Paulo 		hlen = SHA256_MAC_LEN;
845f05cddf9SRui Paulo 		if (conn->verify.sha256_server == NULL ||
846f05cddf9SRui Paulo 		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
847f05cddf9SRui Paulo 		    < 0) {
848f05cddf9SRui Paulo 			conn->verify.sha256_server = NULL;
849f05cddf9SRui Paulo 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
850f05cddf9SRui Paulo 					   TLS_ALERT_INTERNAL_ERROR);
851f05cddf9SRui Paulo 			return -1;
852f05cddf9SRui Paulo 		}
853f05cddf9SRui Paulo 		conn->verify.sha256_server = NULL;
854f05cddf9SRui Paulo 	} else {
855f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
856f05cddf9SRui Paulo 
85739beb93cSSam Leffler 	hlen = MD5_MAC_LEN;
85839beb93cSSam Leffler 	if (conn->verify.md5_server == NULL ||
85939beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
86039beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
86139beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
86239beb93cSSam Leffler 		conn->verify.md5_server = NULL;
86339beb93cSSam Leffler 		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
86439beb93cSSam Leffler 		conn->verify.sha1_server = NULL;
86539beb93cSSam Leffler 		return -1;
86639beb93cSSam Leffler 	}
86739beb93cSSam Leffler 	conn->verify.md5_server = NULL;
86839beb93cSSam Leffler 	hlen = SHA1_MAC_LEN;
86939beb93cSSam Leffler 	if (conn->verify.sha1_server == NULL ||
87039beb93cSSam Leffler 	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
87139beb93cSSam Leffler 			       &hlen) < 0) {
87239beb93cSSam Leffler 		conn->verify.sha1_server = NULL;
87339beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
87439beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
87539beb93cSSam Leffler 		return -1;
87639beb93cSSam Leffler 	}
87739beb93cSSam Leffler 	conn->verify.sha1_server = NULL;
878f05cddf9SRui Paulo 	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
87939beb93cSSam Leffler 
880f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
881f05cddf9SRui Paulo 	}
882f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
883f05cddf9SRui Paulo 
884f05cddf9SRui Paulo 	if (tls_prf(conn->rl.tls_version,
885f05cddf9SRui Paulo 		    conn->master_secret, TLS_MASTER_SECRET_LEN,
886f05cddf9SRui Paulo 		    "server finished", hash, hlen,
887f05cddf9SRui Paulo 		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
88839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
88939beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
89039beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
89139beb93cSSam Leffler 		return -1;
89239beb93cSSam Leffler 	}
89339beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
894f05cddf9SRui Paulo 			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
8955b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
8965b9c547cSRui Paulo 	if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
8975b9c547cSRui Paulo 		tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
8985b9c547cSRui Paulo 		verify_data[1 + 3 + 1] ^= 0x80;
8995b9c547cSRui Paulo 	}
9005b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
90139beb93cSSam Leffler 
90239beb93cSSam Leffler 	/* Handshake */
903f05cddf9SRui Paulo 	pos = hs_start = verify_data;
90439beb93cSSam Leffler 	/* HandshakeType msg_type */
90539beb93cSSam Leffler 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
906f05cddf9SRui Paulo 	/* uint24 length */
907f05cddf9SRui Paulo 	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
90839beb93cSSam Leffler 	pos += 3;
90939beb93cSSam Leffler 	pos += TLS_VERIFY_DATA_LEN;
91039beb93cSSam Leffler 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
91139beb93cSSam Leffler 
91239beb93cSSam Leffler 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
913f05cddf9SRui Paulo 			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
914f05cddf9SRui Paulo 			      &rlen) < 0) {
91539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
91639beb93cSSam Leffler 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
91739beb93cSSam Leffler 				   TLS_ALERT_INTERNAL_ERROR);
91839beb93cSSam Leffler 		return -1;
91939beb93cSSam Leffler 	}
92039beb93cSSam Leffler 
921f05cddf9SRui Paulo 	*msgpos += rlen;
92239beb93cSSam Leffler 
92339beb93cSSam Leffler 	return 0;
92439beb93cSSam Leffler }
92539beb93cSSam Leffler 
92639beb93cSSam Leffler 
92739beb93cSSam Leffler static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
92839beb93cSSam Leffler {
92939beb93cSSam Leffler 	u8 *msg, *end, *pos;
93039beb93cSSam Leffler 	size_t msglen;
931*780fb4a2SCy Schubert 	int ocsp_multi = 0;
932*780fb4a2SCy Schubert 	char *ocsp_resp = NULL;
933*780fb4a2SCy Schubert 	size_t ocsp_resp_len = 0;
93439beb93cSSam Leffler 
93539beb93cSSam Leffler 	*out_len = 0;
93639beb93cSSam Leffler 
937*780fb4a2SCy Schubert 	if (conn->status_request_multi &&
938*780fb4a2SCy Schubert 	    conn->cred->ocsp_stapling_response_multi) {
939*780fb4a2SCy Schubert 		ocsp_resp = os_readfile(
940*780fb4a2SCy Schubert 			conn->cred->ocsp_stapling_response_multi,
941*780fb4a2SCy Schubert 			&ocsp_resp_len);
942*780fb4a2SCy Schubert 		ocsp_multi = 1;
943*780fb4a2SCy Schubert 	} else if ((conn->status_request || conn->status_request_v2) &&
944*780fb4a2SCy Schubert 		   conn->cred->ocsp_stapling_response) {
945*780fb4a2SCy Schubert 		ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
946*780fb4a2SCy Schubert 					&ocsp_resp_len);
947*780fb4a2SCy Schubert 	}
948*780fb4a2SCy Schubert 	if (!ocsp_resp)
949*780fb4a2SCy Schubert 		ocsp_resp_len = 0;
950*780fb4a2SCy Schubert 
951*780fb4a2SCy Schubert 	msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
95239beb93cSSam Leffler 
95339beb93cSSam Leffler 	msg = os_malloc(msglen);
954*780fb4a2SCy Schubert 	if (msg == NULL) {
955*780fb4a2SCy Schubert 		os_free(ocsp_resp);
95639beb93cSSam Leffler 		return NULL;
957*780fb4a2SCy Schubert 	}
95839beb93cSSam Leffler 
95939beb93cSSam Leffler 	pos = msg;
96039beb93cSSam Leffler 	end = msg + msglen;
96139beb93cSSam Leffler 
96239beb93cSSam Leffler 	if (tls_write_server_hello(conn, &pos, end) < 0) {
96339beb93cSSam Leffler 		os_free(msg);
964*780fb4a2SCy Schubert 		os_free(ocsp_resp);
96539beb93cSSam Leffler 		return NULL;
96639beb93cSSam Leffler 	}
96739beb93cSSam Leffler 
96839beb93cSSam Leffler 	if (conn->use_session_ticket) {
969*780fb4a2SCy Schubert 		os_free(ocsp_resp);
970*780fb4a2SCy Schubert 
97139beb93cSSam Leffler 		/* Abbreviated handshake using session ticket; RFC 4507 */
97239beb93cSSam Leffler 		if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
97339beb93cSSam Leffler 		    tls_write_server_finished(conn, &pos, end) < 0) {
97439beb93cSSam Leffler 			os_free(msg);
97539beb93cSSam Leffler 			return NULL;
97639beb93cSSam Leffler 		}
97739beb93cSSam Leffler 
97839beb93cSSam Leffler 		*out_len = pos - msg;
97939beb93cSSam Leffler 
98039beb93cSSam Leffler 		conn->state = CHANGE_CIPHER_SPEC;
98139beb93cSSam Leffler 
98239beb93cSSam Leffler 		return msg;
98339beb93cSSam Leffler 	}
98439beb93cSSam Leffler 
98539beb93cSSam Leffler 	/* Full handshake */
98639beb93cSSam Leffler 	if (tls_write_server_certificate(conn, &pos, end) < 0 ||
987*780fb4a2SCy Schubert 	    tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
988*780fb4a2SCy Schubert 						ocsp_resp, ocsp_resp_len) < 0 ||
98939beb93cSSam Leffler 	    tls_write_server_key_exchange(conn, &pos, end) < 0 ||
99039beb93cSSam Leffler 	    tls_write_server_certificate_request(conn, &pos, end) < 0 ||
99139beb93cSSam Leffler 	    tls_write_server_hello_done(conn, &pos, end) < 0) {
99239beb93cSSam Leffler 		os_free(msg);
993*780fb4a2SCy Schubert 		os_free(ocsp_resp);
99439beb93cSSam Leffler 		return NULL;
99539beb93cSSam Leffler 	}
996*780fb4a2SCy Schubert 	os_free(ocsp_resp);
99739beb93cSSam Leffler 
99839beb93cSSam Leffler 	*out_len = pos - msg;
99939beb93cSSam Leffler 
100039beb93cSSam Leffler 	conn->state = CLIENT_CERTIFICATE;
100139beb93cSSam Leffler 
100239beb93cSSam Leffler 	return msg;
100339beb93cSSam Leffler }
100439beb93cSSam Leffler 
100539beb93cSSam Leffler 
100639beb93cSSam Leffler static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
100739beb93cSSam Leffler 					size_t *out_len)
100839beb93cSSam Leffler {
100939beb93cSSam Leffler 	u8 *msg, *end, *pos;
101039beb93cSSam Leffler 
101139beb93cSSam Leffler 	*out_len = 0;
101239beb93cSSam Leffler 
101339beb93cSSam Leffler 	msg = os_malloc(1000);
101439beb93cSSam Leffler 	if (msg == NULL)
101539beb93cSSam Leffler 		return NULL;
101639beb93cSSam Leffler 
101739beb93cSSam Leffler 	pos = msg;
101839beb93cSSam Leffler 	end = msg + 1000;
101939beb93cSSam Leffler 
102039beb93cSSam Leffler 	if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
102139beb93cSSam Leffler 	    tls_write_server_finished(conn, &pos, end) < 0) {
102239beb93cSSam Leffler 		os_free(msg);
102339beb93cSSam Leffler 		return NULL;
102439beb93cSSam Leffler 	}
102539beb93cSSam Leffler 
102639beb93cSSam Leffler 	*out_len = pos - msg;
102739beb93cSSam Leffler 
10285b9c547cSRui Paulo 	tlsv1_server_log(conn, "Handshake completed successfully");
102939beb93cSSam Leffler 	conn->state = ESTABLISHED;
103039beb93cSSam Leffler 
103139beb93cSSam Leffler 	return msg;
103239beb93cSSam Leffler }
103339beb93cSSam Leffler 
103439beb93cSSam Leffler 
103539beb93cSSam Leffler u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
103639beb93cSSam Leffler {
103739beb93cSSam Leffler 	switch (conn->state) {
103839beb93cSSam Leffler 	case SERVER_HELLO:
103939beb93cSSam Leffler 		return tls_send_server_hello(conn, out_len);
104039beb93cSSam Leffler 	case SERVER_CHANGE_CIPHER_SPEC:
104139beb93cSSam Leffler 		return tls_send_change_cipher_spec(conn, out_len);
104239beb93cSSam Leffler 	default:
104339beb93cSSam Leffler 		if (conn->state == ESTABLISHED && conn->use_session_ticket) {
104439beb93cSSam Leffler 			/* Abbreviated handshake was already completed. */
104539beb93cSSam Leffler 			return NULL;
104639beb93cSSam Leffler 		}
10475b9c547cSRui Paulo 		tlsv1_server_log(conn, "Unexpected state %d while generating reply",
10485b9c547cSRui Paulo 				 conn->state);
104939beb93cSSam Leffler 		return NULL;
105039beb93cSSam Leffler 	}
105139beb93cSSam Leffler }
105239beb93cSSam Leffler 
105339beb93cSSam Leffler 
105439beb93cSSam Leffler u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
105539beb93cSSam Leffler 			     u8 description, size_t *out_len)
105639beb93cSSam Leffler {
105739beb93cSSam Leffler 	u8 *alert, *pos, *length;
105839beb93cSSam Leffler 
10595b9c547cSRui Paulo 	tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
106039beb93cSSam Leffler 	*out_len = 0;
106139beb93cSSam Leffler 
106239beb93cSSam Leffler 	alert = os_malloc(10);
106339beb93cSSam Leffler 	if (alert == NULL)
106439beb93cSSam Leffler 		return NULL;
106539beb93cSSam Leffler 
106639beb93cSSam Leffler 	pos = alert;
106739beb93cSSam Leffler 
106839beb93cSSam Leffler 	/* TLSPlaintext */
106939beb93cSSam Leffler 	/* ContentType type */
107039beb93cSSam Leffler 	*pos++ = TLS_CONTENT_TYPE_ALERT;
107139beb93cSSam Leffler 	/* ProtocolVersion version */
1072f05cddf9SRui Paulo 	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
1073f05cddf9SRui Paulo 		     TLS_VERSION);
107439beb93cSSam Leffler 	pos += 2;
107539beb93cSSam Leffler 	/* uint16 length (to be filled) */
107639beb93cSSam Leffler 	length = pos;
107739beb93cSSam Leffler 	pos += 2;
107839beb93cSSam Leffler 	/* opaque fragment[TLSPlaintext.length] */
107939beb93cSSam Leffler 
108039beb93cSSam Leffler 	/* Alert */
108139beb93cSSam Leffler 	/* AlertLevel level */
108239beb93cSSam Leffler 	*pos++ = level;
108339beb93cSSam Leffler 	/* AlertDescription description */
108439beb93cSSam Leffler 	*pos++ = description;
108539beb93cSSam Leffler 
108639beb93cSSam Leffler 	WPA_PUT_BE16(length, pos - length - 2);
108739beb93cSSam Leffler 	*out_len = pos - alert;
108839beb93cSSam Leffler 
108939beb93cSSam Leffler 	return alert;
109039beb93cSSam Leffler }
1091