1189251Ssam/* 2189251Ssam * TLSv1 client - 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_client.h" 20189251Ssam#include "tlsv1_client_i.h" 21189251Ssam 22189251Ssamstatic int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, 23189251Ssam const u8 *in_data, size_t *in_len); 24189251Ssamstatic int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, 25189251Ssam const u8 *in_data, size_t *in_len); 26189251Ssamstatic int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, 27189251Ssam const u8 *in_data, size_t *in_len); 28189251Ssam 29189251Ssam 30189251Ssamstatic int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, 31189251Ssam const u8 *in_data, size_t *in_len) 32189251Ssam{ 33189251Ssam const u8 *pos, *end; 34189251Ssam size_t left, len, i; 35189251Ssam u16 cipher_suite; 36252726Srpaulo u16 tls_version; 37189251Ssam 38189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 39189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 40189251Ssam "received content type 0x%x", ct); 41189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 42189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 43189251Ssam return -1; 44189251Ssam } 45189251Ssam 46189251Ssam pos = in_data; 47189251Ssam left = *in_len; 48189251Ssam 49189251Ssam if (left < 4) 50189251Ssam goto decode_error; 51189251Ssam 52189251Ssam /* HandshakeType msg_type */ 53189251Ssam if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) { 54189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 55189251Ssam "message %d (expected ServerHello)", *pos); 56189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 57189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 58189251Ssam return -1; 59189251Ssam } 60189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello"); 61189251Ssam pos++; 62189251Ssam /* uint24 length */ 63189251Ssam len = WPA_GET_BE24(pos); 64189251Ssam pos += 3; 65189251Ssam left -= 4; 66189251Ssam 67189251Ssam if (len > left) 68189251Ssam goto decode_error; 69189251Ssam 70189251Ssam /* body - ServerHello */ 71189251Ssam 72189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len); 73189251Ssam end = pos + len; 74189251Ssam 75189251Ssam /* ProtocolVersion server_version */ 76189251Ssam if (end - pos < 2) 77189251Ssam goto decode_error; 78252726Srpaulo tls_version = WPA_GET_BE16(pos); 79252726Srpaulo if (!tls_version_ok(tls_version)) { 80189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " 81252726Srpaulo "ServerHello %u.%u", pos[0], pos[1]); 82189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 83189251Ssam TLS_ALERT_PROTOCOL_VERSION); 84189251Ssam return -1; 85189251Ssam } 86189251Ssam pos += 2; 87189251Ssam 88252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s", 89252726Srpaulo tls_version_str(tls_version)); 90252726Srpaulo conn->rl.tls_version = tls_version; 91252726Srpaulo 92189251Ssam /* Random random */ 93189251Ssam if (end - pos < TLS_RANDOM_LEN) 94189251Ssam goto decode_error; 95189251Ssam 96189251Ssam os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN); 97189251Ssam pos += TLS_RANDOM_LEN; 98189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", 99189251Ssam conn->server_random, TLS_RANDOM_LEN); 100189251Ssam 101189251Ssam /* SessionID session_id */ 102189251Ssam if (end - pos < 1) 103189251Ssam goto decode_error; 104189251Ssam if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) 105189251Ssam goto decode_error; 106189251Ssam if (conn->session_id_len && conn->session_id_len == *pos && 107189251Ssam os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) { 108189251Ssam pos += 1 + conn->session_id_len; 109189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session"); 110189251Ssam conn->session_resumed = 1; 111189251Ssam } else { 112189251Ssam conn->session_id_len = *pos; 113189251Ssam pos++; 114189251Ssam os_memcpy(conn->session_id, pos, conn->session_id_len); 115189251Ssam pos += conn->session_id_len; 116189251Ssam } 117189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", 118189251Ssam conn->session_id, conn->session_id_len); 119189251Ssam 120189251Ssam /* CipherSuite cipher_suite */ 121189251Ssam if (end - pos < 2) 122189251Ssam goto decode_error; 123189251Ssam cipher_suite = WPA_GET_BE16(pos); 124189251Ssam pos += 2; 125189251Ssam for (i = 0; i < conn->num_cipher_suites; i++) { 126189251Ssam if (cipher_suite == conn->cipher_suites[i]) 127189251Ssam break; 128189251Ssam } 129189251Ssam if (i == conn->num_cipher_suites) { 130189251Ssam wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " 131189251Ssam "cipher suite 0x%04x", cipher_suite); 132189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 133189251Ssam TLS_ALERT_ILLEGAL_PARAMETER); 134189251Ssam return -1; 135189251Ssam } 136189251Ssam 137189251Ssam if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) { 138189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different " 139189251Ssam "cipher suite for a resumed connection (0x%04x != " 140189251Ssam "0x%04x)", cipher_suite, conn->prev_cipher_suite); 141189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 142189251Ssam TLS_ALERT_ILLEGAL_PARAMETER); 143189251Ssam return -1; 144189251Ssam } 145189251Ssam 146189251Ssam if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { 147189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " 148189251Ssam "record layer"); 149189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 150189251Ssam TLS_ALERT_INTERNAL_ERROR); 151189251Ssam return -1; 152189251Ssam } 153189251Ssam 154189251Ssam conn->prev_cipher_suite = cipher_suite; 155189251Ssam 156189251Ssam /* CompressionMethod compression_method */ 157189251Ssam if (end - pos < 1) 158189251Ssam goto decode_error; 159189251Ssam if (*pos != TLS_COMPRESSION_NULL) { 160189251Ssam wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " 161189251Ssam "compression 0x%02x", *pos); 162189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 163189251Ssam TLS_ALERT_ILLEGAL_PARAMETER); 164189251Ssam return -1; 165189251Ssam } 166189251Ssam pos++; 167189251Ssam 168189251Ssam if (end != pos) { 169189251Ssam /* TODO: ServerHello extensions */ 170189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the " 171189251Ssam "end of ServerHello", pos, end - pos); 172189251Ssam goto decode_error; 173189251Ssam } 174189251Ssam 175189251Ssam if (conn->session_ticket_included && conn->session_ticket_cb) { 176189251Ssam /* TODO: include SessionTicket extension if one was included in 177189251Ssam * ServerHello */ 178189251Ssam int res = conn->session_ticket_cb( 179189251Ssam conn->session_ticket_cb_ctx, NULL, 0, 180189251Ssam conn->client_random, conn->server_random, 181189251Ssam conn->master_secret); 182189251Ssam if (res < 0) { 183189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " 184189251Ssam "indicated failure"); 185189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 186189251Ssam TLS_ALERT_HANDSHAKE_FAILURE); 187189251Ssam return -1; 188189251Ssam } 189189251Ssam conn->use_session_ticket = !!res; 190189251Ssam } 191189251Ssam 192189251Ssam if ((conn->session_resumed || conn->use_session_ticket) && 193189251Ssam tls_derive_keys(conn, NULL, 0)) { 194189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); 195189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 196189251Ssam TLS_ALERT_INTERNAL_ERROR); 197189251Ssam return -1; 198189251Ssam } 199189251Ssam 200189251Ssam *in_len = end - in_data; 201189251Ssam 202189251Ssam conn->state = (conn->session_resumed || conn->use_session_ticket) ? 203189251Ssam SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE; 204189251Ssam 205189251Ssam return 0; 206189251Ssam 207189251Ssamdecode_error: 208189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello"); 209189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 210189251Ssam return -1; 211189251Ssam} 212189251Ssam 213189251Ssam 214189251Ssamstatic int tls_process_certificate(struct tlsv1_client *conn, u8 ct, 215189251Ssam const u8 *in_data, size_t *in_len) 216189251Ssam{ 217189251Ssam const u8 *pos, *end; 218189251Ssam size_t left, len, list_len, cert_len, idx; 219189251Ssam u8 type; 220189251Ssam struct x509_certificate *chain = NULL, *last = NULL, *cert; 221189251Ssam int reason; 222189251Ssam 223189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 224189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 225189251Ssam "received content type 0x%x", ct); 226189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 227189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 228189251Ssam return -1; 229189251Ssam } 230189251Ssam 231189251Ssam pos = in_data; 232189251Ssam left = *in_len; 233189251Ssam 234189251Ssam if (left < 4) { 235189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " 236189251Ssam "(len=%lu)", (unsigned long) left); 237189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 238189251Ssam return -1; 239189251Ssam } 240189251Ssam 241189251Ssam type = *pos++; 242189251Ssam len = WPA_GET_BE24(pos); 243189251Ssam pos += 3; 244189251Ssam left -= 4; 245189251Ssam 246189251Ssam if (len > left) { 247189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " 248189251Ssam "length (len=%lu != left=%lu)", 249189251Ssam (unsigned long) len, (unsigned long) left); 250189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 251189251Ssam return -1; 252189251Ssam } 253189251Ssam 254189251Ssam if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) 255189251Ssam return tls_process_server_key_exchange(conn, ct, in_data, 256189251Ssam in_len); 257189251Ssam if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) 258189251Ssam return tls_process_certificate_request(conn, ct, in_data, 259189251Ssam in_len); 260189251Ssam if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) 261189251Ssam return tls_process_server_hello_done(conn, ct, in_data, 262189251Ssam in_len); 263189251Ssam if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { 264189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 265189251Ssam "message %d (expected Certificate/" 266189251Ssam "ServerKeyExchange/CertificateRequest/" 267189251Ssam "ServerHelloDone)", type); 268189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 269189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 270189251Ssam return -1; 271189251Ssam } 272189251Ssam 273189251Ssam wpa_printf(MSG_DEBUG, 274189251Ssam "TLSv1: Received Certificate (certificate_list len %lu)", 275189251Ssam (unsigned long) len); 276189251Ssam 277189251Ssam /* 278189251Ssam * opaque ASN.1Cert<2^24-1>; 279189251Ssam * 280189251Ssam * struct { 281189251Ssam * ASN.1Cert certificate_list<1..2^24-1>; 282189251Ssam * } Certificate; 283189251Ssam */ 284189251Ssam 285189251Ssam end = pos + len; 286189251Ssam 287189251Ssam if (end - pos < 3) { 288189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " 289189251Ssam "(left=%lu)", (unsigned long) left); 290189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 291189251Ssam return -1; 292189251Ssam } 293189251Ssam 294189251Ssam list_len = WPA_GET_BE24(pos); 295189251Ssam pos += 3; 296189251Ssam 297189251Ssam if ((size_t) (end - pos) != list_len) { 298189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " 299189251Ssam "length (len=%lu left=%lu)", 300189251Ssam (unsigned long) list_len, 301189251Ssam (unsigned long) (end - pos)); 302189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 303189251Ssam return -1; 304189251Ssam } 305189251Ssam 306189251Ssam idx = 0; 307189251Ssam while (pos < end) { 308189251Ssam if (end - pos < 3) { 309189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " 310189251Ssam "certificate_list"); 311189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 312189251Ssam TLS_ALERT_DECODE_ERROR); 313189251Ssam x509_certificate_chain_free(chain); 314189251Ssam return -1; 315189251Ssam } 316189251Ssam 317189251Ssam cert_len = WPA_GET_BE24(pos); 318189251Ssam pos += 3; 319189251Ssam 320189251Ssam if ((size_t) (end - pos) < cert_len) { 321189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " 322189251Ssam "length (len=%lu left=%lu)", 323189251Ssam (unsigned long) cert_len, 324189251Ssam (unsigned long) (end - pos)); 325189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 326189251Ssam TLS_ALERT_DECODE_ERROR); 327189251Ssam x509_certificate_chain_free(chain); 328189251Ssam return -1; 329189251Ssam } 330189251Ssam 331189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", 332189251Ssam (unsigned long) idx, (unsigned long) cert_len); 333189251Ssam 334189251Ssam if (idx == 0) { 335189251Ssam crypto_public_key_free(conn->server_rsa_key); 336189251Ssam if (tls_parse_cert(pos, cert_len, 337189251Ssam &conn->server_rsa_key)) { 338189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " 339189251Ssam "the certificate"); 340189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 341189251Ssam TLS_ALERT_BAD_CERTIFICATE); 342189251Ssam x509_certificate_chain_free(chain); 343189251Ssam return -1; 344189251Ssam } 345189251Ssam } 346189251Ssam 347189251Ssam cert = x509_certificate_parse(pos, cert_len); 348189251Ssam if (cert == NULL) { 349189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " 350189251Ssam "the certificate"); 351189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 352189251Ssam TLS_ALERT_BAD_CERTIFICATE); 353189251Ssam x509_certificate_chain_free(chain); 354189251Ssam return -1; 355189251Ssam } 356189251Ssam 357189251Ssam if (last == NULL) 358189251Ssam chain = cert; 359189251Ssam else 360189251Ssam last->next = cert; 361189251Ssam last = cert; 362189251Ssam 363189251Ssam idx++; 364189251Ssam pos += cert_len; 365189251Ssam } 366189251Ssam 367189251Ssam if (conn->cred && 368189251Ssam x509_certificate_chain_validate(conn->cred->trusted_certs, chain, 369252726Srpaulo &reason, conn->disable_time_checks) 370252726Srpaulo < 0) { 371189251Ssam int tls_reason; 372189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " 373189251Ssam "validation failed (reason=%d)", reason); 374189251Ssam switch (reason) { 375189251Ssam case X509_VALIDATE_BAD_CERTIFICATE: 376189251Ssam tls_reason = TLS_ALERT_BAD_CERTIFICATE; 377189251Ssam break; 378189251Ssam case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: 379189251Ssam tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; 380189251Ssam break; 381189251Ssam case X509_VALIDATE_CERTIFICATE_REVOKED: 382189251Ssam tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; 383189251Ssam break; 384189251Ssam case X509_VALIDATE_CERTIFICATE_EXPIRED: 385189251Ssam tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; 386189251Ssam break; 387189251Ssam case X509_VALIDATE_CERTIFICATE_UNKNOWN: 388189251Ssam tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; 389189251Ssam break; 390189251Ssam case X509_VALIDATE_UNKNOWN_CA: 391189251Ssam tls_reason = TLS_ALERT_UNKNOWN_CA; 392189251Ssam break; 393189251Ssam default: 394189251Ssam tls_reason = TLS_ALERT_BAD_CERTIFICATE; 395189251Ssam break; 396189251Ssam } 397189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); 398189251Ssam x509_certificate_chain_free(chain); 399189251Ssam return -1; 400189251Ssam } 401189251Ssam 402189251Ssam x509_certificate_chain_free(chain); 403189251Ssam 404189251Ssam *in_len = end - in_data; 405189251Ssam 406189251Ssam conn->state = SERVER_KEY_EXCHANGE; 407189251Ssam 408189251Ssam return 0; 409189251Ssam} 410189251Ssam 411189251Ssam 412189251Ssamstatic int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, 413189251Ssam const u8 *buf, size_t len) 414189251Ssam{ 415189251Ssam const u8 *pos, *end; 416189251Ssam 417189251Ssam tlsv1_client_free_dh(conn); 418189251Ssam 419189251Ssam pos = buf; 420189251Ssam end = buf + len; 421189251Ssam 422189251Ssam if (end - pos < 3) 423189251Ssam goto fail; 424189251Ssam conn->dh_p_len = WPA_GET_BE16(pos); 425189251Ssam pos += 2; 426189251Ssam if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) { 427189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu", 428189251Ssam (unsigned long) conn->dh_p_len); 429189251Ssam goto fail; 430189251Ssam } 431189251Ssam conn->dh_p = os_malloc(conn->dh_p_len); 432189251Ssam if (conn->dh_p == NULL) 433189251Ssam goto fail; 434189251Ssam os_memcpy(conn->dh_p, pos, conn->dh_p_len); 435189251Ssam pos += conn->dh_p_len; 436189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)", 437189251Ssam conn->dh_p, conn->dh_p_len); 438189251Ssam 439189251Ssam if (end - pos < 3) 440189251Ssam goto fail; 441189251Ssam conn->dh_g_len = WPA_GET_BE16(pos); 442189251Ssam pos += 2; 443189251Ssam if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len) 444189251Ssam goto fail; 445189251Ssam conn->dh_g = os_malloc(conn->dh_g_len); 446189251Ssam if (conn->dh_g == NULL) 447189251Ssam goto fail; 448189251Ssam os_memcpy(conn->dh_g, pos, conn->dh_g_len); 449189251Ssam pos += conn->dh_g_len; 450189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)", 451189251Ssam conn->dh_g, conn->dh_g_len); 452189251Ssam if (conn->dh_g_len == 1 && conn->dh_g[0] < 2) 453189251Ssam goto fail; 454189251Ssam 455189251Ssam if (end - pos < 3) 456189251Ssam goto fail; 457189251Ssam conn->dh_ys_len = WPA_GET_BE16(pos); 458189251Ssam pos += 2; 459189251Ssam if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len) 460189251Ssam goto fail; 461189251Ssam conn->dh_ys = os_malloc(conn->dh_ys_len); 462189251Ssam if (conn->dh_ys == NULL) 463189251Ssam goto fail; 464189251Ssam os_memcpy(conn->dh_ys, pos, conn->dh_ys_len); 465189251Ssam pos += conn->dh_ys_len; 466189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", 467189251Ssam conn->dh_ys, conn->dh_ys_len); 468189251Ssam 469189251Ssam return 0; 470189251Ssam 471189251Ssamfail: 472189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed"); 473189251Ssam tlsv1_client_free_dh(conn); 474189251Ssam return -1; 475189251Ssam} 476189251Ssam 477189251Ssam 478189251Ssamstatic int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, 479189251Ssam const u8 *in_data, size_t *in_len) 480189251Ssam{ 481189251Ssam const u8 *pos, *end; 482189251Ssam size_t left, len; 483189251Ssam u8 type; 484189251Ssam const struct tls_cipher_suite *suite; 485189251Ssam 486189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 487189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 488189251Ssam "received content type 0x%x", ct); 489189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 490189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 491189251Ssam return -1; 492189251Ssam } 493189251Ssam 494189251Ssam pos = in_data; 495189251Ssam left = *in_len; 496189251Ssam 497189251Ssam if (left < 4) { 498189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange " 499189251Ssam "(Left=%lu)", (unsigned long) left); 500189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 501189251Ssam return -1; 502189251Ssam } 503189251Ssam 504189251Ssam type = *pos++; 505189251Ssam len = WPA_GET_BE24(pos); 506189251Ssam pos += 3; 507189251Ssam left -= 4; 508189251Ssam 509189251Ssam if (len > left) { 510189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange " 511189251Ssam "length (len=%lu != left=%lu)", 512189251Ssam (unsigned long) len, (unsigned long) left); 513189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 514189251Ssam return -1; 515189251Ssam } 516189251Ssam 517189251Ssam end = pos + len; 518189251Ssam 519189251Ssam if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) 520189251Ssam return tls_process_certificate_request(conn, ct, in_data, 521189251Ssam in_len); 522189251Ssam if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) 523189251Ssam return tls_process_server_hello_done(conn, ct, in_data, 524189251Ssam in_len); 525189251Ssam if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) { 526189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 527189251Ssam "message %d (expected ServerKeyExchange/" 528189251Ssam "CertificateRequest/ServerHelloDone)", type); 529189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 530189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 531189251Ssam return -1; 532189251Ssam } 533189251Ssam 534189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange"); 535189251Ssam 536189251Ssam if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { 537189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed " 538189251Ssam "with the selected cipher suite"); 539189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 540189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 541189251Ssam return -1; 542189251Ssam } 543189251Ssam 544189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len); 545189251Ssam suite = tls_get_cipher_suite(conn->rl.cipher_suite); 546189251Ssam if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { 547189251Ssam if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) { 548189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 549189251Ssam TLS_ALERT_DECODE_ERROR); 550189251Ssam return -1; 551189251Ssam } 552189251Ssam } else { 553189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange"); 554189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 555189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 556189251Ssam return -1; 557189251Ssam } 558189251Ssam 559189251Ssam *in_len = end - in_data; 560189251Ssam 561189251Ssam conn->state = SERVER_CERTIFICATE_REQUEST; 562189251Ssam 563189251Ssam return 0; 564189251Ssam} 565189251Ssam 566189251Ssam 567189251Ssamstatic int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, 568189251Ssam const u8 *in_data, size_t *in_len) 569189251Ssam{ 570189251Ssam const u8 *pos, *end; 571189251Ssam size_t left, len; 572189251Ssam u8 type; 573189251Ssam 574189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 575189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 576189251Ssam "received content type 0x%x", ct); 577189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 578189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 579189251Ssam return -1; 580189251Ssam } 581189251Ssam 582189251Ssam pos = in_data; 583189251Ssam left = *in_len; 584189251Ssam 585189251Ssam if (left < 4) { 586189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest " 587189251Ssam "(left=%lu)", (unsigned long) left); 588189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 589189251Ssam return -1; 590189251Ssam } 591189251Ssam 592189251Ssam type = *pos++; 593189251Ssam len = WPA_GET_BE24(pos); 594189251Ssam pos += 3; 595189251Ssam left -= 4; 596189251Ssam 597189251Ssam if (len > left) { 598189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest " 599189251Ssam "length (len=%lu != left=%lu)", 600189251Ssam (unsigned long) len, (unsigned long) left); 601189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 602189251Ssam return -1; 603189251Ssam } 604189251Ssam 605189251Ssam end = pos + len; 606189251Ssam 607189251Ssam if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) 608189251Ssam return tls_process_server_hello_done(conn, ct, in_data, 609189251Ssam in_len); 610189251Ssam if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) { 611189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 612189251Ssam "message %d (expected CertificateRequest/" 613189251Ssam "ServerHelloDone)", type); 614189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 615189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 616189251Ssam return -1; 617189251Ssam } 618189251Ssam 619189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest"); 620189251Ssam 621189251Ssam conn->certificate_requested = 1; 622189251Ssam 623189251Ssam *in_len = end - in_data; 624189251Ssam 625189251Ssam conn->state = SERVER_HELLO_DONE; 626189251Ssam 627189251Ssam return 0; 628189251Ssam} 629189251Ssam 630189251Ssam 631189251Ssamstatic int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, 632189251Ssam const u8 *in_data, size_t *in_len) 633189251Ssam{ 634189251Ssam const u8 *pos, *end; 635189251Ssam size_t left, len; 636189251Ssam u8 type; 637189251Ssam 638189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 639189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " 640189251Ssam "received content type 0x%x", ct); 641189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 642189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 643189251Ssam return -1; 644189251Ssam } 645189251Ssam 646189251Ssam pos = in_data; 647189251Ssam left = *in_len; 648189251Ssam 649189251Ssam if (left < 4) { 650189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone " 651189251Ssam "(left=%lu)", (unsigned long) left); 652189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 653189251Ssam return -1; 654189251Ssam } 655189251Ssam 656189251Ssam type = *pos++; 657189251Ssam len = WPA_GET_BE24(pos); 658189251Ssam pos += 3; 659189251Ssam left -= 4; 660189251Ssam 661189251Ssam if (len > left) { 662189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone " 663189251Ssam "length (len=%lu != left=%lu)", 664189251Ssam (unsigned long) len, (unsigned long) left); 665189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 666189251Ssam return -1; 667189251Ssam } 668189251Ssam end = pos + len; 669189251Ssam 670189251Ssam if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) { 671189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " 672189251Ssam "message %d (expected ServerHelloDone)", type); 673189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 674189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 675189251Ssam return -1; 676189251Ssam } 677189251Ssam 678189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone"); 679189251Ssam 680189251Ssam *in_len = end - in_data; 681189251Ssam 682189251Ssam conn->state = CLIENT_KEY_EXCHANGE; 683189251Ssam 684189251Ssam return 0; 685189251Ssam} 686189251Ssam 687189251Ssam 688189251Ssamstatic int tls_process_server_change_cipher_spec(struct tlsv1_client *conn, 689189251Ssam u8 ct, const u8 *in_data, 690189251Ssam size_t *in_len) 691189251Ssam{ 692189251Ssam const u8 *pos; 693189251Ssam size_t left; 694189251Ssam 695189251Ssam if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { 696189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " 697189251Ssam "received content type 0x%x", ct); 698189251Ssam if (conn->use_session_ticket) { 699189251Ssam int res; 700189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Server may have " 701189251Ssam "rejected SessionTicket"); 702189251Ssam conn->use_session_ticket = 0; 703189251Ssam 704189251Ssam /* Notify upper layers that SessionTicket failed */ 705189251Ssam res = conn->session_ticket_cb( 706189251Ssam conn->session_ticket_cb_ctx, NULL, 0, NULL, 707189251Ssam NULL, NULL); 708189251Ssam if (res < 0) { 709189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket " 710189251Ssam "callback indicated failure"); 711189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 712189251Ssam TLS_ALERT_HANDSHAKE_FAILURE); 713189251Ssam return -1; 714189251Ssam } 715189251Ssam 716189251Ssam conn->state = SERVER_CERTIFICATE; 717189251Ssam return tls_process_certificate(conn, ct, in_data, 718189251Ssam in_len); 719189251Ssam } 720189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 721189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 722189251Ssam return -1; 723189251Ssam } 724189251Ssam 725189251Ssam pos = in_data; 726189251Ssam left = *in_len; 727189251Ssam 728189251Ssam if (left < 1) { 729189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); 730189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); 731189251Ssam return -1; 732189251Ssam } 733189251Ssam 734189251Ssam if (*pos != TLS_CHANGE_CIPHER_SPEC) { 735189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " 736189251Ssam "received data 0x%x", *pos); 737189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 738189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 739189251Ssam return -1; 740189251Ssam } 741189251Ssam 742189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); 743189251Ssam if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { 744189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " 745189251Ssam "for record layer"); 746189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 747189251Ssam TLS_ALERT_INTERNAL_ERROR); 748189251Ssam return -1; 749189251Ssam } 750189251Ssam 751189251Ssam *in_len = pos + 1 - in_data; 752189251Ssam 753189251Ssam conn->state = SERVER_FINISHED; 754189251Ssam 755189251Ssam return 0; 756189251Ssam} 757189251Ssam 758189251Ssam 759189251Ssamstatic int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, 760189251Ssam const u8 *in_data, size_t *in_len) 761189251Ssam{ 762189251Ssam const u8 *pos, *end; 763189251Ssam size_t left, len, hlen; 764189251Ssam u8 verify_data[TLS_VERIFY_DATA_LEN]; 765189251Ssam u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; 766189251Ssam 767189251Ssam if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { 768189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " 769189251Ssam "received content type 0x%x", ct); 770189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 771189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 772189251Ssam return -1; 773189251Ssam } 774189251Ssam 775189251Ssam pos = in_data; 776189251Ssam left = *in_len; 777189251Ssam 778189251Ssam if (left < 4) { 779189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " 780189251Ssam "Finished", 781189251Ssam (unsigned long) left); 782189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 783189251Ssam TLS_ALERT_DECODE_ERROR); 784189251Ssam return -1; 785189251Ssam } 786189251Ssam 787189251Ssam if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { 788189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " 789189251Ssam "type 0x%x", pos[0]); 790189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 791189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 792189251Ssam return -1; 793189251Ssam } 794189251Ssam 795189251Ssam len = WPA_GET_BE24(pos + 1); 796189251Ssam 797189251Ssam pos += 4; 798189251Ssam left -= 4; 799189251Ssam 800189251Ssam if (len > left) { 801189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " 802189251Ssam "(len=%lu > left=%lu)", 803189251Ssam (unsigned long) len, (unsigned long) left); 804189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 805189251Ssam TLS_ALERT_DECODE_ERROR); 806189251Ssam return -1; 807189251Ssam } 808189251Ssam end = pos + len; 809189251Ssam if (len != TLS_VERIFY_DATA_LEN) { 810189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " 811189251Ssam "in Finished: %lu (expected %d)", 812189251Ssam (unsigned long) len, TLS_VERIFY_DATA_LEN); 813189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 814189251Ssam TLS_ALERT_DECODE_ERROR); 815189251Ssam return -1; 816189251Ssam } 817189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", 818189251Ssam pos, TLS_VERIFY_DATA_LEN); 819189251Ssam 820252726Srpaulo#ifdef CONFIG_TLSV12 821252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 822252726Srpaulo hlen = SHA256_MAC_LEN; 823252726Srpaulo if (conn->verify.sha256_server == NULL || 824252726Srpaulo crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) 825252726Srpaulo < 0) { 826252726Srpaulo tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 827252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 828252726Srpaulo conn->verify.sha256_server = NULL; 829252726Srpaulo return -1; 830252726Srpaulo } 831252726Srpaulo conn->verify.sha256_server = NULL; 832252726Srpaulo } else { 833252726Srpaulo#endif /* CONFIG_TLSV12 */ 834252726Srpaulo 835189251Ssam hlen = MD5_MAC_LEN; 836189251Ssam if (conn->verify.md5_server == NULL || 837189251Ssam crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { 838189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 839189251Ssam TLS_ALERT_INTERNAL_ERROR); 840189251Ssam conn->verify.md5_server = NULL; 841189251Ssam crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); 842189251Ssam conn->verify.sha1_server = NULL; 843189251Ssam return -1; 844189251Ssam } 845189251Ssam conn->verify.md5_server = NULL; 846189251Ssam hlen = SHA1_MAC_LEN; 847189251Ssam if (conn->verify.sha1_server == NULL || 848189251Ssam crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, 849189251Ssam &hlen) < 0) { 850189251Ssam conn->verify.sha1_server = NULL; 851189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 852189251Ssam TLS_ALERT_INTERNAL_ERROR); 853189251Ssam return -1; 854189251Ssam } 855189251Ssam conn->verify.sha1_server = NULL; 856252726Srpaulo hlen = MD5_MAC_LEN + SHA1_MAC_LEN; 857189251Ssam 858252726Srpaulo#ifdef CONFIG_TLSV12 859252726Srpaulo } 860252726Srpaulo#endif /* CONFIG_TLSV12 */ 861252726Srpaulo 862252726Srpaulo if (tls_prf(conn->rl.tls_version, 863252726Srpaulo conn->master_secret, TLS_MASTER_SECRET_LEN, 864252726Srpaulo "server finished", hash, hlen, 865189251Ssam verify_data, TLS_VERIFY_DATA_LEN)) { 866189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); 867189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 868189251Ssam TLS_ALERT_DECRYPT_ERROR); 869189251Ssam return -1; 870189251Ssam } 871189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", 872189251Ssam verify_data, TLS_VERIFY_DATA_LEN); 873189251Ssam 874189251Ssam if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { 875189251Ssam wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); 876189251Ssam return -1; 877189251Ssam } 878189251Ssam 879189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); 880189251Ssam 881189251Ssam *in_len = end - in_data; 882189251Ssam 883189251Ssam conn->state = (conn->session_resumed || conn->use_session_ticket) ? 884189251Ssam CHANGE_CIPHER_SPEC : ACK_FINISHED; 885189251Ssam 886189251Ssam return 0; 887189251Ssam} 888189251Ssam 889189251Ssam 890189251Ssamstatic int tls_process_application_data(struct tlsv1_client *conn, u8 ct, 891189251Ssam const u8 *in_data, size_t *in_len, 892189251Ssam u8 **out_data, size_t *out_len) 893189251Ssam{ 894189251Ssam const u8 *pos; 895189251Ssam size_t left; 896189251Ssam 897189251Ssam if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { 898189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; " 899189251Ssam "received content type 0x%x", ct); 900189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 901189251Ssam TLS_ALERT_UNEXPECTED_MESSAGE); 902189251Ssam return -1; 903189251Ssam } 904189251Ssam 905189251Ssam pos = in_data; 906189251Ssam left = *in_len; 907189251Ssam 908189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake", 909189251Ssam pos, left); 910189251Ssam 911189251Ssam *out_data = os_malloc(left); 912189251Ssam if (*out_data) { 913189251Ssam os_memcpy(*out_data, pos, left); 914189251Ssam *out_len = left; 915189251Ssam } 916189251Ssam 917189251Ssam return 0; 918189251Ssam} 919189251Ssam 920189251Ssam 921189251Ssamint tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, 922189251Ssam const u8 *buf, size_t *len, 923189251Ssam u8 **out_data, size_t *out_len) 924189251Ssam{ 925189251Ssam if (ct == TLS_CONTENT_TYPE_ALERT) { 926189251Ssam if (*len < 2) { 927189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); 928189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 929189251Ssam TLS_ALERT_DECODE_ERROR); 930189251Ssam return -1; 931189251Ssam } 932189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", 933189251Ssam buf[0], buf[1]); 934189251Ssam *len = 2; 935189251Ssam conn->state = FAILED; 936189251Ssam return -1; 937189251Ssam } 938189251Ssam 939189251Ssam if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 && 940189251Ssam buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) { 941189251Ssam size_t hr_len = WPA_GET_BE24(buf + 1); 942189251Ssam if (hr_len > *len - 4) { 943189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow"); 944189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 945189251Ssam TLS_ALERT_DECODE_ERROR); 946189251Ssam return -1; 947189251Ssam } 948189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest"); 949189251Ssam *len = 4 + hr_len; 950189251Ssam return 0; 951189251Ssam } 952189251Ssam 953189251Ssam switch (conn->state) { 954189251Ssam case SERVER_HELLO: 955189251Ssam if (tls_process_server_hello(conn, ct, buf, len)) 956189251Ssam return -1; 957189251Ssam break; 958189251Ssam case SERVER_CERTIFICATE: 959189251Ssam if (tls_process_certificate(conn, ct, buf, len)) 960189251Ssam return -1; 961189251Ssam break; 962189251Ssam case SERVER_KEY_EXCHANGE: 963189251Ssam if (tls_process_server_key_exchange(conn, ct, buf, len)) 964189251Ssam return -1; 965189251Ssam break; 966189251Ssam case SERVER_CERTIFICATE_REQUEST: 967189251Ssam if (tls_process_certificate_request(conn, ct, buf, len)) 968189251Ssam return -1; 969189251Ssam break; 970189251Ssam case SERVER_HELLO_DONE: 971189251Ssam if (tls_process_server_hello_done(conn, ct, buf, len)) 972189251Ssam return -1; 973189251Ssam break; 974189251Ssam case SERVER_CHANGE_CIPHER_SPEC: 975189251Ssam if (tls_process_server_change_cipher_spec(conn, ct, buf, len)) 976189251Ssam return -1; 977189251Ssam break; 978189251Ssam case SERVER_FINISHED: 979189251Ssam if (tls_process_server_finished(conn, ct, buf, len)) 980189251Ssam return -1; 981189251Ssam break; 982189251Ssam case ACK_FINISHED: 983189251Ssam if (out_data && 984189251Ssam tls_process_application_data(conn, ct, buf, len, out_data, 985189251Ssam out_len)) 986189251Ssam return -1; 987189251Ssam break; 988189251Ssam default: 989189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " 990189251Ssam "while processing received message", 991189251Ssam conn->state); 992189251Ssam return -1; 993189251Ssam } 994189251Ssam 995189251Ssam if (ct == TLS_CONTENT_TYPE_HANDSHAKE) 996189251Ssam tls_verify_hash_add(&conn->verify, buf, *len); 997189251Ssam 998189251Ssam return 0; 999189251Ssam} 1000