1189251Ssam/*
2189251Ssam * TLSv1 server - read 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 int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
29189251Ssam					   const u8 *in_data, size_t *in_len);
30189251Ssamstatic int tls_process_change_cipher_spec(struct tlsv1_server *conn,
31189251Ssam					  u8 ct, const u8 *in_data,
32189251Ssam					  size_t *in_len);
33189251Ssam
34189251Ssam
35189251Ssamstatic int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
36189251Ssam				    const u8 *in_data, size_t *in_len)
37189251Ssam{
38189251Ssam	const u8 *pos, *end, *c;
39189251Ssam	size_t left, len, i, j;
40189251Ssam	u16 cipher_suite;
41189251Ssam	u16 num_suites;
42189251Ssam	int compr_null_found;
43209158Srpaulo	u16 ext_type, ext_len;
44189251Ssam
45189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
46189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
47189251Ssam			   "received content type 0x%x", ct);
48189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
49189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
50189251Ssam		return -1;
51189251Ssam	}
52189251Ssam
53189251Ssam	pos = in_data;
54189251Ssam	left = *in_len;
55189251Ssam
56189251Ssam	if (left < 4)
57189251Ssam		goto decode_error;
58189251Ssam
59189251Ssam	/* HandshakeType msg_type */
60189251Ssam	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
61189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
62189251Ssam			   "message %d (expected ClientHello)", *pos);
63189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
64189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
65189251Ssam		return -1;
66189251Ssam	}
67189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
68189251Ssam	pos++;
69189251Ssam	/* uint24 length */
70189251Ssam	len = WPA_GET_BE24(pos);
71189251Ssam	pos += 3;
72189251Ssam	left -= 4;
73189251Ssam
74189251Ssam	if (len > left)
75189251Ssam		goto decode_error;
76189251Ssam
77189251Ssam	/* body - ClientHello */
78189251Ssam
79189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
80189251Ssam	end = pos + len;
81189251Ssam
82189251Ssam	/* ProtocolVersion client_version */
83189251Ssam	if (end - pos < 2)
84189251Ssam		goto decode_error;
85189251Ssam	conn->client_version = WPA_GET_BE16(pos);
86189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
87189251Ssam		   conn->client_version >> 8, conn->client_version & 0xff);
88189251Ssam	if (conn->client_version < TLS_VERSION) {
89189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
90189251Ssam			   "ClientHello");
91189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
92189251Ssam				   TLS_ALERT_PROTOCOL_VERSION);
93189251Ssam		return -1;
94189251Ssam	}
95189251Ssam	pos += 2;
96189251Ssam
97189251Ssam	/* Random random */
98189251Ssam	if (end - pos < TLS_RANDOM_LEN)
99189251Ssam		goto decode_error;
100189251Ssam
101189251Ssam	os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
102189251Ssam	pos += TLS_RANDOM_LEN;
103189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
104189251Ssam		    conn->client_random, TLS_RANDOM_LEN);
105189251Ssam
106189251Ssam	/* SessionID session_id */
107189251Ssam	if (end - pos < 1)
108189251Ssam		goto decode_error;
109189251Ssam	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
110189251Ssam		goto decode_error;
111189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
112189251Ssam	pos += 1 + *pos;
113189251Ssam	/* TODO: add support for session resumption */
114189251Ssam
115189251Ssam	/* CipherSuite cipher_suites<2..2^16-1> */
116189251Ssam	if (end - pos < 2)
117189251Ssam		goto decode_error;
118189251Ssam	num_suites = WPA_GET_BE16(pos);
119189251Ssam	pos += 2;
120189251Ssam	if (end - pos < num_suites)
121189251Ssam		goto decode_error;
122189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
123189251Ssam		    pos, num_suites);
124189251Ssam	if (num_suites & 1)
125189251Ssam		goto decode_error;
126189251Ssam	num_suites /= 2;
127189251Ssam
128189251Ssam	cipher_suite = 0;
129189251Ssam	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
130189251Ssam		c = pos;
131189251Ssam		for (j = 0; j < num_suites; j++) {
132189251Ssam			u16 tmp = WPA_GET_BE16(c);
133189251Ssam			c += 2;
134189251Ssam			if (!cipher_suite && tmp == conn->cipher_suites[i]) {
135189251Ssam				cipher_suite = tmp;
136189251Ssam				break;
137189251Ssam			}
138189251Ssam		}
139189251Ssam	}
140189251Ssam	pos += num_suites * 2;
141189251Ssam	if (!cipher_suite) {
142189251Ssam		wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
143189251Ssam			   "available");
144189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
145189251Ssam				   TLS_ALERT_ILLEGAL_PARAMETER);
146189251Ssam		return -1;
147189251Ssam	}
148189251Ssam
149189251Ssam	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
150189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
151189251Ssam			   "record layer");
152189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
153189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
154189251Ssam		return -1;
155189251Ssam	}
156189251Ssam
157189251Ssam	conn->cipher_suite = cipher_suite;
158189251Ssam
159189251Ssam	/* CompressionMethod compression_methods<1..2^8-1> */
160189251Ssam	if (end - pos < 1)
161189251Ssam		goto decode_error;
162189251Ssam	num_suites = *pos++;
163189251Ssam	if (end - pos < num_suites)
164189251Ssam		goto decode_error;
165189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
166189251Ssam		    pos, num_suites);
167189251Ssam	compr_null_found = 0;
168189251Ssam	for (i = 0; i < num_suites; i++) {
169189251Ssam		if (*pos++ == TLS_COMPRESSION_NULL)
170189251Ssam			compr_null_found = 1;
171189251Ssam	}
172189251Ssam	if (!compr_null_found) {
173189251Ssam		wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
174189251Ssam			   "compression");
175189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
176189251Ssam				   TLS_ALERT_ILLEGAL_PARAMETER);
177189251Ssam		return -1;
178189251Ssam	}
179189251Ssam
180189251Ssam	if (end - pos == 1) {
181189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
182189251Ssam			    "end of ClientHello: 0x%02x", *pos);
183189251Ssam		goto decode_error;
184189251Ssam	}
185189251Ssam
186189251Ssam	if (end - pos >= 2) {
187189251Ssam		/* Extension client_hello_extension_list<0..2^16-1> */
188189251Ssam		ext_len = WPA_GET_BE16(pos);
189189251Ssam		pos += 2;
190189251Ssam
191189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
192189251Ssam			   "extensions", ext_len);
193189251Ssam		if (end - pos != ext_len) {
194189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
195189251Ssam				   "extension list length %u (expected %u)",
196209158Srpaulo				   ext_len, (unsigned int) (end - pos));
197189251Ssam			goto decode_error;
198189251Ssam		}
199189251Ssam
200189251Ssam		/*
201189251Ssam		 * struct {
202189251Ssam		 *   ExtensionType extension_type (0..65535)
203189251Ssam		 *   opaque extension_data<0..2^16-1>
204189251Ssam		 * } Extension;
205189251Ssam		 */
206189251Ssam
207189251Ssam		while (pos < end) {
208189251Ssam			if (end - pos < 2) {
209189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
210189251Ssam					   "extension_type field");
211189251Ssam				goto decode_error;
212189251Ssam			}
213189251Ssam
214189251Ssam			ext_type = WPA_GET_BE16(pos);
215189251Ssam			pos += 2;
216189251Ssam
217189251Ssam			if (end - pos < 2) {
218189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
219189251Ssam					   "extension_data length field");
220189251Ssam				goto decode_error;
221189251Ssam			}
222189251Ssam
223189251Ssam			ext_len = WPA_GET_BE16(pos);
224189251Ssam			pos += 2;
225189251Ssam
226189251Ssam			if (end - pos < ext_len) {
227189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
228189251Ssam					   "extension_data field");
229189251Ssam				goto decode_error;
230189251Ssam			}
231189251Ssam
232189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
233189251Ssam				   "type %u", ext_type);
234189251Ssam			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
235189251Ssam				    "Extension data", pos, ext_len);
236189251Ssam
237189251Ssam			if (ext_type == TLS_EXT_SESSION_TICKET) {
238189251Ssam				os_free(conn->session_ticket);
239189251Ssam				conn->session_ticket = os_malloc(ext_len);
240189251Ssam				if (conn->session_ticket) {
241189251Ssam					os_memcpy(conn->session_ticket, pos,
242189251Ssam						  ext_len);
243189251Ssam					conn->session_ticket_len = ext_len;
244189251Ssam				}
245189251Ssam			}
246189251Ssam
247189251Ssam			pos += ext_len;
248189251Ssam		}
249189251Ssam	}
250189251Ssam
251189251Ssam	*in_len = end - in_data;
252189251Ssam
253189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
254189251Ssam		   "ServerHello");
255189251Ssam	conn->state = SERVER_HELLO;
256189251Ssam
257189251Ssam	return 0;
258189251Ssam
259189251Ssamdecode_error:
260189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
261189251Ssam	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
262189251Ssam			   TLS_ALERT_DECODE_ERROR);
263189251Ssam	return -1;
264189251Ssam}
265189251Ssam
266189251Ssam
267189251Ssamstatic int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
268189251Ssam				   const u8 *in_data, size_t *in_len)
269189251Ssam{
270189251Ssam	const u8 *pos, *end;
271189251Ssam	size_t left, len, list_len, cert_len, idx;
272189251Ssam	u8 type;
273189251Ssam	struct x509_certificate *chain = NULL, *last = NULL, *cert;
274189251Ssam	int reason;
275189251Ssam
276189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
277189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
278189251Ssam			   "received content type 0x%x", ct);
279189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
280189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
281189251Ssam		return -1;
282189251Ssam	}
283189251Ssam
284189251Ssam	pos = in_data;
285189251Ssam	left = *in_len;
286189251Ssam
287189251Ssam	if (left < 4) {
288189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
289189251Ssam			   "(len=%lu)", (unsigned long) left);
290189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
291189251Ssam				   TLS_ALERT_DECODE_ERROR);
292189251Ssam		return -1;
293189251Ssam	}
294189251Ssam
295189251Ssam	type = *pos++;
296189251Ssam	len = WPA_GET_BE24(pos);
297189251Ssam	pos += 3;
298189251Ssam	left -= 4;
299189251Ssam
300189251Ssam	if (len > left) {
301189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
302189251Ssam			   "length (len=%lu != left=%lu)",
303189251Ssam			   (unsigned long) len, (unsigned long) left);
304189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
305189251Ssam				   TLS_ALERT_DECODE_ERROR);
306189251Ssam		return -1;
307189251Ssam	}
308189251Ssam
309189251Ssam	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
310189251Ssam		if (conn->verify_peer) {
311189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
312189251Ssam				   "Certificate");
313189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
314189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
315189251Ssam			return -1;
316189251Ssam		}
317189251Ssam
318189251Ssam		return tls_process_client_key_exchange(conn, ct, in_data,
319189251Ssam						       in_len);
320189251Ssam	}
321189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
322189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
323189251Ssam			   "message %d (expected Certificate/"
324189251Ssam			   "ClientKeyExchange)", type);
325189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
326189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
327189251Ssam		return -1;
328189251Ssam	}
329189251Ssam
330189251Ssam	wpa_printf(MSG_DEBUG,
331189251Ssam		   "TLSv1: Received Certificate (certificate_list len %lu)",
332189251Ssam		   (unsigned long) len);
333189251Ssam
334189251Ssam	/*
335189251Ssam	 * opaque ASN.1Cert<2^24-1>;
336189251Ssam	 *
337189251Ssam	 * struct {
338189251Ssam	 *     ASN.1Cert certificate_list<1..2^24-1>;
339189251Ssam	 * } Certificate;
340189251Ssam	 */
341189251Ssam
342189251Ssam	end = pos + len;
343189251Ssam
344189251Ssam	if (end - pos < 3) {
345189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
346189251Ssam			   "(left=%lu)", (unsigned long) left);
347189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
348189251Ssam				   TLS_ALERT_DECODE_ERROR);
349189251Ssam		return -1;
350189251Ssam	}
351189251Ssam
352189251Ssam	list_len = WPA_GET_BE24(pos);
353189251Ssam	pos += 3;
354189251Ssam
355189251Ssam	if ((size_t) (end - pos) != list_len) {
356189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
357189251Ssam			   "length (len=%lu left=%lu)",
358189251Ssam			   (unsigned long) list_len,
359189251Ssam			   (unsigned long) (end - pos));
360189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
361189251Ssam				   TLS_ALERT_DECODE_ERROR);
362189251Ssam		return -1;
363189251Ssam	}
364189251Ssam
365189251Ssam	idx = 0;
366189251Ssam	while (pos < end) {
367189251Ssam		if (end - pos < 3) {
368189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
369189251Ssam				   "certificate_list");
370189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
371189251Ssam					   TLS_ALERT_DECODE_ERROR);
372189251Ssam			x509_certificate_chain_free(chain);
373189251Ssam			return -1;
374189251Ssam		}
375189251Ssam
376189251Ssam		cert_len = WPA_GET_BE24(pos);
377189251Ssam		pos += 3;
378189251Ssam
379189251Ssam		if ((size_t) (end - pos) < cert_len) {
380189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
381189251Ssam				   "length (len=%lu left=%lu)",
382189251Ssam				   (unsigned long) cert_len,
383189251Ssam				   (unsigned long) (end - pos));
384189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
385189251Ssam					   TLS_ALERT_DECODE_ERROR);
386189251Ssam			x509_certificate_chain_free(chain);
387189251Ssam			return -1;
388189251Ssam		}
389189251Ssam
390189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
391189251Ssam			   (unsigned long) idx, (unsigned long) cert_len);
392189251Ssam
393189251Ssam		if (idx == 0) {
394189251Ssam			crypto_public_key_free(conn->client_rsa_key);
395189251Ssam			if (tls_parse_cert(pos, cert_len,
396189251Ssam					   &conn->client_rsa_key)) {
397189251Ssam				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
398189251Ssam					   "the certificate");
399189251Ssam				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
400189251Ssam						   TLS_ALERT_BAD_CERTIFICATE);
401189251Ssam				x509_certificate_chain_free(chain);
402189251Ssam				return -1;
403189251Ssam			}
404189251Ssam		}
405189251Ssam
406189251Ssam		cert = x509_certificate_parse(pos, cert_len);
407189251Ssam		if (cert == NULL) {
408189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
409189251Ssam				   "the certificate");
410189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
411189251Ssam					   TLS_ALERT_BAD_CERTIFICATE);
412189251Ssam			x509_certificate_chain_free(chain);
413189251Ssam			return -1;
414189251Ssam		}
415189251Ssam
416189251Ssam		if (last == NULL)
417189251Ssam			chain = cert;
418189251Ssam		else
419189251Ssam			last->next = cert;
420189251Ssam		last = cert;
421189251Ssam
422189251Ssam		idx++;
423189251Ssam		pos += cert_len;
424189251Ssam	}
425189251Ssam
426189251Ssam	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
427189251Ssam					    &reason) < 0) {
428189251Ssam		int tls_reason;
429189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
430189251Ssam			   "validation failed (reason=%d)", reason);
431189251Ssam		switch (reason) {
432189251Ssam		case X509_VALIDATE_BAD_CERTIFICATE:
433189251Ssam			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
434189251Ssam			break;
435189251Ssam		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
436189251Ssam			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
437189251Ssam			break;
438189251Ssam		case X509_VALIDATE_CERTIFICATE_REVOKED:
439189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
440189251Ssam			break;
441189251Ssam		case X509_VALIDATE_CERTIFICATE_EXPIRED:
442189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
443189251Ssam			break;
444189251Ssam		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
445189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
446189251Ssam			break;
447189251Ssam		case X509_VALIDATE_UNKNOWN_CA:
448189251Ssam			tls_reason = TLS_ALERT_UNKNOWN_CA;
449189251Ssam			break;
450189251Ssam		default:
451189251Ssam			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
452189251Ssam			break;
453189251Ssam		}
454189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
455189251Ssam		x509_certificate_chain_free(chain);
456189251Ssam		return -1;
457189251Ssam	}
458189251Ssam
459189251Ssam	x509_certificate_chain_free(chain);
460189251Ssam
461189251Ssam	*in_len = end - in_data;
462189251Ssam
463189251Ssam	conn->state = CLIENT_KEY_EXCHANGE;
464189251Ssam
465189251Ssam	return 0;
466189251Ssam}
467189251Ssam
468189251Ssam
469189251Ssamstatic int tls_process_client_key_exchange_rsa(
470189251Ssam	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
471189251Ssam{
472189251Ssam	u8 *out;
473189251Ssam	size_t outlen, outbuflen;
474189251Ssam	u16 encr_len;
475189251Ssam	int res;
476189251Ssam	int use_random = 0;
477189251Ssam
478189251Ssam	if (end - pos < 2) {
479189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
480189251Ssam				   TLS_ALERT_DECODE_ERROR);
481189251Ssam		return -1;
482189251Ssam	}
483189251Ssam
484189251Ssam	encr_len = WPA_GET_BE16(pos);
485189251Ssam	pos += 2;
486189251Ssam
487189251Ssam	outbuflen = outlen = end - pos;
488189251Ssam	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
489189251Ssam			outlen : TLS_PRE_MASTER_SECRET_LEN);
490189251Ssam	if (out == NULL) {
491189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
492189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
493189251Ssam		return -1;
494189251Ssam	}
495189251Ssam
496189251Ssam	/*
497189251Ssam	 * struct {
498189251Ssam	 *   ProtocolVersion client_version;
499189251Ssam	 *   opaque random[46];
500189251Ssam	 * } PreMasterSecret;
501189251Ssam	 *
502189251Ssam	 * struct {
503189251Ssam	 *   public-key-encrypted PreMasterSecret pre_master_secret;
504189251Ssam	 * } EncryptedPreMasterSecret;
505189251Ssam	 */
506189251Ssam
507189251Ssam	/*
508189251Ssam	 * Note: To avoid Bleichenbacher attack, we do not report decryption or
509189251Ssam	 * parsing errors from EncryptedPreMasterSecret processing to the
510189251Ssam	 * client. Instead, a random pre-master secret is used to force the
511189251Ssam	 * handshake to fail.
512189251Ssam	 */
513189251Ssam
514189251Ssam	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
515189251Ssam						 pos, end - pos,
516189251Ssam						 out, &outlen) < 0) {
517189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
518189251Ssam			   "PreMasterSecret (encr_len=%d outlen=%lu)",
519209158Srpaulo			   (int) (end - pos), (unsigned long) outlen);
520189251Ssam		use_random = 1;
521189251Ssam	}
522189251Ssam
523189251Ssam	if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
524189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
525189251Ssam			   "length %lu", (unsigned long) outlen);
526189251Ssam		use_random = 1;
527189251Ssam	}
528189251Ssam
529189251Ssam	if (WPA_GET_BE16(out) != conn->client_version) {
530189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
531189251Ssam			   "ClientKeyExchange does not match with version in "
532189251Ssam			   "ClientHello");
533189251Ssam		use_random = 1;
534189251Ssam	}
535189251Ssam
536189251Ssam	if (use_random) {
537189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
538189251Ssam			   "to avoid revealing information about private key");
539189251Ssam		outlen = TLS_PRE_MASTER_SECRET_LEN;
540189251Ssam		if (os_get_random(out, outlen)) {
541189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
542189251Ssam				   "data");
543189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
544189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
545189251Ssam			os_free(out);
546189251Ssam			return -1;
547189251Ssam		}
548189251Ssam	}
549189251Ssam
550189251Ssam	res = tlsv1_server_derive_keys(conn, out, outlen);
551189251Ssam
552189251Ssam	/* Clear the pre-master secret since it is not needed anymore */
553189251Ssam	os_memset(out, 0, outbuflen);
554189251Ssam	os_free(out);
555189251Ssam
556189251Ssam	if (res) {
557189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
558189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
559189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
560189251Ssam		return -1;
561189251Ssam	}
562189251Ssam
563189251Ssam	return 0;
564189251Ssam}
565189251Ssam
566189251Ssam
567189251Ssamstatic int tls_process_client_key_exchange_dh_anon(
568189251Ssam	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
569189251Ssam{
570189251Ssam	const u8 *dh_yc;
571189251Ssam	u16 dh_yc_len;
572189251Ssam	u8 *shared;
573189251Ssam	size_t shared_len;
574189251Ssam	int res;
575189251Ssam
576189251Ssam	/*
577189251Ssam	 * struct {
578189251Ssam	 *   select (PublicValueEncoding) {
579189251Ssam	 *     case implicit: struct { };
580189251Ssam	 *     case explicit: opaque dh_Yc<1..2^16-1>;
581189251Ssam	 *   } dh_public;
582189251Ssam	 * } ClientDiffieHellmanPublic;
583189251Ssam	 */
584189251Ssam
585189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
586189251Ssam		    pos, end - pos);
587189251Ssam
588189251Ssam	if (end == pos) {
589189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
590189251Ssam			   "not supported");
591189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
592189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
593189251Ssam		return -1;
594189251Ssam	}
595189251Ssam
596189251Ssam	if (end - pos < 3) {
597189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
598189251Ssam			   "length");
599189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
600189251Ssam				   TLS_ALERT_DECODE_ERROR);
601189251Ssam		return -1;
602189251Ssam	}
603189251Ssam
604189251Ssam	dh_yc_len = WPA_GET_BE16(pos);
605189251Ssam	dh_yc = pos + 2;
606189251Ssam
607189251Ssam	if (dh_yc + dh_yc_len > end) {
608189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
609189251Ssam			   "(length %d)", dh_yc_len);
610189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
611189251Ssam				   TLS_ALERT_DECODE_ERROR);
612189251Ssam		return -1;
613189251Ssam	}
614189251Ssam
615189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
616189251Ssam		    dh_yc, dh_yc_len);
617189251Ssam
618189251Ssam	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
619189251Ssam	    conn->dh_secret == NULL) {
620189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
621189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
622189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
623189251Ssam		return -1;
624189251Ssam	}
625189251Ssam
626189251Ssam	shared_len = conn->cred->dh_p_len;
627189251Ssam	shared = os_malloc(shared_len);
628189251Ssam	if (shared == NULL) {
629189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
630189251Ssam			   "DH");
631189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
632189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
633189251Ssam		return -1;
634189251Ssam	}
635189251Ssam
636189251Ssam	/* shared = Yc^secret mod p */
637189251Ssam	if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
638189251Ssam			   conn->dh_secret_len,
639189251Ssam			   conn->cred->dh_p, conn->cred->dh_p_len,
640189251Ssam			   shared, &shared_len)) {
641189251Ssam		os_free(shared);
642189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
643189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
644189251Ssam		return -1;
645189251Ssam	}
646189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
647189251Ssam			shared, shared_len);
648189251Ssam
649189251Ssam	os_memset(conn->dh_secret, 0, conn->dh_secret_len);
650189251Ssam	os_free(conn->dh_secret);
651189251Ssam	conn->dh_secret = NULL;
652189251Ssam
653189251Ssam	res = tlsv1_server_derive_keys(conn, shared, shared_len);
654189251Ssam
655189251Ssam	/* Clear the pre-master secret since it is not needed anymore */
656189251Ssam	os_memset(shared, 0, shared_len);
657189251Ssam	os_free(shared);
658189251Ssam
659189251Ssam	if (res) {
660189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
661189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
662189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
663189251Ssam		return -1;
664189251Ssam	}
665189251Ssam
666189251Ssam	return 0;
667189251Ssam}
668189251Ssam
669189251Ssam
670189251Ssamstatic int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
671189251Ssam					   const u8 *in_data, size_t *in_len)
672189251Ssam{
673189251Ssam	const u8 *pos, *end;
674189251Ssam	size_t left, len;
675189251Ssam	u8 type;
676189251Ssam	tls_key_exchange keyx;
677189251Ssam	const struct tls_cipher_suite *suite;
678189251Ssam
679189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
680189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
681189251Ssam			   "received content type 0x%x", ct);
682189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
683189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
684189251Ssam		return -1;
685189251Ssam	}
686189251Ssam
687189251Ssam	pos = in_data;
688189251Ssam	left = *in_len;
689189251Ssam
690189251Ssam	if (left < 4) {
691189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
692189251Ssam			   "(Left=%lu)", (unsigned long) left);
693189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
694189251Ssam				   TLS_ALERT_DECODE_ERROR);
695189251Ssam		return -1;
696189251Ssam	}
697189251Ssam
698189251Ssam	type = *pos++;
699189251Ssam	len = WPA_GET_BE24(pos);
700189251Ssam	pos += 3;
701189251Ssam	left -= 4;
702189251Ssam
703189251Ssam	if (len > left) {
704189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
705189251Ssam			   "length (len=%lu != left=%lu)",
706189251Ssam			   (unsigned long) len, (unsigned long) left);
707189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
708189251Ssam				   TLS_ALERT_DECODE_ERROR);
709189251Ssam		return -1;
710189251Ssam	}
711189251Ssam
712189251Ssam	end = pos + len;
713189251Ssam
714189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
715189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
716189251Ssam			   "message %d (expected ClientKeyExchange)", type);
717189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
718189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
719189251Ssam		return -1;
720189251Ssam	}
721189251Ssam
722189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
723189251Ssam
724189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
725189251Ssam
726189251Ssam	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
727189251Ssam	if (suite == NULL)
728189251Ssam		keyx = TLS_KEY_X_NULL;
729189251Ssam	else
730189251Ssam		keyx = suite->key_exchange;
731189251Ssam
732189251Ssam	if (keyx == TLS_KEY_X_DH_anon &&
733189251Ssam	    tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
734189251Ssam		return -1;
735189251Ssam
736189251Ssam	if (keyx != TLS_KEY_X_DH_anon &&
737189251Ssam	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
738189251Ssam		return -1;
739189251Ssam
740189251Ssam	*in_len = end - in_data;
741189251Ssam
742189251Ssam	conn->state = CERTIFICATE_VERIFY;
743189251Ssam
744189251Ssam	return 0;
745189251Ssam}
746189251Ssam
747189251Ssam
748189251Ssamstatic int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
749189251Ssam					  const u8 *in_data, size_t *in_len)
750189251Ssam{
751189251Ssam	const u8 *pos, *end;
752189251Ssam	size_t left, len;
753189251Ssam	u8 type;
754189251Ssam	size_t hlen, buflen;
755189251Ssam	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
756189251Ssam	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
757189251Ssam	u16 slen;
758189251Ssam
759189251Ssam	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
760189251Ssam		if (conn->verify_peer) {
761189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
762189251Ssam				   "CertificateVerify");
763189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
764189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
765189251Ssam			return -1;
766189251Ssam		}
767189251Ssam
768189251Ssam		return tls_process_change_cipher_spec(conn, ct, in_data,
769189251Ssam						      in_len);
770189251Ssam	}
771189251Ssam
772189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
773189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
774189251Ssam			   "received content type 0x%x", ct);
775189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
776189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
777189251Ssam		return -1;
778189251Ssam	}
779189251Ssam
780189251Ssam	pos = in_data;
781189251Ssam	left = *in_len;
782189251Ssam
783189251Ssam	if (left < 4) {
784189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
785189251Ssam			   "message (len=%lu)", (unsigned long) left);
786189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
787189251Ssam				   TLS_ALERT_DECODE_ERROR);
788189251Ssam		return -1;
789189251Ssam	}
790189251Ssam
791189251Ssam	type = *pos++;
792189251Ssam	len = WPA_GET_BE24(pos);
793189251Ssam	pos += 3;
794189251Ssam	left -= 4;
795189251Ssam
796189251Ssam	if (len > left) {
797189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
798189251Ssam			   "message length (len=%lu != left=%lu)",
799189251Ssam			   (unsigned long) len, (unsigned long) left);
800189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
801189251Ssam				   TLS_ALERT_DECODE_ERROR);
802189251Ssam		return -1;
803189251Ssam	}
804189251Ssam
805189251Ssam	end = pos + len;
806189251Ssam
807189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
808189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
809189251Ssam			   "message %d (expected CertificateVerify)", type);
810189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
811189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
812189251Ssam		return -1;
813189251Ssam	}
814189251Ssam
815189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
816189251Ssam
817189251Ssam	/*
818189251Ssam	 * struct {
819189251Ssam	 *   Signature signature;
820189251Ssam	 * } CertificateVerify;
821189251Ssam	 */
822189251Ssam
823189251Ssam	hpos = hash;
824189251Ssam
825189251Ssam	if (alg == SIGN_ALG_RSA) {
826189251Ssam		hlen = MD5_MAC_LEN;
827189251Ssam		if (conn->verify.md5_cert == NULL ||
828189251Ssam		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
829189251Ssam		{
830189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
831189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
832189251Ssam			conn->verify.md5_cert = NULL;
833189251Ssam			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
834189251Ssam			conn->verify.sha1_cert = NULL;
835189251Ssam			return -1;
836189251Ssam		}
837189251Ssam		hpos += MD5_MAC_LEN;
838189251Ssam	} else
839189251Ssam		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
840189251Ssam
841189251Ssam	conn->verify.md5_cert = NULL;
842189251Ssam	hlen = SHA1_MAC_LEN;
843189251Ssam	if (conn->verify.sha1_cert == NULL ||
844189251Ssam	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
845189251Ssam		conn->verify.sha1_cert = NULL;
846189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
847189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
848189251Ssam		return -1;
849189251Ssam	}
850189251Ssam	conn->verify.sha1_cert = NULL;
851189251Ssam
852189251Ssam	if (alg == SIGN_ALG_RSA)
853189251Ssam		hlen += MD5_MAC_LEN;
854189251Ssam
855189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
856189251Ssam
857189251Ssam	if (end - pos < 2) {
858189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
859189251Ssam				   TLS_ALERT_DECODE_ERROR);
860189251Ssam		return -1;
861189251Ssam	}
862189251Ssam	slen = WPA_GET_BE16(pos);
863189251Ssam	pos += 2;
864189251Ssam	if (end - pos < slen) {
865189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
866189251Ssam				   TLS_ALERT_DECODE_ERROR);
867189251Ssam		return -1;
868189251Ssam	}
869189251Ssam
870189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
871189251Ssam	if (conn->client_rsa_key == NULL) {
872189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
873189251Ssam			   "signature");
874189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
875189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
876189251Ssam		return -1;
877189251Ssam	}
878189251Ssam
879189251Ssam	buflen = end - pos;
880189251Ssam	buf = os_malloc(end - pos);
881189251Ssam	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
882189251Ssam					    pos, end - pos, buf, &buflen) < 0)
883189251Ssam	{
884189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
885189251Ssam		os_free(buf);
886189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
887189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
888189251Ssam		return -1;
889189251Ssam	}
890189251Ssam
891189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
892189251Ssam			buf, buflen);
893189251Ssam
894189251Ssam	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
895189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
896189251Ssam			   "CertificateVerify - did not match with calculated "
897189251Ssam			   "hash");
898189251Ssam		os_free(buf);
899189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
900189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
901189251Ssam		return -1;
902189251Ssam	}
903189251Ssam
904189251Ssam	os_free(buf);
905189251Ssam
906189251Ssam	*in_len = end - in_data;
907189251Ssam
908189251Ssam	conn->state = CHANGE_CIPHER_SPEC;
909189251Ssam
910189251Ssam	return 0;
911189251Ssam}
912189251Ssam
913189251Ssam
914189251Ssamstatic int tls_process_change_cipher_spec(struct tlsv1_server *conn,
915189251Ssam					  u8 ct, const u8 *in_data,
916189251Ssam					  size_t *in_len)
917189251Ssam{
918189251Ssam	const u8 *pos;
919189251Ssam	size_t left;
920189251Ssam
921189251Ssam	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
922189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
923189251Ssam			   "received content type 0x%x", ct);
924189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
925189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
926189251Ssam		return -1;
927189251Ssam	}
928189251Ssam
929189251Ssam	pos = in_data;
930189251Ssam	left = *in_len;
931189251Ssam
932189251Ssam	if (left < 1) {
933189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
934189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
935189251Ssam				   TLS_ALERT_DECODE_ERROR);
936189251Ssam		return -1;
937189251Ssam	}
938189251Ssam
939189251Ssam	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
940189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
941189251Ssam			   "received data 0x%x", *pos);
942189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
943189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
944189251Ssam		return -1;
945189251Ssam	}
946189251Ssam
947189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
948189251Ssam	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
949189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
950189251Ssam			   "for record layer");
951189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
952189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
953189251Ssam		return -1;
954189251Ssam	}
955189251Ssam
956189251Ssam	*in_len = pos + 1 - in_data;
957189251Ssam
958189251Ssam	conn->state = CLIENT_FINISHED;
959189251Ssam
960189251Ssam	return 0;
961189251Ssam}
962189251Ssam
963189251Ssam
964189251Ssamstatic int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
965189251Ssam				       const u8 *in_data, size_t *in_len)
966189251Ssam{
967189251Ssam	const u8 *pos, *end;
968189251Ssam	size_t left, len, hlen;
969189251Ssam	u8 verify_data[TLS_VERIFY_DATA_LEN];
970189251Ssam	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
971189251Ssam
972189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
973189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
974189251Ssam			   "received content type 0x%x", ct);
975189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
976189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
977189251Ssam		return -1;
978189251Ssam	}
979189251Ssam
980189251Ssam	pos = in_data;
981189251Ssam	left = *in_len;
982189251Ssam
983189251Ssam	if (left < 4) {
984189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
985189251Ssam			   "Finished",
986189251Ssam			   (unsigned long) left);
987189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
988189251Ssam				   TLS_ALERT_DECODE_ERROR);
989189251Ssam		return -1;
990189251Ssam	}
991189251Ssam
992189251Ssam	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
993189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
994189251Ssam			   "type 0x%x", pos[0]);
995189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
996189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
997189251Ssam		return -1;
998189251Ssam	}
999189251Ssam
1000189251Ssam	len = WPA_GET_BE24(pos + 1);
1001189251Ssam
1002189251Ssam	pos += 4;
1003189251Ssam	left -= 4;
1004189251Ssam
1005189251Ssam	if (len > left) {
1006189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
1007189251Ssam			   "(len=%lu > left=%lu)",
1008189251Ssam			   (unsigned long) len, (unsigned long) left);
1009189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1010189251Ssam				   TLS_ALERT_DECODE_ERROR);
1011189251Ssam		return -1;
1012189251Ssam	}
1013189251Ssam	end = pos + len;
1014189251Ssam	if (len != TLS_VERIFY_DATA_LEN) {
1015189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
1016189251Ssam			   "in Finished: %lu (expected %d)",
1017189251Ssam			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
1018189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1019189251Ssam				   TLS_ALERT_DECODE_ERROR);
1020189251Ssam		return -1;
1021189251Ssam	}
1022189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
1023189251Ssam		    pos, TLS_VERIFY_DATA_LEN);
1024189251Ssam
1025189251Ssam	hlen = MD5_MAC_LEN;
1026189251Ssam	if (conn->verify.md5_client == NULL ||
1027189251Ssam	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
1028189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1029189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1030189251Ssam		conn->verify.md5_client = NULL;
1031189251Ssam		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
1032189251Ssam		conn->verify.sha1_client = NULL;
1033189251Ssam		return -1;
1034189251Ssam	}
1035189251Ssam	conn->verify.md5_client = NULL;
1036189251Ssam	hlen = SHA1_MAC_LEN;
1037189251Ssam	if (conn->verify.sha1_client == NULL ||
1038189251Ssam	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
1039189251Ssam			       &hlen) < 0) {
1040189251Ssam		conn->verify.sha1_client = NULL;
1041189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1042189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1043189251Ssam		return -1;
1044189251Ssam	}
1045189251Ssam	conn->verify.sha1_client = NULL;
1046189251Ssam
1047189251Ssam	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
1048189251Ssam		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
1049189251Ssam		    verify_data, TLS_VERIFY_DATA_LEN)) {
1050189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
1051189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1052189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
1053189251Ssam		return -1;
1054189251Ssam	}
1055189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
1056189251Ssam			verify_data, TLS_VERIFY_DATA_LEN);
1057189251Ssam
1058189251Ssam	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
1059189251Ssam		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
1060189251Ssam		return -1;
1061189251Ssam	}
1062189251Ssam
1063189251Ssam	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
1064189251Ssam
1065189251Ssam	*in_len = end - in_data;
1066189251Ssam
1067189251Ssam	if (conn->use_session_ticket) {
1068189251Ssam		/* Abbreviated handshake using session ticket; RFC 4507 */
1069189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
1070189251Ssam			   "successfully");
1071189251Ssam		conn->state = ESTABLISHED;
1072189251Ssam	} else {
1073189251Ssam		/* Full handshake */
1074189251Ssam		conn->state = SERVER_CHANGE_CIPHER_SPEC;
1075189251Ssam	}
1076189251Ssam
1077189251Ssam	return 0;
1078189251Ssam}
1079189251Ssam
1080189251Ssam
1081189251Ssamint tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
1082189251Ssam				   const u8 *buf, size_t *len)
1083189251Ssam{
1084189251Ssam	if (ct == TLS_CONTENT_TYPE_ALERT) {
1085189251Ssam		if (*len < 2) {
1086189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
1087189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1088189251Ssam					   TLS_ALERT_DECODE_ERROR);
1089189251Ssam			return -1;
1090189251Ssam		}
1091189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
1092189251Ssam			   buf[0], buf[1]);
1093189251Ssam		*len = 2;
1094189251Ssam		conn->state = FAILED;
1095189251Ssam		return -1;
1096189251Ssam	}
1097189251Ssam
1098189251Ssam	switch (conn->state) {
1099189251Ssam	case CLIENT_HELLO:
1100189251Ssam		if (tls_process_client_hello(conn, ct, buf, len))
1101189251Ssam			return -1;
1102189251Ssam		break;
1103189251Ssam	case CLIENT_CERTIFICATE:
1104189251Ssam		if (tls_process_certificate(conn, ct, buf, len))
1105189251Ssam			return -1;
1106189251Ssam		break;
1107189251Ssam	case CLIENT_KEY_EXCHANGE:
1108189251Ssam		if (tls_process_client_key_exchange(conn, ct, buf, len))
1109189251Ssam			return -1;
1110189251Ssam		break;
1111189251Ssam	case CERTIFICATE_VERIFY:
1112189251Ssam		if (tls_process_certificate_verify(conn, ct, buf, len))
1113189251Ssam			return -1;
1114189251Ssam		break;
1115189251Ssam	case CHANGE_CIPHER_SPEC:
1116189251Ssam		if (tls_process_change_cipher_spec(conn, ct, buf, len))
1117189251Ssam			return -1;
1118189251Ssam		break;
1119189251Ssam	case CLIENT_FINISHED:
1120189251Ssam		if (tls_process_client_finished(conn, ct, buf, len))
1121189251Ssam			return -1;
1122189251Ssam		break;
1123189251Ssam	default:
1124189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
1125189251Ssam			   "while processing received message",
1126189251Ssam			   conn->state);
1127189251Ssam		return -1;
1128189251Ssam	}
1129189251Ssam
1130189251Ssam	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
1131189251Ssam		tls_verify_hash_add(&conn->verify, buf, *len);
1132189251Ssam
1133189251Ssam	return 0;
1134189251Ssam}
1135