1189251Ssam/*
2189251Ssam * TLSv1 server - read handshake message
3252726Srpaulo * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/md5.h"
13214734Srpaulo#include "crypto/sha1.h"
14252726Srpaulo#include "crypto/sha256.h"
15214734Srpaulo#include "crypto/tls.h"
16189251Ssam#include "x509v3.h"
17189251Ssam#include "tlsv1_common.h"
18189251Ssam#include "tlsv1_record.h"
19189251Ssam#include "tlsv1_server.h"
20189251Ssam#include "tlsv1_server_i.h"
21189251Ssam
22189251Ssam
23189251Ssamstatic int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
24189251Ssam					   const u8 *in_data, size_t *in_len);
25189251Ssamstatic int tls_process_change_cipher_spec(struct tlsv1_server *conn,
26189251Ssam					  u8 ct, const u8 *in_data,
27189251Ssam					  size_t *in_len);
28189251Ssam
29189251Ssam
30189251Ssamstatic int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
31189251Ssam				    const u8 *in_data, size_t *in_len)
32189251Ssam{
33189251Ssam	const u8 *pos, *end, *c;
34189251Ssam	size_t left, len, i, j;
35189251Ssam	u16 cipher_suite;
36189251Ssam	u16 num_suites;
37189251Ssam	int compr_null_found;
38209158Srpaulo	u16 ext_type, ext_len;
39189251Ssam
40189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
41189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
42189251Ssam			   "received content type 0x%x", ct);
43189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
44189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
45189251Ssam		return -1;
46189251Ssam	}
47189251Ssam
48189251Ssam	pos = in_data;
49189251Ssam	left = *in_len;
50189251Ssam
51189251Ssam	if (left < 4)
52189251Ssam		goto decode_error;
53189251Ssam
54189251Ssam	/* HandshakeType msg_type */
55189251Ssam	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
56189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
57189251Ssam			   "message %d (expected ClientHello)", *pos);
58189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
59189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
60189251Ssam		return -1;
61189251Ssam	}
62189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
63189251Ssam	pos++;
64189251Ssam	/* uint24 length */
65189251Ssam	len = WPA_GET_BE24(pos);
66189251Ssam	pos += 3;
67189251Ssam	left -= 4;
68189251Ssam
69189251Ssam	if (len > left)
70189251Ssam		goto decode_error;
71189251Ssam
72189251Ssam	/* body - ClientHello */
73189251Ssam
74189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
75189251Ssam	end = pos + len;
76189251Ssam
77189251Ssam	/* ProtocolVersion client_version */
78189251Ssam	if (end - pos < 2)
79189251Ssam		goto decode_error;
80189251Ssam	conn->client_version = WPA_GET_BE16(pos);
81189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
82189251Ssam		   conn->client_version >> 8, conn->client_version & 0xff);
83252726Srpaulo	if (conn->client_version < TLS_VERSION_1) {
84189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
85252726Srpaulo			   "ClientHello %u.%u",
86252726Srpaulo			   conn->client_version >> 8,
87252726Srpaulo			   conn->client_version & 0xff);
88189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
89189251Ssam				   TLS_ALERT_PROTOCOL_VERSION);
90189251Ssam		return -1;
91189251Ssam	}
92189251Ssam	pos += 2;
93189251Ssam
94252726Srpaulo	if (TLS_VERSION == TLS_VERSION_1)
95252726Srpaulo		conn->rl.tls_version = TLS_VERSION_1;
96252726Srpaulo#ifdef CONFIG_TLSV12
97252726Srpaulo	else if (conn->client_version >= TLS_VERSION_1_2)
98252726Srpaulo		conn->rl.tls_version = TLS_VERSION_1_2;
99252726Srpaulo#endif /* CONFIG_TLSV12 */
100252726Srpaulo	else if (conn->client_version > TLS_VERSION_1_1)
101252726Srpaulo		conn->rl.tls_version = TLS_VERSION_1_1;
102252726Srpaulo	else
103252726Srpaulo		conn->rl.tls_version = conn->client_version;
104252726Srpaulo	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
105252726Srpaulo		   tls_version_str(conn->rl.tls_version));
106252726Srpaulo
107189251Ssam	/* Random random */
108189251Ssam	if (end - pos < TLS_RANDOM_LEN)
109189251Ssam		goto decode_error;
110189251Ssam
111189251Ssam	os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
112189251Ssam	pos += TLS_RANDOM_LEN;
113189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
114189251Ssam		    conn->client_random, TLS_RANDOM_LEN);
115189251Ssam
116189251Ssam	/* SessionID session_id */
117189251Ssam	if (end - pos < 1)
118189251Ssam		goto decode_error;
119189251Ssam	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
120189251Ssam		goto decode_error;
121189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
122189251Ssam	pos += 1 + *pos;
123189251Ssam	/* TODO: add support for session resumption */
124189251Ssam
125189251Ssam	/* CipherSuite cipher_suites<2..2^16-1> */
126189251Ssam	if (end - pos < 2)
127189251Ssam		goto decode_error;
128189251Ssam	num_suites = WPA_GET_BE16(pos);
129189251Ssam	pos += 2;
130189251Ssam	if (end - pos < num_suites)
131189251Ssam		goto decode_error;
132189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
133189251Ssam		    pos, num_suites);
134189251Ssam	if (num_suites & 1)
135189251Ssam		goto decode_error;
136189251Ssam	num_suites /= 2;
137189251Ssam
138189251Ssam	cipher_suite = 0;
139189251Ssam	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
140189251Ssam		c = pos;
141189251Ssam		for (j = 0; j < num_suites; j++) {
142189251Ssam			u16 tmp = WPA_GET_BE16(c);
143189251Ssam			c += 2;
144189251Ssam			if (!cipher_suite && tmp == conn->cipher_suites[i]) {
145189251Ssam				cipher_suite = tmp;
146189251Ssam				break;
147189251Ssam			}
148189251Ssam		}
149189251Ssam	}
150189251Ssam	pos += num_suites * 2;
151189251Ssam	if (!cipher_suite) {
152189251Ssam		wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
153189251Ssam			   "available");
154189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
155189251Ssam				   TLS_ALERT_ILLEGAL_PARAMETER);
156189251Ssam		return -1;
157189251Ssam	}
158189251Ssam
159189251Ssam	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
160189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
161189251Ssam			   "record layer");
162189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
163189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
164189251Ssam		return -1;
165189251Ssam	}
166189251Ssam
167189251Ssam	conn->cipher_suite = cipher_suite;
168189251Ssam
169189251Ssam	/* CompressionMethod compression_methods<1..2^8-1> */
170189251Ssam	if (end - pos < 1)
171189251Ssam		goto decode_error;
172189251Ssam	num_suites = *pos++;
173189251Ssam	if (end - pos < num_suites)
174189251Ssam		goto decode_error;
175189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
176189251Ssam		    pos, num_suites);
177189251Ssam	compr_null_found = 0;
178189251Ssam	for (i = 0; i < num_suites; i++) {
179189251Ssam		if (*pos++ == TLS_COMPRESSION_NULL)
180189251Ssam			compr_null_found = 1;
181189251Ssam	}
182189251Ssam	if (!compr_null_found) {
183189251Ssam		wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
184189251Ssam			   "compression");
185189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
186189251Ssam				   TLS_ALERT_ILLEGAL_PARAMETER);
187189251Ssam		return -1;
188189251Ssam	}
189189251Ssam
190189251Ssam	if (end - pos == 1) {
191189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
192189251Ssam			    "end of ClientHello: 0x%02x", *pos);
193189251Ssam		goto decode_error;
194189251Ssam	}
195189251Ssam
196189251Ssam	if (end - pos >= 2) {
197189251Ssam		/* Extension client_hello_extension_list<0..2^16-1> */
198189251Ssam		ext_len = WPA_GET_BE16(pos);
199189251Ssam		pos += 2;
200189251Ssam
201189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
202189251Ssam			   "extensions", ext_len);
203189251Ssam		if (end - pos != ext_len) {
204189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
205189251Ssam				   "extension list length %u (expected %u)",
206209158Srpaulo				   ext_len, (unsigned int) (end - pos));
207189251Ssam			goto decode_error;
208189251Ssam		}
209189251Ssam
210189251Ssam		/*
211189251Ssam		 * struct {
212189251Ssam		 *   ExtensionType extension_type (0..65535)
213189251Ssam		 *   opaque extension_data<0..2^16-1>
214189251Ssam		 * } Extension;
215189251Ssam		 */
216189251Ssam
217189251Ssam		while (pos < end) {
218189251Ssam			if (end - pos < 2) {
219189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
220189251Ssam					   "extension_type field");
221189251Ssam				goto decode_error;
222189251Ssam			}
223189251Ssam
224189251Ssam			ext_type = WPA_GET_BE16(pos);
225189251Ssam			pos += 2;
226189251Ssam
227189251Ssam			if (end - pos < 2) {
228189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
229189251Ssam					   "extension_data length field");
230189251Ssam				goto decode_error;
231189251Ssam			}
232189251Ssam
233189251Ssam			ext_len = WPA_GET_BE16(pos);
234189251Ssam			pos += 2;
235189251Ssam
236189251Ssam			if (end - pos < ext_len) {
237189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
238189251Ssam					   "extension_data field");
239189251Ssam				goto decode_error;
240189251Ssam			}
241189251Ssam
242189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
243189251Ssam				   "type %u", ext_type);
244189251Ssam			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
245189251Ssam				    "Extension data", pos, ext_len);
246189251Ssam
247189251Ssam			if (ext_type == TLS_EXT_SESSION_TICKET) {
248189251Ssam				os_free(conn->session_ticket);
249189251Ssam				conn->session_ticket = os_malloc(ext_len);
250189251Ssam				if (conn->session_ticket) {
251189251Ssam					os_memcpy(conn->session_ticket, pos,
252189251Ssam						  ext_len);
253189251Ssam					conn->session_ticket_len = ext_len;
254189251Ssam				}
255189251Ssam			}
256189251Ssam
257189251Ssam			pos += ext_len;
258189251Ssam		}
259189251Ssam	}
260189251Ssam
261189251Ssam	*in_len = end - in_data;
262189251Ssam
263189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
264189251Ssam		   "ServerHello");
265189251Ssam	conn->state = SERVER_HELLO;
266189251Ssam
267189251Ssam	return 0;
268189251Ssam
269189251Ssamdecode_error:
270189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
271189251Ssam	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
272189251Ssam			   TLS_ALERT_DECODE_ERROR);
273189251Ssam	return -1;
274189251Ssam}
275189251Ssam
276189251Ssam
277189251Ssamstatic int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
278189251Ssam				   const u8 *in_data, size_t *in_len)
279189251Ssam{
280189251Ssam	const u8 *pos, *end;
281189251Ssam	size_t left, len, list_len, cert_len, idx;
282189251Ssam	u8 type;
283189251Ssam	struct x509_certificate *chain = NULL, *last = NULL, *cert;
284189251Ssam	int reason;
285189251Ssam
286189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
287189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
288189251Ssam			   "received content type 0x%x", ct);
289189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
290189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
291189251Ssam		return -1;
292189251Ssam	}
293189251Ssam
294189251Ssam	pos = in_data;
295189251Ssam	left = *in_len;
296189251Ssam
297189251Ssam	if (left < 4) {
298189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
299189251Ssam			   "(len=%lu)", (unsigned long) left);
300189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
301189251Ssam				   TLS_ALERT_DECODE_ERROR);
302189251Ssam		return -1;
303189251Ssam	}
304189251Ssam
305189251Ssam	type = *pos++;
306189251Ssam	len = WPA_GET_BE24(pos);
307189251Ssam	pos += 3;
308189251Ssam	left -= 4;
309189251Ssam
310189251Ssam	if (len > left) {
311189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
312189251Ssam			   "length (len=%lu != left=%lu)",
313189251Ssam			   (unsigned long) len, (unsigned long) left);
314189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
315189251Ssam				   TLS_ALERT_DECODE_ERROR);
316189251Ssam		return -1;
317189251Ssam	}
318189251Ssam
319189251Ssam	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
320189251Ssam		if (conn->verify_peer) {
321189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
322189251Ssam				   "Certificate");
323189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
324189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
325189251Ssam			return -1;
326189251Ssam		}
327189251Ssam
328189251Ssam		return tls_process_client_key_exchange(conn, ct, in_data,
329189251Ssam						       in_len);
330189251Ssam	}
331189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
332189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
333189251Ssam			   "message %d (expected Certificate/"
334189251Ssam			   "ClientKeyExchange)", type);
335189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
336189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
337189251Ssam		return -1;
338189251Ssam	}
339189251Ssam
340189251Ssam	wpa_printf(MSG_DEBUG,
341189251Ssam		   "TLSv1: Received Certificate (certificate_list len %lu)",
342189251Ssam		   (unsigned long) len);
343189251Ssam
344189251Ssam	/*
345189251Ssam	 * opaque ASN.1Cert<2^24-1>;
346189251Ssam	 *
347189251Ssam	 * struct {
348189251Ssam	 *     ASN.1Cert certificate_list<1..2^24-1>;
349189251Ssam	 * } Certificate;
350189251Ssam	 */
351189251Ssam
352189251Ssam	end = pos + len;
353189251Ssam
354189251Ssam	if (end - pos < 3) {
355189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
356189251Ssam			   "(left=%lu)", (unsigned long) left);
357189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
358189251Ssam				   TLS_ALERT_DECODE_ERROR);
359189251Ssam		return -1;
360189251Ssam	}
361189251Ssam
362189251Ssam	list_len = WPA_GET_BE24(pos);
363189251Ssam	pos += 3;
364189251Ssam
365189251Ssam	if ((size_t) (end - pos) != list_len) {
366189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
367189251Ssam			   "length (len=%lu left=%lu)",
368189251Ssam			   (unsigned long) list_len,
369189251Ssam			   (unsigned long) (end - pos));
370189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
371189251Ssam				   TLS_ALERT_DECODE_ERROR);
372189251Ssam		return -1;
373189251Ssam	}
374189251Ssam
375189251Ssam	idx = 0;
376189251Ssam	while (pos < end) {
377189251Ssam		if (end - pos < 3) {
378189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
379189251Ssam				   "certificate_list");
380189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
381189251Ssam					   TLS_ALERT_DECODE_ERROR);
382189251Ssam			x509_certificate_chain_free(chain);
383189251Ssam			return -1;
384189251Ssam		}
385189251Ssam
386189251Ssam		cert_len = WPA_GET_BE24(pos);
387189251Ssam		pos += 3;
388189251Ssam
389189251Ssam		if ((size_t) (end - pos) < cert_len) {
390189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
391189251Ssam				   "length (len=%lu left=%lu)",
392189251Ssam				   (unsigned long) cert_len,
393189251Ssam				   (unsigned long) (end - pos));
394189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
395189251Ssam					   TLS_ALERT_DECODE_ERROR);
396189251Ssam			x509_certificate_chain_free(chain);
397189251Ssam			return -1;
398189251Ssam		}
399189251Ssam
400189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
401189251Ssam			   (unsigned long) idx, (unsigned long) cert_len);
402189251Ssam
403189251Ssam		if (idx == 0) {
404189251Ssam			crypto_public_key_free(conn->client_rsa_key);
405189251Ssam			if (tls_parse_cert(pos, cert_len,
406189251Ssam					   &conn->client_rsa_key)) {
407189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
408189251Ssam					   "the certificate");
409189251Ssam				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
410189251Ssam						   TLS_ALERT_BAD_CERTIFICATE);
411189251Ssam				x509_certificate_chain_free(chain);
412189251Ssam				return -1;
413189251Ssam			}
414189251Ssam		}
415189251Ssam
416189251Ssam		cert = x509_certificate_parse(pos, cert_len);
417189251Ssam		if (cert == NULL) {
418189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
419189251Ssam				   "the certificate");
420189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
421189251Ssam					   TLS_ALERT_BAD_CERTIFICATE);
422189251Ssam			x509_certificate_chain_free(chain);
423189251Ssam			return -1;
424189251Ssam		}
425189251Ssam
426189251Ssam		if (last == NULL)
427189251Ssam			chain = cert;
428189251Ssam		else
429189251Ssam			last->next = cert;
430189251Ssam		last = cert;
431189251Ssam
432189251Ssam		idx++;
433189251Ssam		pos += cert_len;
434189251Ssam	}
435189251Ssam
436189251Ssam	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
437252726Srpaulo					    &reason, 0) < 0) {
438189251Ssam		int tls_reason;
439189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
440189251Ssam			   "validation failed (reason=%d)", reason);
441189251Ssam		switch (reason) {
442189251Ssam		case X509_VALIDATE_BAD_CERTIFICATE:
443189251Ssam			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
444189251Ssam			break;
445189251Ssam		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
446189251Ssam			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
447189251Ssam			break;
448189251Ssam		case X509_VALIDATE_CERTIFICATE_REVOKED:
449189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
450189251Ssam			break;
451189251Ssam		case X509_VALIDATE_CERTIFICATE_EXPIRED:
452189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
453189251Ssam			break;
454189251Ssam		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
455189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
456189251Ssam			break;
457189251Ssam		case X509_VALIDATE_UNKNOWN_CA:
458189251Ssam			tls_reason = TLS_ALERT_UNKNOWN_CA;
459189251Ssam			break;
460189251Ssam		default:
461189251Ssam			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
462189251Ssam			break;
463189251Ssam		}
464189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
465189251Ssam		x509_certificate_chain_free(chain);
466189251Ssam		return -1;
467189251Ssam	}
468189251Ssam
469189251Ssam	x509_certificate_chain_free(chain);
470189251Ssam
471189251Ssam	*in_len = end - in_data;
472189251Ssam
473189251Ssam	conn->state = CLIENT_KEY_EXCHANGE;
474189251Ssam
475189251Ssam	return 0;
476189251Ssam}
477189251Ssam
478189251Ssam
479189251Ssamstatic int tls_process_client_key_exchange_rsa(
480189251Ssam	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
481189251Ssam{
482189251Ssam	u8 *out;
483189251Ssam	size_t outlen, outbuflen;
484189251Ssam	u16 encr_len;
485189251Ssam	int res;
486189251Ssam	int use_random = 0;
487189251Ssam
488189251Ssam	if (end - pos < 2) {
489189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
490189251Ssam				   TLS_ALERT_DECODE_ERROR);
491189251Ssam		return -1;
492189251Ssam	}
493189251Ssam
494189251Ssam	encr_len = WPA_GET_BE16(pos);
495189251Ssam	pos += 2;
496252726Srpaulo	if (pos + encr_len > end) {
497252726Srpaulo		wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
498252726Srpaulo			   "format: encr_len=%u left=%u",
499252726Srpaulo			   encr_len, (unsigned int) (end - pos));
500252726Srpaulo		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
501252726Srpaulo				   TLS_ALERT_DECODE_ERROR);
502252726Srpaulo		return -1;
503252726Srpaulo	}
504189251Ssam
505189251Ssam	outbuflen = outlen = end - pos;
506189251Ssam	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
507189251Ssam			outlen : TLS_PRE_MASTER_SECRET_LEN);
508189251Ssam	if (out == NULL) {
509189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
510189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
511189251Ssam		return -1;
512189251Ssam	}
513189251Ssam
514189251Ssam	/*
515189251Ssam	 * struct {
516189251Ssam	 *   ProtocolVersion client_version;
517189251Ssam	 *   opaque random[46];
518189251Ssam	 * } PreMasterSecret;
519189251Ssam	 *
520189251Ssam	 * struct {
521189251Ssam	 *   public-key-encrypted PreMasterSecret pre_master_secret;
522189251Ssam	 * } EncryptedPreMasterSecret;
523189251Ssam	 */
524189251Ssam
525189251Ssam	/*
526189251Ssam	 * Note: To avoid Bleichenbacher attack, we do not report decryption or
527189251Ssam	 * parsing errors from EncryptedPreMasterSecret processing to the
528189251Ssam	 * client. Instead, a random pre-master secret is used to force the
529189251Ssam	 * handshake to fail.
530189251Ssam	 */
531189251Ssam
532189251Ssam	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
533252726Srpaulo						 pos, encr_len,
534189251Ssam						 out, &outlen) < 0) {
535189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
536252726Srpaulo			   "PreMasterSecret (encr_len=%u outlen=%lu)",
537252726Srpaulo			   encr_len, (unsigned long) outlen);
538189251Ssam		use_random = 1;
539189251Ssam	}
540189251Ssam
541252726Srpaulo	if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
542189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
543189251Ssam			   "length %lu", (unsigned long) outlen);
544189251Ssam		use_random = 1;
545189251Ssam	}
546189251Ssam
547252726Srpaulo	if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
548189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
549189251Ssam			   "ClientKeyExchange does not match with version in "
550189251Ssam			   "ClientHello");
551189251Ssam		use_random = 1;
552189251Ssam	}
553189251Ssam
554189251Ssam	if (use_random) {
555189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
556189251Ssam			   "to avoid revealing information about private key");
557189251Ssam		outlen = TLS_PRE_MASTER_SECRET_LEN;
558189251Ssam		if (os_get_random(out, outlen)) {
559189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
560189251Ssam				   "data");
561189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
562189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
563189251Ssam			os_free(out);
564189251Ssam			return -1;
565189251Ssam		}
566189251Ssam	}
567189251Ssam
568189251Ssam	res = tlsv1_server_derive_keys(conn, out, outlen);
569189251Ssam
570189251Ssam	/* Clear the pre-master secret since it is not needed anymore */
571189251Ssam	os_memset(out, 0, outbuflen);
572189251Ssam	os_free(out);
573189251Ssam
574189251Ssam	if (res) {
575189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
576189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
577189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
578189251Ssam		return -1;
579189251Ssam	}
580189251Ssam
581189251Ssam	return 0;
582189251Ssam}
583189251Ssam
584189251Ssam
585189251Ssamstatic int tls_process_client_key_exchange_dh_anon(
586189251Ssam	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
587189251Ssam{
588189251Ssam	const u8 *dh_yc;
589189251Ssam	u16 dh_yc_len;
590189251Ssam	u8 *shared;
591189251Ssam	size_t shared_len;
592189251Ssam	int res;
593189251Ssam
594189251Ssam	/*
595189251Ssam	 * struct {
596189251Ssam	 *   select (PublicValueEncoding) {
597189251Ssam	 *     case implicit: struct { };
598189251Ssam	 *     case explicit: opaque dh_Yc<1..2^16-1>;
599189251Ssam	 *   } dh_public;
600189251Ssam	 * } ClientDiffieHellmanPublic;
601189251Ssam	 */
602189251Ssam
603189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
604189251Ssam		    pos, end - pos);
605189251Ssam
606189251Ssam	if (end == pos) {
607189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
608189251Ssam			   "not supported");
609189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
610189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
611189251Ssam		return -1;
612189251Ssam	}
613189251Ssam
614189251Ssam	if (end - pos < 3) {
615189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
616189251Ssam			   "length");
617189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
618189251Ssam				   TLS_ALERT_DECODE_ERROR);
619189251Ssam		return -1;
620189251Ssam	}
621189251Ssam
622189251Ssam	dh_yc_len = WPA_GET_BE16(pos);
623189251Ssam	dh_yc = pos + 2;
624189251Ssam
625189251Ssam	if (dh_yc + dh_yc_len > end) {
626189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
627189251Ssam			   "(length %d)", dh_yc_len);
628189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
629189251Ssam				   TLS_ALERT_DECODE_ERROR);
630189251Ssam		return -1;
631189251Ssam	}
632189251Ssam
633189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
634189251Ssam		    dh_yc, dh_yc_len);
635189251Ssam
636189251Ssam	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
637189251Ssam	    conn->dh_secret == NULL) {
638189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
639189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
640189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
641189251Ssam		return -1;
642189251Ssam	}
643189251Ssam
644189251Ssam	shared_len = conn->cred->dh_p_len;
645189251Ssam	shared = os_malloc(shared_len);
646189251Ssam	if (shared == NULL) {
647189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
648189251Ssam			   "DH");
649189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
650189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
651189251Ssam		return -1;
652189251Ssam	}
653189251Ssam
654189251Ssam	/* shared = Yc^secret mod p */
655189251Ssam	if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
656189251Ssam			   conn->dh_secret_len,
657189251Ssam			   conn->cred->dh_p, conn->cred->dh_p_len,
658189251Ssam			   shared, &shared_len)) {
659189251Ssam		os_free(shared);
660189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
661189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
662189251Ssam		return -1;
663189251Ssam	}
664189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
665189251Ssam			shared, shared_len);
666189251Ssam
667189251Ssam	os_memset(conn->dh_secret, 0, conn->dh_secret_len);
668189251Ssam	os_free(conn->dh_secret);
669189251Ssam	conn->dh_secret = NULL;
670189251Ssam
671189251Ssam	res = tlsv1_server_derive_keys(conn, shared, shared_len);
672189251Ssam
673189251Ssam	/* Clear the pre-master secret since it is not needed anymore */
674189251Ssam	os_memset(shared, 0, shared_len);
675189251Ssam	os_free(shared);
676189251Ssam
677189251Ssam	if (res) {
678189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
679189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
680189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
681189251Ssam		return -1;
682189251Ssam	}
683189251Ssam
684189251Ssam	return 0;
685189251Ssam}
686189251Ssam
687189251Ssam
688189251Ssamstatic int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
689189251Ssam					   const u8 *in_data, size_t *in_len)
690189251Ssam{
691189251Ssam	const u8 *pos, *end;
692189251Ssam	size_t left, len;
693189251Ssam	u8 type;
694189251Ssam	tls_key_exchange keyx;
695189251Ssam	const struct tls_cipher_suite *suite;
696189251Ssam
697189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
698189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
699189251Ssam			   "received content type 0x%x", ct);
700189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
701189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
702189251Ssam		return -1;
703189251Ssam	}
704189251Ssam
705189251Ssam	pos = in_data;
706189251Ssam	left = *in_len;
707189251Ssam
708189251Ssam	if (left < 4) {
709189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
710189251Ssam			   "(Left=%lu)", (unsigned long) left);
711189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
712189251Ssam				   TLS_ALERT_DECODE_ERROR);
713189251Ssam		return -1;
714189251Ssam	}
715189251Ssam
716189251Ssam	type = *pos++;
717189251Ssam	len = WPA_GET_BE24(pos);
718189251Ssam	pos += 3;
719189251Ssam	left -= 4;
720189251Ssam
721189251Ssam	if (len > left) {
722189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
723189251Ssam			   "length (len=%lu != left=%lu)",
724189251Ssam			   (unsigned long) len, (unsigned long) left);
725189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
726189251Ssam				   TLS_ALERT_DECODE_ERROR);
727189251Ssam		return -1;
728189251Ssam	}
729189251Ssam
730189251Ssam	end = pos + len;
731189251Ssam
732189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
733189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
734189251Ssam			   "message %d (expected ClientKeyExchange)", type);
735189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
736189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
737189251Ssam		return -1;
738189251Ssam	}
739189251Ssam
740189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
741189251Ssam
742189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
743189251Ssam
744189251Ssam	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
745189251Ssam	if (suite == NULL)
746189251Ssam		keyx = TLS_KEY_X_NULL;
747189251Ssam	else
748189251Ssam		keyx = suite->key_exchange;
749189251Ssam
750189251Ssam	if (keyx == TLS_KEY_X_DH_anon &&
751189251Ssam	    tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
752189251Ssam		return -1;
753189251Ssam
754189251Ssam	if (keyx != TLS_KEY_X_DH_anon &&
755189251Ssam	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
756189251Ssam		return -1;
757189251Ssam
758189251Ssam	*in_len = end - in_data;
759189251Ssam
760189251Ssam	conn->state = CERTIFICATE_VERIFY;
761189251Ssam
762189251Ssam	return 0;
763189251Ssam}
764189251Ssam
765189251Ssam
766189251Ssamstatic int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
767189251Ssam					  const u8 *in_data, size_t *in_len)
768189251Ssam{
769189251Ssam	const u8 *pos, *end;
770189251Ssam	size_t left, len;
771189251Ssam	u8 type;
772189251Ssam	size_t hlen, buflen;
773189251Ssam	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
774189251Ssam	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
775189251Ssam	u16 slen;
776189251Ssam
777189251Ssam	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
778189251Ssam		if (conn->verify_peer) {
779189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
780189251Ssam				   "CertificateVerify");
781189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
782189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
783189251Ssam			return -1;
784189251Ssam		}
785189251Ssam
786189251Ssam		return tls_process_change_cipher_spec(conn, ct, in_data,
787189251Ssam						      in_len);
788189251Ssam	}
789189251Ssam
790189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
791189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
792189251Ssam			   "received content type 0x%x", ct);
793189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
794189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
795189251Ssam		return -1;
796189251Ssam	}
797189251Ssam
798189251Ssam	pos = in_data;
799189251Ssam	left = *in_len;
800189251Ssam
801189251Ssam	if (left < 4) {
802189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
803189251Ssam			   "message (len=%lu)", (unsigned long) left);
804189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
805189251Ssam				   TLS_ALERT_DECODE_ERROR);
806189251Ssam		return -1;
807189251Ssam	}
808189251Ssam
809189251Ssam	type = *pos++;
810189251Ssam	len = WPA_GET_BE24(pos);
811189251Ssam	pos += 3;
812189251Ssam	left -= 4;
813189251Ssam
814189251Ssam	if (len > left) {
815189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
816189251Ssam			   "message length (len=%lu != left=%lu)",
817189251Ssam			   (unsigned long) len, (unsigned long) left);
818189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
819189251Ssam				   TLS_ALERT_DECODE_ERROR);
820189251Ssam		return -1;
821189251Ssam	}
822189251Ssam
823189251Ssam	end = pos + len;
824189251Ssam
825189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
826189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
827189251Ssam			   "message %d (expected CertificateVerify)", type);
828189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
829189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
830189251Ssam		return -1;
831189251Ssam	}
832189251Ssam
833189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
834189251Ssam
835189251Ssam	/*
836189251Ssam	 * struct {
837189251Ssam	 *   Signature signature;
838189251Ssam	 * } CertificateVerify;
839189251Ssam	 */
840189251Ssam
841189251Ssam	hpos = hash;
842189251Ssam
843252726Srpaulo#ifdef CONFIG_TLSV12
844252726Srpaulo	if (conn->rl.tls_version == TLS_VERSION_1_2) {
845252726Srpaulo		/*
846252726Srpaulo		 * RFC 5246, 4.7:
847252726Srpaulo		 * TLS v1.2 adds explicit indication of the used signature and
848252726Srpaulo		 * hash algorithms.
849252726Srpaulo		 *
850252726Srpaulo		 * struct {
851252726Srpaulo		 *   HashAlgorithm hash;
852252726Srpaulo		 *   SignatureAlgorithm signature;
853252726Srpaulo		 * } SignatureAndHashAlgorithm;
854252726Srpaulo		 */
855252726Srpaulo		if (end - pos < 2) {
856252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
857252726Srpaulo					   TLS_ALERT_DECODE_ERROR);
858252726Srpaulo			return -1;
859252726Srpaulo		}
860252726Srpaulo		if (pos[0] != TLS_HASH_ALG_SHA256 ||
861252726Srpaulo		    pos[1] != TLS_SIGN_ALG_RSA) {
862252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
863252726Srpaulo				   "signature(%u) algorithm",
864252726Srpaulo				   pos[0], pos[1]);
865252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
866252726Srpaulo					   TLS_ALERT_INTERNAL_ERROR);
867252726Srpaulo			return -1;
868252726Srpaulo		}
869252726Srpaulo		pos += 2;
870252726Srpaulo
871252726Srpaulo		hlen = SHA256_MAC_LEN;
872252726Srpaulo		if (conn->verify.sha256_cert == NULL ||
873252726Srpaulo		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
874252726Srpaulo		    0) {
875252726Srpaulo			conn->verify.sha256_cert = NULL;
876252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
877252726Srpaulo					   TLS_ALERT_INTERNAL_ERROR);
878252726Srpaulo			return -1;
879252726Srpaulo		}
880252726Srpaulo		conn->verify.sha256_cert = NULL;
881252726Srpaulo	} else {
882252726Srpaulo#endif /* CONFIG_TLSV12 */
883252726Srpaulo
884189251Ssam	if (alg == SIGN_ALG_RSA) {
885189251Ssam		hlen = MD5_MAC_LEN;
886189251Ssam		if (conn->verify.md5_cert == NULL ||
887189251Ssam		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
888189251Ssam		{
889189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
890189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
891189251Ssam			conn->verify.md5_cert = NULL;
892189251Ssam			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
893189251Ssam			conn->verify.sha1_cert = NULL;
894189251Ssam			return -1;
895189251Ssam		}
896189251Ssam		hpos += MD5_MAC_LEN;
897189251Ssam	} else
898189251Ssam		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
899189251Ssam
900189251Ssam	conn->verify.md5_cert = NULL;
901189251Ssam	hlen = SHA1_MAC_LEN;
902189251Ssam	if (conn->verify.sha1_cert == NULL ||
903189251Ssam	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
904189251Ssam		conn->verify.sha1_cert = NULL;
905189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
906189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
907189251Ssam		return -1;
908189251Ssam	}
909189251Ssam	conn->verify.sha1_cert = NULL;
910189251Ssam
911189251Ssam	if (alg == SIGN_ALG_RSA)
912189251Ssam		hlen += MD5_MAC_LEN;
913189251Ssam
914252726Srpaulo#ifdef CONFIG_TLSV12
915252726Srpaulo	}
916252726Srpaulo#endif /* CONFIG_TLSV12 */
917252726Srpaulo
918189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
919189251Ssam
920189251Ssam	if (end - pos < 2) {
921189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
922189251Ssam				   TLS_ALERT_DECODE_ERROR);
923189251Ssam		return -1;
924189251Ssam	}
925189251Ssam	slen = WPA_GET_BE16(pos);
926189251Ssam	pos += 2;
927189251Ssam	if (end - pos < slen) {
928189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
929189251Ssam				   TLS_ALERT_DECODE_ERROR);
930189251Ssam		return -1;
931189251Ssam	}
932189251Ssam
933189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
934189251Ssam	if (conn->client_rsa_key == NULL) {
935189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
936189251Ssam			   "signature");
937189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
938189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
939189251Ssam		return -1;
940189251Ssam	}
941189251Ssam
942189251Ssam	buflen = end - pos;
943189251Ssam	buf = os_malloc(end - pos);
944189251Ssam	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
945189251Ssam					    pos, end - pos, buf, &buflen) < 0)
946189251Ssam	{
947189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
948189251Ssam		os_free(buf);
949189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
950189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
951189251Ssam		return -1;
952189251Ssam	}
953189251Ssam
954189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
955189251Ssam			buf, buflen);
956189251Ssam
957252726Srpaulo#ifdef CONFIG_TLSV12
958252726Srpaulo	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
959252726Srpaulo		/*
960252726Srpaulo		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
961252726Srpaulo		 *
962252726Srpaulo		 * DigestInfo ::= SEQUENCE {
963252726Srpaulo		 *   digestAlgorithm DigestAlgorithm,
964252726Srpaulo		 *   digest OCTET STRING
965252726Srpaulo		 * }
966252726Srpaulo		 *
967252726Srpaulo		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
968252726Srpaulo		 *
969252726Srpaulo		 * DER encoded DigestInfo for SHA256 per RFC 3447:
970252726Srpaulo		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
971252726Srpaulo		 * H
972252726Srpaulo		 */
973252726Srpaulo		if (buflen >= 19 + 32 &&
974252726Srpaulo		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
975252726Srpaulo			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
976252726Srpaulo		{
977252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
978252726Srpaulo				   "SHA-256");
979252726Srpaulo			os_memmove(buf, buf + 19, buflen - 19);
980252726Srpaulo			buflen -= 19;
981252726Srpaulo		} else {
982252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
983252726Srpaulo				   "DigestInfo");
984252726Srpaulo			os_free(buf);
985252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
986252726Srpaulo					   TLS_ALERT_DECRYPT_ERROR);
987252726Srpaulo			return -1;
988252726Srpaulo		}
989252726Srpaulo	}
990252726Srpaulo#endif /* CONFIG_TLSV12 */
991252726Srpaulo
992189251Ssam	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
993189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
994189251Ssam			   "CertificateVerify - did not match with calculated "
995189251Ssam			   "hash");
996189251Ssam		os_free(buf);
997189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
998189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
999189251Ssam		return -1;
1000189251Ssam	}
1001189251Ssam
1002189251Ssam	os_free(buf);
1003189251Ssam
1004189251Ssam	*in_len = end - in_data;
1005189251Ssam
1006189251Ssam	conn->state = CHANGE_CIPHER_SPEC;
1007189251Ssam
1008189251Ssam	return 0;
1009189251Ssam}
1010189251Ssam
1011189251Ssam
1012189251Ssamstatic int tls_process_change_cipher_spec(struct tlsv1_server *conn,
1013189251Ssam					  u8 ct, const u8 *in_data,
1014189251Ssam					  size_t *in_len)
1015189251Ssam{
1016189251Ssam	const u8 *pos;
1017189251Ssam	size_t left;
1018189251Ssam
1019189251Ssam	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
1020189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
1021189251Ssam			   "received content type 0x%x", ct);
1022189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1023189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
1024189251Ssam		return -1;
1025189251Ssam	}
1026189251Ssam
1027189251Ssam	pos = in_data;
1028189251Ssam	left = *in_len;
1029189251Ssam
1030189251Ssam	if (left < 1) {
1031189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
1032189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1033189251Ssam				   TLS_ALERT_DECODE_ERROR);
1034189251Ssam		return -1;
1035189251Ssam	}
1036189251Ssam
1037189251Ssam	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
1038189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
1039189251Ssam			   "received data 0x%x", *pos);
1040189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1041189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
1042189251Ssam		return -1;
1043189251Ssam	}
1044189251Ssam
1045189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
1046189251Ssam	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
1047189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
1048189251Ssam			   "for record layer");
1049189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1050189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1051189251Ssam		return -1;
1052189251Ssam	}
1053189251Ssam
1054189251Ssam	*in_len = pos + 1 - in_data;
1055189251Ssam
1056189251Ssam	conn->state = CLIENT_FINISHED;
1057189251Ssam
1058189251Ssam	return 0;
1059189251Ssam}
1060189251Ssam
1061189251Ssam
1062189251Ssamstatic int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
1063189251Ssam				       const u8 *in_data, size_t *in_len)
1064189251Ssam{
1065189251Ssam	const u8 *pos, *end;
1066189251Ssam	size_t left, len, hlen;
1067189251Ssam	u8 verify_data[TLS_VERIFY_DATA_LEN];
1068189251Ssam	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
1069189251Ssam
1070189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
1071189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
1072189251Ssam			   "received content type 0x%x", ct);
1073189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1074189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
1075189251Ssam		return -1;
1076189251Ssam	}
1077189251Ssam
1078189251Ssam	pos = in_data;
1079189251Ssam	left = *in_len;
1080189251Ssam
1081189251Ssam	if (left < 4) {
1082189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
1083189251Ssam			   "Finished",
1084189251Ssam			   (unsigned long) left);
1085189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1086189251Ssam				   TLS_ALERT_DECODE_ERROR);
1087189251Ssam		return -1;
1088189251Ssam	}
1089189251Ssam
1090189251Ssam	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
1091189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
1092189251Ssam			   "type 0x%x", pos[0]);
1093189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1094189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
1095189251Ssam		return -1;
1096189251Ssam	}
1097189251Ssam
1098189251Ssam	len = WPA_GET_BE24(pos + 1);
1099189251Ssam
1100189251Ssam	pos += 4;
1101189251Ssam	left -= 4;
1102189251Ssam
1103189251Ssam	if (len > left) {
1104189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
1105189251Ssam			   "(len=%lu > left=%lu)",
1106189251Ssam			   (unsigned long) len, (unsigned long) left);
1107189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1108189251Ssam				   TLS_ALERT_DECODE_ERROR);
1109189251Ssam		return -1;
1110189251Ssam	}
1111189251Ssam	end = pos + len;
1112189251Ssam	if (len != TLS_VERIFY_DATA_LEN) {
1113189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
1114189251Ssam			   "in Finished: %lu (expected %d)",
1115189251Ssam			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
1116189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1117189251Ssam				   TLS_ALERT_DECODE_ERROR);
1118189251Ssam		return -1;
1119189251Ssam	}
1120189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
1121189251Ssam		    pos, TLS_VERIFY_DATA_LEN);
1122189251Ssam
1123252726Srpaulo#ifdef CONFIG_TLSV12
1124252726Srpaulo	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
1125252726Srpaulo		hlen = SHA256_MAC_LEN;
1126252726Srpaulo		if (conn->verify.sha256_client == NULL ||
1127252726Srpaulo		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
1128252726Srpaulo		    < 0) {
1129252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1130252726Srpaulo					   TLS_ALERT_INTERNAL_ERROR);
1131252726Srpaulo			conn->verify.sha256_client = NULL;
1132252726Srpaulo			return -1;
1133252726Srpaulo		}
1134252726Srpaulo		conn->verify.sha256_client = NULL;
1135252726Srpaulo	} else {
1136252726Srpaulo#endif /* CONFIG_TLSV12 */
1137252726Srpaulo
1138189251Ssam	hlen = MD5_MAC_LEN;
1139189251Ssam	if (conn->verify.md5_client == NULL ||
1140189251Ssam	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
1141189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1142189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1143189251Ssam		conn->verify.md5_client = NULL;
1144189251Ssam		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
1145189251Ssam		conn->verify.sha1_client = NULL;
1146189251Ssam		return -1;
1147189251Ssam	}
1148189251Ssam	conn->verify.md5_client = NULL;
1149189251Ssam	hlen = SHA1_MAC_LEN;
1150189251Ssam	if (conn->verify.sha1_client == NULL ||
1151189251Ssam	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
1152189251Ssam			       &hlen) < 0) {
1153189251Ssam		conn->verify.sha1_client = NULL;
1154189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1155189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1156189251Ssam		return -1;
1157189251Ssam	}
1158189251Ssam	conn->verify.sha1_client = NULL;
1159252726Srpaulo	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
1160189251Ssam
1161252726Srpaulo#ifdef CONFIG_TLSV12
1162252726Srpaulo	}
1163252726Srpaulo#endif /* CONFIG_TLSV12 */
1164252726Srpaulo
1165252726Srpaulo	if (tls_prf(conn->rl.tls_version,
1166252726Srpaulo		    conn->master_secret, TLS_MASTER_SECRET_LEN,
1167252726Srpaulo		    "client finished", hash, hlen,
1168189251Ssam		    verify_data, TLS_VERIFY_DATA_LEN)) {
1169189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
1170189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1171189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
1172189251Ssam		return -1;
1173189251Ssam	}
1174189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
1175189251Ssam			verify_data, TLS_VERIFY_DATA_LEN);
1176189251Ssam
1177189251Ssam	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
1178189251Ssam		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
1179189251Ssam		return -1;
1180189251Ssam	}
1181189251Ssam
1182189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
1183189251Ssam
1184189251Ssam	*in_len = end - in_data;
1185189251Ssam
1186189251Ssam	if (conn->use_session_ticket) {
1187189251Ssam		/* Abbreviated handshake using session ticket; RFC 4507 */
1188189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
1189189251Ssam			   "successfully");
1190189251Ssam		conn->state = ESTABLISHED;
1191189251Ssam	} else {
1192189251Ssam		/* Full handshake */
1193189251Ssam		conn->state = SERVER_CHANGE_CIPHER_SPEC;
1194189251Ssam	}
1195189251Ssam
1196189251Ssam	return 0;
1197189251Ssam}
1198189251Ssam
1199189251Ssam
1200189251Ssamint tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
1201189251Ssam				   const u8 *buf, size_t *len)
1202189251Ssam{
1203189251Ssam	if (ct == TLS_CONTENT_TYPE_ALERT) {
1204189251Ssam		if (*len < 2) {
1205189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
1206189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1207189251Ssam					   TLS_ALERT_DECODE_ERROR);
1208189251Ssam			return -1;
1209189251Ssam		}
1210189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
1211189251Ssam			   buf[0], buf[1]);
1212189251Ssam		*len = 2;
1213189251Ssam		conn->state = FAILED;
1214189251Ssam		return -1;
1215189251Ssam	}
1216189251Ssam
1217189251Ssam	switch (conn->state) {
1218189251Ssam	case CLIENT_HELLO:
1219189251Ssam		if (tls_process_client_hello(conn, ct, buf, len))
1220189251Ssam			return -1;
1221189251Ssam		break;
1222189251Ssam	case CLIENT_CERTIFICATE:
1223189251Ssam		if (tls_process_certificate(conn, ct, buf, len))
1224189251Ssam			return -1;
1225189251Ssam		break;
1226189251Ssam	case CLIENT_KEY_EXCHANGE:
1227189251Ssam		if (tls_process_client_key_exchange(conn, ct, buf, len))
1228189251Ssam			return -1;
1229189251Ssam		break;
1230189251Ssam	case CERTIFICATE_VERIFY:
1231189251Ssam		if (tls_process_certificate_verify(conn, ct, buf, len))
1232189251Ssam			return -1;
1233189251Ssam		break;
1234189251Ssam	case CHANGE_CIPHER_SPEC:
1235189251Ssam		if (tls_process_change_cipher_spec(conn, ct, buf, len))
1236189251Ssam			return -1;
1237189251Ssam		break;
1238189251Ssam	case CLIENT_FINISHED:
1239189251Ssam		if (tls_process_client_finished(conn, ct, buf, len))
1240189251Ssam			return -1;
1241189251Ssam		break;
1242189251Ssam	default:
1243189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
1244189251Ssam			   "while processing received message",
1245189251Ssam			   conn->state);
1246189251Ssam		return -1;
1247189251Ssam	}
1248189251Ssam
1249189251Ssam	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
1250189251Ssam		tls_verify_hash_add(&conn->verify, buf, *len);
1251189251Ssam
1252189251Ssam	return 0;
1253189251Ssam}
1254