TLS: Use a helper function for calculating ServerKeyExchange hash

Instead of separate server and client side implementations, use a common
set of helper functions for calculating the ServerParams hash for
ServerKeyExchange.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-03-09 16:26:27 +02:00
parent 65074a2a7c
commit 6531963584
4 changed files with 132 additions and 144 deletions

View file

@ -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;

View file

@ -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;
}

View file

@ -1,6 +1,6 @@
/*
* TLSv1 common definitions
* 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.
* 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 */

View file

@ -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