1189251Ssam/*
2189251Ssam * TLSv1 server - write handshake message
3189251Ssam * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#include "common.h"
18214734Srpaulo#include "crypto/md5.h"
19214734Srpaulo#include "crypto/sha1.h"
20214734Srpaulo#include "crypto/tls.h"
21189251Ssam#include "x509v3.h"
22189251Ssam#include "tlsv1_common.h"
23189251Ssam#include "tlsv1_record.h"
24189251Ssam#include "tlsv1_server.h"
25189251Ssam#include "tlsv1_server_i.h"
26189251Ssam
27189251Ssam
28189251Ssamstatic size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
29189251Ssam{
30189251Ssam	size_t len = 0;
31189251Ssam	struct x509_certificate *cert;
32189251Ssam
33189251Ssam	cert = conn->cred->cert;
34189251Ssam	while (cert) {
35189251Ssam		len += 3 + cert->cert_len;
36189251Ssam		if (x509_certificate_self_signed(cert))
37189251Ssam			break;
38189251Ssam		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
39189251Ssam						    &cert->issuer);
40189251Ssam	}
41189251Ssam
42189251Ssam	return len;
43189251Ssam}
44189251Ssam
45189251Ssam
46189251Ssamstatic int tls_write_server_hello(struct tlsv1_server *conn,
47189251Ssam				  u8 **msgpos, u8 *end)
48189251Ssam{
49189251Ssam	u8 *pos, *rhdr, *hs_start, *hs_length;
50189251Ssam	struct os_time now;
51189251Ssam	size_t rlen;
52189251Ssam
53189251Ssam	pos = *msgpos;
54189251Ssam
55189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
56189251Ssam	rhdr = pos;
57189251Ssam	pos += TLS_RECORD_HEADER_LEN;
58189251Ssam
59189251Ssam	os_get_time(&now);
60189251Ssam	WPA_PUT_BE32(conn->server_random, now.sec);
61189251Ssam	if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
62189251Ssam		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
63189251Ssam			   "server_random");
64189251Ssam		return -1;
65189251Ssam	}
66189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
67189251Ssam		    conn->server_random, TLS_RANDOM_LEN);
68189251Ssam
69189251Ssam	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
70189251Ssam	if (os_get_random(conn->session_id, conn->session_id_len)) {
71189251Ssam		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
72189251Ssam			   "session_id");
73189251Ssam		return -1;
74189251Ssam	}
75189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
76189251Ssam		    conn->session_id, conn->session_id_len);
77189251Ssam
78189251Ssam	/* opaque fragment[TLSPlaintext.length] */
79189251Ssam
80189251Ssam	/* Handshake */
81189251Ssam	hs_start = pos;
82189251Ssam	/* HandshakeType msg_type */
83189251Ssam	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
84189251Ssam	/* uint24 length (to be filled) */
85189251Ssam	hs_length = pos;
86189251Ssam	pos += 3;
87189251Ssam	/* body - ServerHello */
88189251Ssam	/* ProtocolVersion server_version */
89189251Ssam	WPA_PUT_BE16(pos, TLS_VERSION);
90189251Ssam	pos += 2;
91189251Ssam	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
92189251Ssam	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
93189251Ssam	pos += TLS_RANDOM_LEN;
94189251Ssam	/* SessionID session_id */
95189251Ssam	*pos++ = conn->session_id_len;
96189251Ssam	os_memcpy(pos, conn->session_id, conn->session_id_len);
97189251Ssam	pos += conn->session_id_len;
98189251Ssam	/* CipherSuite cipher_suite */
99189251Ssam	WPA_PUT_BE16(pos, conn->cipher_suite);
100189251Ssam	pos += 2;
101189251Ssam	/* CompressionMethod compression_method */
102189251Ssam	*pos++ = TLS_COMPRESSION_NULL;
103189251Ssam
104189251Ssam	if (conn->session_ticket && conn->session_ticket_cb) {
105189251Ssam		int res = conn->session_ticket_cb(
106189251Ssam			conn->session_ticket_cb_ctx,
107189251Ssam			conn->session_ticket, conn->session_ticket_len,
108189251Ssam			conn->client_random, conn->server_random,
109189251Ssam			conn->master_secret);
110189251Ssam		if (res < 0) {
111189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
112189251Ssam				   "indicated failure");
113189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
114189251Ssam					   TLS_ALERT_HANDSHAKE_FAILURE);
115189251Ssam			return -1;
116189251Ssam		}
117189251Ssam		conn->use_session_ticket = res;
118189251Ssam
119189251Ssam		if (conn->use_session_ticket) {
120189251Ssam			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
121189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
122189251Ssam					   "derive keys");
123189251Ssam				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
124189251Ssam						   TLS_ALERT_INTERNAL_ERROR);
125189251Ssam				return -1;
126189251Ssam			}
127189251Ssam		}
128189251Ssam
129189251Ssam		/*
130189251Ssam		 * RFC 4507 specifies that server would include an empty
131189251Ssam		 * SessionTicket extension in ServerHello and a
132189251Ssam		 * NewSessionTicket message after the ServerHello. However,
133189251Ssam		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
134189251Ssam		 * extension at the moment, does not use such extensions.
135189251Ssam		 *
136189251Ssam		 * TODO: Add support for configuring RFC 4507 behavior and make
137189251Ssam		 * EAP-FAST disable it.
138189251Ssam		 */
139189251Ssam	}
140189251Ssam
141189251Ssam	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
142189251Ssam	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
143189251Ssam
144189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
145189251Ssam			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
146189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
147189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
148189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
149189251Ssam		return -1;
150189251Ssam	}
151189251Ssam	pos = rhdr + rlen;
152189251Ssam
153189251Ssam	*msgpos = pos;
154189251Ssam
155189251Ssam	return 0;
156189251Ssam}
157189251Ssam
158189251Ssam
159189251Ssamstatic int tls_write_server_certificate(struct tlsv1_server *conn,
160189251Ssam					u8 **msgpos, u8 *end)
161189251Ssam{
162189251Ssam	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
163189251Ssam	size_t rlen;
164189251Ssam	struct x509_certificate *cert;
165189251Ssam	const struct tls_cipher_suite *suite;
166189251Ssam
167189251Ssam	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
168189251Ssam	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
169189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
170189251Ssam			   "using anonymous DH");
171189251Ssam		return 0;
172189251Ssam	}
173189251Ssam
174189251Ssam	pos = *msgpos;
175189251Ssam
176189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
177189251Ssam	rhdr = pos;
178189251Ssam	pos += TLS_RECORD_HEADER_LEN;
179189251Ssam
180189251Ssam	/* opaque fragment[TLSPlaintext.length] */
181189251Ssam
182189251Ssam	/* Handshake */
183189251Ssam	hs_start = pos;
184189251Ssam	/* HandshakeType msg_type */
185189251Ssam	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
186189251Ssam	/* uint24 length (to be filled) */
187189251Ssam	hs_length = pos;
188189251Ssam	pos += 3;
189189251Ssam	/* body - Certificate */
190189251Ssam	/* uint24 length (to be filled) */
191189251Ssam	cert_start = pos;
192189251Ssam	pos += 3;
193189251Ssam	cert = conn->cred->cert;
194189251Ssam	while (cert) {
195189251Ssam		if (pos + 3 + cert->cert_len > end) {
196189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
197189251Ssam				   "for Certificate (cert_len=%lu left=%lu)",
198189251Ssam				   (unsigned long) cert->cert_len,
199189251Ssam				   (unsigned long) (end - pos));
200189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
201189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
202189251Ssam			return -1;
203189251Ssam		}
204189251Ssam		WPA_PUT_BE24(pos, cert->cert_len);
205189251Ssam		pos += 3;
206189251Ssam		os_memcpy(pos, cert->cert_start, cert->cert_len);
207189251Ssam		pos += cert->cert_len;
208189251Ssam
209189251Ssam		if (x509_certificate_self_signed(cert))
210189251Ssam			break;
211189251Ssam		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
212189251Ssam						    &cert->issuer);
213189251Ssam	}
214189251Ssam	if (cert == conn->cred->cert || cert == NULL) {
215189251Ssam		/*
216189251Ssam		 * Server was not configured with all the needed certificates
217189251Ssam		 * to form a full certificate chain. The client may fail to
218189251Ssam		 * validate the chain unless it is configured with all the
219189251Ssam		 * missing CA certificates.
220189251Ssam		 */
221189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
222189251Ssam			   "not configured - validation may fail");
223189251Ssam	}
224189251Ssam	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
225189251Ssam
226189251Ssam	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
227189251Ssam
228189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
229189251Ssam			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
230189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
231189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
232189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
233189251Ssam		return -1;
234189251Ssam	}
235189251Ssam	pos = rhdr + rlen;
236189251Ssam
237189251Ssam	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
238189251Ssam
239189251Ssam	*msgpos = pos;
240189251Ssam
241189251Ssam	return 0;
242189251Ssam}
243189251Ssam
244189251Ssam
245189251Ssamstatic int tls_write_server_key_exchange(struct tlsv1_server *conn,
246189251Ssam					 u8 **msgpos, u8 *end)
247189251Ssam{
248189251Ssam	tls_key_exchange keyx;
249189251Ssam	const struct tls_cipher_suite *suite;
250189251Ssam	u8 *pos, *rhdr, *hs_start, *hs_length;
251189251Ssam	size_t rlen;
252189251Ssam	u8 *dh_ys;
253189251Ssam	size_t dh_ys_len;
254189251Ssam
255189251Ssam	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
256189251Ssam	if (suite == NULL)
257189251Ssam		keyx = TLS_KEY_X_NULL;
258189251Ssam	else
259189251Ssam		keyx = suite->key_exchange;
260189251Ssam
261189251Ssam	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
262189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
263189251Ssam		return 0;
264189251Ssam	}
265189251Ssam
266189251Ssam	if (keyx != TLS_KEY_X_DH_anon) {
267189251Ssam		/* TODO? */
268189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
269189251Ssam			   "supported with key exchange type %d", keyx);
270189251Ssam		return -1;
271189251Ssam	}
272189251Ssam
273189251Ssam	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
274189251Ssam	    conn->cred->dh_g == NULL) {
275189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
276189251Ssam			   "ServerKeyExhcange");
277189251Ssam		return -1;
278189251Ssam	}
279189251Ssam
280189251Ssam	os_free(conn->dh_secret);
281189251Ssam	conn->dh_secret_len = conn->cred->dh_p_len;
282189251Ssam	conn->dh_secret = os_malloc(conn->dh_secret_len);
283189251Ssam	if (conn->dh_secret == NULL) {
284189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
285189251Ssam			   "memory for secret (Diffie-Hellman)");
286189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
287189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
288189251Ssam		return -1;
289189251Ssam	}
290189251Ssam	if (os_get_random(conn->dh_secret, conn->dh_secret_len)) {
291189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
292189251Ssam			   "data for Diffie-Hellman");
293189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
294189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
295189251Ssam		os_free(conn->dh_secret);
296189251Ssam		conn->dh_secret = NULL;
297189251Ssam		return -1;
298189251Ssam	}
299189251Ssam
300189251Ssam	if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
301189251Ssam	    0)
302189251Ssam		conn->dh_secret[0] = 0; /* make sure secret < p */
303189251Ssam
304189251Ssam	pos = conn->dh_secret;
305189251Ssam	while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
306189251Ssam		pos++;
307189251Ssam	if (pos != conn->dh_secret) {
308189251Ssam		os_memmove(conn->dh_secret, pos,
309189251Ssam			   conn->dh_secret_len - (pos - conn->dh_secret));
310189251Ssam		conn->dh_secret_len -= pos - conn->dh_secret;
311189251Ssam	}
312189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
313189251Ssam			conn->dh_secret, conn->dh_secret_len);
314189251Ssam
315189251Ssam	/* Ys = g^secret mod p */
316189251Ssam	dh_ys_len = conn->cred->dh_p_len;
317189251Ssam	dh_ys = os_malloc(dh_ys_len);
318189251Ssam	if (dh_ys == NULL) {
319189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
320189251Ssam			   "Diffie-Hellman");
321189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
322189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
323189251Ssam		return -1;
324189251Ssam	}
325189251Ssam	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
326189251Ssam			   conn->dh_secret, conn->dh_secret_len,
327189251Ssam			   conn->cred->dh_p, conn->cred->dh_p_len,
328189251Ssam			   dh_ys, &dh_ys_len)) {
329189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
330189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
331189251Ssam		os_free(dh_ys);
332189251Ssam		return -1;
333189251Ssam	}
334189251Ssam
335189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
336189251Ssam		    dh_ys, dh_ys_len);
337189251Ssam
338189251Ssam	/*
339189251Ssam	 * struct {
340189251Ssam	 *    select (KeyExchangeAlgorithm) {
341189251Ssam	 *       case diffie_hellman:
342189251Ssam	 *          ServerDHParams params;
343189251Ssam	 *          Signature signed_params;
344189251Ssam	 *       case rsa:
345189251Ssam	 *          ServerRSAParams params;
346189251Ssam	 *          Signature signed_params;
347189251Ssam	 *    };
348189251Ssam	 * } ServerKeyExchange;
349189251Ssam	 *
350189251Ssam	 * struct {
351189251Ssam	 *    opaque dh_p<1..2^16-1>;
352189251Ssam	 *    opaque dh_g<1..2^16-1>;
353189251Ssam	 *    opaque dh_Ys<1..2^16-1>;
354189251Ssam	 * } ServerDHParams;
355189251Ssam	 */
356189251Ssam
357189251Ssam	pos = *msgpos;
358189251Ssam
359189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
360189251Ssam	rhdr = pos;
361189251Ssam	pos += TLS_RECORD_HEADER_LEN;
362189251Ssam
363189251Ssam	/* opaque fragment[TLSPlaintext.length] */
364189251Ssam
365189251Ssam	/* Handshake */
366189251Ssam	hs_start = pos;
367189251Ssam	/* HandshakeType msg_type */
368189251Ssam	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
369189251Ssam	/* uint24 length (to be filled) */
370189251Ssam	hs_length = pos;
371189251Ssam	pos += 3;
372189251Ssam
373189251Ssam	/* body - ServerDHParams */
374189251Ssam	/* dh_p */
375189251Ssam	if (pos + 2 + conn->cred->dh_p_len > end) {
376189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
377189251Ssam			   "dh_p");
378189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
379189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
380189251Ssam		os_free(dh_ys);
381189251Ssam		return -1;
382189251Ssam	}
383189251Ssam	WPA_PUT_BE16(pos, conn->cred->dh_p_len);
384189251Ssam	pos += 2;
385189251Ssam	os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
386189251Ssam	pos += conn->cred->dh_p_len;
387189251Ssam
388189251Ssam	/* dh_g */
389189251Ssam	if (pos + 2 + conn->cred->dh_g_len > end) {
390189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
391189251Ssam			   "dh_g");
392189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
393189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
394189251Ssam		os_free(dh_ys);
395189251Ssam		return -1;
396189251Ssam	}
397189251Ssam	WPA_PUT_BE16(pos, conn->cred->dh_g_len);
398189251Ssam	pos += 2;
399189251Ssam	os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
400189251Ssam	pos += conn->cred->dh_g_len;
401189251Ssam
402189251Ssam	/* dh_Ys */
403189251Ssam	if (pos + 2 + dh_ys_len > end) {
404189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
405189251Ssam			   "dh_Ys");
406189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
407189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
408189251Ssam		os_free(dh_ys);
409189251Ssam		return -1;
410189251Ssam	}
411189251Ssam	WPA_PUT_BE16(pos, dh_ys_len);
412189251Ssam	pos += 2;
413189251Ssam	os_memcpy(pos, dh_ys, dh_ys_len);
414189251Ssam	pos += dh_ys_len;
415189251Ssam	os_free(dh_ys);
416189251Ssam
417189251Ssam	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
418189251Ssam
419189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
420189251Ssam			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
421189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
422189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
423189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
424189251Ssam		return -1;
425189251Ssam	}
426189251Ssam	pos = rhdr + rlen;
427189251Ssam
428189251Ssam	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
429189251Ssam
430189251Ssam	*msgpos = pos;
431189251Ssam
432189251Ssam	return 0;
433189251Ssam}
434189251Ssam
435189251Ssam
436189251Ssamstatic int tls_write_server_certificate_request(struct tlsv1_server *conn,
437189251Ssam						u8 **msgpos, u8 *end)
438189251Ssam{
439189251Ssam	u8 *pos, *rhdr, *hs_start, *hs_length;
440189251Ssam	size_t rlen;
441189251Ssam
442189251Ssam	if (!conn->verify_peer) {
443189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
444189251Ssam		return 0;
445189251Ssam	}
446189251Ssam
447189251Ssam	pos = *msgpos;
448189251Ssam
449189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
450189251Ssam	rhdr = pos;
451189251Ssam	pos += TLS_RECORD_HEADER_LEN;
452189251Ssam
453189251Ssam	/* opaque fragment[TLSPlaintext.length] */
454189251Ssam
455189251Ssam	/* Handshake */
456189251Ssam	hs_start = pos;
457189251Ssam	/* HandshakeType msg_type */
458189251Ssam	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
459189251Ssam	/* uint24 length (to be filled) */
460189251Ssam	hs_length = pos;
461189251Ssam	pos += 3;
462189251Ssam	/* body - CertificateRequest */
463189251Ssam
464189251Ssam	/*
465189251Ssam	 * enum {
466189251Ssam	 *   rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
467189251Ssam	 *   (255)
468189251Ssam	 * } ClientCertificateType;
469189251Ssam	 * ClientCertificateType certificate_types<1..2^8-1>
470189251Ssam	 */
471189251Ssam	*pos++ = 1;
472189251Ssam	*pos++ = 1; /* rsa_sign */
473189251Ssam
474189251Ssam	/*
475189251Ssam	 * opaque DistinguishedName<1..2^16-1>
476189251Ssam	 * DistinguishedName certificate_authorities<3..2^16-1>
477189251Ssam	 */
478189251Ssam	/* TODO: add support for listing DNs for trusted CAs */
479189251Ssam	WPA_PUT_BE16(pos, 0);
480189251Ssam	pos += 2;
481189251Ssam
482189251Ssam	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
483189251Ssam
484189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
485189251Ssam			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
486189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
487189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
488189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
489189251Ssam		return -1;
490189251Ssam	}
491189251Ssam	pos = rhdr + rlen;
492189251Ssam
493189251Ssam	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
494189251Ssam
495189251Ssam	*msgpos = pos;
496189251Ssam
497189251Ssam	return 0;
498189251Ssam}
499189251Ssam
500189251Ssam
501189251Ssamstatic int tls_write_server_hello_done(struct tlsv1_server *conn,
502189251Ssam				       u8 **msgpos, u8 *end)
503189251Ssam{
504189251Ssam	u8 *pos, *rhdr, *hs_start, *hs_length;
505189251Ssam	size_t rlen;
506189251Ssam
507189251Ssam	pos = *msgpos;
508189251Ssam
509189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
510189251Ssam	rhdr = pos;
511189251Ssam	pos += TLS_RECORD_HEADER_LEN;
512189251Ssam
513189251Ssam	/* opaque fragment[TLSPlaintext.length] */
514189251Ssam
515189251Ssam	/* Handshake */
516189251Ssam	hs_start = pos;
517189251Ssam	/* HandshakeType msg_type */
518189251Ssam	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
519189251Ssam	/* uint24 length (to be filled) */
520189251Ssam	hs_length = pos;
521189251Ssam	pos += 3;
522189251Ssam	/* body - ServerHelloDone (empty) */
523189251Ssam
524189251Ssam	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
525189251Ssam
526189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
527189251Ssam			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
528189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
529189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
530189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
531189251Ssam		return -1;
532189251Ssam	}
533189251Ssam	pos = rhdr + rlen;
534189251Ssam
535189251Ssam	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
536189251Ssam
537189251Ssam	*msgpos = pos;
538189251Ssam
539189251Ssam	return 0;
540189251Ssam}
541189251Ssam
542189251Ssam
543189251Ssamstatic int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
544189251Ssam					       u8 **msgpos, u8 *end)
545189251Ssam{
546189251Ssam	u8 *pos, *rhdr;
547189251Ssam	size_t rlen;
548189251Ssam
549189251Ssam	pos = *msgpos;
550189251Ssam
551189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
552189251Ssam	rhdr = pos;
553189251Ssam	pos += TLS_RECORD_HEADER_LEN;
554189251Ssam	*pos = TLS_CHANGE_CIPHER_SPEC;
555189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
556189251Ssam			      rhdr, end - rhdr, 1, &rlen) < 0) {
557189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
558189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
559189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
560189251Ssam		return -1;
561189251Ssam	}
562189251Ssam
563189251Ssam	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
564189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
565189251Ssam			   "record layer");
566189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
567189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
568189251Ssam		return -1;
569189251Ssam	}
570189251Ssam
571189251Ssam	*msgpos = rhdr + rlen;
572189251Ssam
573189251Ssam	return 0;
574189251Ssam}
575189251Ssam
576189251Ssam
577189251Ssamstatic int tls_write_server_finished(struct tlsv1_server *conn,
578189251Ssam				     u8 **msgpos, u8 *end)
579189251Ssam{
580189251Ssam	u8 *pos, *rhdr, *hs_start, *hs_length;
581189251Ssam	size_t rlen, hlen;
582189251Ssam	u8 verify_data[TLS_VERIFY_DATA_LEN];
583189251Ssam	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
584189251Ssam
585189251Ssam	pos = *msgpos;
586189251Ssam
587189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
588189251Ssam
589189251Ssam	/* Encrypted Handshake Message: Finished */
590189251Ssam
591189251Ssam	hlen = MD5_MAC_LEN;
592189251Ssam	if (conn->verify.md5_server == NULL ||
593189251Ssam	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
594189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
595189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
596189251Ssam		conn->verify.md5_server = NULL;
597189251Ssam		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
598189251Ssam		conn->verify.sha1_server = NULL;
599189251Ssam		return -1;
600189251Ssam	}
601189251Ssam	conn->verify.md5_server = NULL;
602189251Ssam	hlen = SHA1_MAC_LEN;
603189251Ssam	if (conn->verify.sha1_server == NULL ||
604189251Ssam	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
605189251Ssam			       &hlen) < 0) {
606189251Ssam		conn->verify.sha1_server = NULL;
607189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
608189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
609189251Ssam		return -1;
610189251Ssam	}
611189251Ssam	conn->verify.sha1_server = NULL;
612189251Ssam
613189251Ssam	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
614189251Ssam		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
615189251Ssam		    verify_data, TLS_VERIFY_DATA_LEN)) {
616189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
617189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
618189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
619189251Ssam		return -1;
620189251Ssam	}
621189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
622189251Ssam			verify_data, TLS_VERIFY_DATA_LEN);
623189251Ssam
624189251Ssam	rhdr = pos;
625189251Ssam	pos += TLS_RECORD_HEADER_LEN;
626189251Ssam	/* Handshake */
627189251Ssam	hs_start = pos;
628189251Ssam	/* HandshakeType msg_type */
629189251Ssam	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
630189251Ssam	/* uint24 length (to be filled) */
631189251Ssam	hs_length = pos;
632189251Ssam	pos += 3;
633189251Ssam	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
634189251Ssam	pos += TLS_VERIFY_DATA_LEN;
635189251Ssam	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
636189251Ssam	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
637189251Ssam
638189251Ssam	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
639189251Ssam			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
640189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
641189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
642189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
643189251Ssam		return -1;
644189251Ssam	}
645189251Ssam
646189251Ssam	pos = rhdr + rlen;
647189251Ssam
648189251Ssam	*msgpos = pos;
649189251Ssam
650189251Ssam	return 0;
651189251Ssam}
652189251Ssam
653189251Ssam
654189251Ssamstatic u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
655189251Ssam{
656189251Ssam	u8 *msg, *end, *pos;
657189251Ssam	size_t msglen;
658189251Ssam
659189251Ssam	*out_len = 0;
660189251Ssam
661189251Ssam	msglen = 1000 + tls_server_cert_chain_der_len(conn);
662189251Ssam
663189251Ssam	msg = os_malloc(msglen);
664189251Ssam	if (msg == NULL)
665189251Ssam		return NULL;
666189251Ssam
667189251Ssam	pos = msg;
668189251Ssam	end = msg + msglen;
669189251Ssam
670189251Ssam	if (tls_write_server_hello(conn, &pos, end) < 0) {
671189251Ssam		os_free(msg);
672189251Ssam		return NULL;
673189251Ssam	}
674189251Ssam
675189251Ssam	if (conn->use_session_ticket) {
676189251Ssam		/* Abbreviated handshake using session ticket; RFC 4507 */
677189251Ssam		if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
678189251Ssam		    tls_write_server_finished(conn, &pos, end) < 0) {
679189251Ssam			os_free(msg);
680189251Ssam			return NULL;
681189251Ssam		}
682189251Ssam
683189251Ssam		*out_len = pos - msg;
684189251Ssam
685189251Ssam		conn->state = CHANGE_CIPHER_SPEC;
686189251Ssam
687189251Ssam		return msg;
688189251Ssam	}
689189251Ssam
690189251Ssam	/* Full handshake */
691189251Ssam	if (tls_write_server_certificate(conn, &pos, end) < 0 ||
692189251Ssam	    tls_write_server_key_exchange(conn, &pos, end) < 0 ||
693189251Ssam	    tls_write_server_certificate_request(conn, &pos, end) < 0 ||
694189251Ssam	    tls_write_server_hello_done(conn, &pos, end) < 0) {
695189251Ssam		os_free(msg);
696189251Ssam		return NULL;
697189251Ssam	}
698189251Ssam
699189251Ssam	*out_len = pos - msg;
700189251Ssam
701189251Ssam	conn->state = CLIENT_CERTIFICATE;
702189251Ssam
703189251Ssam	return msg;
704189251Ssam}
705189251Ssam
706189251Ssam
707189251Ssamstatic u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
708189251Ssam					size_t *out_len)
709189251Ssam{
710189251Ssam	u8 *msg, *end, *pos;
711189251Ssam
712189251Ssam	*out_len = 0;
713189251Ssam
714189251Ssam	msg = os_malloc(1000);
715189251Ssam	if (msg == NULL)
716189251Ssam		return NULL;
717189251Ssam
718189251Ssam	pos = msg;
719189251Ssam	end = msg + 1000;
720189251Ssam
721189251Ssam	if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
722189251Ssam	    tls_write_server_finished(conn, &pos, end) < 0) {
723189251Ssam		os_free(msg);
724189251Ssam		return NULL;
725189251Ssam	}
726189251Ssam
727189251Ssam	*out_len = pos - msg;
728189251Ssam
729189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
730189251Ssam	conn->state = ESTABLISHED;
731189251Ssam
732189251Ssam	return msg;
733189251Ssam}
734189251Ssam
735189251Ssam
736189251Ssamu8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
737189251Ssam{
738189251Ssam	switch (conn->state) {
739189251Ssam	case SERVER_HELLO:
740189251Ssam		return tls_send_server_hello(conn, out_len);
741189251Ssam	case SERVER_CHANGE_CIPHER_SPEC:
742189251Ssam		return tls_send_change_cipher_spec(conn, out_len);
743189251Ssam	default:
744189251Ssam		if (conn->state == ESTABLISHED && conn->use_session_ticket) {
745189251Ssam			/* Abbreviated handshake was already completed. */
746189251Ssam			return NULL;
747189251Ssam		}
748189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
749189251Ssam			   "generating reply", conn->state);
750189251Ssam		return NULL;
751189251Ssam	}
752189251Ssam}
753189251Ssam
754189251Ssam
755189251Ssamu8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
756189251Ssam			     u8 description, size_t *out_len)
757189251Ssam{
758189251Ssam	u8 *alert, *pos, *length;
759189251Ssam
760189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
761189251Ssam	*out_len = 0;
762189251Ssam
763189251Ssam	alert = os_malloc(10);
764189251Ssam	if (alert == NULL)
765189251Ssam		return NULL;
766189251Ssam
767189251Ssam	pos = alert;
768189251Ssam
769189251Ssam	/* TLSPlaintext */
770189251Ssam	/* ContentType type */
771189251Ssam	*pos++ = TLS_CONTENT_TYPE_ALERT;
772189251Ssam	/* ProtocolVersion version */
773189251Ssam	WPA_PUT_BE16(pos, TLS_VERSION);
774189251Ssam	pos += 2;
775189251Ssam	/* uint16 length (to be filled) */
776189251Ssam	length = pos;
777189251Ssam	pos += 2;
778189251Ssam	/* opaque fragment[TLSPlaintext.length] */
779189251Ssam
780189251Ssam	/* Alert */
781189251Ssam	/* AlertLevel level */
782189251Ssam	*pos++ = level;
783189251Ssam	/* AlertDescription description */
784189251Ssam	*pos++ = description;
785189251Ssam
786189251Ssam	WPA_PUT_BE16(length, pos - length - 2);
787189251Ssam	*out_len = pos - alert;
788189251Ssam
789189251Ssam	return alert;
790189251Ssam}
791