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 <j@w1.fi>
This commit is contained in:
parent
41ebfe97ec
commit
65074a2a7c
7 changed files with 368 additions and 21 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
|
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -459,10 +459,15 @@ struct tlsv1_client * tlsv1_client_init(void)
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
suites = conn->cipher_suites;
|
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_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_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_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_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_3DES_EDE_CBC_SHA;
|
||||||
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
||||||
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLSv1 client - read handshake message
|
* TLSv1 client - read handshake message
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* 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,
|
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);
|
tlsv1_client_free_dh(conn);
|
||||||
|
|
||||||
|
@ -421,6 +422,7 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
|
||||||
|
|
||||||
if (end - pos < 3)
|
if (end - pos < 3)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
server_params = pos;
|
||||||
conn->dh_p_len = WPA_GET_BE16(pos);
|
conn->dh_p_len = WPA_GET_BE16(pos);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
|
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;
|
pos += conn->dh_ys_len;
|
||||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
|
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
|
||||||
conn->dh_ys, conn->dh_ys_len);
|
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;
|
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);
|
wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
|
||||||
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
||||||
if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
|
if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
|
||||||
if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
|
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(conn, TLS_ALERT_LEVEL_FATAL,
|
||||||
TLS_ALERT_DECODE_ERROR);
|
TLS_ALERT_DECODE_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLSv1 client - write handshake message
|
* TLSv1 client - write handshake message
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* 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 */
|
/* ClientDiffieHellmanPublic */
|
||||||
u8 *csecret, *csecret_start, *dh_yc, *shared;
|
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;
|
hs_length = pos;
|
||||||
pos += 3;
|
pos += 3;
|
||||||
/* body - ClientKeyExchange */
|
/* body - ClientKeyExchange */
|
||||||
if (keyx == TLS_KEY_X_DH_anon) {
|
if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
|
||||||
if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
|
if (tlsv1_key_x_dh(conn, &pos, end) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
|
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLSv1 common routines
|
* TLSv1 common routines
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -33,6 +33,10 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
|
||||||
TLS_HASH_SHA },
|
TLS_HASH_SHA },
|
||||||
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
|
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
|
||||||
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
|
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_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
|
||||||
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
|
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
|
||||||
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
|
{ 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_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
|
||||||
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
|
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
|
||||||
TLS_HASH_SHA },
|
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_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
|
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_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
|
||||||
TLS_HASH_SHA },
|
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_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||||
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
|
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
|
||||||
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
|
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
|
||||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
||||||
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
|
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
|
||||||
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
|
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_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
|
||||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
||||||
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
|
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
|
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -361,10 +361,15 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
suites = conn->cipher_suites;
|
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_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_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_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_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_3DES_EDE_CBC_SHA;
|
||||||
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
||||||
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLSv1 server - read handshake message
|
* TLSv1 server - read handshake message
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* 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)
|
struct tlsv1_server *conn, const u8 *pos, const u8 *end)
|
||||||
{
|
{
|
||||||
const u8 *dh_yc;
|
const u8 *dh_yc;
|
||||||
|
@ -747,11 +747,11 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
|
||||||
else
|
else
|
||||||
keyx = suite->key_exchange;
|
keyx = suite->key_exchange;
|
||||||
|
|
||||||
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_dh_anon(conn, pos, end) < 0)
|
tls_process_client_key_exchange_dh(conn, pos, end) < 0)
|
||||||
return -1;
|
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)
|
tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TLSv1 server - write handshake message
|
* TLSv1 server - write handshake message
|
||||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -245,7 +245,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||||
{
|
{
|
||||||
tls_key_exchange keyx;
|
tls_key_exchange keyx;
|
||||||
const struct tls_cipher_suite *suite;
|
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;
|
size_t rlen;
|
||||||
u8 *dh_ys;
|
u8 *dh_ys;
|
||||||
size_t dh_ys_len;
|
size_t dh_ys_len;
|
||||||
|
@ -261,8 +261,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyx != TLS_KEY_X_DH_anon) {
|
if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
|
||||||
/* TODO? */
|
|
||||||
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
|
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
|
||||||
"supported with key exchange type %d", keyx);
|
"supported with key exchange type %d", keyx);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -369,6 +368,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||||
pos += 3;
|
pos += 3;
|
||||||
|
|
||||||
/* body - ServerDHParams */
|
/* body - ServerDHParams */
|
||||||
|
server_params = pos;
|
||||||
/* dh_p */
|
/* dh_p */
|
||||||
if (pos + 2 + conn->cred->dh_p_len > end) {
|
if (pos + 2 + conn->cred->dh_p_len > end) {
|
||||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
|
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;
|
pos += dh_ys_len;
|
||||||
os_free(dh_ys);
|
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);
|
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||||
|
|
||||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||||
|
|
Loading…
Reference in a new issue