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