1189251Ssam/* 2189251Ssam * TLSv1 client - write handshake message 3252726Srpaulo * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/md5.h" 13214734Srpaulo#include "crypto/sha1.h" 14252726Srpaulo#include "crypto/sha256.h" 15214734Srpaulo#include "crypto/tls.h" 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 208189251Ssamstatic int tlsv1_key_x_anon_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 */ 402189251Ssam if (keyx == TLS_KEY_X_DH_anon) { 403189251Ssam if (tlsv1_key_x_anon_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 enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; 436189251Ssam 437189251Ssam pos = *msgpos; 438189251Ssam 439189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify"); 440189251Ssam rhdr = pos; 441189251Ssam pos += TLS_RECORD_HEADER_LEN; 442189251Ssam 443189251Ssam /* Handshake */ 444189251Ssam hs_start = pos; 445189251Ssam /* HandshakeType msg_type */ 446189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY; 447189251Ssam /* uint24 length (to be filled) */ 448189251Ssam hs_length = pos; 449189251Ssam pos += 3; 450189251Ssam 451189251Ssam /* 452189251Ssam * RFC 2246: 7.4.3 and 7.4.8: 453189251Ssam * Signature signature 454189251Ssam * 455189251Ssam * RSA: 456189251Ssam * digitally-signed struct { 457189251Ssam * opaque md5_hash[16]; 458189251Ssam * opaque sha_hash[20]; 459189251Ssam * }; 460189251Ssam * 461189251Ssam * DSA: 462189251Ssam * digitally-signed struct { 463189251Ssam * opaque sha_hash[20]; 464189251Ssam * }; 465189251Ssam * 466189251Ssam * The hash values are calculated over all handshake messages sent or 467189251Ssam * received starting at ClientHello up to, but not including, this 468189251Ssam * CertificateVerify message, including the type and length fields of 469189251Ssam * the handshake messages. 470189251Ssam */ 471189251Ssam 472189251Ssam hpos = hash; 473189251Ssam 474252726Srpaulo#ifdef CONFIG_TLSV12 475252726Srpaulo if (conn->rl.tls_version == TLS_VERSION_1_2) { 476252726Srpaulo hlen = SHA256_MAC_LEN; 477252726Srpaulo if (conn->verify.sha256_cert == NULL || 478252726Srpaulo crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < 479252726Srpaulo 0) { 480252726Srpaulo conn->verify.sha256_cert = NULL; 481252726Srpaulo tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 482252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 483252726Srpaulo return -1; 484252726Srpaulo } 485252726Srpaulo conn->verify.sha256_cert = NULL; 486252726Srpaulo 487252726Srpaulo /* 488252726Srpaulo * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 489252726Srpaulo * 490252726Srpaulo * DigestInfo ::= SEQUENCE { 491252726Srpaulo * digestAlgorithm DigestAlgorithm, 492252726Srpaulo * digest OCTET STRING 493252726Srpaulo * } 494252726Srpaulo * 495252726Srpaulo * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} 496252726Srpaulo * 497252726Srpaulo * DER encoded DigestInfo for SHA256 per RFC 3447: 498252726Srpaulo * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || 499252726Srpaulo * H 500252726Srpaulo */ 501252726Srpaulo os_memmove(hash + 19, hash, hlen); 502252726Srpaulo hlen += 19; 503252726Srpaulo os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65" 504252726Srpaulo "\x03\x04\x02\x01\x05\x00\x04\x20", 19); 505252726Srpaulo } else { 506252726Srpaulo#endif /* CONFIG_TLSV12 */ 507252726Srpaulo 508189251Ssam if (alg == SIGN_ALG_RSA) { 509189251Ssam hlen = MD5_MAC_LEN; 510189251Ssam if (conn->verify.md5_cert == NULL || 511189251Ssam crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) 512189251Ssam { 513189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 514189251Ssam TLS_ALERT_INTERNAL_ERROR); 515189251Ssam conn->verify.md5_cert = NULL; 516189251Ssam crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); 517189251Ssam conn->verify.sha1_cert = NULL; 518189251Ssam return -1; 519189251Ssam } 520189251Ssam hpos += MD5_MAC_LEN; 521189251Ssam } else 522189251Ssam crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); 523189251Ssam 524189251Ssam conn->verify.md5_cert = NULL; 525189251Ssam hlen = SHA1_MAC_LEN; 526189251Ssam if (conn->verify.sha1_cert == NULL || 527189251Ssam crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { 528189251Ssam conn->verify.sha1_cert = NULL; 529189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 530189251Ssam TLS_ALERT_INTERNAL_ERROR); 531189251Ssam return -1; 532189251Ssam } 533189251Ssam conn->verify.sha1_cert = NULL; 534189251Ssam 535189251Ssam if (alg == SIGN_ALG_RSA) 536189251Ssam hlen += MD5_MAC_LEN; 537189251Ssam 538252726Srpaulo#ifdef CONFIG_TLSV12 539252726Srpaulo } 540252726Srpaulo#endif /* CONFIG_TLSV12 */ 541252726Srpaulo 542189251Ssam wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); 543189251Ssam 544252726Srpaulo#ifdef CONFIG_TLSV12 545252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 546252726Srpaulo /* 547252726Srpaulo * RFC 5246, 4.7: 548252726Srpaulo * TLS v1.2 adds explicit indication of the used signature and 549252726Srpaulo * hash algorithms. 550252726Srpaulo * 551252726Srpaulo * struct { 552252726Srpaulo * HashAlgorithm hash; 553252726Srpaulo * SignatureAlgorithm signature; 554252726Srpaulo * } SignatureAndHashAlgorithm; 555252726Srpaulo */ 556252726Srpaulo *pos++ = TLS_HASH_ALG_SHA256; 557252726Srpaulo *pos++ = TLS_SIGN_ALG_RSA; 558252726Srpaulo } 559252726Srpaulo#endif /* CONFIG_TLSV12 */ 560252726Srpaulo 561189251Ssam /* 562189251Ssam * RFC 2246, 4.7: 563189251Ssam * In digital signing, one-way hash functions are used as input for a 564189251Ssam * signing algorithm. A digitally-signed element is encoded as an 565189251Ssam * opaque vector <0..2^16-1>, where the length is specified by the 566189251Ssam * signing algorithm and key. 567189251Ssam * 568189251Ssam * In RSA signing, a 36-byte structure of two hashes (one SHA and one 569189251Ssam * MD5) is signed (encrypted with the private key). It is encoded with 570189251Ssam * PKCS #1 block type 0 or type 1 as described in [PKCS1]. 571189251Ssam */ 572189251Ssam signed_start = pos; /* length to be filled */ 573189251Ssam pos += 2; 574189251Ssam clen = end - pos; 575189251Ssam if (conn->cred == NULL || 576189251Ssam crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, 577189251Ssam pos, &clen) < 0) { 578189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); 579189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 580189251Ssam TLS_ALERT_INTERNAL_ERROR); 581189251Ssam return -1; 582189251Ssam } 583189251Ssam WPA_PUT_BE16(signed_start, clen); 584189251Ssam 585189251Ssam pos += clen; 586189251Ssam 587189251Ssam WPA_PUT_BE24(hs_length, pos - hs_length - 3); 588189251Ssam 589189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 590252726Srpaulo rhdr, end - rhdr, hs_start, pos - hs_start, 591252726Srpaulo &rlen) < 0) { 592189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 593189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 594189251Ssam TLS_ALERT_INTERNAL_ERROR); 595189251Ssam return -1; 596189251Ssam } 597189251Ssam pos = rhdr + rlen; 598189251Ssam 599189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 600189251Ssam 601189251Ssam *msgpos = pos; 602189251Ssam 603189251Ssam return 0; 604189251Ssam} 605189251Ssam 606189251Ssam 607189251Ssamstatic int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, 608189251Ssam u8 **msgpos, u8 *end) 609189251Ssam{ 610189251Ssam size_t rlen; 611252726Srpaulo u8 payload[1]; 612189251Ssam 613252726Srpaulo wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); 614189251Ssam 615252726Srpaulo payload[0] = TLS_CHANGE_CIPHER_SPEC; 616252726Srpaulo 617189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, 618252726Srpaulo *msgpos, end - *msgpos, payload, sizeof(payload), 619252726Srpaulo &rlen) < 0) { 620189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 621189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 622189251Ssam TLS_ALERT_INTERNAL_ERROR); 623189251Ssam return -1; 624189251Ssam } 625189251Ssam 626189251Ssam if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { 627189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " 628189251Ssam "record layer"); 629189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 630189251Ssam TLS_ALERT_INTERNAL_ERROR); 631189251Ssam return -1; 632189251Ssam } 633189251Ssam 634252726Srpaulo *msgpos += rlen; 635189251Ssam 636189251Ssam return 0; 637189251Ssam} 638189251Ssam 639189251Ssam 640189251Ssamstatic int tls_write_client_finished(struct tlsv1_client *conn, 641189251Ssam u8 **msgpos, u8 *end) 642189251Ssam{ 643252726Srpaulo u8 *pos, *hs_start; 644189251Ssam size_t rlen, hlen; 645252726Srpaulo u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; 646189251Ssam u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; 647189251Ssam 648189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); 649189251Ssam 650189251Ssam /* Encrypted Handshake Message: Finished */ 651189251Ssam 652252726Srpaulo#ifdef CONFIG_TLSV12 653252726Srpaulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 654252726Srpaulo hlen = SHA256_MAC_LEN; 655252726Srpaulo if (conn->verify.sha256_client == NULL || 656252726Srpaulo crypto_hash_finish(conn->verify.sha256_client, hash, &hlen) 657252726Srpaulo < 0) { 658252726Srpaulo tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 659252726Srpaulo TLS_ALERT_INTERNAL_ERROR); 660252726Srpaulo conn->verify.sha256_client = NULL; 661252726Srpaulo return -1; 662252726Srpaulo } 663252726Srpaulo conn->verify.sha256_client = NULL; 664252726Srpaulo } else { 665252726Srpaulo#endif /* CONFIG_TLSV12 */ 666252726Srpaulo 667189251Ssam hlen = MD5_MAC_LEN; 668189251Ssam if (conn->verify.md5_client == NULL || 669189251Ssam crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { 670189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 671189251Ssam TLS_ALERT_INTERNAL_ERROR); 672189251Ssam conn->verify.md5_client = NULL; 673189251Ssam crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); 674189251Ssam conn->verify.sha1_client = NULL; 675189251Ssam return -1; 676189251Ssam } 677189251Ssam conn->verify.md5_client = NULL; 678189251Ssam hlen = SHA1_MAC_LEN; 679189251Ssam if (conn->verify.sha1_client == NULL || 680189251Ssam crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, 681189251Ssam &hlen) < 0) { 682189251Ssam conn->verify.sha1_client = NULL; 683189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 684189251Ssam TLS_ALERT_INTERNAL_ERROR); 685189251Ssam return -1; 686189251Ssam } 687189251Ssam conn->verify.sha1_client = NULL; 688252726Srpaulo hlen = MD5_MAC_LEN + SHA1_MAC_LEN; 689189251Ssam 690252726Srpaulo#ifdef CONFIG_TLSV12 691252726Srpaulo } 692252726Srpaulo#endif /* CONFIG_TLSV12 */ 693252726Srpaulo 694252726Srpaulo if (tls_prf(conn->rl.tls_version, 695252726Srpaulo conn->master_secret, TLS_MASTER_SECRET_LEN, 696252726Srpaulo "client finished", hash, hlen, 697252726Srpaulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) { 698189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); 699189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 700189251Ssam TLS_ALERT_INTERNAL_ERROR); 701189251Ssam return -1; 702189251Ssam } 703189251Ssam wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", 704252726Srpaulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); 705189251Ssam 706189251Ssam /* Handshake */ 707252726Srpaulo pos = hs_start = verify_data; 708189251Ssam /* HandshakeType msg_type */ 709189251Ssam *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; 710252726Srpaulo /* uint24 length */ 711252726Srpaulo WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); 712189251Ssam pos += 3; 713252726Srpaulo pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */ 714189251Ssam tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 715189251Ssam 716189251Ssam if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 717252726Srpaulo *msgpos, end - *msgpos, hs_start, pos - hs_start, 718252726Srpaulo &rlen) < 0) { 719189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 720189251Ssam tls_alert(conn, TLS_ALERT_LEVEL_FATAL, 721189251Ssam TLS_ALERT_INTERNAL_ERROR); 722189251Ssam return -1; 723189251Ssam } 724189251Ssam 725252726Srpaulo *msgpos += rlen; 726189251Ssam 727189251Ssam return 0; 728189251Ssam} 729189251Ssam 730189251Ssam 731189251Ssamstatic u8 * tls_send_client_key_exchange(struct tlsv1_client *conn, 732189251Ssam size_t *out_len) 733189251Ssam{ 734189251Ssam u8 *msg, *end, *pos; 735189251Ssam size_t msglen; 736189251Ssam 737189251Ssam *out_len = 0; 738189251Ssam 739252726Srpaulo msglen = 2000; 740189251Ssam if (conn->certificate_requested) 741189251Ssam msglen += tls_client_cert_chain_der_len(conn); 742189251Ssam 743189251Ssam msg = os_malloc(msglen); 744189251Ssam if (msg == NULL) 745189251Ssam return NULL; 746189251Ssam 747189251Ssam pos = msg; 748189251Ssam end = msg + msglen; 749189251Ssam 750189251Ssam if (conn->certificate_requested) { 751189251Ssam if (tls_write_client_certificate(conn, &pos, end) < 0) { 752189251Ssam os_free(msg); 753189251Ssam return NULL; 754189251Ssam } 755189251Ssam } 756189251Ssam 757189251Ssam if (tls_write_client_key_exchange(conn, &pos, end) < 0 || 758189251Ssam (conn->certificate_requested && conn->cred && conn->cred->key && 759189251Ssam tls_write_client_certificate_verify(conn, &pos, end) < 0) || 760189251Ssam tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || 761189251Ssam tls_write_client_finished(conn, &pos, end) < 0) { 762189251Ssam os_free(msg); 763189251Ssam return NULL; 764189251Ssam } 765189251Ssam 766189251Ssam *out_len = pos - msg; 767189251Ssam 768189251Ssam conn->state = SERVER_CHANGE_CIPHER_SPEC; 769189251Ssam 770189251Ssam return msg; 771189251Ssam} 772189251Ssam 773189251Ssam 774189251Ssamstatic u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn, 775189251Ssam size_t *out_len) 776189251Ssam{ 777189251Ssam u8 *msg, *end, *pos; 778189251Ssam 779189251Ssam *out_len = 0; 780189251Ssam 781189251Ssam msg = os_malloc(1000); 782189251Ssam if (msg == NULL) 783189251Ssam return NULL; 784189251Ssam 785189251Ssam pos = msg; 786189251Ssam end = msg + 1000; 787189251Ssam 788189251Ssam if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || 789189251Ssam tls_write_client_finished(conn, &pos, end) < 0) { 790189251Ssam os_free(msg); 791189251Ssam return NULL; 792189251Ssam } 793189251Ssam 794189251Ssam *out_len = pos - msg; 795189251Ssam 796189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed " 797189251Ssam "successfully"); 798189251Ssam conn->state = ESTABLISHED; 799189251Ssam 800189251Ssam return msg; 801189251Ssam} 802189251Ssam 803189251Ssam 804189251Ssamu8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, 805189251Ssam int no_appl_data) 806189251Ssam{ 807189251Ssam switch (conn->state) { 808189251Ssam case CLIENT_KEY_EXCHANGE: 809189251Ssam return tls_send_client_key_exchange(conn, out_len); 810189251Ssam case CHANGE_CIPHER_SPEC: 811189251Ssam return tls_send_change_cipher_spec(conn, out_len); 812189251Ssam case ACK_FINISHED: 813189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed " 814189251Ssam "successfully"); 815189251Ssam conn->state = ESTABLISHED; 816189251Ssam *out_len = 0; 817189251Ssam if (no_appl_data) { 818189251Ssam /* Need to return something to get final TLS ACK. */ 819189251Ssam return os_malloc(1); 820189251Ssam } 821189251Ssam return NULL; 822189251Ssam default: 823189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " 824189251Ssam "generating reply", conn->state); 825189251Ssam return NULL; 826189251Ssam } 827189251Ssam} 828189251Ssam 829189251Ssam 830189251Ssamu8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, 831189251Ssam u8 description, size_t *out_len) 832189251Ssam{ 833189251Ssam u8 *alert, *pos, *length; 834189251Ssam 835189251Ssam wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); 836189251Ssam *out_len = 0; 837189251Ssam 838189251Ssam alert = os_malloc(10); 839189251Ssam if (alert == NULL) 840189251Ssam return NULL; 841189251Ssam 842189251Ssam pos = alert; 843189251Ssam 844189251Ssam /* TLSPlaintext */ 845189251Ssam /* ContentType type */ 846189251Ssam *pos++ = TLS_CONTENT_TYPE_ALERT; 847189251Ssam /* ProtocolVersion version */ 848252726Srpaulo WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : 849252726Srpaulo TLS_VERSION); 850189251Ssam pos += 2; 851189251Ssam /* uint16 length (to be filled) */ 852189251Ssam length = pos; 853189251Ssam pos += 2; 854189251Ssam /* opaque fragment[TLSPlaintext.length] */ 855189251Ssam 856189251Ssam /* Alert */ 857189251Ssam /* AlertLevel level */ 858189251Ssam *pos++ = level; 859189251Ssam /* AlertDescription description */ 860189251Ssam *pos++ = description; 861189251Ssam 862189251Ssam WPA_PUT_BE16(length, pos - length - 2); 863189251Ssam *out_len = pos - alert; 864189251Ssam 865189251Ssam return alert; 866189251Ssam} 867