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