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