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