From 65074a2a7ca5c9d0d1fc8a72da2176ac0e81a246 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 9 Mar 2014 15:43:50 +0200 Subject: [PATCH] TLS: Add support for DHE-RSA cipher suites This extends the internal TLS implementation to support DHE-RSA cipher suites in both server and client roles. Signed-off-by: Jouni Malinen --- src/tls/tlsv1_client.c | 7 +- src/tls/tlsv1_client_read.c | 161 ++++++++++++++++++++++++++++++- src/tls/tlsv1_client_write.c | 8 +- src/tls/tlsv1_common.c | 14 ++- src/tls/tlsv1_server.c | 7 +- src/tls/tlsv1_server_read.c | 10 +- src/tls/tlsv1_server_write.c | 182 ++++++++++++++++++++++++++++++++++- 7 files changed, 368 insertions(+), 21 deletions(-) diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index 12148b61d..4a4f0b69d 100644 --- a/src/tls/tlsv1_client.c +++ b/src/tls/tlsv1_client.c @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -459,10 +459,15 @@ struct tlsv1_client * tlsv1_client_init(void) count = 0; suites = conn->cipher_suites; + suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256; + suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; + suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256; + suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; + suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 3269ecf66..8313efbe2 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -1,6 +1,6 @@ /* * TLSv1 client - read handshake message - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -410,9 +410,10 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + tls_key_exchange key_exchange) { - const u8 *pos, *end; + const u8 *pos, *end, *server_params, *server_params_end; tlsv1_client_free_dh(conn); @@ -421,6 +422,7 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, if (end - pos < 3) goto fail; + server_params = pos; conn->dh_p_len = WPA_GET_BE16(pos); pos += 2; if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) { @@ -465,6 +467,153 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, pos += conn->dh_ys_len; wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", conn->dh_ys, conn->dh_ys_len); + server_params_end = pos; + + if (key_exchange == TLS_KEY_X_DHE_RSA) { + u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *sbuf; + size_t hlen, buflen; + enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; + u16 slen; + struct crypto_hash *ctx; + + hpos = hash; + +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version == TLS_VERSION_1_2) { + /* + * RFC 5246, 4.7: + * TLS v1.2 adds explicit indication of the used + * signature and hash algorithms. + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + */ + if (end - pos < 2) + goto fail; + if (pos[0] != TLS_HASH_ALG_SHA256 || + pos[1] != TLS_SIGN_ALG_RSA) { + wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm", + pos[0], pos[1]); + goto fail; + } + pos += 2; + + ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + if (ctx == NULL) + goto fail; + crypto_hash_update(ctx, conn->client_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, conn->server_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, + server_params_end - server_params); + hlen = SHA256_MAC_LEN; + if (crypto_hash_finish(ctx, hpos, &hlen) < 0) + goto fail; + } else { +#endif /* CONFIG_TLSV12 */ + if (alg == SIGN_ALG_RSA) { + ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); + if (ctx == NULL) + goto fail; + crypto_hash_update(ctx, conn->client_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, conn->server_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, + server_params_end - server_params); + hlen = sizeof(hash); + if (crypto_hash_finish(ctx, hash, &hlen) < 0) + goto fail; + hpos += hlen; + } + ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); + if (ctx == NULL) + goto fail; + crypto_hash_update(ctx, conn->client_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, conn->server_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, + server_params_end - server_params); + hlen = hash + sizeof(hash) - hpos; + if (crypto_hash_finish(ctx, hpos, &hlen) < 0) + goto fail; + hpos += hlen; + hlen = hpos - hash; +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ + + wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash", + hash, hlen); + + if (end - pos < 2) + goto fail; + slen = WPA_GET_BE16(pos); + pos += 2; + if (end - pos < slen) + goto fail; + + wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos); + if (conn->server_rsa_key == NULL) { + wpa_printf(MSG_DEBUG, "TLSv1: No server public key to verify signature"); + goto fail; + } + + buflen = end - pos; + sbuf = os_malloc(end - pos); + if (crypto_public_key_decrypt_pkcs1(conn->server_rsa_key, + pos, end - pos, sbuf, + &buflen) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature"); + os_free(sbuf); + goto fail; + } + + wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature", + sbuf, buflen); + +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + /* + * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithm, + * digest OCTET STRING + * } + * + * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} + * + * DER encoded DigestInfo for SHA256 per RFC 3447: + * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 + * 04 20 || H + */ + if (buflen >= 19 + 32 && + os_memcmp(sbuf, + "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01" + "\x65\x03\x04\x02\x01\x05\x00\x04\x20", + 19) == 0) { + wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256"); + os_memmove(sbuf, sbuf + 19, buflen - 19); + buflen -= 19; + } else { + wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo"); + os_free(sbuf); + goto fail; + } + } +#endif /* CONFIG_TLSV12 */ + + if (buflen != hlen || os_memcmp(sbuf, hash, buflen) != 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in ServerKeyExchange - did not match calculated hash"); + os_free(sbuf); + goto fail; + } + + os_free(sbuf); + } return 0; @@ -543,8 +692,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len); suite = tls_get_cipher_suite(conn->rl.cipher_suite); - if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { - if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) { + if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon || + suite->key_exchange == TLS_KEY_X_DHE_RSA)) { + if (tlsv1_process_diffie_hellman(conn, pos, len, + suite->key_exchange) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c index d789efb42..839eb90ab 100644 --- a/src/tls/tlsv1_client_write.c +++ b/src/tls/tlsv1_client_write.c @@ -1,6 +1,6 @@ /* * TLSv1 client - write handshake message - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -205,7 +205,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn, } -static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) +static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) { /* ClientDiffieHellmanPublic */ u8 *csecret, *csecret_start, *dh_yc, *shared; @@ -399,8 +399,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn, hs_length = pos; pos += 3; /* body - ClientKeyExchange */ - if (keyx == TLS_KEY_X_DH_anon) { - if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0) + if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) { + if (tlsv1_key_x_dh(conn, &pos, end) < 0) return -1; } else { if (tlsv1_key_x_rsa(conn, &pos, end) < 0) diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c index 4578b2272..d05df856d 100644 --- a/src/tls/tlsv1_common.c +++ b/src/tls/tlsv1_common.c @@ -1,6 +1,6 @@ /* * TLSv1 common routines - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -33,6 +33,10 @@ static const struct tls_cipher_suite tls_cipher_suites[] = { TLS_HASH_SHA }, { TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, + { TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_DHE_RSA, TLS_CIPHER_DES_CBC, + TLS_HASH_SHA}, + { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DHE_RSA, + TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon, TLS_CIPHER_RC4_128, TLS_HASH_MD5 }, { TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon, @@ -41,16 +45,24 @@ static const struct tls_cipher_suite tls_cipher_suites[] = { TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, { TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, + { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_DHE_RSA, + TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon, TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, { TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }, + { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_DHE_RSA, + TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }, { TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon, TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }, { TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 }, { TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }, + { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DHE_RSA, + TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 }, + { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DHE_RSA, + TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }, { TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon, TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 }, { TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon, diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c index 55f5a78fb..db2059b02 100644 --- a/src/tls/tlsv1_server.c +++ b/src/tls/tlsv1_server.c @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -361,10 +361,15 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred) count = 0; suites = conn->cipher_suites; + suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256; + suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; + suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256; + suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; + suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_SHA; suites[count++] = TLS_RSA_WITH_RC4_128_MD5; diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 6f6539b1b..137fd3abd 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -1,6 +1,6 @@ /* * TLSv1 server - read handshake message - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -582,7 +582,7 @@ static int tls_process_client_key_exchange_rsa( } -static int tls_process_client_key_exchange_dh_anon( +static int tls_process_client_key_exchange_dh( struct tlsv1_server *conn, const u8 *pos, const u8 *end) { const u8 *dh_yc; @@ -747,11 +747,11 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, else keyx = suite->key_exchange; - if (keyx == TLS_KEY_X_DH_anon && - tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0) + if ((keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) && + tls_process_client_key_exchange_dh(conn, pos, end) < 0) return -1; - if (keyx != TLS_KEY_X_DH_anon && + if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA && tls_process_client_key_exchange_rsa(conn, pos, end) < 0) return -1; diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c index 6d8e55ed4..39dbad4fe 100644 --- a/src/tls/tlsv1_server_write.c +++ b/src/tls/tlsv1_server_write.c @@ -1,6 +1,6 @@ /* * TLSv1 server - write handshake message - * Copyright (c) 2006-2011, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -245,7 +245,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, { tls_key_exchange keyx; const struct tls_cipher_suite *suite; - u8 *pos, *rhdr, *hs_start, *hs_length; + u8 *pos, *rhdr, *hs_start, *hs_length, *server_params; size_t rlen; u8 *dh_ys; size_t dh_ys_len; @@ -261,8 +261,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, return 0; } - if (keyx != TLS_KEY_X_DH_anon) { - /* TODO? */ + if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) { wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " "supported with key exchange type %d", keyx); return -1; @@ -369,6 +368,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, pos += 3; /* body - ServerDHParams */ + server_params = pos; /* dh_p */ if (pos + 2 + conn->cred->dh_p_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " @@ -412,6 +412,180 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, pos += dh_ys_len; os_free(dh_ys); + /* + * select (SignatureAlgorithm) + * { case anonymous: struct { }; + * case rsa: + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * case dsa: + * digitally-signed struct { + * opaque sha_hash[20]; + * }; + * } Signature; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + ServerParams); + * + * sha_hash + * SHA(ClientHello.random + ServerHello.random + ServerParams); + */ + + if (keyx == TLS_KEY_X_DHE_RSA) { + u8 hash[100], *hpos; + u8 *signed_start; + size_t hlen, clen; + enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; + struct crypto_hash *ctx; + +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version == TLS_VERSION_1_2) { + ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + if (ctx == NULL) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + crypto_hash_update(ctx, conn->client_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, conn->server_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, + pos - server_params); + hlen = sizeof(hash) - 19; + if (crypto_hash_finish(ctx, hash + 19, &hlen) < 0) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + + /* + * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithm, + * digest OCTET STRING + * } + * + * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} + * + * DER encoded DigestInfo for SHA256 per RFC 3447: + * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 + * 04 20 || H + */ + hlen += 19; + os_memcpy(hash, + "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65" + "\x03\x04\x02\x01\x05\x00\x04\x20", 19); + } else { +#endif /* CONFIG_TLSV12 */ + hpos = hash; + + if (alg == SIGN_ALG_RSA) { + ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, + NULL, 0); + if (ctx == NULL) { + tlsv1_server_alert( + conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + crypto_hash_update(ctx, conn->client_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, conn->server_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, + pos - server_params); + hlen = sizeof(hash); + if (crypto_hash_finish(ctx, hash, &hlen) < 0) { + tlsv1_server_alert( + conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + hpos += hlen; + } + + ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); + if (ctx == NULL) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + crypto_hash_update(ctx, conn->client_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, conn->server_random, + TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, + pos - server_params); + hlen = hash + sizeof(hash) - hpos; + if (crypto_hash_finish(ctx, hpos, &hlen) < 0) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + hpos += hlen; + hlen = hpos - hash; +#ifdef CONFIG_TLSV12 + } +#endif /* CONFIG_TLSV12 */ + + wpa_hexdump(MSG_MSGDUMP, + "TLSv1: ServerKeyExchange signed_params hash", + hash, hlen); + +#ifdef CONFIG_TLSV12 + if (conn->rl.tls_version >= TLS_VERSION_1_2) { + /* + * RFC 5246, 4.7: + * TLS v1.2 adds explicit indication of the used + * signature and hash algorithms. + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + */ + if (pos + 2 > end) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + *pos++ = TLS_HASH_ALG_SHA256; + *pos++ = TLS_SIGN_ALG_RSA; + } +#endif /* CONFIG_TLSV12 */ + + /* + * RFC 2246, 4.7: + * In digital signing, one-way hash functions are used as input + * for a signing algorithm. A digitally-signed element is + * encoded as an opaque vector <0..2^16-1>, where the length is + * specified by the signing algorithm and key. + * + * In RSA signing, a 36-byte structure of two hashes (one SHA + * and one MD5) is signed (encrypted with the private key). It + * is encoded with PKCS #1 block type 0 or type 1 as described + * in [PKCS1]. + */ + signed_start = pos; /* length to be filled */ + pos += 2; + clen = end - pos; + if (conn->cred == NULL || + crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, + pos, &clen) < 0) { + wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + WPA_PUT_BE16(signed_start, clen); + + pos += clen; + } + WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,