1189251Ssam/* 2189251Ssam * TLSv1 client - write handshake message 3281806Srpaulo * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/md5.h" 13214734Srpaulo#include "crypto/sha1.h" 14252726Srpaulo#include "crypto/sha256.h" 15214734Srpaulo#include "crypto/tls.h" 16252726Srpaulo#include "crypto/random.h" 17189251Ssam#include "x509v3.h" 18189251Ssam#include "tlsv1_common.h" 19189251Ssam#include "tlsv1_record.h" 20189251Ssam#include "tlsv1_client.h" 21189251Ssam#include "tlsv1_client_i.h" 22189251Ssam 23189251Ssam 24189251Ssamstatic size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn) 25189251Ssam{ 26189251Ssam size_t len = 0; 27189251Ssam struct x509_certificate *cert; 28189251Ssam 29189251Ssam if (conn->cred == NULL) 30189251Ssam return 0; 31189251Ssam 32189251Ssam cert = conn->cred->cert; 33189251Ssam while (cert) { 34189251Ssam len += 3 + cert->cert_len; 35189251Ssam if (x509_certificate_self_signed(cert)) 36189251Ssam break; 37189251Ssam cert = x509_certificate_get_subject(conn->cred->trusted_certs, 38189251Ssam &cert->issuer); 39189251Ssam } 40189251Ssam 41189251Ssam return len; 42189251Ssam} 43189251Ssam 44189251Ssam 45189251Ssamu8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len) 46189251Ssam{ 47189251Ssam u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr; 48189251Ssam struct os_time now; 49189251Ssam size_t len, i; 50189251Ssam 51189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello"); 52189251Ssam *out_len = 0; 53189251Ssam 54189251Ssam os_get_time(&now); 55189251Ssam WPA_PUT_BE32(conn->client_random, now.sec); 56252726Srpaulo if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) { 57189251Ssam wpa_printf(MSG_ERROR, "TLSv1: Could not generate " 58189251Ssam "client_random"); 59189251Ssam return NULL; 60189251Ssam } 61189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", 62189251Ssam conn->client_random, TLS_RANDOM_LEN); 63189251Ssam 64189251Ssam len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len; 65189251Ssam hello = os_malloc(len); 66189251Ssam if (hello == NULL) 67189251Ssam return NULL; 68189251Ssam end = hello + len; 69189251Ssam 70189251Ssam rhdr = hello; 71189251Ssam pos = rhdr + TLS_RECORD_HEADER_LEN; 72189251Ssam 73189251Ssam /* opaque fragment[TLSPlaintext.length] */ 74189251Ssam 75189251Ssam /* Handshake */ 76189251Ssam hs_start = pos; 77189251Ssam /* HandshakeType msg_type */ 78189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO; 79189251Ssam /* uint24 length (to be filled) */ 80189251Ssam hs_length = pos; 81189251Ssam pos += 3; 82189251Ssam /* body - ClientHello */ 83189251Ssam /* ProtocolVersion client_version */ 84189251Ssam WPA_PUT_BE16(pos, TLS_VERSION); 85189251Ssam pos += 2; 86189251Ssam /* Random random: uint32 gmt_unix_time, opaque random_bytes */ 87189251Ssam os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN); 88189251Ssam pos += TLS_RANDOM_LEN; 89189251Ssam /* SessionID session_id */ 90189251Ssam *pos++ = conn->session_id_len; 91189251Ssam os_memcpy(pos, conn->session_id, conn->session_id_len); 92189251Ssam pos += conn->session_id_len; 93189251Ssam /* CipherSuite cipher_suites<2..2^16-1> */ 94189251Ssam WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites); 95189251Ssam pos += 2; 96189251Ssam for (i = 0; i < conn->num_cipher_suites; i++) { 97189251Ssam WPA_PUT_BE16(pos, conn->cipher_suites[i]); 98189251Ssam pos += 2; 99189251Ssam } 100189251Ssam /* CompressionMethod compression_methods<1..2^8-1> */ 101189251Ssam *pos++ = 1; 102189251Ssam *pos++ = TLS_COMPRESSION_NULL; 103189251Ssam 104189251Ssam if (conn->client_hello_ext) { 105189251Ssam os_memcpy(pos, conn->client_hello_ext, 106189251Ssam conn->client_hello_ext_len); 107189251Ssam pos += conn->client_hello_ext_len; 108189251Ssam } 109189251Ssam 110189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 111189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 112189251Ssam 113189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 114252726Srpaulo rhdr, end - rhdr, hs_start, pos - hs_start, 115252726Srpaulo out_len) < 0) { 116189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); 117189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 118189251Ssam TLS_ALERT_INTERNAL_ERROR); 119189251Ssam os_free(hello); 120189251Ssam return NULL; 121189251Ssam } 122189251Ssam 123189251Ssam conn->state = SERVER_HELLO; 124189251Ssam 125189251Ssam return hello; 126189251Ssam} 127189251Ssam 128189251Ssam 129189251Ssamstatic int tls_write_client_certificate(struct tlsv1_client *conn, 130189251Ssam u8 **msgpos, u8 *end) 131189251Ssam{ 132189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; 133189251Ssam size_t rlen; 134189251Ssam struct x509_certificate *cert; 135189251Ssam 136189251Ssam pos = *msgpos; 137189251Ssam 138189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); 139189251Ssam rhdr = pos; 140189251Ssam pos += TLS_RECORD_HEADER_LEN; 141189251Ssam 142189251Ssam /* opaque fragment[TLSPlaintext.length] */ 143189251Ssam 144189251Ssam /* Handshake */ 145189251Ssam hs_start = pos; 146189251Ssam /* HandshakeType msg_type */ 147189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; 148189251Ssam /* uint24 length (to be filled) */ 149189251Ssam hs_length = pos; 150189251Ssam pos += 3; 151189251Ssam /* body - Certificate */ 152189251Ssam /* uint24 length (to be filled) */ 153189251Ssam cert_start = pos; 154189251Ssam pos += 3; 155189251Ssam cert = conn->cred ? conn->cred->cert : NULL; 156189251Ssam while (cert) { 157189251Ssam if (pos + 3 + cert->cert_len > end) { 158189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " 159189251Ssam "for Certificate (cert_len=%lu left=%lu)", 160189251Ssam (unsigned long) cert->cert_len, 161189251Ssam (unsigned long) (end - pos)); 162189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 163189251Ssam TLS_ALERT_INTERNAL_ERROR); 164189251Ssam return -1; 165189251Ssam } 166189251Ssam WPA_PUT_BE24(pos, cert->cert_len); 167189251Ssam pos += 3; 168189251Ssam os_memcpy(pos, cert->cert_start, cert->cert_len); 169189251Ssam pos += cert->cert_len; 170189251Ssam 171189251Ssam if (x509_certificate_self_signed(cert)) 172189251Ssam break; 173189251Ssam cert = x509_certificate_get_subject(conn->cred->trusted_certs, 174189251Ssam &cert->issuer); 175189251Ssam } 176189251Ssam if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) { 177189251Ssam /* 178189251Ssam * Client was not configured with all the needed certificates 179189251Ssam * to form a full certificate chain. The server may fail to 180189251Ssam * validate the chain unless it is configured with all the 181189251Ssam * missing CA certificates. 182189251Ssam */ 183189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain " 184189251Ssam "not configured - validation may fail"); 185189251Ssam } 186189251Ssam WPA_PUT_BE24(cert_start, pos - cert_start - 3); 187189251Ssam 188189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 189189251Ssam 190189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 191252726Srpaulo rhdr, end - rhdr, hs_start, pos - hs_start, 192252726Srpaulo &rlen) < 0) { 193189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 194189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 195189251Ssam TLS_ALERT_INTERNAL_ERROR); 196189251Ssam return -1; 197189251Ssam } 198189251Ssam pos = rhdr + rlen; 199189251Ssam 200189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 201189251Ssam 202189251Ssam *msgpos = pos; 203189251Ssam 204189251Ssam return 0; 205189251Ssam} 206189251Ssam 207189251Ssam 208281806Srpaulostatic int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) 209189251Ssam{ 210189251Ssam /* ClientDiffieHellmanPublic */ 211189251Ssam u8 *csecret, *csecret_start, *dh_yc, *shared; 212189251Ssam size_t csecret_len, dh_yc_len, shared_len; 213189251Ssam 214189251Ssam csecret_len = conn->dh_p_len; 215189251Ssam csecret = os_malloc(csecret_len); 216189251Ssam if (csecret == NULL) { 217189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " 218189251Ssam "memory for Yc (Diffie-Hellman)"); 219189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 220189251Ssam TLS_ALERT_INTERNAL_ERROR); 221189251Ssam return -1; 222189251Ssam } 223252726Srpaulo if (random_get_bytes(csecret, csecret_len)) { 224189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " 225189251Ssam "data for Diffie-Hellman"); 226189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 227189251Ssam TLS_ALERT_INTERNAL_ERROR); 228189251Ssam os_free(csecret); 229189251Ssam return -1; 230189251Ssam } 231189251Ssam 232189251Ssam if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0) 233189251Ssam csecret[0] = 0; /* make sure Yc < p */ 234189251Ssam 235189251Ssam csecret_start = csecret; 236189251Ssam while (csecret_len > 1 && *csecret_start == 0) { 237189251Ssam csecret_start++; 238189251Ssam csecret_len--; 239189251Ssam } 240189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value", 241189251Ssam csecret_start, csecret_len); 242189251Ssam 243189251Ssam /* Yc = g^csecret mod p */ 244189251Ssam dh_yc_len = conn->dh_p_len; 245189251Ssam dh_yc = os_malloc(dh_yc_len); 246189251Ssam if (dh_yc == NULL) { 247189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " 248189251Ssam "memory for Diffie-Hellman"); 249189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 250189251Ssam TLS_ALERT_INTERNAL_ERROR); 251189251Ssam os_free(csecret); 252189251Ssam return -1; 253189251Ssam } 254189251Ssam if (crypto_mod_exp(conn->dh_g, conn->dh_g_len, 255189251Ssam csecret_start, csecret_len, 256189251Ssam conn->dh_p, conn->dh_p_len, 257189251Ssam dh_yc, &dh_yc_len)) { 258189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 259189251Ssam TLS_ALERT_INTERNAL_ERROR); 260189251Ssam os_free(csecret); 261189251Ssam os_free(dh_yc); 262189251Ssam return -1; 263189251Ssam } 264189251Ssam 265189251Ssam wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", 266189251Ssam dh_yc, dh_yc_len); 267189251Ssam 268189251Ssam WPA_PUT_BE16(*pos, dh_yc_len); 269189251Ssam *pos += 2; 270189251Ssam if (*pos + dh_yc_len > end) { 271189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the " 272189251Ssam "message buffer for Yc"); 273189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 274189251Ssam TLS_ALERT_INTERNAL_ERROR); 275189251Ssam os_free(csecret); 276189251Ssam os_free(dh_yc); 277189251Ssam return -1; 278189251Ssam } 279189251Ssam os_memcpy(*pos, dh_yc, dh_yc_len); 280189251Ssam *pos += dh_yc_len; 281189251Ssam os_free(dh_yc); 282189251Ssam 283189251Ssam shared_len = conn->dh_p_len; 284189251Ssam shared = os_malloc(shared_len); 285189251Ssam if (shared == NULL) { 286189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " 287189251Ssam "DH"); 288189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 289189251Ssam TLS_ALERT_INTERNAL_ERROR); 290189251Ssam os_free(csecret); 291189251Ssam return -1; 292189251Ssam } 293189251Ssam 294189251Ssam /* shared = Ys^csecret mod p */ 295189251Ssam if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, 296189251Ssam csecret_start, csecret_len, 297189251Ssam conn->dh_p, conn->dh_p_len, 298189251Ssam shared, &shared_len)) { 299189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 300189251Ssam TLS_ALERT_INTERNAL_ERROR); 301189251Ssam os_free(csecret); 302189251Ssam os_free(shared); 303189251Ssam return -1; 304189251Ssam } 305189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", 306189251Ssam shared, shared_len); 307189251Ssam 308189251Ssam os_memset(csecret_start, 0, csecret_len); 309189251Ssam os_free(csecret); 310189251Ssam if (tls_derive_keys(conn, shared, shared_len)) { 311189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); 312189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 313189251Ssam TLS_ALERT_INTERNAL_ERROR); 314189251Ssam os_free(shared); 315189251Ssam return -1; 316189251Ssam } 317189251Ssam os_memset(shared, 0, shared_len); 318189251Ssam os_free(shared); 319189251Ssam tlsv1_client_free_dh(conn); 320189251Ssam return 0; 321189251Ssam} 322189251Ssam 323189251Ssam 324189251Ssamstatic int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end) 325189251Ssam{ 326189251Ssam u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN]; 327189251Ssam size_t clen; 328189251Ssam int res; 329189251Ssam 330189251Ssam if (tls_derive_pre_master_secret(pre_master_secret) < 0 || 331189251Ssam tls_derive_keys(conn, pre_master_secret, 332189251Ssam TLS_PRE_MASTER_SECRET_LEN)) { 333189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); 334189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 335189251Ssam TLS_ALERT_INTERNAL_ERROR); 336189251Ssam return -1; 337189251Ssam } 338189251Ssam 339189251Ssam /* EncryptedPreMasterSecret */ 340189251Ssam if (conn->server_rsa_key == NULL) { 341189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to " 342189251Ssam "use for encrypting pre-master secret"); 343189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 344189251Ssam TLS_ALERT_INTERNAL_ERROR); 345189251Ssam return -1; 346189251Ssam } 347189251Ssam 348189251Ssam /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */ 349189251Ssam *pos += 2; 350189251Ssam clen = end - *pos; 351189251Ssam res = crypto_public_key_encrypt_pkcs1_v15( 352189251Ssam conn->server_rsa_key, 353189251Ssam pre_master_secret, TLS_PRE_MASTER_SECRET_LEN, 354189251Ssam *pos, &clen); 355189251Ssam os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN); 356189251Ssam if (res < 0) { 357189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed"); 358189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 359189251Ssam TLS_ALERT_INTERNAL_ERROR); 360189251Ssam return -1; 361189251Ssam } 362189251Ssam WPA_PUT_BE16(*pos - 2, clen); 363189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret", 364189251Ssam *pos, clen); 365189251Ssam *pos += clen; 366189251Ssam 367189251Ssam return 0; 368189251Ssam} 369189251Ssam 370189251Ssam 371189251Ssamstatic int tls_write_client_key_exchange(struct tlsv1_client *conn, 372189251Ssam u8 **msgpos, u8 *end) 373189251Ssam{ 374189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length; 375189251Ssam size_t rlen; 376189251Ssam tls_key_exchange keyx; 377189251Ssam const struct tls_cipher_suite *suite; 378189251Ssam 379189251Ssam suite = tls_get_cipher_suite(conn->rl.cipher_suite); 380189251Ssam if (suite == NULL) 381189251Ssam keyx = TLS_KEY_X_NULL; 382189251Ssam else 383189251Ssam keyx = suite->key_exchange; 384189251Ssam 385189251Ssam pos = *msgpos; 386189251Ssam 387189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange"); 388189251Ssam 389189251Ssam rhdr = pos; 390189251Ssam pos += TLS_RECORD_HEADER_LEN; 391189251Ssam 392189251Ssam /* opaque fragment[TLSPlaintext.length] */ 393189251Ssam 394189251Ssam /* Handshake */ 395189251Ssam hs_start = pos; 396189251Ssam /* HandshakeType msg_type */ 397189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE; 398189251Ssam /* uint24 length (to be filled) */ 399189251Ssam hs_length = pos; 400189251Ssam pos += 3; 401189251Ssam /* body - ClientKeyExchange */ 402281806Srpaulo if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) { 403281806Srpaulo if (tlsv1_key_x_dh(conn, &pos, end) < 0) 404189251Ssam return -1; 405189251Ssam } else { 406189251Ssam if (tlsv1_key_x_rsa(conn, &pos, end) < 0) 407189251Ssam return -1; 408189251Ssam } 409189251Ssam 410189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 411189251Ssam 412189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 413252726Srpaulo rhdr, end - rhdr, hs_start, pos - hs_start, 414252726Srpaulo &rlen) < 0) { 415189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 416189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 417189251Ssam TLS_ALERT_INTERNAL_ERROR); 418189251Ssam return -1; 419189251Ssam } 420189251Ssam pos = rhdr + rlen; 421189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 422189251Ssam 423189251Ssam *msgpos = pos; 424189251Ssam 425189251Ssam return 0; 426189251Ssam} 427189251Ssam 428189251Ssam 429189251Ssamstatic int tls_write_client_certificate_verify(struct tlsv1_client *conn, 430189251Ssam u8 **msgpos, u8 *end) 431189251Ssam{ 432189251Ssam u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; 433189251Ssam size_t rlen, hlen, clen; 434252726Srpaulo u8 hash[100], *hpos; 435189251Ssam 436189251Ssam pos = *msgpos; 437189251Ssam 438189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify"); 439189251Ssam rhdr = pos; 440189251Ssam pos += TLS_RECORD_HEADER_LEN; 441189251Ssam 442189251Ssam /* Handshake */ 443189251Ssam hs_start = pos; 444189251Ssam /* HandshakeType msg_type */ 445189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY; 446189251Ssam /* uint24 length (to be filled) */ 447189251Ssam hs_length = pos; 448189251Ssam pos += 3; 449189251Ssam 450189251Ssam /* 451189251Ssam * RFC 2246: 7.4.3 and 7.4.8: 452189251Ssam * Signature signature 453189251Ssam * 454189251Ssam * RSA: 455189251Ssam * digitally-signed struct { 456189251Ssam * opaque md5_hash[16]; 457189251Ssam * opaque sha_hash[20]; 458189251Ssam * }; 459189251Ssam * 460189251Ssam * DSA: 461189251Ssam * digitally-signed struct { 462189251Ssam * opaque sha_hash[20]; 463189251Ssam * }; 464189251Ssam * 465189251Ssam * The hash values are calculated over all handshake messages sent or 466189251Ssam * received starting at ClientHello up to, but not including, this 467189251Ssam * CertificateVerify message, including the type and length fields of 468189251Ssam * the handshake messages. 469189251Ssam */ 470189251Ssam 471189251Ssam hpos = hash; 472189251Ssam 473252726Srpaulo#ifdef CONFIG_TLSV12 474252726Srpaulo if (conn->rl.tls_version == TLS_VERSION_1_2) { 475252726Srpaulo hlen = SHA256_MAC_LEN; 476252726Srpaulo if (conn->verify.sha256_cert == NULL || 477252726Srpaulo crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < 478252726Srpaulo 0) { 479252726Srpaulo conn->verify.sha256_cert = NULL; 480252726Srpaulo tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 481252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 482252726Srpaulo return -1; 483252726Srpaulo } 484252726Srpaulo conn->verify.sha256_cert = NULL; 485252726Srpaulo 486252726Srpaulo /* 487252726Srpaulo * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 488252726Srpaulo * 489252726Srpaulo * DigestInfo ::= SEQUENCE { 490252726Srpaulo * digestAlgorithm DigestAlgorithm, 491252726Srpaulo * digest OCTET STRING 492252726Srpaulo * } 493252726Srpaulo * 494252726Srpaulo * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} 495252726Srpaulo * 496252726Srpaulo * DER encoded DigestInfo for SHA256 per RFC 3447: 497252726Srpaulo * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || 498252726Srpaulo * H 499252726Srpaulo */ 500252726Srpaulo os_memmove(hash + 19, hash, hlen); 501252726Srpaulo hlen += 19; 502252726Srpaulo os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65" 503252726Srpaulo "\x03\x04\x02\x01\x05\x00\x04\x20", 19); 504252726Srpaulo } else { 505252726Srpaulo#endif /* CONFIG_TLSV12 */ 506252726Srpaulo 507281806Srpaulo hlen = MD5_MAC_LEN; 508281806Srpaulo if (conn->verify.md5_cert == NULL || 509281806Srpaulo crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) { 510281806Srpaulo tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 511281806Srpaulo TLS_ALERT_INTERNAL_ERROR); 512281806Srpaulo conn->verify.md5_cert = NULL; 513281806Srpaulo crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); 514281806Srpaulo conn->verify.sha1_cert = NULL; 515281806Srpaulo return -1; 516281806Srpaulo } 517281806Srpaulo hpos += MD5_MAC_LEN; 518189251Ssam 519189251Ssam conn->verify.md5_cert = NULL; 520189251Ssam hlen = SHA1_MAC_LEN; 521189251Ssam if (conn->verify.sha1_cert == NULL || 522189251Ssam crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { 523189251Ssam conn->verify.sha1_cert = NULL; 524189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 525189251Ssam TLS_ALERT_INTERNAL_ERROR); 526189251Ssam return -1; 527189251Ssam } 528189251Ssam conn->verify.sha1_cert = NULL; 529189251Ssam 530281806Srpaulo hlen += MD5_MAC_LEN; 531189251Ssam 532252726Srpaulo#ifdef CONFIG_TLSV12 533252726Srpaulo } 534252726Srpaulo#endif /* CONFIG_TLSV12 */ 535252726Srpaulo 536189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); 537189251Ssam 538252726Srpaulo#ifdef CONFIG_TLSV12 539252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 540252726Srpaulo /* 541252726Srpaulo * RFC 5246, 4.7: 542252726Srpaulo * TLS v1.2 adds explicit indication of the used signature and 543252726Srpaulo * hash algorithms. 544252726Srpaulo * 545252726Srpaulo * struct { 546252726Srpaulo * HashAlgorithm hash; 547252726Srpaulo * SignatureAlgorithm signature; 548252726Srpaulo * } SignatureAndHashAlgorithm; 549252726Srpaulo */ 550252726Srpaulo *pos++ = TLS_HASH_ALG_SHA256; 551252726Srpaulo *pos++ = TLS_SIGN_ALG_RSA; 552252726Srpaulo } 553252726Srpaulo#endif /* CONFIG_TLSV12 */ 554252726Srpaulo 555189251Ssam /* 556189251Ssam * RFC 2246, 4.7: 557189251Ssam * In digital signing, one-way hash functions are used as input for a 558189251Ssam * signing algorithm. A digitally-signed element is encoded as an 559189251Ssam * opaque vector <0..2^16-1>, where the length is specified by the 560189251Ssam * signing algorithm and key. 561189251Ssam * 562189251Ssam * In RSA signing, a 36-byte structure of two hashes (one SHA and one 563189251Ssam * MD5) is signed (encrypted with the private key). It is encoded with 564189251Ssam * PKCS #1 block type 0 or type 1 as described in [PKCS1]. 565189251Ssam */ 566189251Ssam signed_start = pos; /* length to be filled */ 567189251Ssam pos += 2; 568189251Ssam clen = end - pos; 569189251Ssam if (conn->cred == NULL || 570189251Ssam crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, 571189251Ssam pos, &clen) < 0) { 572189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); 573189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 574189251Ssam TLS_ALERT_INTERNAL_ERROR); 575189251Ssam return -1; 576189251Ssam } 577189251Ssam WPA_PUT_BE16(signed_start, clen); 578189251Ssam 579189251Ssam pos += clen; 580189251Ssam 581189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 582189251Ssam 583189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 584252726Srpaulo rhdr, end - rhdr, hs_start, pos - hs_start, 585252726Srpaulo &rlen) < 0) { 586189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 587189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 588189251Ssam TLS_ALERT_INTERNAL_ERROR); 589189251Ssam return -1; 590189251Ssam } 591189251Ssam pos = rhdr + rlen; 592189251Ssam 593189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 594189251Ssam 595189251Ssam *msgpos = pos; 596189251Ssam 597189251Ssam return 0; 598189251Ssam} 599189251Ssam 600189251Ssam 601189251Ssamstatic int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, 602189251Ssam u8 **msgpos, u8 *end) 603189251Ssam{ 604189251Ssam size_t rlen; 605252726Srpaulo u8 payload[1]; 606189251Ssam 607252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); 608189251Ssam 609252726Srpaulo payload[0] = TLS_CHANGE_CIPHER_SPEC; 610252726Srpaulo 611189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, 612252726Srpaulo *msgpos, end - *msgpos, payload, sizeof(payload), 613252726Srpaulo &rlen) < 0) { 614189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 615189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 616189251Ssam TLS_ALERT_INTERNAL_ERROR); 617189251Ssam return -1; 618189251Ssam } 619189251Ssam 620189251Ssam if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { 621189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " 622189251Ssam "record layer"); 623189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 624189251Ssam TLS_ALERT_INTERNAL_ERROR); 625189251Ssam return -1; 626189251Ssam } 627189251Ssam 628252726Srpaulo *msgpos += rlen; 629189251Ssam 630189251Ssam return 0; 631189251Ssam} 632189251Ssam 633189251Ssam 634189251Ssamstatic int tls_write_client_finished(struct tlsv1_client *conn, 635189251Ssam u8 **msgpos, u8 *end) 636189251Ssam{ 637252726Srpaulo u8 *pos, *hs_start; 638189251Ssam size_t rlen, hlen; 639252726Srpaulo u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; 640189251Ssam u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; 641189251Ssam 642189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); 643189251Ssam 644189251Ssam /* Encrypted Handshake Message: Finished */ 645189251Ssam 646252726Srpaulo#ifdef CONFIG_TLSV12 647252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 648252726Srpaulo hlen = SHA256_MAC_LEN; 649252726Srpaulo if (conn->verify.sha256_client == NULL || 650252726Srpaulo crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) 651252726Srpaulo < 0) { 652252726Srpaulo tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 653252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 654252726Srpaulo conn->verify.sha256_client = NULL; 655252726Srpaulo return -1; 656252726Srpaulo } 657252726Srpaulo conn->verify.sha256_client = NULL; 658252726Srpaulo } else { 659252726Srpaulo#endif /* CONFIG_TLSV12 */ 660252726Srpaulo 661189251Ssam hlen = MD5_MAC_LEN; 662189251Ssam if (conn->verify.md5_client == NULL || 663189251Ssam crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { 664189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 665189251Ssam TLS_ALERT_INTERNAL_ERROR); 666189251Ssam conn->verify.md5_client = NULL; 667189251Ssam crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); 668189251Ssam conn->verify.sha1_client = NULL; 669189251Ssam return -1; 670189251Ssam } 671189251Ssam conn->verify.md5_client = NULL; 672189251Ssam hlen = SHA1_MAC_LEN; 673189251Ssam if (conn->verify.sha1_client == NULL || 674189251Ssam crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, 675189251Ssam &hlen) < 0) { 676189251Ssam conn->verify.sha1_client = NULL; 677189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 678189251Ssam TLS_ALERT_INTERNAL_ERROR); 679189251Ssam return -1; 680189251Ssam } 681189251Ssam conn->verify.sha1_client = NULL; 682252726Srpaulo hlen = MD5_MAC_LEN + SHA1_MAC_LEN; 683189251Ssam 684252726Srpaulo#ifdef CONFIG_TLSV12 685252726Srpaulo } 686252726Srpaulo#endif /* CONFIG_TLSV12 */ 687252726Srpaulo 688252726Srpaulo if (tls_prf(conn->rl.tls_version, 689252726Srpaulo conn->master_secret, TLS_MASTER_SECRET_LEN, 690252726Srpaulo "client finished", hash, hlen, 691252726Srpaulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) { 692189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); 693189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 694189251Ssam TLS_ALERT_INTERNAL_ERROR); 695189251Ssam return -1; 696189251Ssam } 697189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", 698252726Srpaulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); 699189251Ssam 700189251Ssam /* Handshake */ 701252726Srpaulo pos = hs_start = verify_data; 702189251Ssam /* HandshakeType msg_type */ 703189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; 704252726Srpaulo /* uint24 length */ 705252726Srpaulo WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); 706189251Ssam pos += 3; 707252726Srpaulo pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */ 708189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 709189251Ssam 710189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 711252726Srpaulo *msgpos, end - *msgpos, hs_start, pos - hs_start, 712252726Srpaulo &rlen) < 0) { 713189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 714189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 715189251Ssam TLS_ALERT_INTERNAL_ERROR); 716189251Ssam return -1; 717189251Ssam } 718189251Ssam 719252726Srpaulo *msgpos += rlen; 720189251Ssam 721189251Ssam return 0; 722189251Ssam} 723189251Ssam 724189251Ssam 725189251Ssamstatic u8 * tls_send_client_key_exchange(struct tlsv1_client *conn, 726189251Ssam size_t *out_len) 727189251Ssam{ 728189251Ssam u8 *msg, *end, *pos; 729189251Ssam size_t msglen; 730189251Ssam 731189251Ssam *out_len = 0; 732189251Ssam 733252726Srpaulo msglen = 2000; 734189251Ssam if (conn->certificate_requested) 735189251Ssam msglen += tls_client_cert_chain_der_len(conn); 736189251Ssam 737189251Ssam msg = os_malloc(msglen); 738189251Ssam if (msg == NULL) 739189251Ssam return NULL; 740189251Ssam 741189251Ssam pos = msg; 742189251Ssam end = msg + msglen; 743189251Ssam 744189251Ssam if (conn->certificate_requested) { 745189251Ssam if (tls_write_client_certificate(conn, &pos, end) < 0) { 746189251Ssam os_free(msg); 747189251Ssam return NULL; 748189251Ssam } 749189251Ssam } 750189251Ssam 751189251Ssam if (tls_write_client_key_exchange(conn, &pos, end) < 0 || 752189251Ssam (conn->certificate_requested && conn->cred && conn->cred->key && 753189251Ssam tls_write_client_certificate_verify(conn, &pos, end) < 0) || 754189251Ssam tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || 755189251Ssam tls_write_client_finished(conn, &pos, end) < 0) { 756189251Ssam os_free(msg); 757189251Ssam return NULL; 758189251Ssam } 759189251Ssam 760189251Ssam *out_len = pos - msg; 761189251Ssam 762189251Ssam conn->state = SERVER_CHANGE_CIPHER_SPEC; 763189251Ssam 764189251Ssam return msg; 765189251Ssam} 766189251Ssam 767189251Ssam 768189251Ssamstatic u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn, 769189251Ssam size_t *out_len) 770189251Ssam{ 771189251Ssam u8 *msg, *end, *pos; 772189251Ssam 773189251Ssam *out_len = 0; 774189251Ssam 775189251Ssam msg = os_malloc(1000); 776189251Ssam if (msg == NULL) 777189251Ssam return NULL; 778189251Ssam 779189251Ssam pos = msg; 780189251Ssam end = msg + 1000; 781189251Ssam 782189251Ssam if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || 783189251Ssam tls_write_client_finished(conn, &pos, end) < 0) { 784189251Ssam os_free(msg); 785189251Ssam return NULL; 786189251Ssam } 787189251Ssam 788189251Ssam *out_len = pos - msg; 789189251Ssam 790189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed " 791189251Ssam "successfully"); 792189251Ssam conn->state = ESTABLISHED; 793189251Ssam 794189251Ssam return msg; 795189251Ssam} 796189251Ssam 797189251Ssam 798189251Ssamu8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, 799189251Ssam int no_appl_data) 800189251Ssam{ 801189251Ssam switch (conn->state) { 802189251Ssam case CLIENT_KEY_EXCHANGE: 803189251Ssam return tls_send_client_key_exchange(conn, out_len); 804189251Ssam case CHANGE_CIPHER_SPEC: 805189251Ssam return tls_send_change_cipher_spec(conn, out_len); 806189251Ssam case ACK_FINISHED: 807189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed " 808189251Ssam "successfully"); 809189251Ssam conn->state = ESTABLISHED; 810189251Ssam *out_len = 0; 811189251Ssam if (no_appl_data) { 812189251Ssam /* Need to return something to get final TLS ACK. */ 813189251Ssam return os_malloc(1); 814189251Ssam } 815189251Ssam return NULL; 816189251Ssam default: 817189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " 818189251Ssam "generating reply", conn->state); 819189251Ssam return NULL; 820189251Ssam } 821189251Ssam} 822189251Ssam 823189251Ssam 824189251Ssamu8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, 825189251Ssam u8 description, size_t *out_len) 826189251Ssam{ 827189251Ssam u8 *alert, *pos, *length; 828189251Ssam 829189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); 830189251Ssam *out_len = 0; 831189251Ssam 832189251Ssam alert = os_malloc(10); 833189251Ssam if (alert == NULL) 834189251Ssam return NULL; 835189251Ssam 836189251Ssam pos = alert; 837189251Ssam 838189251Ssam /* TLSPlaintext */ 839189251Ssam /* ContentType type */ 840189251Ssam *pos++ = TLS_CONTENT_TYPE_ALERT; 841189251Ssam /* ProtocolVersion version */ 842252726Srpaulo WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : 843252726Srpaulo TLS_VERSION); 844189251Ssam pos += 2; 845189251Ssam /* uint16 length (to be filled) */ 846189251Ssam length = pos; 847189251Ssam pos += 2; 848189251Ssam /* opaque fragment[TLSPlaintext.length] */ 849189251Ssam 850189251Ssam /* Alert */ 851189251Ssam /* AlertLevel level */ 852189251Ssam *pos++ = level; 853189251Ssam /* AlertDescription description */ 854189251Ssam *pos++ = description; 855189251Ssam 856189251Ssam WPA_PUT_BE16(length, pos - length - 2); 857189251Ssam *out_len = pos - alert; 858189251Ssam 859189251Ssam return alert; 860189251Ssam} 861