Browse Source

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>
Jouni Malinen 11 years ago
parent
commit
6531963584
4 changed files with 131 additions and 143 deletions
  1. 19 50
      src/tls/tlsv1_client_read.c
  2. 65 0
      src/tls/tlsv1_common.c
  3. 9 1
      src/tls/tlsv1_common.h
  4. 38 92
      src/tls/tlsv1_server_write.c

+ 19 - 50
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;
-		} 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)
+			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;
-		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 */
+		} else {
+			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);
+		}
 
+		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;

+ 65 - 0
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;
+}

+ 9 - 1
src/tls/tlsv1_common.h

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

+ 38 - 92
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 {
+
+#else /* CONFIG_TLSV12 */
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
 #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;
-			}
+		} else {
+			hlen = tls_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				pos - server_params, hash);
+		}
 
-			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
+		if (hlen < 0) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
 		}
-#endif /* CONFIG_TLSV12 */
 
-		wpa_hexdump(MSG_MSGDUMP,
-			    "TLSv1: ServerKeyExchange signed_params hash",
+		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