1189251Ssam/*
2189251Ssam * TLSv1 server - read handshake message
3281806Srpaulo * Copyright (c) 2006-2014, 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
30281806Srpaulostatic int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
31281806Srpaulo{
32281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS
33281806Srpaulo	if ((conn->test_flags &
34281806Srpaulo	     (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE |
35281806Srpaulo	      TLS_DHE_PRIME_511B | TLS_DHE_PRIME_767B | TLS_DHE_PRIME_15 |
36281806Srpaulo	      TLS_DHE_PRIME_58B | TLS_DHE_NON_PRIME)) &&
37281806Srpaulo	    suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
38281806Srpaulo	    suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
39281806Srpaulo	    suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
40281806Srpaulo	    suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
41281806Srpaulo	    suite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
42281806Srpaulo		return 1;
43281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */
44281806Srpaulo
45281806Srpaulo	return 0;
46281806Srpaulo}
47281806Srpaulo
48281806Srpaulo
49189251Ssamstatic int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
50189251Ssam				    const u8 *in_data, size_t *in_len)
51189251Ssam{
52189251Ssam	const u8 *pos, *end, *c;
53189251Ssam	size_t left, len, i, j;
54189251Ssam	u16 cipher_suite;
55189251Ssam	u16 num_suites;
56189251Ssam	int compr_null_found;
57209158Srpaulo	u16 ext_type, ext_len;
58189251Ssam
59189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
60281806Srpaulo		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
61281806Srpaulo				 ct);
62189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
63189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
64189251Ssam		return -1;
65189251Ssam	}
66189251Ssam
67189251Ssam	pos = in_data;
68189251Ssam	left = *in_len;
69189251Ssam
70189251Ssam	if (left < 4)
71189251Ssam		goto decode_error;
72189251Ssam
73189251Ssam	/* HandshakeType msg_type */
74189251Ssam	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
75281806Srpaulo		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientHello)",
76281806Srpaulo				 *pos);
77189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
78189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
79189251Ssam		return -1;
80189251Ssam	}
81281806Srpaulo	tlsv1_server_log(conn, "Received ClientHello");
82189251Ssam	pos++;
83189251Ssam	/* uint24 length */
84189251Ssam	len = WPA_GET_BE24(pos);
85189251Ssam	pos += 3;
86189251Ssam	left -= 4;
87189251Ssam
88189251Ssam	if (len > left)
89189251Ssam		goto decode_error;
90189251Ssam
91189251Ssam	/* body - ClientHello */
92189251Ssam
93189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
94189251Ssam	end = pos + len;
95189251Ssam
96189251Ssam	/* ProtocolVersion client_version */
97189251Ssam	if (end - pos < 2)
98189251Ssam		goto decode_error;
99189251Ssam	conn->client_version = WPA_GET_BE16(pos);
100281806Srpaulo	tlsv1_server_log(conn, "Client version %d.%d",
101281806Srpaulo			 conn->client_version >> 8,
102281806Srpaulo			 conn->client_version & 0xff);
103252726Srpaulo	if (conn->client_version < TLS_VERSION_1) {
104281806Srpaulo		tlsv1_server_log(conn, "Unexpected protocol version in ClientHello %u.%u",
105281806Srpaulo				 conn->client_version >> 8,
106281806Srpaulo				 conn->client_version & 0xff);
107189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
108189251Ssam				   TLS_ALERT_PROTOCOL_VERSION);
109189251Ssam		return -1;
110189251Ssam	}
111189251Ssam	pos += 2;
112189251Ssam
113252726Srpaulo	if (TLS_VERSION == TLS_VERSION_1)
114252726Srpaulo		conn->rl.tls_version = TLS_VERSION_1;
115252726Srpaulo#ifdef CONFIG_TLSV12
116252726Srpaulo	else if (conn->client_version >= TLS_VERSION_1_2)
117252726Srpaulo		conn->rl.tls_version = TLS_VERSION_1_2;
118252726Srpaulo#endif /* CONFIG_TLSV12 */
119252726Srpaulo	else if (conn->client_version > TLS_VERSION_1_1)
120252726Srpaulo		conn->rl.tls_version = TLS_VERSION_1_1;
121252726Srpaulo	else
122252726Srpaulo		conn->rl.tls_version = conn->client_version;
123281806Srpaulo	tlsv1_server_log(conn, "Using TLS v%s",
124281806Srpaulo			 tls_version_str(conn->rl.tls_version));
125252726Srpaulo
126189251Ssam	/* Random random */
127189251Ssam	if (end - pos < TLS_RANDOM_LEN)
128189251Ssam		goto decode_error;
129189251Ssam
130189251Ssam	os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
131189251Ssam	pos += TLS_RANDOM_LEN;
132189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
133189251Ssam		    conn->client_random, TLS_RANDOM_LEN);
134189251Ssam
135189251Ssam	/* SessionID session_id */
136189251Ssam	if (end - pos < 1)
137189251Ssam		goto decode_error;
138189251Ssam	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
139189251Ssam		goto decode_error;
140189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
141189251Ssam	pos += 1 + *pos;
142189251Ssam	/* TODO: add support for session resumption */
143189251Ssam
144189251Ssam	/* CipherSuite cipher_suites<2..2^16-1> */
145189251Ssam	if (end - pos < 2)
146189251Ssam		goto decode_error;
147189251Ssam	num_suites = WPA_GET_BE16(pos);
148189251Ssam	pos += 2;
149189251Ssam	if (end - pos < num_suites)
150189251Ssam		goto decode_error;
151189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
152189251Ssam		    pos, num_suites);
153189251Ssam	if (num_suites & 1)
154189251Ssam		goto decode_error;
155189251Ssam	num_suites /= 2;
156189251Ssam
157189251Ssam	cipher_suite = 0;
158189251Ssam	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
159281806Srpaulo		if (testing_cipher_suite_filter(conn, conn->cipher_suites[i]))
160281806Srpaulo			continue;
161189251Ssam		c = pos;
162189251Ssam		for (j = 0; j < num_suites; j++) {
163189251Ssam			u16 tmp = WPA_GET_BE16(c);
164189251Ssam			c += 2;
165189251Ssam			if (!cipher_suite && tmp == conn->cipher_suites[i]) {
166189251Ssam				cipher_suite = tmp;
167189251Ssam				break;
168189251Ssam			}
169189251Ssam		}
170189251Ssam	}
171189251Ssam	pos += num_suites * 2;
172189251Ssam	if (!cipher_suite) {
173281806Srpaulo		tlsv1_server_log(conn, "No supported cipher suite available");
174189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
175189251Ssam				   TLS_ALERT_ILLEGAL_PARAMETER);
176189251Ssam		return -1;
177189251Ssam	}
178189251Ssam
179189251Ssam	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
180189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
181189251Ssam			   "record layer");
182189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
183189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
184189251Ssam		return -1;
185189251Ssam	}
186189251Ssam
187189251Ssam	conn->cipher_suite = cipher_suite;
188189251Ssam
189189251Ssam	/* CompressionMethod compression_methods<1..2^8-1> */
190189251Ssam	if (end - pos < 1)
191189251Ssam		goto decode_error;
192189251Ssam	num_suites = *pos++;
193189251Ssam	if (end - pos < num_suites)
194189251Ssam		goto decode_error;
195189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
196189251Ssam		    pos, num_suites);
197189251Ssam	compr_null_found = 0;
198189251Ssam	for (i = 0; i < num_suites; i++) {
199189251Ssam		if (*pos++ == TLS_COMPRESSION_NULL)
200189251Ssam			compr_null_found = 1;
201189251Ssam	}
202189251Ssam	if (!compr_null_found) {
203281806Srpaulo		tlsv1_server_log(conn, "Client does not accept NULL compression");
204189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
205189251Ssam				   TLS_ALERT_ILLEGAL_PARAMETER);
206189251Ssam		return -1;
207189251Ssam	}
208189251Ssam
209189251Ssam	if (end - pos == 1) {
210281806Srpaulo		tlsv1_server_log(conn, "Unexpected extra octet in the end of ClientHello: 0x%02x",
211281806Srpaulo				 *pos);
212189251Ssam		goto decode_error;
213189251Ssam	}
214189251Ssam
215189251Ssam	if (end - pos >= 2) {
216189251Ssam		/* Extension client_hello_extension_list<0..2^16-1> */
217189251Ssam		ext_len = WPA_GET_BE16(pos);
218189251Ssam		pos += 2;
219189251Ssam
220281806Srpaulo		tlsv1_server_log(conn, "%u bytes of ClientHello extensions",
221281806Srpaulo				 ext_len);
222189251Ssam		if (end - pos != ext_len) {
223281806Srpaulo			tlsv1_server_log(conn, "Invalid ClientHello extension list length %u (expected %u)",
224281806Srpaulo					 ext_len, (unsigned int) (end - pos));
225189251Ssam			goto decode_error;
226189251Ssam		}
227189251Ssam
228189251Ssam		/*
229189251Ssam		 * struct {
230189251Ssam		 *   ExtensionType extension_type (0..65535)
231189251Ssam		 *   opaque extension_data<0..2^16-1>
232189251Ssam		 * } Extension;
233189251Ssam		 */
234189251Ssam
235189251Ssam		while (pos < end) {
236189251Ssam			if (end - pos < 2) {
237281806Srpaulo				tlsv1_server_log(conn, "Invalid extension_type field");
238189251Ssam				goto decode_error;
239189251Ssam			}
240189251Ssam
241189251Ssam			ext_type = WPA_GET_BE16(pos);
242189251Ssam			pos += 2;
243189251Ssam
244189251Ssam			if (end - pos < 2) {
245281806Srpaulo				tlsv1_server_log(conn, "Invalid extension_data length field");
246189251Ssam				goto decode_error;
247189251Ssam			}
248189251Ssam
249189251Ssam			ext_len = WPA_GET_BE16(pos);
250189251Ssam			pos += 2;
251189251Ssam
252189251Ssam			if (end - pos < ext_len) {
253281806Srpaulo				tlsv1_server_log(conn, "Invalid extension_data field");
254189251Ssam				goto decode_error;
255189251Ssam			}
256189251Ssam
257281806Srpaulo			tlsv1_server_log(conn, "ClientHello Extension type %u",
258281806Srpaulo					 ext_type);
259189251Ssam			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
260189251Ssam				    "Extension data", pos, ext_len);
261189251Ssam
262189251Ssam			if (ext_type == TLS_EXT_SESSION_TICKET) {
263189251Ssam				os_free(conn->session_ticket);
264189251Ssam				conn->session_ticket = os_malloc(ext_len);
265189251Ssam				if (conn->session_ticket) {
266189251Ssam					os_memcpy(conn->session_ticket, pos,
267189251Ssam						  ext_len);
268189251Ssam					conn->session_ticket_len = ext_len;
269189251Ssam				}
270189251Ssam			}
271189251Ssam
272189251Ssam			pos += ext_len;
273189251Ssam		}
274189251Ssam	}
275189251Ssam
276189251Ssam	*in_len = end - in_data;
277189251Ssam
278281806Srpaulo	tlsv1_server_log(conn, "ClientHello OK - proceed to ServerHello");
279189251Ssam	conn->state = SERVER_HELLO;
280189251Ssam
281189251Ssam	return 0;
282189251Ssam
283189251Ssamdecode_error:
284281806Srpaulo	tlsv1_server_log(conn, "Failed to decode ClientHello");
285189251Ssam	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
286189251Ssam			   TLS_ALERT_DECODE_ERROR);
287189251Ssam	return -1;
288189251Ssam}
289189251Ssam
290189251Ssam
291189251Ssamstatic int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
292189251Ssam				   const u8 *in_data, size_t *in_len)
293189251Ssam{
294189251Ssam	const u8 *pos, *end;
295189251Ssam	size_t left, len, list_len, cert_len, idx;
296189251Ssam	u8 type;
297189251Ssam	struct x509_certificate *chain = NULL, *last = NULL, *cert;
298189251Ssam	int reason;
299189251Ssam
300189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
301281806Srpaulo		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
302281806Srpaulo				 ct);
303189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
304189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
305189251Ssam		return -1;
306189251Ssam	}
307189251Ssam
308189251Ssam	pos = in_data;
309189251Ssam	left = *in_len;
310189251Ssam
311189251Ssam	if (left < 4) {
312281806Srpaulo		tlsv1_server_log(conn, "Too short Certificate message (len=%lu)",
313281806Srpaulo				 (unsigned long) left);
314189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
315189251Ssam				   TLS_ALERT_DECODE_ERROR);
316189251Ssam		return -1;
317189251Ssam	}
318189251Ssam
319189251Ssam	type = *pos++;
320189251Ssam	len = WPA_GET_BE24(pos);
321189251Ssam	pos += 3;
322189251Ssam	left -= 4;
323189251Ssam
324189251Ssam	if (len > left) {
325281806Srpaulo		tlsv1_server_log(conn, "Unexpected Certificate message length (len=%lu != left=%lu)",
326281806Srpaulo				 (unsigned long) len, (unsigned long) left);
327189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
328189251Ssam				   TLS_ALERT_DECODE_ERROR);
329189251Ssam		return -1;
330189251Ssam	}
331189251Ssam
332189251Ssam	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
333189251Ssam		if (conn->verify_peer) {
334281806Srpaulo			tlsv1_server_log(conn, "Client did not include Certificate");
335189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
336189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
337189251Ssam			return -1;
338189251Ssam		}
339189251Ssam
340189251Ssam		return tls_process_client_key_exchange(conn, ct, in_data,
341189251Ssam						       in_len);
342189251Ssam	}
343189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
344281806Srpaulo		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected Certificate/ClientKeyExchange)",
345281806Srpaulo				 type);
346189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
347189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
348189251Ssam		return -1;
349189251Ssam	}
350189251Ssam
351281806Srpaulo	tlsv1_server_log(conn, "Received Certificate (certificate_list len %lu)",
352281806Srpaulo			 (unsigned long) len);
353189251Ssam
354189251Ssam	/*
355189251Ssam	 * opaque ASN.1Cert<2^24-1>;
356189251Ssam	 *
357189251Ssam	 * struct {
358189251Ssam	 *     ASN.1Cert certificate_list<1..2^24-1>;
359189251Ssam	 * } Certificate;
360189251Ssam	 */
361189251Ssam
362189251Ssam	end = pos + len;
363189251Ssam
364189251Ssam	if (end - pos < 3) {
365281806Srpaulo		tlsv1_server_log(conn, "Too short Certificate (left=%lu)",
366281806Srpaulo				 (unsigned long) left);
367189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
368189251Ssam				   TLS_ALERT_DECODE_ERROR);
369189251Ssam		return -1;
370189251Ssam	}
371189251Ssam
372189251Ssam	list_len = WPA_GET_BE24(pos);
373189251Ssam	pos += 3;
374189251Ssam
375189251Ssam	if ((size_t) (end - pos) != list_len) {
376281806Srpaulo		tlsv1_server_log(conn, "Unexpected certificate_list length (len=%lu left=%lu)",
377281806Srpaulo				 (unsigned long) list_len,
378281806Srpaulo				 (unsigned long) (end - pos));
379189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
380189251Ssam				   TLS_ALERT_DECODE_ERROR);
381189251Ssam		return -1;
382189251Ssam	}
383189251Ssam
384189251Ssam	idx = 0;
385189251Ssam	while (pos < end) {
386189251Ssam		if (end - pos < 3) {
387281806Srpaulo			tlsv1_server_log(conn, "Failed to parse certificate_list");
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		cert_len = WPA_GET_BE24(pos);
395189251Ssam		pos += 3;
396189251Ssam
397189251Ssam		if ((size_t) (end - pos) < cert_len) {
398281806Srpaulo			tlsv1_server_log(conn, "Unexpected certificate length (len=%lu left=%lu)",
399281806Srpaulo					 (unsigned long) cert_len,
400281806Srpaulo					 (unsigned long) (end - pos));
401189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
402189251Ssam					   TLS_ALERT_DECODE_ERROR);
403189251Ssam			x509_certificate_chain_free(chain);
404189251Ssam			return -1;
405189251Ssam		}
406189251Ssam
407281806Srpaulo		tlsv1_server_log(conn, "Certificate %lu (len %lu)",
408281806Srpaulo				 (unsigned long) idx, (unsigned long) cert_len);
409189251Ssam
410189251Ssam		if (idx == 0) {
411189251Ssam			crypto_public_key_free(conn->client_rsa_key);
412189251Ssam			if (tls_parse_cert(pos, cert_len,
413189251Ssam					   &conn->client_rsa_key)) {
414281806Srpaulo				tlsv1_server_log(conn, "Failed to parse the certificate");
415189251Ssam				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
416189251Ssam						   TLS_ALERT_BAD_CERTIFICATE);
417189251Ssam				x509_certificate_chain_free(chain);
418189251Ssam				return -1;
419189251Ssam			}
420189251Ssam		}
421189251Ssam
422189251Ssam		cert = x509_certificate_parse(pos, cert_len);
423189251Ssam		if (cert == NULL) {
424281806Srpaulo			tlsv1_server_log(conn, "Failed to parse the certificate");
425189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
426189251Ssam					   TLS_ALERT_BAD_CERTIFICATE);
427189251Ssam			x509_certificate_chain_free(chain);
428189251Ssam			return -1;
429189251Ssam		}
430189251Ssam
431189251Ssam		if (last == NULL)
432189251Ssam			chain = cert;
433189251Ssam		else
434189251Ssam			last->next = cert;
435189251Ssam		last = cert;
436189251Ssam
437189251Ssam		idx++;
438189251Ssam		pos += cert_len;
439189251Ssam	}
440189251Ssam
441189251Ssam	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
442252726Srpaulo					    &reason, 0) < 0) {
443189251Ssam		int tls_reason;
444281806Srpaulo		tlsv1_server_log(conn, "Server certificate chain validation failed (reason=%d)",
445281806Srpaulo				 reason);
446189251Ssam		switch (reason) {
447189251Ssam		case X509_VALIDATE_BAD_CERTIFICATE:
448189251Ssam			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
449189251Ssam			break;
450189251Ssam		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
451189251Ssam			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
452189251Ssam			break;
453189251Ssam		case X509_VALIDATE_CERTIFICATE_REVOKED:
454189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
455189251Ssam			break;
456189251Ssam		case X509_VALIDATE_CERTIFICATE_EXPIRED:
457189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
458189251Ssam			break;
459189251Ssam		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
460189251Ssam			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
461189251Ssam			break;
462189251Ssam		case X509_VALIDATE_UNKNOWN_CA:
463189251Ssam			tls_reason = TLS_ALERT_UNKNOWN_CA;
464189251Ssam			break;
465189251Ssam		default:
466189251Ssam			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
467189251Ssam			break;
468189251Ssam		}
469189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
470189251Ssam		x509_certificate_chain_free(chain);
471189251Ssam		return -1;
472189251Ssam	}
473189251Ssam
474189251Ssam	x509_certificate_chain_free(chain);
475189251Ssam
476189251Ssam	*in_len = end - in_data;
477189251Ssam
478189251Ssam	conn->state = CLIENT_KEY_EXCHANGE;
479189251Ssam
480189251Ssam	return 0;
481189251Ssam}
482189251Ssam
483189251Ssam
484189251Ssamstatic int tls_process_client_key_exchange_rsa(
485189251Ssam	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
486189251Ssam{
487189251Ssam	u8 *out;
488189251Ssam	size_t outlen, outbuflen;
489189251Ssam	u16 encr_len;
490189251Ssam	int res;
491189251Ssam	int use_random = 0;
492189251Ssam
493189251Ssam	if (end - pos < 2) {
494189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
495189251Ssam				   TLS_ALERT_DECODE_ERROR);
496189251Ssam		return -1;
497189251Ssam	}
498189251Ssam
499189251Ssam	encr_len = WPA_GET_BE16(pos);
500189251Ssam	pos += 2;
501252726Srpaulo	if (pos + encr_len > end) {
502281806Srpaulo		tlsv1_server_log(conn, "Invalid ClientKeyExchange format: encr_len=%u left=%u",
503281806Srpaulo				 encr_len, (unsigned int) (end - pos));
504252726Srpaulo		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
505252726Srpaulo				   TLS_ALERT_DECODE_ERROR);
506252726Srpaulo		return -1;
507252726Srpaulo	}
508189251Ssam
509189251Ssam	outbuflen = outlen = end - pos;
510189251Ssam	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
511189251Ssam			outlen : TLS_PRE_MASTER_SECRET_LEN);
512189251Ssam	if (out == NULL) {
513189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
514189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
515189251Ssam		return -1;
516189251Ssam	}
517189251Ssam
518189251Ssam	/*
519189251Ssam	 * struct {
520189251Ssam	 *   ProtocolVersion client_version;
521189251Ssam	 *   opaque random[46];
522189251Ssam	 * } PreMasterSecret;
523189251Ssam	 *
524189251Ssam	 * struct {
525189251Ssam	 *   public-key-encrypted PreMasterSecret pre_master_secret;
526189251Ssam	 * } EncryptedPreMasterSecret;
527189251Ssam	 */
528189251Ssam
529189251Ssam	/*
530189251Ssam	 * Note: To avoid Bleichenbacher attack, we do not report decryption or
531189251Ssam	 * parsing errors from EncryptedPreMasterSecret processing to the
532189251Ssam	 * client. Instead, a random pre-master secret is used to force the
533189251Ssam	 * handshake to fail.
534189251Ssam	 */
535189251Ssam
536189251Ssam	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
537252726Srpaulo						 pos, encr_len,
538189251Ssam						 out, &outlen) < 0) {
539189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
540252726Srpaulo			   "PreMasterSecret (encr_len=%u outlen=%lu)",
541252726Srpaulo			   encr_len, (unsigned long) outlen);
542189251Ssam		use_random = 1;
543189251Ssam	}
544189251Ssam
545252726Srpaulo	if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
546281806Srpaulo		tlsv1_server_log(conn, "Unexpected PreMasterSecret length %lu",
547281806Srpaulo				 (unsigned long) outlen);
548189251Ssam		use_random = 1;
549189251Ssam	}
550189251Ssam
551252726Srpaulo	if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
552281806Srpaulo		tlsv1_server_log(conn, "Client version in ClientKeyExchange does not match with version in ClientHello");
553189251Ssam		use_random = 1;
554189251Ssam	}
555189251Ssam
556189251Ssam	if (use_random) {
557189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
558189251Ssam			   "to avoid revealing information about private key");
559189251Ssam		outlen = TLS_PRE_MASTER_SECRET_LEN;
560189251Ssam		if (os_get_random(out, outlen)) {
561189251Ssam			wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
562189251Ssam				   "data");
563189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
564189251Ssam					   TLS_ALERT_INTERNAL_ERROR);
565189251Ssam			os_free(out);
566189251Ssam			return -1;
567189251Ssam		}
568189251Ssam	}
569189251Ssam
570189251Ssam	res = tlsv1_server_derive_keys(conn, out, outlen);
571189251Ssam
572189251Ssam	/* Clear the pre-master secret since it is not needed anymore */
573189251Ssam	os_memset(out, 0, outbuflen);
574189251Ssam	os_free(out);
575189251Ssam
576189251Ssam	if (res) {
577189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
578189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
579189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
580189251Ssam		return -1;
581189251Ssam	}
582189251Ssam
583189251Ssam	return 0;
584189251Ssam}
585189251Ssam
586189251Ssam
587281806Srpaulostatic int tls_process_client_key_exchange_dh(
588189251Ssam	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
589189251Ssam{
590189251Ssam	const u8 *dh_yc;
591189251Ssam	u16 dh_yc_len;
592189251Ssam	u8 *shared;
593189251Ssam	size_t shared_len;
594189251Ssam	int res;
595281806Srpaulo	const u8 *dh_p;
596281806Srpaulo	size_t dh_p_len;
597189251Ssam
598189251Ssam	/*
599189251Ssam	 * struct {
600189251Ssam	 *   select (PublicValueEncoding) {
601189251Ssam	 *     case implicit: struct { };
602189251Ssam	 *     case explicit: opaque dh_Yc<1..2^16-1>;
603189251Ssam	 *   } dh_public;
604189251Ssam	 * } ClientDiffieHellmanPublic;
605189251Ssam	 */
606189251Ssam
607281806Srpaulo	tlsv1_server_log(conn, "ClientDiffieHellmanPublic received");
608189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
609189251Ssam		    pos, end - pos);
610189251Ssam
611189251Ssam	if (end == pos) {
612189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
613189251Ssam			   "not supported");
614189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
615189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
616189251Ssam		return -1;
617189251Ssam	}
618189251Ssam
619189251Ssam	if (end - pos < 3) {
620281806Srpaulo		tlsv1_server_log(conn, "Invalid client public value length");
621189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
622189251Ssam				   TLS_ALERT_DECODE_ERROR);
623189251Ssam		return -1;
624189251Ssam	}
625189251Ssam
626189251Ssam	dh_yc_len = WPA_GET_BE16(pos);
627189251Ssam	dh_yc = pos + 2;
628189251Ssam
629281806Srpaulo	if (dh_yc_len > end - dh_yc) {
630281806Srpaulo		tlsv1_server_log(conn, "Client public value overflow (length %d)",
631281806Srpaulo				 dh_yc_len);
632189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
633189251Ssam				   TLS_ALERT_DECODE_ERROR);
634189251Ssam		return -1;
635189251Ssam	}
636189251Ssam
637189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
638189251Ssam		    dh_yc, dh_yc_len);
639189251Ssam
640189251Ssam	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
641189251Ssam	    conn->dh_secret == NULL) {
642189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
643189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
644189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
645189251Ssam		return -1;
646189251Ssam	}
647189251Ssam
648281806Srpaulo	tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
649281806Srpaulo
650281806Srpaulo	shared_len = dh_p_len;
651189251Ssam	shared = os_malloc(shared_len);
652189251Ssam	if (shared == NULL) {
653189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
654189251Ssam			   "DH");
655189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
656189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
657189251Ssam		return -1;
658189251Ssam	}
659189251Ssam
660189251Ssam	/* shared = Yc^secret mod p */
661189251Ssam	if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
662281806Srpaulo			   conn->dh_secret_len, dh_p, dh_p_len,
663189251Ssam			   shared, &shared_len)) {
664189251Ssam		os_free(shared);
665189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
666189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
667189251Ssam		return -1;
668189251Ssam	}
669189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
670189251Ssam			shared, shared_len);
671189251Ssam
672189251Ssam	os_memset(conn->dh_secret, 0, conn->dh_secret_len);
673189251Ssam	os_free(conn->dh_secret);
674189251Ssam	conn->dh_secret = NULL;
675189251Ssam
676189251Ssam	res = tlsv1_server_derive_keys(conn, shared, shared_len);
677189251Ssam
678189251Ssam	/* Clear the pre-master secret since it is not needed anymore */
679189251Ssam	os_memset(shared, 0, shared_len);
680189251Ssam	os_free(shared);
681189251Ssam
682189251Ssam	if (res) {
683189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
684189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
685189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
686189251Ssam		return -1;
687189251Ssam	}
688189251Ssam
689189251Ssam	return 0;
690189251Ssam}
691189251Ssam
692189251Ssam
693189251Ssamstatic int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
694189251Ssam					   const u8 *in_data, size_t *in_len)
695189251Ssam{
696189251Ssam	const u8 *pos, *end;
697189251Ssam	size_t left, len;
698189251Ssam	u8 type;
699189251Ssam	tls_key_exchange keyx;
700189251Ssam	const struct tls_cipher_suite *suite;
701189251Ssam
702189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
703281806Srpaulo		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
704281806Srpaulo				 ct);
705189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
706189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
707189251Ssam		return -1;
708189251Ssam	}
709189251Ssam
710189251Ssam	pos = in_data;
711189251Ssam	left = *in_len;
712189251Ssam
713189251Ssam	if (left < 4) {
714281806Srpaulo		tlsv1_server_log(conn, "Too short ClientKeyExchange (Left=%lu)",
715281806Srpaulo				 (unsigned long) left);
716189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
717189251Ssam				   TLS_ALERT_DECODE_ERROR);
718189251Ssam		return -1;
719189251Ssam	}
720189251Ssam
721189251Ssam	type = *pos++;
722189251Ssam	len = WPA_GET_BE24(pos);
723189251Ssam	pos += 3;
724189251Ssam	left -= 4;
725189251Ssam
726189251Ssam	if (len > left) {
727281806Srpaulo		tlsv1_server_log(conn, "Mismatch in ClientKeyExchange length (len=%lu != left=%lu)",
728281806Srpaulo				 (unsigned long) len, (unsigned long) left);
729189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
730189251Ssam				   TLS_ALERT_DECODE_ERROR);
731189251Ssam		return -1;
732189251Ssam	}
733189251Ssam
734189251Ssam	end = pos + len;
735189251Ssam
736189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
737281806Srpaulo		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientKeyExchange)",
738281806Srpaulo				 type);
739189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
740189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
741189251Ssam		return -1;
742189251Ssam	}
743189251Ssam
744281806Srpaulo	tlsv1_server_log(conn, "Received ClientKeyExchange");
745189251Ssam
746189251Ssam	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
747189251Ssam
748189251Ssam	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
749189251Ssam	if (suite == NULL)
750189251Ssam		keyx = TLS_KEY_X_NULL;
751189251Ssam	else
752189251Ssam		keyx = suite->key_exchange;
753189251Ssam
754281806Srpaulo	if ((keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) &&
755281806Srpaulo	    tls_process_client_key_exchange_dh(conn, pos, end) < 0)
756189251Ssam		return -1;
757189251Ssam
758281806Srpaulo	if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA &&
759189251Ssam	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
760189251Ssam		return -1;
761189251Ssam
762189251Ssam	*in_len = end - in_data;
763189251Ssam
764189251Ssam	conn->state = CERTIFICATE_VERIFY;
765189251Ssam
766189251Ssam	return 0;
767189251Ssam}
768189251Ssam
769189251Ssam
770189251Ssamstatic int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
771189251Ssam					  const u8 *in_data, size_t *in_len)
772189251Ssam{
773189251Ssam	const u8 *pos, *end;
774189251Ssam	size_t left, len;
775189251Ssam	u8 type;
776281806Srpaulo	size_t hlen;
777281806Srpaulo	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
778281806Srpaulo	u8 alert;
779189251Ssam
780189251Ssam	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
781189251Ssam		if (conn->verify_peer) {
782281806Srpaulo			tlsv1_server_log(conn, "Client did not include CertificateVerify");
783189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
784189251Ssam					   TLS_ALERT_UNEXPECTED_MESSAGE);
785189251Ssam			return -1;
786189251Ssam		}
787189251Ssam
788189251Ssam		return tls_process_change_cipher_spec(conn, ct, in_data,
789189251Ssam						      in_len);
790189251Ssam	}
791189251Ssam
792189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
793281806Srpaulo		tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
794281806Srpaulo				 ct);
795189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
796189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
797189251Ssam		return -1;
798189251Ssam	}
799189251Ssam
800189251Ssam	pos = in_data;
801189251Ssam	left = *in_len;
802189251Ssam
803189251Ssam	if (left < 4) {
804281806Srpaulo		tlsv1_server_log(conn, "Too short CertificateVerify message (len=%lu)",
805281806Srpaulo				 (unsigned long) left);
806189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
807189251Ssam				   TLS_ALERT_DECODE_ERROR);
808189251Ssam		return -1;
809189251Ssam	}
810189251Ssam
811189251Ssam	type = *pos++;
812189251Ssam	len = WPA_GET_BE24(pos);
813189251Ssam	pos += 3;
814189251Ssam	left -= 4;
815189251Ssam
816189251Ssam	if (len > left) {
817281806Srpaulo		tlsv1_server_log(conn, "Unexpected CertificateVerify message length (len=%lu != left=%lu)",
818281806Srpaulo				 (unsigned long) len, (unsigned long) left);
819189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
820189251Ssam				   TLS_ALERT_DECODE_ERROR);
821189251Ssam		return -1;
822189251Ssam	}
823189251Ssam
824189251Ssam	end = pos + len;
825189251Ssam
826189251Ssam	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
827281806Srpaulo		tlsv1_server_log(conn, "Received unexpected handshake message %d (expected CertificateVerify)",
828281806Srpaulo				 type);
829189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
830189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
831189251Ssam		return -1;
832189251Ssam	}
833189251Ssam
834281806Srpaulo	tlsv1_server_log(conn, "Received CertificateVerify");
835189251Ssam
836189251Ssam	/*
837189251Ssam	 * struct {
838189251Ssam	 *   Signature signature;
839189251Ssam	 * } CertificateVerify;
840189251Ssam	 */
841189251Ssam
842189251Ssam	hpos = hash;
843189251Ssam
844252726Srpaulo#ifdef CONFIG_TLSV12
845252726Srpaulo	if (conn->rl.tls_version == TLS_VERSION_1_2) {
846252726Srpaulo		/*
847252726Srpaulo		 * RFC 5246, 4.7:
848252726Srpaulo		 * TLS v1.2 adds explicit indication of the used signature and
849252726Srpaulo		 * hash algorithms.
850252726Srpaulo		 *
851252726Srpaulo		 * struct {
852252726Srpaulo		 *   HashAlgorithm hash;
853252726Srpaulo		 *   SignatureAlgorithm signature;
854252726Srpaulo		 * } SignatureAndHashAlgorithm;
855252726Srpaulo		 */
856252726Srpaulo		if (end - pos < 2) {
857252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
858252726Srpaulo					   TLS_ALERT_DECODE_ERROR);
859252726Srpaulo			return -1;
860252726Srpaulo		}
861252726Srpaulo		if (pos[0] != TLS_HASH_ALG_SHA256 ||
862252726Srpaulo		    pos[1] != TLS_SIGN_ALG_RSA) {
863252726Srpaulo			wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
864252726Srpaulo				   "signature(%u) algorithm",
865252726Srpaulo				   pos[0], pos[1]);
866252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
867252726Srpaulo					   TLS_ALERT_INTERNAL_ERROR);
868252726Srpaulo			return -1;
869252726Srpaulo		}
870252726Srpaulo		pos += 2;
871252726Srpaulo
872252726Srpaulo		hlen = SHA256_MAC_LEN;
873252726Srpaulo		if (conn->verify.sha256_cert == NULL ||
874252726Srpaulo		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
875252726Srpaulo		    0) {
876252726Srpaulo			conn->verify.sha256_cert = NULL;
877252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
878252726Srpaulo					   TLS_ALERT_INTERNAL_ERROR);
879252726Srpaulo			return -1;
880252726Srpaulo		}
881252726Srpaulo		conn->verify.sha256_cert = NULL;
882252726Srpaulo	} else {
883252726Srpaulo#endif /* CONFIG_TLSV12 */
884252726Srpaulo
885281806Srpaulo	hlen = MD5_MAC_LEN;
886281806Srpaulo	if (conn->verify.md5_cert == NULL ||
887281806Srpaulo	    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
888281806Srpaulo		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
889281806Srpaulo				   TLS_ALERT_INTERNAL_ERROR);
890281806Srpaulo		conn->verify.md5_cert = NULL;
891281806Srpaulo		crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
892281806Srpaulo		conn->verify.sha1_cert = NULL;
893281806Srpaulo		return -1;
894281806Srpaulo	}
895281806Srpaulo	hpos += MD5_MAC_LEN;
896189251Ssam
897189251Ssam	conn->verify.md5_cert = NULL;
898189251Ssam	hlen = SHA1_MAC_LEN;
899189251Ssam	if (conn->verify.sha1_cert == NULL ||
900189251Ssam	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
901189251Ssam		conn->verify.sha1_cert = NULL;
902189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
903189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
904189251Ssam		return -1;
905189251Ssam	}
906189251Ssam	conn->verify.sha1_cert = NULL;
907189251Ssam
908281806Srpaulo	hlen += MD5_MAC_LEN;
909189251Ssam
910252726Srpaulo#ifdef CONFIG_TLSV12
911252726Srpaulo	}
912252726Srpaulo#endif /* CONFIG_TLSV12 */
913252726Srpaulo
914189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
915189251Ssam
916281806Srpaulo	if (tls_verify_signature(conn->rl.tls_version, conn->client_rsa_key,
917281806Srpaulo				 hash, hlen, pos, end - pos, &alert) < 0) {
918281806Srpaulo		tlsv1_server_log(conn, "Invalid Signature in CertificateVerify");
919281806Srpaulo		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
920189251Ssam		return -1;
921189251Ssam	}
922189251Ssam
923189251Ssam	*in_len = end - in_data;
924189251Ssam
925189251Ssam	conn->state = CHANGE_CIPHER_SPEC;
926189251Ssam
927189251Ssam	return 0;
928189251Ssam}
929189251Ssam
930189251Ssam
931189251Ssamstatic int tls_process_change_cipher_spec(struct tlsv1_server *conn,
932189251Ssam					  u8 ct, const u8 *in_data,
933189251Ssam					  size_t *in_len)
934189251Ssam{
935189251Ssam	const u8 *pos;
936189251Ssam	size_t left;
937189251Ssam
938189251Ssam	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
939281806Srpaulo		tlsv1_server_log(conn, "Expected ChangeCipherSpec; received content type 0x%x",
940281806Srpaulo				 ct);
941189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
942189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
943189251Ssam		return -1;
944189251Ssam	}
945189251Ssam
946189251Ssam	pos = in_data;
947189251Ssam	left = *in_len;
948189251Ssam
949189251Ssam	if (left < 1) {
950281806Srpaulo		tlsv1_server_log(conn, "Too short ChangeCipherSpec");
951189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
952189251Ssam				   TLS_ALERT_DECODE_ERROR);
953189251Ssam		return -1;
954189251Ssam	}
955189251Ssam
956189251Ssam	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
957281806Srpaulo		tlsv1_server_log(conn, "Expected ChangeCipherSpec; received data 0x%x",
958281806Srpaulo				 *pos);
959189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
960189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
961189251Ssam		return -1;
962189251Ssam	}
963189251Ssam
964281806Srpaulo	tlsv1_server_log(conn, "Received ChangeCipherSpec");
965189251Ssam	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
966189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
967189251Ssam			   "for record layer");
968189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
969189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
970189251Ssam		return -1;
971189251Ssam	}
972189251Ssam
973189251Ssam	*in_len = pos + 1 - in_data;
974189251Ssam
975189251Ssam	conn->state = CLIENT_FINISHED;
976189251Ssam
977189251Ssam	return 0;
978189251Ssam}
979189251Ssam
980189251Ssam
981189251Ssamstatic int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
982189251Ssam				       const u8 *in_data, size_t *in_len)
983189251Ssam{
984189251Ssam	const u8 *pos, *end;
985189251Ssam	size_t left, len, hlen;
986189251Ssam	u8 verify_data[TLS_VERIFY_DATA_LEN];
987189251Ssam	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
988189251Ssam
989281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS
990281806Srpaulo	if ((conn->test_flags &
991281806Srpaulo	     (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
992281806Srpaulo	    !conn->test_failure_reported) {
993281806Srpaulo		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
994281806Srpaulo		conn->test_failure_reported = 1;
995281806Srpaulo	}
996281806Srpaulo
997281806Srpaulo	if ((conn->test_flags & TLS_DHE_PRIME_15) &&
998281806Srpaulo	    !conn->test_failure_reported) {
999281806Srpaulo		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after bogus DHE \"prime\" 15");
1000281806Srpaulo		conn->test_failure_reported = 1;
1001281806Srpaulo	}
1002281806Srpaulo
1003281806Srpaulo	if ((conn->test_flags & TLS_DHE_PRIME_58B) &&
1004281806Srpaulo	    !conn->test_failure_reported) {
1005281806Srpaulo		tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after short 58-bit DHE prime in long container");
1006281806Srpaulo		conn->test_failure_reported = 1;
1007281806Srpaulo	}
1008281806Srpaulo
1009281806Srpaulo	if ((conn->test_flags & TLS_DHE_PRIME_511B) &&
1010281806Srpaulo	    !conn->test_failure_reported) {
1011281806Srpaulo		tlsv1_server_log(conn, "TEST-WARNING: Client Finished received after short 511-bit DHE prime (insecure)");
1012281806Srpaulo		conn->test_failure_reported = 1;
1013281806Srpaulo	}
1014281806Srpaulo
1015281806Srpaulo	if ((conn->test_flags & TLS_DHE_PRIME_767B) &&
1016281806Srpaulo	    !conn->test_failure_reported) {
1017281806Srpaulo		tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after 767-bit DHE prime (relatively insecure)");
1018281806Srpaulo		conn->test_failure_reported = 1;
1019281806Srpaulo	}
1020281806Srpaulo
1021281806Srpaulo	if ((conn->test_flags & TLS_DHE_NON_PRIME) &&
1022281806Srpaulo	    !conn->test_failure_reported) {
1023281806Srpaulo		tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after non-prime claimed as DHE prime");
1024281806Srpaulo		conn->test_failure_reported = 1;
1025281806Srpaulo	}
1026281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */
1027281806Srpaulo
1028189251Ssam	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
1029281806Srpaulo		tlsv1_server_log(conn, "Expected Finished; received content type 0x%x",
1030281806Srpaulo				 ct);
1031189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1032189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
1033189251Ssam		return -1;
1034189251Ssam	}
1035189251Ssam
1036189251Ssam	pos = in_data;
1037189251Ssam	left = *in_len;
1038189251Ssam
1039189251Ssam	if (left < 4) {
1040281806Srpaulo		tlsv1_server_log(conn, "Too short record (left=%lu) forFinished",
1041281806Srpaulo				 (unsigned long) left);
1042189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1043189251Ssam				   TLS_ALERT_DECODE_ERROR);
1044189251Ssam		return -1;
1045189251Ssam	}
1046189251Ssam
1047189251Ssam	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
1048189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
1049189251Ssam			   "type 0x%x", pos[0]);
1050189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1051189251Ssam				   TLS_ALERT_UNEXPECTED_MESSAGE);
1052189251Ssam		return -1;
1053189251Ssam	}
1054189251Ssam
1055189251Ssam	len = WPA_GET_BE24(pos + 1);
1056189251Ssam
1057189251Ssam	pos += 4;
1058189251Ssam	left -= 4;
1059189251Ssam
1060189251Ssam	if (len > left) {
1061281806Srpaulo		tlsv1_server_log(conn, "Too short buffer for Finished (len=%lu > left=%lu)",
1062281806Srpaulo				 (unsigned long) len, (unsigned long) left);
1063189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1064189251Ssam				   TLS_ALERT_DECODE_ERROR);
1065189251Ssam		return -1;
1066189251Ssam	}
1067189251Ssam	end = pos + len;
1068189251Ssam	if (len != TLS_VERIFY_DATA_LEN) {
1069281806Srpaulo		tlsv1_server_log(conn, "Unexpected verify_data length in Finished: %lu (expected %d)",
1070281806Srpaulo				 (unsigned long) len, TLS_VERIFY_DATA_LEN);
1071189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1072189251Ssam				   TLS_ALERT_DECODE_ERROR);
1073189251Ssam		return -1;
1074189251Ssam	}
1075189251Ssam	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
1076189251Ssam		    pos, TLS_VERIFY_DATA_LEN);
1077189251Ssam
1078252726Srpaulo#ifdef CONFIG_TLSV12
1079252726Srpaulo	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
1080252726Srpaulo		hlen = SHA256_MAC_LEN;
1081252726Srpaulo		if (conn->verify.sha256_client == NULL ||
1082252726Srpaulo		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
1083252726Srpaulo		    < 0) {
1084252726Srpaulo			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1085252726Srpaulo					   TLS_ALERT_INTERNAL_ERROR);
1086252726Srpaulo			conn->verify.sha256_client = NULL;
1087252726Srpaulo			return -1;
1088252726Srpaulo		}
1089252726Srpaulo		conn->verify.sha256_client = NULL;
1090252726Srpaulo	} else {
1091252726Srpaulo#endif /* CONFIG_TLSV12 */
1092252726Srpaulo
1093189251Ssam	hlen = MD5_MAC_LEN;
1094189251Ssam	if (conn->verify.md5_client == NULL ||
1095189251Ssam	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
1096189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1097189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1098189251Ssam		conn->verify.md5_client = NULL;
1099189251Ssam		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
1100189251Ssam		conn->verify.sha1_client = NULL;
1101189251Ssam		return -1;
1102189251Ssam	}
1103189251Ssam	conn->verify.md5_client = NULL;
1104189251Ssam	hlen = SHA1_MAC_LEN;
1105189251Ssam	if (conn->verify.sha1_client == NULL ||
1106189251Ssam	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
1107189251Ssam			       &hlen) < 0) {
1108189251Ssam		conn->verify.sha1_client = NULL;
1109189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1110189251Ssam				   TLS_ALERT_INTERNAL_ERROR);
1111189251Ssam		return -1;
1112189251Ssam	}
1113189251Ssam	conn->verify.sha1_client = NULL;
1114252726Srpaulo	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
1115189251Ssam
1116252726Srpaulo#ifdef CONFIG_TLSV12
1117252726Srpaulo	}
1118252726Srpaulo#endif /* CONFIG_TLSV12 */
1119252726Srpaulo
1120252726Srpaulo	if (tls_prf(conn->rl.tls_version,
1121252726Srpaulo		    conn->master_secret, TLS_MASTER_SECRET_LEN,
1122252726Srpaulo		    "client finished", hash, hlen,
1123189251Ssam		    verify_data, TLS_VERIFY_DATA_LEN)) {
1124189251Ssam		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
1125189251Ssam		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1126189251Ssam				   TLS_ALERT_DECRYPT_ERROR);
1127189251Ssam		return -1;
1128189251Ssam	}
1129189251Ssam	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
1130189251Ssam			verify_data, TLS_VERIFY_DATA_LEN);
1131189251Ssam
1132281806Srpaulo	if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
1133281806Srpaulo		tlsv1_server_log(conn, "Mismatch in verify_data");
1134189251Ssam		return -1;
1135189251Ssam	}
1136189251Ssam
1137281806Srpaulo	tlsv1_server_log(conn, "Received Finished");
1138189251Ssam
1139189251Ssam	*in_len = end - in_data;
1140189251Ssam
1141189251Ssam	if (conn->use_session_ticket) {
1142189251Ssam		/* Abbreviated handshake using session ticket; RFC 4507 */
1143281806Srpaulo		tlsv1_server_log(conn, "Abbreviated handshake completed successfully");
1144189251Ssam		conn->state = ESTABLISHED;
1145189251Ssam	} else {
1146189251Ssam		/* Full handshake */
1147189251Ssam		conn->state = SERVER_CHANGE_CIPHER_SPEC;
1148189251Ssam	}
1149189251Ssam
1150189251Ssam	return 0;
1151189251Ssam}
1152189251Ssam
1153189251Ssam
1154189251Ssamint tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
1155189251Ssam				   const u8 *buf, size_t *len)
1156189251Ssam{
1157189251Ssam	if (ct == TLS_CONTENT_TYPE_ALERT) {
1158189251Ssam		if (*len < 2) {
1159281806Srpaulo			tlsv1_server_log(conn, "Alert underflow");
1160189251Ssam			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
1161189251Ssam					   TLS_ALERT_DECODE_ERROR);
1162189251Ssam			return -1;
1163189251Ssam		}
1164281806Srpaulo		tlsv1_server_log(conn, "Received alert %d:%d", buf[0], buf[1]);
1165189251Ssam		*len = 2;
1166189251Ssam		conn->state = FAILED;
1167189251Ssam		return -1;
1168189251Ssam	}
1169189251Ssam
1170189251Ssam	switch (conn->state) {
1171189251Ssam	case CLIENT_HELLO:
1172189251Ssam		if (tls_process_client_hello(conn, ct, buf, len))
1173189251Ssam			return -1;
1174189251Ssam		break;
1175189251Ssam	case CLIENT_CERTIFICATE:
1176189251Ssam		if (tls_process_certificate(conn, ct, buf, len))
1177189251Ssam			return -1;
1178189251Ssam		break;
1179189251Ssam	case CLIENT_KEY_EXCHANGE:
1180189251Ssam		if (tls_process_client_key_exchange(conn, ct, buf, len))
1181189251Ssam			return -1;
1182189251Ssam		break;
1183189251Ssam	case CERTIFICATE_VERIFY:
1184189251Ssam		if (tls_process_certificate_verify(conn, ct, buf, len))
1185189251Ssam			return -1;
1186189251Ssam		break;
1187189251Ssam	case CHANGE_CIPHER_SPEC:
1188189251Ssam		if (tls_process_change_cipher_spec(conn, ct, buf, len))
1189189251Ssam			return -1;
1190189251Ssam		break;
1191189251Ssam	case CLIENT_FINISHED:
1192189251Ssam		if (tls_process_client_finished(conn, ct, buf, len))
1193189251Ssam			return -1;
1194189251Ssam		break;
1195189251Ssam	default:
1196281806Srpaulo		tlsv1_server_log(conn, "Unexpected state %d while processing received message",
1197281806Srpaulo				 conn->state);
1198189251Ssam		return -1;
1199189251Ssam	}
1200189251Ssam
1201189251Ssam	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
1202189251Ssam		tls_verify_hash_add(&conn->verify, buf, *len);
1203189251Ssam
1204189251Ssam	return 0;
1205189251Ssam}
1206