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