1189251Ssam/* 2189251Ssam * TLSv1 server - read handshake message 3252726Srpaulo * Copyright (c) 2006-2011, 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 30189251Ssamstatic int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, 31189251Ssam const u8 *in_data, size_t *in_len) 32189251Ssam{ 33189251Ssam const u8 *pos, *end, *c; 34189251Ssam size_t left, len, i, j; 35189251Ssam u16 cipher_suite; 36189251Ssam u16 num_suites; 37189251Ssam int compr_null_found; 38209158Srpaulo u16 ext_type, ext_len; 39189251Ssam 40189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 41189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 42189251Ssam "received content type 0x%x", ct); 43189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 44189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 45189251Ssam return -1; 46189251Ssam } 47189251Ssam 48189251Ssam pos = in_data; 49189251Ssam left = *in_len; 50189251Ssam 51189251Ssam if (left < 4) 52189251Ssam goto decode_error; 53189251Ssam 54189251Ssam /* HandshakeType msg_type */ 55189251Ssam if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { 56189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 57189251Ssam "message %d (expected ClientHello)", *pos); 58189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 59189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 60189251Ssam return -1; 61189251Ssam } 62189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello"); 63189251Ssam pos++; 64189251Ssam /* uint24 length */ 65189251Ssam len = WPA_GET_BE24(pos); 66189251Ssam pos += 3; 67189251Ssam left -= 4; 68189251Ssam 69189251Ssam if (len > left) 70189251Ssam goto decode_error; 71189251Ssam 72189251Ssam /* body - ClientHello */ 73189251Ssam 74189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len); 75189251Ssam end = pos + len; 76189251Ssam 77189251Ssam /* ProtocolVersion client_version */ 78189251Ssam if (end - pos < 2) 79189251Ssam goto decode_error; 80189251Ssam conn->client_version = WPA_GET_BE16(pos); 81189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d", 82189251Ssam conn->client_version >> 8, conn->client_version & 0xff); 83252726Srpaulo if (conn->client_version < TLS_VERSION_1) { 84189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " 85252726Srpaulo "ClientHello %u.%u", 86252726Srpaulo conn->client_version >> 8, 87252726Srpaulo conn->client_version & 0xff); 88189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 89189251Ssam TLS_ALERT_PROTOCOL_VERSION); 90189251Ssam return -1; 91189251Ssam } 92189251Ssam pos += 2; 93189251Ssam 94252726Srpaulo if (TLS_VERSION == TLS_VERSION_1) 95252726Srpaulo conn->rl.tls_version = TLS_VERSION_1; 96252726Srpaulo#ifdef CONFIG_TLSV12 97252726Srpaulo else if (conn->client_version >= TLS_VERSION_1_2) 98252726Srpaulo conn->rl.tls_version = TLS_VERSION_1_2; 99252726Srpaulo#endif /* CONFIG_TLSV12 */ 100252726Srpaulo else if (conn->client_version > TLS_VERSION_1_1) 101252726Srpaulo conn->rl.tls_version = TLS_VERSION_1_1; 102252726Srpaulo else 103252726Srpaulo conn->rl.tls_version = conn->client_version; 104252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s", 105252726Srpaulo tls_version_str(conn->rl.tls_version)); 106252726Srpaulo 107189251Ssam /* Random random */ 108189251Ssam if (end - pos < TLS_RANDOM_LEN) 109189251Ssam goto decode_error; 110189251Ssam 111189251Ssam os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN); 112189251Ssam pos += TLS_RANDOM_LEN; 113189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", 114189251Ssam conn->client_random, TLS_RANDOM_LEN); 115189251Ssam 116189251Ssam /* SessionID session_id */ 117189251Ssam if (end - pos < 1) 118189251Ssam goto decode_error; 119189251Ssam if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) 120189251Ssam goto decode_error; 121189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos); 122189251Ssam pos += 1 + *pos; 123189251Ssam /* TODO: add support for session resumption */ 124189251Ssam 125189251Ssam /* CipherSuite cipher_suites<2..2^16-1> */ 126189251Ssam if (end - pos < 2) 127189251Ssam goto decode_error; 128189251Ssam num_suites = WPA_GET_BE16(pos); 129189251Ssam pos += 2; 130189251Ssam if (end - pos < num_suites) 131189251Ssam goto decode_error; 132189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites", 133189251Ssam pos, num_suites); 134189251Ssam if (num_suites & 1) 135189251Ssam goto decode_error; 136189251Ssam num_suites /= 2; 137189251Ssam 138189251Ssam cipher_suite = 0; 139189251Ssam for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) { 140189251Ssam c = pos; 141189251Ssam for (j = 0; j < num_suites; j++) { 142189251Ssam u16 tmp = WPA_GET_BE16(c); 143189251Ssam c += 2; 144189251Ssam if (!cipher_suite && tmp == conn->cipher_suites[i]) { 145189251Ssam cipher_suite = tmp; 146189251Ssam break; 147189251Ssam } 148189251Ssam } 149189251Ssam } 150189251Ssam pos += num_suites * 2; 151189251Ssam if (!cipher_suite) { 152189251Ssam wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite " 153189251Ssam "available"); 154189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 155189251Ssam TLS_ALERT_ILLEGAL_PARAMETER); 156189251Ssam return -1; 157189251Ssam } 158189251Ssam 159189251Ssam if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { 160189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " 161189251Ssam "record layer"); 162189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 163189251Ssam TLS_ALERT_INTERNAL_ERROR); 164189251Ssam return -1; 165189251Ssam } 166189251Ssam 167189251Ssam conn->cipher_suite = cipher_suite; 168189251Ssam 169189251Ssam /* CompressionMethod compression_methods<1..2^8-1> */ 170189251Ssam if (end - pos < 1) 171189251Ssam goto decode_error; 172189251Ssam num_suites = *pos++; 173189251Ssam if (end - pos < num_suites) 174189251Ssam goto decode_error; 175189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods", 176189251Ssam pos, num_suites); 177189251Ssam compr_null_found = 0; 178189251Ssam for (i = 0; i < num_suites; i++) { 179189251Ssam if (*pos++ == TLS_COMPRESSION_NULL) 180189251Ssam compr_null_found = 1; 181189251Ssam } 182189251Ssam if (!compr_null_found) { 183189251Ssam wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL " 184189251Ssam "compression"); 185189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 186189251Ssam TLS_ALERT_ILLEGAL_PARAMETER); 187189251Ssam return -1; 188189251Ssam } 189189251Ssam 190189251Ssam if (end - pos == 1) { 191189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the " 192189251Ssam "end of ClientHello: 0x%02x", *pos); 193189251Ssam goto decode_error; 194189251Ssam } 195189251Ssam 196189251Ssam if (end - pos >= 2) { 197189251Ssam /* Extension client_hello_extension_list<0..2^16-1> */ 198189251Ssam ext_len = WPA_GET_BE16(pos); 199189251Ssam pos += 2; 200189251Ssam 201189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello " 202189251Ssam "extensions", ext_len); 203189251Ssam if (end - pos != ext_len) { 204189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello " 205189251Ssam "extension list length %u (expected %u)", 206209158Srpaulo ext_len, (unsigned int) (end - pos)); 207189251Ssam goto decode_error; 208189251Ssam } 209189251Ssam 210189251Ssam /* 211189251Ssam * struct { 212189251Ssam * ExtensionType extension_type (0..65535) 213189251Ssam * opaque extension_data<0..2^16-1> 214189251Ssam * } Extension; 215189251Ssam */ 216189251Ssam 217189251Ssam while (pos < end) { 218189251Ssam if (end - pos < 2) { 219189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid " 220189251Ssam "extension_type field"); 221189251Ssam goto decode_error; 222189251Ssam } 223189251Ssam 224189251Ssam ext_type = WPA_GET_BE16(pos); 225189251Ssam pos += 2; 226189251Ssam 227189251Ssam if (end - pos < 2) { 228189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid " 229189251Ssam "extension_data length field"); 230189251Ssam goto decode_error; 231189251Ssam } 232189251Ssam 233189251Ssam ext_len = WPA_GET_BE16(pos); 234189251Ssam pos += 2; 235189251Ssam 236189251Ssam if (end - pos < ext_len) { 237189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid " 238189251Ssam "extension_data field"); 239189251Ssam goto decode_error; 240189251Ssam } 241189251Ssam 242189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension " 243189251Ssam "type %u", ext_type); 244189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello " 245189251Ssam "Extension data", pos, ext_len); 246189251Ssam 247189251Ssam if (ext_type == TLS_EXT_SESSION_TICKET) { 248189251Ssam os_free(conn->session_ticket); 249189251Ssam conn->session_ticket = os_malloc(ext_len); 250189251Ssam if (conn->session_ticket) { 251189251Ssam os_memcpy(conn->session_ticket, pos, 252189251Ssam ext_len); 253189251Ssam conn->session_ticket_len = ext_len; 254189251Ssam } 255189251Ssam } 256189251Ssam 257189251Ssam pos += ext_len; 258189251Ssam } 259189251Ssam } 260189251Ssam 261189251Ssam *in_len = end - in_data; 262189251Ssam 263189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to " 264189251Ssam "ServerHello"); 265189251Ssam conn->state = SERVER_HELLO; 266189251Ssam 267189251Ssam return 0; 268189251Ssam 269189251Ssamdecode_error: 270189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello"); 271189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 272189251Ssam TLS_ALERT_DECODE_ERROR); 273189251Ssam return -1; 274189251Ssam} 275189251Ssam 276189251Ssam 277189251Ssamstatic int tls_process_certificate(struct tlsv1_server *conn, u8 ct, 278189251Ssam const u8 *in_data, size_t *in_len) 279189251Ssam{ 280189251Ssam const u8 *pos, *end; 281189251Ssam size_t left, len, list_len, cert_len, idx; 282189251Ssam u8 type; 283189251Ssam struct x509_certificate *chain = NULL, *last = NULL, *cert; 284189251Ssam int reason; 285189251Ssam 286189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 287189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 288189251Ssam "received content type 0x%x", ct); 289189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 290189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 291189251Ssam return -1; 292189251Ssam } 293189251Ssam 294189251Ssam pos = in_data; 295189251Ssam left = *in_len; 296189251Ssam 297189251Ssam if (left < 4) { 298189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " 299189251Ssam "(len=%lu)", (unsigned long) left); 300189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 301189251Ssam TLS_ALERT_DECODE_ERROR); 302189251Ssam return -1; 303189251Ssam } 304189251Ssam 305189251Ssam type = *pos++; 306189251Ssam len = WPA_GET_BE24(pos); 307189251Ssam pos += 3; 308189251Ssam left -= 4; 309189251Ssam 310189251Ssam if (len > left) { 311189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " 312189251Ssam "length (len=%lu != left=%lu)", 313189251Ssam (unsigned long) len, (unsigned long) left); 314189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 315189251Ssam TLS_ALERT_DECODE_ERROR); 316189251Ssam return -1; 317189251Ssam } 318189251Ssam 319189251Ssam if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { 320189251Ssam if (conn->verify_peer) { 321189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " 322189251Ssam "Certificate"); 323189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 324189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 325189251Ssam return -1; 326189251Ssam } 327189251Ssam 328189251Ssam return tls_process_client_key_exchange(conn, ct, in_data, 329189251Ssam in_len); 330189251Ssam } 331189251Ssam if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { 332189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 333189251Ssam "message %d (expected Certificate/" 334189251Ssam "ClientKeyExchange)", type); 335189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 336189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 337189251Ssam return -1; 338189251Ssam } 339189251Ssam 340189251Ssam wpa_printf(MSG_DEBUG, 341189251Ssam "TLSv1: Received Certificate (certificate_list len %lu)", 342189251Ssam (unsigned long) len); 343189251Ssam 344189251Ssam /* 345189251Ssam * opaque ASN.1Cert<2^24-1>; 346189251Ssam * 347189251Ssam * struct { 348189251Ssam * ASN.1Cert certificate_list<1..2^24-1>; 349189251Ssam * } Certificate; 350189251Ssam */ 351189251Ssam 352189251Ssam end = pos + len; 353189251Ssam 354189251Ssam if (end - pos < 3) { 355189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " 356189251Ssam "(left=%lu)", (unsigned long) left); 357189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 358189251Ssam TLS_ALERT_DECODE_ERROR); 359189251Ssam return -1; 360189251Ssam } 361189251Ssam 362189251Ssam list_len = WPA_GET_BE24(pos); 363189251Ssam pos += 3; 364189251Ssam 365189251Ssam if ((size_t) (end - pos) != list_len) { 366189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " 367189251Ssam "length (len=%lu left=%lu)", 368189251Ssam (unsigned long) list_len, 369189251Ssam (unsigned long) (end - pos)); 370189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 371189251Ssam TLS_ALERT_DECODE_ERROR); 372189251Ssam return -1; 373189251Ssam } 374189251Ssam 375189251Ssam idx = 0; 376189251Ssam while (pos < end) { 377189251Ssam if (end - pos < 3) { 378189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " 379189251Ssam "certificate_list"); 380189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 381189251Ssam TLS_ALERT_DECODE_ERROR); 382189251Ssam x509_certificate_chain_free(chain); 383189251Ssam return -1; 384189251Ssam } 385189251Ssam 386189251Ssam cert_len = WPA_GET_BE24(pos); 387189251Ssam pos += 3; 388189251Ssam 389189251Ssam if ((size_t) (end - pos) < cert_len) { 390189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " 391189251Ssam "length (len=%lu left=%lu)", 392189251Ssam (unsigned long) cert_len, 393189251Ssam (unsigned long) (end - pos)); 394189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 395189251Ssam TLS_ALERT_DECODE_ERROR); 396189251Ssam x509_certificate_chain_free(chain); 397189251Ssam return -1; 398189251Ssam } 399189251Ssam 400189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", 401189251Ssam (unsigned long) idx, (unsigned long) cert_len); 402189251Ssam 403189251Ssam if (idx == 0) { 404189251Ssam crypto_public_key_free(conn->client_rsa_key); 405189251Ssam if (tls_parse_cert(pos, cert_len, 406189251Ssam &conn->client_rsa_key)) { 407189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " 408189251Ssam "the certificate"); 409189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 410189251Ssam TLS_ALERT_BAD_CERTIFICATE); 411189251Ssam x509_certificate_chain_free(chain); 412189251Ssam return -1; 413189251Ssam } 414189251Ssam } 415189251Ssam 416189251Ssam cert = x509_certificate_parse(pos, cert_len); 417189251Ssam if (cert == NULL) { 418189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " 419189251Ssam "the certificate"); 420189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 421189251Ssam TLS_ALERT_BAD_CERTIFICATE); 422189251Ssam x509_certificate_chain_free(chain); 423189251Ssam return -1; 424189251Ssam } 425189251Ssam 426189251Ssam if (last == NULL) 427189251Ssam chain = cert; 428189251Ssam else 429189251Ssam last->next = cert; 430189251Ssam last = cert; 431189251Ssam 432189251Ssam idx++; 433189251Ssam pos += cert_len; 434189251Ssam } 435189251Ssam 436189251Ssam if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain, 437252726Srpaulo &reason, 0) < 0) { 438189251Ssam int tls_reason; 439189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " 440189251Ssam "validation failed (reason=%d)", reason); 441189251Ssam switch (reason) { 442189251Ssam case X509_VALIDATE_BAD_CERTIFICATE: 443189251Ssam tls_reason = TLS_ALERT_BAD_CERTIFICATE; 444189251Ssam break; 445189251Ssam case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: 446189251Ssam tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; 447189251Ssam break; 448189251Ssam case X509_VALIDATE_CERTIFICATE_REVOKED: 449189251Ssam tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; 450189251Ssam break; 451189251Ssam case X509_VALIDATE_CERTIFICATE_EXPIRED: 452189251Ssam tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; 453189251Ssam break; 454189251Ssam case X509_VALIDATE_CERTIFICATE_UNKNOWN: 455189251Ssam tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; 456189251Ssam break; 457189251Ssam case X509_VALIDATE_UNKNOWN_CA: 458189251Ssam tls_reason = TLS_ALERT_UNKNOWN_CA; 459189251Ssam break; 460189251Ssam default: 461189251Ssam tls_reason = TLS_ALERT_BAD_CERTIFICATE; 462189251Ssam break; 463189251Ssam } 464189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); 465189251Ssam x509_certificate_chain_free(chain); 466189251Ssam return -1; 467189251Ssam } 468189251Ssam 469189251Ssam x509_certificate_chain_free(chain); 470189251Ssam 471189251Ssam *in_len = end - in_data; 472189251Ssam 473189251Ssam conn->state = CLIENT_KEY_EXCHANGE; 474189251Ssam 475189251Ssam return 0; 476189251Ssam} 477189251Ssam 478189251Ssam 479189251Ssamstatic int tls_process_client_key_exchange_rsa( 480189251Ssam struct tlsv1_server *conn, const u8 *pos, const u8 *end) 481189251Ssam{ 482189251Ssam u8 *out; 483189251Ssam size_t outlen, outbuflen; 484189251Ssam u16 encr_len; 485189251Ssam int res; 486189251Ssam int use_random = 0; 487189251Ssam 488189251Ssam if (end - pos < 2) { 489189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 490189251Ssam TLS_ALERT_DECODE_ERROR); 491189251Ssam return -1; 492189251Ssam } 493189251Ssam 494189251Ssam encr_len = WPA_GET_BE16(pos); 495189251Ssam pos += 2; 496252726Srpaulo if (pos + encr_len > end) { 497252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange " 498252726Srpaulo "format: encr_len=%u left=%u", 499252726Srpaulo encr_len, (unsigned int) (end - pos)); 500252726Srpaulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 501252726Srpaulo TLS_ALERT_DECODE_ERROR); 502252726Srpaulo return -1; 503252726Srpaulo } 504189251Ssam 505189251Ssam outbuflen = outlen = end - pos; 506189251Ssam out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ? 507189251Ssam outlen : TLS_PRE_MASTER_SECRET_LEN); 508189251Ssam if (out == NULL) { 509189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 510189251Ssam TLS_ALERT_INTERNAL_ERROR); 511189251Ssam return -1; 512189251Ssam } 513189251Ssam 514189251Ssam /* 515189251Ssam * struct { 516189251Ssam * ProtocolVersion client_version; 517189251Ssam * opaque random[46]; 518189251Ssam * } PreMasterSecret; 519189251Ssam * 520189251Ssam * struct { 521189251Ssam * public-key-encrypted PreMasterSecret pre_master_secret; 522189251Ssam * } EncryptedPreMasterSecret; 523189251Ssam */ 524189251Ssam 525189251Ssam /* 526189251Ssam * Note: To avoid Bleichenbacher attack, we do not report decryption or 527189251Ssam * parsing errors from EncryptedPreMasterSecret processing to the 528189251Ssam * client. Instead, a random pre-master secret is used to force the 529189251Ssam * handshake to fail. 530189251Ssam */ 531189251Ssam 532189251Ssam if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key, 533252726Srpaulo pos, encr_len, 534189251Ssam out, &outlen) < 0) { 535189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt " 536252726Srpaulo "PreMasterSecret (encr_len=%u outlen=%lu)", 537252726Srpaulo encr_len, (unsigned long) outlen); 538189251Ssam use_random = 1; 539189251Ssam } 540189251Ssam 541252726Srpaulo if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) { 542189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret " 543189251Ssam "length %lu", (unsigned long) outlen); 544189251Ssam use_random = 1; 545189251Ssam } 546189251Ssam 547252726Srpaulo if (!use_random && WPA_GET_BE16(out) != conn->client_version) { 548189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Client version in " 549189251Ssam "ClientKeyExchange does not match with version in " 550189251Ssam "ClientHello"); 551189251Ssam use_random = 1; 552189251Ssam } 553189251Ssam 554189251Ssam if (use_random) { 555189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret " 556189251Ssam "to avoid revealing information about private key"); 557189251Ssam outlen = TLS_PRE_MASTER_SECRET_LEN; 558189251Ssam if (os_get_random(out, outlen)) { 559189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " 560189251Ssam "data"); 561189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 562189251Ssam TLS_ALERT_INTERNAL_ERROR); 563189251Ssam os_free(out); 564189251Ssam return -1; 565189251Ssam } 566189251Ssam } 567189251Ssam 568189251Ssam res = tlsv1_server_derive_keys(conn, out, outlen); 569189251Ssam 570189251Ssam /* Clear the pre-master secret since it is not needed anymore */ 571189251Ssam os_memset(out, 0, outbuflen); 572189251Ssam os_free(out); 573189251Ssam 574189251Ssam if (res) { 575189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); 576189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 577189251Ssam TLS_ALERT_INTERNAL_ERROR); 578189251Ssam return -1; 579189251Ssam } 580189251Ssam 581189251Ssam return 0; 582189251Ssam} 583189251Ssam 584189251Ssam 585189251Ssamstatic int tls_process_client_key_exchange_dh_anon( 586189251Ssam struct tlsv1_server *conn, const u8 *pos, const u8 *end) 587189251Ssam{ 588189251Ssam const u8 *dh_yc; 589189251Ssam u16 dh_yc_len; 590189251Ssam u8 *shared; 591189251Ssam size_t shared_len; 592189251Ssam int res; 593189251Ssam 594189251Ssam /* 595189251Ssam * struct { 596189251Ssam * select (PublicValueEncoding) { 597189251Ssam * case implicit: struct { }; 598189251Ssam * case explicit: opaque dh_Yc<1..2^16-1>; 599189251Ssam * } dh_public; 600189251Ssam * } ClientDiffieHellmanPublic; 601189251Ssam */ 602189251Ssam 603189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic", 604189251Ssam pos, end - pos); 605189251Ssam 606189251Ssam if (end == pos) { 607189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding " 608189251Ssam "not supported"); 609189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 610189251Ssam TLS_ALERT_INTERNAL_ERROR); 611189251Ssam return -1; 612189251Ssam } 613189251Ssam 614189251Ssam if (end - pos < 3) { 615189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value " 616189251Ssam "length"); 617189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 618189251Ssam TLS_ALERT_DECODE_ERROR); 619189251Ssam return -1; 620189251Ssam } 621189251Ssam 622189251Ssam dh_yc_len = WPA_GET_BE16(pos); 623189251Ssam dh_yc = pos + 2; 624189251Ssam 625189251Ssam if (dh_yc + dh_yc_len > end) { 626189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow " 627189251Ssam "(length %d)", dh_yc_len); 628189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 629189251Ssam TLS_ALERT_DECODE_ERROR); 630189251Ssam return -1; 631189251Ssam } 632189251Ssam 633189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", 634189251Ssam dh_yc, dh_yc_len); 635189251Ssam 636189251Ssam if (conn->cred == NULL || conn->cred->dh_p == NULL || 637189251Ssam conn->dh_secret == NULL) { 638189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available"); 639189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 640189251Ssam TLS_ALERT_INTERNAL_ERROR); 641189251Ssam return -1; 642189251Ssam } 643189251Ssam 644189251Ssam shared_len = conn->cred->dh_p_len; 645189251Ssam shared = os_malloc(shared_len); 646189251Ssam if (shared == NULL) { 647189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " 648189251Ssam "DH"); 649189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 650189251Ssam TLS_ALERT_INTERNAL_ERROR); 651189251Ssam return -1; 652189251Ssam } 653189251Ssam 654189251Ssam /* shared = Yc^secret mod p */ 655189251Ssam if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, 656189251Ssam conn->dh_secret_len, 657189251Ssam conn->cred->dh_p, conn->cred->dh_p_len, 658189251Ssam shared, &shared_len)) { 659189251Ssam os_free(shared); 660189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 661189251Ssam TLS_ALERT_INTERNAL_ERROR); 662189251Ssam return -1; 663189251Ssam } 664189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", 665189251Ssam shared, shared_len); 666189251Ssam 667189251Ssam os_memset(conn->dh_secret, 0, conn->dh_secret_len); 668189251Ssam os_free(conn->dh_secret); 669189251Ssam conn->dh_secret = NULL; 670189251Ssam 671189251Ssam res = tlsv1_server_derive_keys(conn, shared, shared_len); 672189251Ssam 673189251Ssam /* Clear the pre-master secret since it is not needed anymore */ 674189251Ssam os_memset(shared, 0, shared_len); 675189251Ssam os_free(shared); 676189251Ssam 677189251Ssam if (res) { 678189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); 679189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 680189251Ssam TLS_ALERT_INTERNAL_ERROR); 681189251Ssam return -1; 682189251Ssam } 683189251Ssam 684189251Ssam return 0; 685189251Ssam} 686189251Ssam 687189251Ssam 688189251Ssamstatic int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, 689189251Ssam const u8 *in_data, size_t *in_len) 690189251Ssam{ 691189251Ssam const u8 *pos, *end; 692189251Ssam size_t left, len; 693189251Ssam u8 type; 694189251Ssam tls_key_exchange keyx; 695189251Ssam const struct tls_cipher_suite *suite; 696189251Ssam 697189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 698189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 699189251Ssam "received content type 0x%x", ct); 700189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 701189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 702189251Ssam return -1; 703189251Ssam } 704189251Ssam 705189251Ssam pos = in_data; 706189251Ssam left = *in_len; 707189251Ssam 708189251Ssam if (left < 4) { 709189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange " 710189251Ssam "(Left=%lu)", (unsigned long) left); 711189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 712189251Ssam TLS_ALERT_DECODE_ERROR); 713189251Ssam return -1; 714189251Ssam } 715189251Ssam 716189251Ssam type = *pos++; 717189251Ssam len = WPA_GET_BE24(pos); 718189251Ssam pos += 3; 719189251Ssam left -= 4; 720189251Ssam 721189251Ssam if (len > left) { 722189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange " 723189251Ssam "length (len=%lu != left=%lu)", 724189251Ssam (unsigned long) len, (unsigned long) left); 725189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 726189251Ssam TLS_ALERT_DECODE_ERROR); 727189251Ssam return -1; 728189251Ssam } 729189251Ssam 730189251Ssam end = pos + len; 731189251Ssam 732189251Ssam if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { 733189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 734189251Ssam "message %d (expected ClientKeyExchange)", type); 735189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 736189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 737189251Ssam return -1; 738189251Ssam } 739189251Ssam 740189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange"); 741189251Ssam 742189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len); 743189251Ssam 744189251Ssam suite = tls_get_cipher_suite(conn->rl.cipher_suite); 745189251Ssam if (suite == NULL) 746189251Ssam keyx = TLS_KEY_X_NULL; 747189251Ssam else 748189251Ssam keyx = suite->key_exchange; 749189251Ssam 750189251Ssam if (keyx == TLS_KEY_X_DH_anon && 751189251Ssam tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0) 752189251Ssam return -1; 753189251Ssam 754189251Ssam if (keyx != TLS_KEY_X_DH_anon && 755189251Ssam tls_process_client_key_exchange_rsa(conn, pos, end) < 0) 756189251Ssam return -1; 757189251Ssam 758189251Ssam *in_len = end - in_data; 759189251Ssam 760189251Ssam conn->state = CERTIFICATE_VERIFY; 761189251Ssam 762189251Ssam return 0; 763189251Ssam} 764189251Ssam 765189251Ssam 766189251Ssamstatic int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, 767189251Ssam const u8 *in_data, size_t *in_len) 768189251Ssam{ 769189251Ssam const u8 *pos, *end; 770189251Ssam size_t left, len; 771189251Ssam u8 type; 772189251Ssam size_t hlen, buflen; 773189251Ssam u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf; 774189251Ssam enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; 775189251Ssam u16 slen; 776189251Ssam 777189251Ssam if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { 778189251Ssam if (conn->verify_peer) { 779189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " 780189251Ssam "CertificateVerify"); 781189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 782189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 783189251Ssam return -1; 784189251Ssam } 785189251Ssam 786189251Ssam return tls_process_change_cipher_spec(conn, ct, in_data, 787189251Ssam in_len); 788189251Ssam } 789189251Ssam 790189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 791189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 792189251Ssam "received content type 0x%x", ct); 793189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 794189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 795189251Ssam return -1; 796189251Ssam } 797189251Ssam 798189251Ssam pos = in_data; 799189251Ssam left = *in_len; 800189251Ssam 801189251Ssam if (left < 4) { 802189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify " 803189251Ssam "message (len=%lu)", (unsigned long) left); 804189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 805189251Ssam TLS_ALERT_DECODE_ERROR); 806189251Ssam return -1; 807189251Ssam } 808189251Ssam 809189251Ssam type = *pos++; 810189251Ssam len = WPA_GET_BE24(pos); 811189251Ssam pos += 3; 812189251Ssam left -= 4; 813189251Ssam 814189251Ssam if (len > left) { 815189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify " 816189251Ssam "message length (len=%lu != left=%lu)", 817189251Ssam (unsigned long) len, (unsigned long) left); 818189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 819189251Ssam TLS_ALERT_DECODE_ERROR); 820189251Ssam return -1; 821189251Ssam } 822189251Ssam 823189251Ssam end = pos + len; 824189251Ssam 825189251Ssam if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) { 826189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 827189251Ssam "message %d (expected CertificateVerify)", type); 828189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 829189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 830189251Ssam return -1; 831189251Ssam } 832189251Ssam 833189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify"); 834189251Ssam 835189251Ssam /* 836189251Ssam * struct { 837189251Ssam * Signature signature; 838189251Ssam * } CertificateVerify; 839189251Ssam */ 840189251Ssam 841189251Ssam hpos = hash; 842189251Ssam 843252726Srpaulo#ifdef CONFIG_TLSV12 844252726Srpaulo if (conn->rl.tls_version == TLS_VERSION_1_2) { 845252726Srpaulo /* 846252726Srpaulo * RFC 5246, 4.7: 847252726Srpaulo * TLS v1.2 adds explicit indication of the used signature and 848252726Srpaulo * hash algorithms. 849252726Srpaulo * 850252726Srpaulo * struct { 851252726Srpaulo * HashAlgorithm hash; 852252726Srpaulo * SignatureAlgorithm signature; 853252726Srpaulo * } SignatureAndHashAlgorithm; 854252726Srpaulo */ 855252726Srpaulo if (end - pos < 2) { 856252726Srpaulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 857252726Srpaulo TLS_ALERT_DECODE_ERROR); 858252726Srpaulo return -1; 859252726Srpaulo } 860252726Srpaulo if (pos[0] != TLS_HASH_ALG_SHA256 || 861252726Srpaulo pos[1] != TLS_SIGN_ALG_RSA) { 862252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/" 863252726Srpaulo "signature(%u) algorithm", 864252726Srpaulo pos[0], pos[1]); 865252726Srpaulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 866252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 867252726Srpaulo return -1; 868252726Srpaulo } 869252726Srpaulo pos += 2; 870252726Srpaulo 871252726Srpaulo hlen = SHA256_MAC_LEN; 872252726Srpaulo if (conn->verify.sha256_cert == NULL || 873252726Srpaulo crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < 874252726Srpaulo 0) { 875252726Srpaulo conn->verify.sha256_cert = NULL; 876252726Srpaulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 877252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 878252726Srpaulo return -1; 879252726Srpaulo } 880252726Srpaulo conn->verify.sha256_cert = NULL; 881252726Srpaulo } else { 882252726Srpaulo#endif /* CONFIG_TLSV12 */ 883252726Srpaulo 884189251Ssam if (alg == SIGN_ALG_RSA) { 885189251Ssam hlen = MD5_MAC_LEN; 886189251Ssam if (conn->verify.md5_cert == NULL || 887189251Ssam crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) 888189251Ssam { 889189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 890189251Ssam TLS_ALERT_INTERNAL_ERROR); 891189251Ssam conn->verify.md5_cert = NULL; 892189251Ssam crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); 893189251Ssam conn->verify.sha1_cert = NULL; 894189251Ssam return -1; 895189251Ssam } 896189251Ssam hpos += MD5_MAC_LEN; 897189251Ssam } else 898189251Ssam crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); 899189251Ssam 900189251Ssam conn->verify.md5_cert = NULL; 901189251Ssam hlen = SHA1_MAC_LEN; 902189251Ssam if (conn->verify.sha1_cert == NULL || 903189251Ssam crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { 904189251Ssam conn->verify.sha1_cert = NULL; 905189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 906189251Ssam TLS_ALERT_INTERNAL_ERROR); 907189251Ssam return -1; 908189251Ssam } 909189251Ssam conn->verify.sha1_cert = NULL; 910189251Ssam 911189251Ssam if (alg == SIGN_ALG_RSA) 912189251Ssam hlen += MD5_MAC_LEN; 913189251Ssam 914252726Srpaulo#ifdef CONFIG_TLSV12 915252726Srpaulo } 916252726Srpaulo#endif /* CONFIG_TLSV12 */ 917252726Srpaulo 918189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); 919189251Ssam 920189251Ssam if (end - pos < 2) { 921189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 922189251Ssam TLS_ALERT_DECODE_ERROR); 923189251Ssam return -1; 924189251Ssam } 925189251Ssam slen = WPA_GET_BE16(pos); 926189251Ssam pos += 2; 927189251Ssam if (end - pos < slen) { 928189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 929189251Ssam TLS_ALERT_DECODE_ERROR); 930189251Ssam return -1; 931189251Ssam } 932189251Ssam 933189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos); 934189251Ssam if (conn->client_rsa_key == NULL) { 935189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify " 936189251Ssam "signature"); 937189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 938189251Ssam TLS_ALERT_INTERNAL_ERROR); 939189251Ssam return -1; 940189251Ssam } 941189251Ssam 942189251Ssam buflen = end - pos; 943189251Ssam buf = os_malloc(end - pos); 944189251Ssam if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key, 945189251Ssam pos, end - pos, buf, &buflen) < 0) 946189251Ssam { 947189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature"); 948189251Ssam os_free(buf); 949189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 950189251Ssam TLS_ALERT_DECRYPT_ERROR); 951189251Ssam return -1; 952189251Ssam } 953189251Ssam 954189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature", 955189251Ssam buf, buflen); 956189251Ssam 957252726Srpaulo#ifdef CONFIG_TLSV12 958252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 959252726Srpaulo /* 960252726Srpaulo * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 961252726Srpaulo * 962252726Srpaulo * DigestInfo ::= SEQUENCE { 963252726Srpaulo * digestAlgorithm DigestAlgorithm, 964252726Srpaulo * digest OCTET STRING 965252726Srpaulo * } 966252726Srpaulo * 967252726Srpaulo * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} 968252726Srpaulo * 969252726Srpaulo * DER encoded DigestInfo for SHA256 per RFC 3447: 970252726Srpaulo * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || 971252726Srpaulo * H 972252726Srpaulo */ 973252726Srpaulo if (buflen >= 19 + 32 && 974252726Srpaulo os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01" 975252726Srpaulo "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0) 976252726Srpaulo { 977252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = " 978252726Srpaulo "SHA-256"); 979252726Srpaulo os_memmove(buf, buf + 19, buflen - 19); 980252726Srpaulo buflen -= 19; 981252726Srpaulo } else { 982252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized " 983252726Srpaulo "DigestInfo"); 984252726Srpaulo os_free(buf); 985252726Srpaulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 986252726Srpaulo TLS_ALERT_DECRYPT_ERROR); 987252726Srpaulo return -1; 988252726Srpaulo } 989252726Srpaulo } 990252726Srpaulo#endif /* CONFIG_TLSV12 */ 991252726Srpaulo 992189251Ssam if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) { 993189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in " 994189251Ssam "CertificateVerify - did not match with calculated " 995189251Ssam "hash"); 996189251Ssam os_free(buf); 997189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 998189251Ssam TLS_ALERT_DECRYPT_ERROR); 999189251Ssam return -1; 1000189251Ssam } 1001189251Ssam 1002189251Ssam os_free(buf); 1003189251Ssam 1004189251Ssam *in_len = end - in_data; 1005189251Ssam 1006189251Ssam conn->state = CHANGE_CIPHER_SPEC; 1007189251Ssam 1008189251Ssam return 0; 1009189251Ssam} 1010189251Ssam 1011189251Ssam 1012189251Ssamstatic int tls_process_change_cipher_spec(struct tlsv1_server *conn, 1013189251Ssam u8 ct, const u8 *in_data, 1014189251Ssam size_t *in_len) 1015189251Ssam{ 1016189251Ssam const u8 *pos; 1017189251Ssam size_t left; 1018189251Ssam 1019189251Ssam if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { 1020189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " 1021189251Ssam "received content type 0x%x", ct); 1022189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1023189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 1024189251Ssam return -1; 1025189251Ssam } 1026189251Ssam 1027189251Ssam pos = in_data; 1028189251Ssam left = *in_len; 1029189251Ssam 1030189251Ssam if (left < 1) { 1031189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); 1032189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1033189251Ssam TLS_ALERT_DECODE_ERROR); 1034189251Ssam return -1; 1035189251Ssam } 1036189251Ssam 1037189251Ssam if (*pos != TLS_CHANGE_CIPHER_SPEC) { 1038189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " 1039189251Ssam "received data 0x%x", *pos); 1040189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1041189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 1042189251Ssam return -1; 1043189251Ssam } 1044189251Ssam 1045189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); 1046189251Ssam if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { 1047189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " 1048189251Ssam "for record layer"); 1049189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1050189251Ssam TLS_ALERT_INTERNAL_ERROR); 1051189251Ssam return -1; 1052189251Ssam } 1053189251Ssam 1054189251Ssam *in_len = pos + 1 - in_data; 1055189251Ssam 1056189251Ssam conn->state = CLIENT_FINISHED; 1057189251Ssam 1058189251Ssam return 0; 1059189251Ssam} 1060189251Ssam 1061189251Ssam 1062189251Ssamstatic int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, 1063189251Ssam const u8 *in_data, size_t *in_len) 1064189251Ssam{ 1065189251Ssam const u8 *pos, *end; 1066189251Ssam size_t left, len, hlen; 1067189251Ssam u8 verify_data[TLS_VERIFY_DATA_LEN]; 1068189251Ssam u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; 1069189251Ssam 1070189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 1071189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " 1072189251Ssam "received content type 0x%x", ct); 1073189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1074189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 1075189251Ssam return -1; 1076189251Ssam } 1077189251Ssam 1078189251Ssam pos = in_data; 1079189251Ssam left = *in_len; 1080189251Ssam 1081189251Ssam if (left < 4) { 1082189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " 1083189251Ssam "Finished", 1084189251Ssam (unsigned long) left); 1085189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1086189251Ssam TLS_ALERT_DECODE_ERROR); 1087189251Ssam return -1; 1088189251Ssam } 1089189251Ssam 1090189251Ssam if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { 1091189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " 1092189251Ssam "type 0x%x", pos[0]); 1093189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1094189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 1095189251Ssam return -1; 1096189251Ssam } 1097189251Ssam 1098189251Ssam len = WPA_GET_BE24(pos + 1); 1099189251Ssam 1100189251Ssam pos += 4; 1101189251Ssam left -= 4; 1102189251Ssam 1103189251Ssam if (len > left) { 1104189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " 1105189251Ssam "(len=%lu > left=%lu)", 1106189251Ssam (unsigned long) len, (unsigned long) left); 1107189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1108189251Ssam TLS_ALERT_DECODE_ERROR); 1109189251Ssam return -1; 1110189251Ssam } 1111189251Ssam end = pos + len; 1112189251Ssam if (len != TLS_VERIFY_DATA_LEN) { 1113189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " 1114189251Ssam "in Finished: %lu (expected %d)", 1115189251Ssam (unsigned long) len, TLS_VERIFY_DATA_LEN); 1116189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1117189251Ssam TLS_ALERT_DECODE_ERROR); 1118189251Ssam return -1; 1119189251Ssam } 1120189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", 1121189251Ssam pos, TLS_VERIFY_DATA_LEN); 1122189251Ssam 1123252726Srpaulo#ifdef CONFIG_TLSV12 1124252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 1125252726Srpaulo hlen = SHA256_MAC_LEN; 1126252726Srpaulo if (conn->verify.sha256_client == NULL || 1127252726Srpaulo crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) 1128252726Srpaulo < 0) { 1129252726Srpaulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1130252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 1131252726Srpaulo conn->verify.sha256_client = NULL; 1132252726Srpaulo return -1; 1133252726Srpaulo } 1134252726Srpaulo conn->verify.sha256_client = NULL; 1135252726Srpaulo } else { 1136252726Srpaulo#endif /* CONFIG_TLSV12 */ 1137252726Srpaulo 1138189251Ssam hlen = MD5_MAC_LEN; 1139189251Ssam if (conn->verify.md5_client == NULL || 1140189251Ssam crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { 1141189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1142189251Ssam TLS_ALERT_INTERNAL_ERROR); 1143189251Ssam conn->verify.md5_client = NULL; 1144189251Ssam crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); 1145189251Ssam conn->verify.sha1_client = NULL; 1146189251Ssam return -1; 1147189251Ssam } 1148189251Ssam conn->verify.md5_client = NULL; 1149189251Ssam hlen = SHA1_MAC_LEN; 1150189251Ssam if (conn->verify.sha1_client == NULL || 1151189251Ssam crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, 1152189251Ssam &hlen) < 0) { 1153189251Ssam conn->verify.sha1_client = NULL; 1154189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1155189251Ssam TLS_ALERT_INTERNAL_ERROR); 1156189251Ssam return -1; 1157189251Ssam } 1158189251Ssam conn->verify.sha1_client = NULL; 1159252726Srpaulo hlen = MD5_MAC_LEN + SHA1_MAC_LEN; 1160189251Ssam 1161252726Srpaulo#ifdef CONFIG_TLSV12 1162252726Srpaulo } 1163252726Srpaulo#endif /* CONFIG_TLSV12 */ 1164252726Srpaulo 1165252726Srpaulo if (tls_prf(conn->rl.tls_version, 1166252726Srpaulo conn->master_secret, TLS_MASTER_SECRET_LEN, 1167252726Srpaulo "client finished", hash, hlen, 1168189251Ssam verify_data, TLS_VERIFY_DATA_LEN)) { 1169189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); 1170189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1171189251Ssam TLS_ALERT_DECRYPT_ERROR); 1172189251Ssam return -1; 1173189251Ssam } 1174189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", 1175189251Ssam verify_data, TLS_VERIFY_DATA_LEN); 1176189251Ssam 1177189251Ssam if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { 1178189251Ssam wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); 1179189251Ssam return -1; 1180189251Ssam } 1181189251Ssam 1182189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); 1183189251Ssam 1184189251Ssam *in_len = end - in_data; 1185189251Ssam 1186189251Ssam if (conn->use_session_ticket) { 1187189251Ssam /* Abbreviated handshake using session ticket; RFC 4507 */ 1188189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed " 1189189251Ssam "successfully"); 1190189251Ssam conn->state = ESTABLISHED; 1191189251Ssam } else { 1192189251Ssam /* Full handshake */ 1193189251Ssam conn->state = SERVER_CHANGE_CIPHER_SPEC; 1194189251Ssam } 1195189251Ssam 1196189251Ssam return 0; 1197189251Ssam} 1198189251Ssam 1199189251Ssam 1200189251Ssamint tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, 1201189251Ssam const u8 *buf, size_t *len) 1202189251Ssam{ 1203189251Ssam if (ct == TLS_CONTENT_TYPE_ALERT) { 1204189251Ssam if (*len < 2) { 1205189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); 1206189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 1207189251Ssam TLS_ALERT_DECODE_ERROR); 1208189251Ssam return -1; 1209189251Ssam } 1210189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", 1211189251Ssam buf[0], buf[1]); 1212189251Ssam *len = 2; 1213189251Ssam conn->state = FAILED; 1214189251Ssam return -1; 1215189251Ssam } 1216189251Ssam 1217189251Ssam switch (conn->state) { 1218189251Ssam case CLIENT_HELLO: 1219189251Ssam if (tls_process_client_hello(conn, ct, buf, len)) 1220189251Ssam return -1; 1221189251Ssam break; 1222189251Ssam case CLIENT_CERTIFICATE: 1223189251Ssam if (tls_process_certificate(conn, ct, buf, len)) 1224189251Ssam return -1; 1225189251Ssam break; 1226189251Ssam case CLIENT_KEY_EXCHANGE: 1227189251Ssam if (tls_process_client_key_exchange(conn, ct, buf, len)) 1228189251Ssam return -1; 1229189251Ssam break; 1230189251Ssam case CERTIFICATE_VERIFY: 1231189251Ssam if (tls_process_certificate_verify(conn, ct, buf, len)) 1232189251Ssam return -1; 1233189251Ssam break; 1234189251Ssam case CHANGE_CIPHER_SPEC: 1235189251Ssam if (tls_process_change_cipher_spec(conn, ct, buf, len)) 1236189251Ssam return -1; 1237189251Ssam break; 1238189251Ssam case CLIENT_FINISHED: 1239189251Ssam if (tls_process_client_finished(conn, ct, buf, len)) 1240189251Ssam return -1; 1241189251Ssam break; 1242189251Ssam default: 1243189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " 1244189251Ssam "while processing received message", 1245189251Ssam conn->state); 1246189251Ssam return -1; 1247189251Ssam } 1248189251Ssam 1249189251Ssam if (ct == TLS_CONTENT_TYPE_HANDSHAKE) 1250189251Ssam tls_verify_hash_add(&conn->verify, buf, *len); 1251189251Ssam 1252189251Ssam return 0; 1253189251Ssam} 1254