diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 8313efbe2..7b79da36d 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -470,16 +470,13 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, 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; + u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *sbuf; + size_t buflen; + int hlen; u16 slen; - struct crypto_hash *ctx; - hpos = hash; - -#ifdef CONFIG_TLSV12 if (conn->rl.tls_version == TLS_VERSION_1_2) { +#ifdef CONFIG_TLSV12 /* * RFC 5246, 4.7: * TLS v1.2 adds explicit indication of the used @@ -500,51 +497,22 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, } 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; + hlen = tlsv12_key_x_server_params_hash( + conn->rl.tls_version, conn->client_random, + conn->server_random, server_params, + server_params_end - server_params, hash); +#else /* CONFIG_TLSV12 */ + goto fail; +#endif /* CONFIG_TLSV12 */ } 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; + hlen = tls_key_x_server_params_hash( + conn->rl.tls_version, conn->client_random, + conn->server_random, server_params, + server_params_end - server_params, hash); } - 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 */ + if (hlen < 0) + goto fail; wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash", hash, hlen); @@ -606,7 +574,8 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, } #endif /* CONFIG_TLSV12 */ - if (buflen != hlen || os_memcmp(sbuf, hash, buflen) != 0) { + if (buflen != (unsigned int) 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; diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c index d05df856d..dd67d28e0 100644 --- a/src/tls/tlsv1_common.c +++ b/src/tls/tlsv1_common.c @@ -9,6 +9,7 @@ #include "includes.h" #include "common.h" +#include "crypto/md5.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "x509v3.h" @@ -331,3 +332,67 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label, return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out, outlen); } + + +#ifdef CONFIG_TLSV12 +int tlsv12_key_x_server_params_hash(u16 tls_version, + const u8 *client_random, + const u8 *server_random, + const u8 *server_params, + size_t server_params_len, u8 *hash) +{ + size_t hlen; + struct crypto_hash *ctx; + + ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0); + if (ctx == NULL) + return -1; + crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, server_params_len); + hlen = SHA256_MAC_LEN; + if (crypto_hash_finish(ctx, hash, &hlen) < 0) + return -1; + + return hlen; +} +#endif /* CONFIG_TLSV12 */ + + +int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, + const u8 *server_random, + const u8 *server_params, + size_t server_params_len, u8 *hash) +{ + u8 *hpos; + size_t hlen; + enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; + struct crypto_hash *ctx; + + hpos = hash; + + if (alg == SIGN_ALG_RSA) { + ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); + if (ctx == NULL) + return -1; + crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, server_params_len); + hlen = MD5_MAC_LEN; + if (crypto_hash_finish(ctx, hash, &hlen) < 0) + return -1; + hpos += hlen; + } + + ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); + if (ctx == NULL) + return -1; + crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, server_params_len); + hlen = hash + sizeof(hash) - hpos; + if (crypto_hash_finish(ctx, hpos, &hlen) < 0) + return -1; + hpos += hlen; + return hpos - hash; +} diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h index f28c0cdc4..4251d3936 100644 --- a/src/tls/tlsv1_common.h +++ b/src/tls/tlsv1_common.h @@ -1,6 +1,6 @@ /* * TLSv1 common definitions - * 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. @@ -257,5 +257,13 @@ int tls_version_ok(u16 ver); const char * tls_version_str(u16 ver); int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen); +int tlsv12_key_x_server_params_hash(u16 tls_version, const u8 *client_random, + const u8 *server_random, + const u8 *server_params, + size_t server_params_len, u8 *hash); +int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, + const u8 *server_random, + const u8 *server_params, + size_t server_params_len, u8 *hash); #endif /* TLSV1_COMMON_H */ diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c index 39dbad4fe..b4eadca27 100644 --- a/src/tls/tlsv1_server_write.c +++ b/src/tls/tlsv1_server_write.c @@ -434,32 +434,35 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, */ if (keyx == TLS_KEY_X_DHE_RSA) { - u8 hash[100], *hpos; + u8 hash[100]; u8 *signed_start; - size_t hlen, clen; - enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; - struct crypto_hash *ctx; + size_t clen; + int hlen; + if (conn->rl.tls_version >= TLS_VERSION_1_2) { #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) { + hlen = tlsv12_key_x_server_params_hash( + conn->rl.tls_version, conn->client_random, + conn->server_random, server_params, + pos - server_params, hash + 19); + + /* + * RFC 5246, 4.7: + * TLS v1.2 adds explicit indication of the used + * signature and hash algorithms. + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + */ + if (hlen < 0 || 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; /* * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 @@ -479,85 +482,28 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65" "\x03\x04\x02\x01\x05\x00\x04\x20", 19); + +#else /* CONFIG_TLSV12 */ + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; +#endif /* CONFIG_TLSV12 */ } 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 + hlen = tls_key_x_server_params_hash( + conn->rl.tls_version, conn->client_random, + conn->server_random, server_params, + pos - server_params, hash); } -#endif /* CONFIG_TLSV12 */ - wpa_hexdump(MSG_MSGDUMP, - "TLSv1: ServerKeyExchange signed_params hash", + if (hlen < 0) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + return -1; + } + + wpa_hexdump(MSG_MSGDUMP, "TLS: 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