1189251Ssam/* 2189251Ssam * TLSv1 server - write handshake message 3189251Ssam * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18214734Srpaulo#include "crypto/md5.h" 19214734Srpaulo#include "crypto/sha1.h" 20214734Srpaulo#include "crypto/tls.h" 21189251Ssam#include "x509v3.h" 22189251Ssam#include "tlsv1_common.h" 23189251Ssam#include "tlsv1_record.h" 24189251Ssam#include "tlsv1_server.h" 25189251Ssam#include "tlsv1_server_i.h" 26189251Ssam 27189251Ssam 28189251Ssamstatic size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) 29189251Ssam{ 30189251Ssam size_t len = 0; 31189251Ssam struct x509_certificate *cert; 32189251Ssam 33189251Ssam cert = conn->cred->cert; 34189251Ssam while (cert) { 35189251Ssam len += 3 + cert->cert_len; 36189251Ssam if (x509_certificate_self_signed(cert)) 37189251Ssam break; 38189251Ssam cert = x509_certificate_get_subject(conn->cred->trusted_certs, 39189251Ssam &cert->issuer); 40189251Ssam } 41189251Ssam 42189251Ssam return len; 43189251Ssam} 44189251Ssam 45189251Ssam 46189251Ssamstatic int tls_write_server_hello(struct tlsv1_server *conn, 47189251Ssam u8 **msgpos, u8 *end) 48189251Ssam{ 49189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length; 50189251Ssam struct os_time now; 51189251Ssam size_t rlen; 52189251Ssam 53189251Ssam pos = *msgpos; 54189251Ssam 55189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello"); 56189251Ssam rhdr = pos; 57189251Ssam pos += TLS_RECORD_HEADER_LEN; 58189251Ssam 59189251Ssam os_get_time(&now); 60189251Ssam WPA_PUT_BE32(conn->server_random, now.sec); 61189251Ssam if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) { 62189251Ssam wpa_printf(MSG_ERROR, "TLSv1: Could not generate " 63189251Ssam "server_random"); 64189251Ssam return -1; 65189251Ssam } 66189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", 67189251Ssam conn->server_random, TLS_RANDOM_LEN); 68189251Ssam 69189251Ssam conn->session_id_len = TLS_SESSION_ID_MAX_LEN; 70189251Ssam if (os_get_random(conn->session_id, conn->session_id_len)) { 71189251Ssam wpa_printf(MSG_ERROR, "TLSv1: Could not generate " 72189251Ssam "session_id"); 73189251Ssam return -1; 74189251Ssam } 75189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", 76189251Ssam conn->session_id, conn->session_id_len); 77189251Ssam 78189251Ssam /* opaque fragment[TLSPlaintext.length] */ 79189251Ssam 80189251Ssam /* Handshake */ 81189251Ssam hs_start = pos; 82189251Ssam /* HandshakeType msg_type */ 83189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO; 84189251Ssam /* uint24 length (to be filled) */ 85189251Ssam hs_length = pos; 86189251Ssam pos += 3; 87189251Ssam /* body - ServerHello */ 88189251Ssam /* ProtocolVersion server_version */ 89189251Ssam WPA_PUT_BE16(pos, TLS_VERSION); 90189251Ssam pos += 2; 91189251Ssam /* Random random: uint32 gmt_unix_time, opaque random_bytes */ 92189251Ssam os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN); 93189251Ssam pos += TLS_RANDOM_LEN; 94189251Ssam /* SessionID session_id */ 95189251Ssam *pos++ = conn->session_id_len; 96189251Ssam os_memcpy(pos, conn->session_id, conn->session_id_len); 97189251Ssam pos += conn->session_id_len; 98189251Ssam /* CipherSuite cipher_suite */ 99189251Ssam WPA_PUT_BE16(pos, conn->cipher_suite); 100189251Ssam pos += 2; 101189251Ssam /* CompressionMethod compression_method */ 102189251Ssam *pos++ = TLS_COMPRESSION_NULL; 103189251Ssam 104189251Ssam if (conn->session_ticket && conn->session_ticket_cb) { 105189251Ssam int res = conn->session_ticket_cb( 106189251Ssam conn->session_ticket_cb_ctx, 107189251Ssam conn->session_ticket, conn->session_ticket_len, 108189251Ssam conn->client_random, conn->server_random, 109189251Ssam conn->master_secret); 110189251Ssam if (res < 0) { 111189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " 112189251Ssam "indicated failure"); 113189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 114189251Ssam TLS_ALERT_HANDSHAKE_FAILURE); 115189251Ssam return -1; 116189251Ssam } 117189251Ssam conn->use_session_ticket = res; 118189251Ssam 119189251Ssam if (conn->use_session_ticket) { 120189251Ssam if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) { 121189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to " 122189251Ssam "derive keys"); 123189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 124189251Ssam TLS_ALERT_INTERNAL_ERROR); 125189251Ssam return -1; 126189251Ssam } 127189251Ssam } 128189251Ssam 129189251Ssam /* 130189251Ssam * RFC 4507 specifies that server would include an empty 131189251Ssam * SessionTicket extension in ServerHello and a 132189251Ssam * NewSessionTicket message after the ServerHello. However, 133189251Ssam * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket 134189251Ssam * extension at the moment, does not use such extensions. 135189251Ssam * 136189251Ssam * TODO: Add support for configuring RFC 4507 behavior and make 137189251Ssam * EAP-FAST disable it. 138189251Ssam */ 139189251Ssam } 140189251Ssam 141189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 142189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 143189251Ssam 144189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 145189251Ssam rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { 146189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); 147189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 148189251Ssam TLS_ALERT_INTERNAL_ERROR); 149189251Ssam return -1; 150189251Ssam } 151189251Ssam pos = rhdr + rlen; 152189251Ssam 153189251Ssam *msgpos = pos; 154189251Ssam 155189251Ssam return 0; 156189251Ssam} 157189251Ssam 158189251Ssam 159189251Ssamstatic int tls_write_server_certificate(struct tlsv1_server *conn, 160189251Ssam u8 **msgpos, u8 *end) 161189251Ssam{ 162189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; 163189251Ssam size_t rlen; 164189251Ssam struct x509_certificate *cert; 165189251Ssam const struct tls_cipher_suite *suite; 166189251Ssam 167189251Ssam suite = tls_get_cipher_suite(conn->rl.cipher_suite); 168189251Ssam if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { 169189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when " 170189251Ssam "using anonymous DH"); 171189251Ssam return 0; 172189251Ssam } 173189251Ssam 174189251Ssam pos = *msgpos; 175189251Ssam 176189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); 177189251Ssam rhdr = pos; 178189251Ssam pos += TLS_RECORD_HEADER_LEN; 179189251Ssam 180189251Ssam /* opaque fragment[TLSPlaintext.length] */ 181189251Ssam 182189251Ssam /* Handshake */ 183189251Ssam hs_start = pos; 184189251Ssam /* HandshakeType msg_type */ 185189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; 186189251Ssam /* uint24 length (to be filled) */ 187189251Ssam hs_length = pos; 188189251Ssam pos += 3; 189189251Ssam /* body - Certificate */ 190189251Ssam /* uint24 length (to be filled) */ 191189251Ssam cert_start = pos; 192189251Ssam pos += 3; 193189251Ssam cert = conn->cred->cert; 194189251Ssam while (cert) { 195189251Ssam if (pos + 3 + cert->cert_len > end) { 196189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " 197189251Ssam "for Certificate (cert_len=%lu left=%lu)", 198189251Ssam (unsigned long) cert->cert_len, 199189251Ssam (unsigned long) (end - pos)); 200189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 201189251Ssam TLS_ALERT_INTERNAL_ERROR); 202189251Ssam return -1; 203189251Ssam } 204189251Ssam WPA_PUT_BE24(pos, cert->cert_len); 205189251Ssam pos += 3; 206189251Ssam os_memcpy(pos, cert->cert_start, cert->cert_len); 207189251Ssam pos += cert->cert_len; 208189251Ssam 209189251Ssam if (x509_certificate_self_signed(cert)) 210189251Ssam break; 211189251Ssam cert = x509_certificate_get_subject(conn->cred->trusted_certs, 212189251Ssam &cert->issuer); 213189251Ssam } 214189251Ssam if (cert == conn->cred->cert || cert == NULL) { 215189251Ssam /* 216189251Ssam * Server was not configured with all the needed certificates 217189251Ssam * to form a full certificate chain. The client may fail to 218189251Ssam * validate the chain unless it is configured with all the 219189251Ssam * missing CA certificates. 220189251Ssam */ 221189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain " 222189251Ssam "not configured - validation may fail"); 223189251Ssam } 224189251Ssam WPA_PUT_BE24(cert_start, pos - cert_start - 3); 225189251Ssam 226189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 227189251Ssam 228189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 229189251Ssam rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { 230189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 231189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 232189251Ssam TLS_ALERT_INTERNAL_ERROR); 233189251Ssam return -1; 234189251Ssam } 235189251Ssam pos = rhdr + rlen; 236189251Ssam 237189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 238189251Ssam 239189251Ssam *msgpos = pos; 240189251Ssam 241189251Ssam return 0; 242189251Ssam} 243189251Ssam 244189251Ssam 245189251Ssamstatic int tls_write_server_key_exchange(struct tlsv1_server *conn, 246189251Ssam u8 **msgpos, u8 *end) 247189251Ssam{ 248189251Ssam tls_key_exchange keyx; 249189251Ssam const struct tls_cipher_suite *suite; 250189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length; 251189251Ssam size_t rlen; 252189251Ssam u8 *dh_ys; 253189251Ssam size_t dh_ys_len; 254189251Ssam 255189251Ssam suite = tls_get_cipher_suite(conn->rl.cipher_suite); 256189251Ssam if (suite == NULL) 257189251Ssam keyx = TLS_KEY_X_NULL; 258189251Ssam else 259189251Ssam keyx = suite->key_exchange; 260189251Ssam 261189251Ssam if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { 262189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); 263189251Ssam return 0; 264189251Ssam } 265189251Ssam 266189251Ssam if (keyx != TLS_KEY_X_DH_anon) { 267189251Ssam /* TODO? */ 268189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " 269189251Ssam "supported with key exchange type %d", keyx); 270189251Ssam return -1; 271189251Ssam } 272189251Ssam 273189251Ssam if (conn->cred == NULL || conn->cred->dh_p == NULL || 274189251Ssam conn->cred->dh_g == NULL) { 275189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " 276189251Ssam "ServerKeyExhcange"); 277189251Ssam return -1; 278189251Ssam } 279189251Ssam 280189251Ssam os_free(conn->dh_secret); 281189251Ssam conn->dh_secret_len = conn->cred->dh_p_len; 282189251Ssam conn->dh_secret = os_malloc(conn->dh_secret_len); 283189251Ssam if (conn->dh_secret == NULL) { 284189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " 285189251Ssam "memory for secret (Diffie-Hellman)"); 286189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 287189251Ssam TLS_ALERT_INTERNAL_ERROR); 288189251Ssam return -1; 289189251Ssam } 290189251Ssam if (os_get_random(conn->dh_secret, conn->dh_secret_len)) { 291189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " 292189251Ssam "data for Diffie-Hellman"); 293189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 294189251Ssam TLS_ALERT_INTERNAL_ERROR); 295189251Ssam os_free(conn->dh_secret); 296189251Ssam conn->dh_secret = NULL; 297189251Ssam return -1; 298189251Ssam } 299189251Ssam 300189251Ssam if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > 301189251Ssam 0) 302189251Ssam conn->dh_secret[0] = 0; /* make sure secret < p */ 303189251Ssam 304189251Ssam pos = conn->dh_secret; 305189251Ssam while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) 306189251Ssam pos++; 307189251Ssam if (pos != conn->dh_secret) { 308189251Ssam os_memmove(conn->dh_secret, pos, 309189251Ssam conn->dh_secret_len - (pos - conn->dh_secret)); 310189251Ssam conn->dh_secret_len -= pos - conn->dh_secret; 311189251Ssam } 312189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", 313189251Ssam conn->dh_secret, conn->dh_secret_len); 314189251Ssam 315189251Ssam /* Ys = g^secret mod p */ 316189251Ssam dh_ys_len = conn->cred->dh_p_len; 317189251Ssam dh_ys = os_malloc(dh_ys_len); 318189251Ssam if (dh_ys == NULL) { 319189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " 320189251Ssam "Diffie-Hellman"); 321189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 322189251Ssam TLS_ALERT_INTERNAL_ERROR); 323189251Ssam return -1; 324189251Ssam } 325189251Ssam if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, 326189251Ssam conn->dh_secret, conn->dh_secret_len, 327189251Ssam conn->cred->dh_p, conn->cred->dh_p_len, 328189251Ssam dh_ys, &dh_ys_len)) { 329189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 330189251Ssam TLS_ALERT_INTERNAL_ERROR); 331189251Ssam os_free(dh_ys); 332189251Ssam return -1; 333189251Ssam } 334189251Ssam 335189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", 336189251Ssam dh_ys, dh_ys_len); 337189251Ssam 338189251Ssam /* 339189251Ssam * struct { 340189251Ssam * select (KeyExchangeAlgorithm) { 341189251Ssam * case diffie_hellman: 342189251Ssam * ServerDHParams params; 343189251Ssam * Signature signed_params; 344189251Ssam * case rsa: 345189251Ssam * ServerRSAParams params; 346189251Ssam * Signature signed_params; 347189251Ssam * }; 348189251Ssam * } ServerKeyExchange; 349189251Ssam * 350189251Ssam * struct { 351189251Ssam * opaque dh_p<1..2^16-1>; 352189251Ssam * opaque dh_g<1..2^16-1>; 353189251Ssam * opaque dh_Ys<1..2^16-1>; 354189251Ssam * } ServerDHParams; 355189251Ssam */ 356189251Ssam 357189251Ssam pos = *msgpos; 358189251Ssam 359189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); 360189251Ssam rhdr = pos; 361189251Ssam pos += TLS_RECORD_HEADER_LEN; 362189251Ssam 363189251Ssam /* opaque fragment[TLSPlaintext.length] */ 364189251Ssam 365189251Ssam /* Handshake */ 366189251Ssam hs_start = pos; 367189251Ssam /* HandshakeType msg_type */ 368189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; 369189251Ssam /* uint24 length (to be filled) */ 370189251Ssam hs_length = pos; 371189251Ssam pos += 3; 372189251Ssam 373189251Ssam /* body - ServerDHParams */ 374189251Ssam /* dh_p */ 375189251Ssam if (pos + 2 + conn->cred->dh_p_len > end) { 376189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " 377189251Ssam "dh_p"); 378189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 379189251Ssam TLS_ALERT_INTERNAL_ERROR); 380189251Ssam os_free(dh_ys); 381189251Ssam return -1; 382189251Ssam } 383189251Ssam WPA_PUT_BE16(pos, conn->cred->dh_p_len); 384189251Ssam pos += 2; 385189251Ssam os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); 386189251Ssam pos += conn->cred->dh_p_len; 387189251Ssam 388189251Ssam /* dh_g */ 389189251Ssam if (pos + 2 + conn->cred->dh_g_len > end) { 390189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " 391189251Ssam "dh_g"); 392189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 393189251Ssam TLS_ALERT_INTERNAL_ERROR); 394189251Ssam os_free(dh_ys); 395189251Ssam return -1; 396189251Ssam } 397189251Ssam WPA_PUT_BE16(pos, conn->cred->dh_g_len); 398189251Ssam pos += 2; 399189251Ssam os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); 400189251Ssam pos += conn->cred->dh_g_len; 401189251Ssam 402189251Ssam /* dh_Ys */ 403189251Ssam if (pos + 2 + dh_ys_len > end) { 404189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " 405189251Ssam "dh_Ys"); 406189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 407189251Ssam TLS_ALERT_INTERNAL_ERROR); 408189251Ssam os_free(dh_ys); 409189251Ssam return -1; 410189251Ssam } 411189251Ssam WPA_PUT_BE16(pos, dh_ys_len); 412189251Ssam pos += 2; 413189251Ssam os_memcpy(pos, dh_ys, dh_ys_len); 414189251Ssam pos += dh_ys_len; 415189251Ssam os_free(dh_ys); 416189251Ssam 417189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 418189251Ssam 419189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 420189251Ssam rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { 421189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 422189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 423189251Ssam TLS_ALERT_INTERNAL_ERROR); 424189251Ssam return -1; 425189251Ssam } 426189251Ssam pos = rhdr + rlen; 427189251Ssam 428189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 429189251Ssam 430189251Ssam *msgpos = pos; 431189251Ssam 432189251Ssam return 0; 433189251Ssam} 434189251Ssam 435189251Ssam 436189251Ssamstatic int tls_write_server_certificate_request(struct tlsv1_server *conn, 437189251Ssam u8 **msgpos, u8 *end) 438189251Ssam{ 439189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length; 440189251Ssam size_t rlen; 441189251Ssam 442189251Ssam if (!conn->verify_peer) { 443189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed"); 444189251Ssam return 0; 445189251Ssam } 446189251Ssam 447189251Ssam pos = *msgpos; 448189251Ssam 449189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest"); 450189251Ssam rhdr = pos; 451189251Ssam pos += TLS_RECORD_HEADER_LEN; 452189251Ssam 453189251Ssam /* opaque fragment[TLSPlaintext.length] */ 454189251Ssam 455189251Ssam /* Handshake */ 456189251Ssam hs_start = pos; 457189251Ssam /* HandshakeType msg_type */ 458189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST; 459189251Ssam /* uint24 length (to be filled) */ 460189251Ssam hs_length = pos; 461189251Ssam pos += 3; 462189251Ssam /* body - CertificateRequest */ 463189251Ssam 464189251Ssam /* 465189251Ssam * enum { 466189251Ssam * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), 467189251Ssam * (255) 468189251Ssam * } ClientCertificateType; 469189251Ssam * ClientCertificateType certificate_types<1..2^8-1> 470189251Ssam */ 471189251Ssam *pos++ = 1; 472189251Ssam *pos++ = 1; /* rsa_sign */ 473189251Ssam 474189251Ssam /* 475189251Ssam * opaque DistinguishedName<1..2^16-1> 476189251Ssam * DistinguishedName certificate_authorities<3..2^16-1> 477189251Ssam */ 478189251Ssam /* TODO: add support for listing DNs for trusted CAs */ 479189251Ssam WPA_PUT_BE16(pos, 0); 480189251Ssam pos += 2; 481189251Ssam 482189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 483189251Ssam 484189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 485189251Ssam rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { 486189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 487189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 488189251Ssam TLS_ALERT_INTERNAL_ERROR); 489189251Ssam return -1; 490189251Ssam } 491189251Ssam pos = rhdr + rlen; 492189251Ssam 493189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 494189251Ssam 495189251Ssam *msgpos = pos; 496189251Ssam 497189251Ssam return 0; 498189251Ssam} 499189251Ssam 500189251Ssam 501189251Ssamstatic int tls_write_server_hello_done(struct tlsv1_server *conn, 502189251Ssam u8 **msgpos, u8 *end) 503189251Ssam{ 504189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length; 505189251Ssam size_t rlen; 506189251Ssam 507189251Ssam pos = *msgpos; 508189251Ssam 509189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); 510189251Ssam rhdr = pos; 511189251Ssam pos += TLS_RECORD_HEADER_LEN; 512189251Ssam 513189251Ssam /* opaque fragment[TLSPlaintext.length] */ 514189251Ssam 515189251Ssam /* Handshake */ 516189251Ssam hs_start = pos; 517189251Ssam /* HandshakeType msg_type */ 518189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; 519189251Ssam /* uint24 length (to be filled) */ 520189251Ssam hs_length = pos; 521189251Ssam pos += 3; 522189251Ssam /* body - ServerHelloDone (empty) */ 523189251Ssam 524189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 525189251Ssam 526189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 527189251Ssam rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { 528189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 529189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 530189251Ssam TLS_ALERT_INTERNAL_ERROR); 531189251Ssam return -1; 532189251Ssam } 533189251Ssam pos = rhdr + rlen; 534189251Ssam 535189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 536189251Ssam 537189251Ssam *msgpos = pos; 538189251Ssam 539189251Ssam return 0; 540189251Ssam} 541189251Ssam 542189251Ssam 543189251Ssamstatic int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, 544189251Ssam u8 **msgpos, u8 *end) 545189251Ssam{ 546189251Ssam u8 *pos, *rhdr; 547189251Ssam size_t rlen; 548189251Ssam 549189251Ssam pos = *msgpos; 550189251Ssam 551189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); 552189251Ssam rhdr = pos; 553189251Ssam pos += TLS_RECORD_HEADER_LEN; 554189251Ssam *pos = TLS_CHANGE_CIPHER_SPEC; 555189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, 556189251Ssam rhdr, end - rhdr, 1, &rlen) < 0) { 557189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 558189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 559189251Ssam TLS_ALERT_INTERNAL_ERROR); 560189251Ssam return -1; 561189251Ssam } 562189251Ssam 563189251Ssam if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { 564189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " 565189251Ssam "record layer"); 566189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 567189251Ssam TLS_ALERT_INTERNAL_ERROR); 568189251Ssam return -1; 569189251Ssam } 570189251Ssam 571189251Ssam *msgpos = rhdr + rlen; 572189251Ssam 573189251Ssam return 0; 574189251Ssam} 575189251Ssam 576189251Ssam 577189251Ssamstatic int tls_write_server_finished(struct tlsv1_server *conn, 578189251Ssam u8 **msgpos, u8 *end) 579189251Ssam{ 580189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length; 581189251Ssam size_t rlen, hlen; 582189251Ssam u8 verify_data[TLS_VERIFY_DATA_LEN]; 583189251Ssam u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; 584189251Ssam 585189251Ssam pos = *msgpos; 586189251Ssam 587189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); 588189251Ssam 589189251Ssam /* Encrypted Handshake Message: Finished */ 590189251Ssam 591189251Ssam hlen = MD5_MAC_LEN; 592189251Ssam if (conn->verify.md5_server == NULL || 593189251Ssam crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { 594189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 595189251Ssam TLS_ALERT_INTERNAL_ERROR); 596189251Ssam conn->verify.md5_server = NULL; 597189251Ssam crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); 598189251Ssam conn->verify.sha1_server = NULL; 599189251Ssam return -1; 600189251Ssam } 601189251Ssam conn->verify.md5_server = NULL; 602189251Ssam hlen = SHA1_MAC_LEN; 603189251Ssam if (conn->verify.sha1_server == NULL || 604189251Ssam crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, 605189251Ssam &hlen) < 0) { 606189251Ssam conn->verify.sha1_server = NULL; 607189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 608189251Ssam TLS_ALERT_INTERNAL_ERROR); 609189251Ssam return -1; 610189251Ssam } 611189251Ssam conn->verify.sha1_server = NULL; 612189251Ssam 613189251Ssam if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, 614189251Ssam "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, 615189251Ssam verify_data, TLS_VERIFY_DATA_LEN)) { 616189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); 617189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 618189251Ssam TLS_ALERT_INTERNAL_ERROR); 619189251Ssam return -1; 620189251Ssam } 621189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", 622189251Ssam verify_data, TLS_VERIFY_DATA_LEN); 623189251Ssam 624189251Ssam rhdr = pos; 625189251Ssam pos += TLS_RECORD_HEADER_LEN; 626189251Ssam /* Handshake */ 627189251Ssam hs_start = pos; 628189251Ssam /* HandshakeType msg_type */ 629189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; 630189251Ssam /* uint24 length (to be filled) */ 631189251Ssam hs_length = pos; 632189251Ssam pos += 3; 633189251Ssam os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); 634189251Ssam pos += TLS_VERIFY_DATA_LEN; 635189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 636189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 637189251Ssam 638189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 639189251Ssam rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { 640189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 641189251Ssam tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 642189251Ssam TLS_ALERT_INTERNAL_ERROR); 643189251Ssam return -1; 644189251Ssam } 645189251Ssam 646189251Ssam pos = rhdr + rlen; 647189251Ssam 648189251Ssam *msgpos = pos; 649189251Ssam 650189251Ssam return 0; 651189251Ssam} 652189251Ssam 653189251Ssam 654189251Ssamstatic u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) 655189251Ssam{ 656189251Ssam u8 *msg, *end, *pos; 657189251Ssam size_t msglen; 658189251Ssam 659189251Ssam *out_len = 0; 660189251Ssam 661189251Ssam msglen = 1000 + tls_server_cert_chain_der_len(conn); 662189251Ssam 663189251Ssam msg = os_malloc(msglen); 664189251Ssam if (msg == NULL) 665189251Ssam return NULL; 666189251Ssam 667189251Ssam pos = msg; 668189251Ssam end = msg + msglen; 669189251Ssam 670189251Ssam if (tls_write_server_hello(conn, &pos, end) < 0) { 671189251Ssam os_free(msg); 672189251Ssam return NULL; 673189251Ssam } 674189251Ssam 675189251Ssam if (conn->use_session_ticket) { 676189251Ssam /* Abbreviated handshake using session ticket; RFC 4507 */ 677189251Ssam if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || 678189251Ssam tls_write_server_finished(conn, &pos, end) < 0) { 679189251Ssam os_free(msg); 680189251Ssam return NULL; 681189251Ssam } 682189251Ssam 683189251Ssam *out_len = pos - msg; 684189251Ssam 685189251Ssam conn->state = CHANGE_CIPHER_SPEC; 686189251Ssam 687189251Ssam return msg; 688189251Ssam } 689189251Ssam 690189251Ssam /* Full handshake */ 691189251Ssam if (tls_write_server_certificate(conn, &pos, end) < 0 || 692189251Ssam tls_write_server_key_exchange(conn, &pos, end) < 0 || 693189251Ssam tls_write_server_certificate_request(conn, &pos, end) < 0 || 694189251Ssam tls_write_server_hello_done(conn, &pos, end) < 0) { 695189251Ssam os_free(msg); 696189251Ssam return NULL; 697189251Ssam } 698189251Ssam 699189251Ssam *out_len = pos - msg; 700189251Ssam 701189251Ssam conn->state = CLIENT_CERTIFICATE; 702189251Ssam 703189251Ssam return msg; 704189251Ssam} 705189251Ssam 706189251Ssam 707189251Ssamstatic u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn, 708189251Ssam size_t *out_len) 709189251Ssam{ 710189251Ssam u8 *msg, *end, *pos; 711189251Ssam 712189251Ssam *out_len = 0; 713189251Ssam 714189251Ssam msg = os_malloc(1000); 715189251Ssam if (msg == NULL) 716189251Ssam return NULL; 717189251Ssam 718189251Ssam pos = msg; 719189251Ssam end = msg + 1000; 720189251Ssam 721189251Ssam if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || 722189251Ssam tls_write_server_finished(conn, &pos, end) < 0) { 723189251Ssam os_free(msg); 724189251Ssam return NULL; 725189251Ssam } 726189251Ssam 727189251Ssam *out_len = pos - msg; 728189251Ssam 729189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully"); 730189251Ssam conn->state = ESTABLISHED; 731189251Ssam 732189251Ssam return msg; 733189251Ssam} 734189251Ssam 735189251Ssam 736189251Ssamu8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len) 737189251Ssam{ 738189251Ssam switch (conn->state) { 739189251Ssam case SERVER_HELLO: 740189251Ssam return tls_send_server_hello(conn, out_len); 741189251Ssam case SERVER_CHANGE_CIPHER_SPEC: 742189251Ssam return tls_send_change_cipher_spec(conn, out_len); 743189251Ssam default: 744189251Ssam if (conn->state == ESTABLISHED && conn->use_session_ticket) { 745189251Ssam /* Abbreviated handshake was already completed. */ 746189251Ssam return NULL; 747189251Ssam } 748189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " 749189251Ssam "generating reply", conn->state); 750189251Ssam return NULL; 751189251Ssam } 752189251Ssam} 753189251Ssam 754189251Ssam 755189251Ssamu8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, 756189251Ssam u8 description, size_t *out_len) 757189251Ssam{ 758189251Ssam u8 *alert, *pos, *length; 759189251Ssam 760189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); 761189251Ssam *out_len = 0; 762189251Ssam 763189251Ssam alert = os_malloc(10); 764189251Ssam if (alert == NULL) 765189251Ssam return NULL; 766189251Ssam 767189251Ssam pos = alert; 768189251Ssam 769189251Ssam /* TLSPlaintext */ 770189251Ssam /* ContentType type */ 771189251Ssam *pos++ = TLS_CONTENT_TYPE_ALERT; 772189251Ssam /* ProtocolVersion version */ 773189251Ssam WPA_PUT_BE16(pos, TLS_VERSION); 774189251Ssam pos += 2; 775189251Ssam /* uint16 length (to be filled) */ 776189251Ssam length = pos; 777189251Ssam pos += 2; 778189251Ssam /* opaque fragment[TLSPlaintext.length] */ 779189251Ssam 780189251Ssam /* Alert */ 781189251Ssam /* AlertLevel level */ 782189251Ssam *pos++ = level; 783189251Ssam /* AlertDescription description */ 784189251Ssam *pos++ = description; 785189251Ssam 786189251Ssam WPA_PUT_BE16(length, pos - length - 2); 787189251Ssam *out_len = pos - alert; 788189251Ssam 789189251Ssam return alert; 790189251Ssam} 791