Browse Source

TLS: Share a helper function for verifying Signature

This same design is used in both the server and the client roles in the
internal TLS implementation. Instead of duplicated implementation, use a
helper function.

Signed-off-by: Jouni Malinen <j@w1.fi>
Jouni Malinen 11 years ago
parent
commit
129b9b991a
4 changed files with 111 additions and 152 deletions
  1. 6 68
      src/tls/tlsv1_client_read.c
  2. 96 0
      src/tls/tlsv1_common.c
  3. 3 0
      src/tls/tlsv1_common.h
  4. 6 84
      src/tls/tlsv1_server_read.c

+ 6 - 68
src/tls/tlsv1_client_read.c

@@ -414,6 +414,7 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 					tls_key_exchange key_exchange)
 {
 	const u8 *pos, *end, *server_params, *server_params_end;
+	u8 alert;
 
 	tlsv1_client_free_dh(conn);
 
@@ -470,10 +471,8 @@ 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], *sbuf;
-		size_t buflen;
+		u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 		int hlen;
-		u16 slen;
 
 		if (conn->rl.tls_version == TLS_VERSION_1_2) {
 #ifdef CONFIG_TLSV12
@@ -516,72 +515,11 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 		wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
 			    hash, hlen);
 
-		if (end - pos < 2)
+		if (tls_verify_signature(conn->rl.tls_version,
+					 conn->server_rsa_key,
+					 hash, hlen, pos, end - pos,
+					 &alert) < 0)
 			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 != (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;
-		}
-
-		os_free(sbuf);
 	}
 
 	return 0;

+ 96 - 0
src/tls/tlsv1_common.c

@@ -396,3 +396,99 @@ int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
 	hpos += hlen;
 	return hpos - hash;
 }
+
+
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+			 const u8 *data, size_t data_len,
+			 const u8 *pos, size_t len, u8 *alert)
+{
+	u8 *buf;
+	const u8 *end = pos + len;
+	const u8 *decrypted;
+	u16 slen;
+	size_t buflen;
+
+	if (end - pos < 2) {
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+	slen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < slen) {
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+	if (end - pos > slen) {
+		wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
+			    pos + slen, end - pos - slen);
+		end = pos + slen;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+	if (pk == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+
+	buflen = end - pos;
+	buf = os_malloc(end - pos);
+	if (buf == NULL) {
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+	if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
+	    0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+		os_free(buf);
+		*alert = TLS_ALERT_DECRYPT_ERROR;
+		return -1;
+	}
+	decrypted = buf;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+			decrypted, buflen);
+
+#ifdef CONFIG_TLSV12
+	if (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(buf, "\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");
+			decrypted = buf + 19;
+			buflen -= 19;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
+			os_free(buf);
+			*alert = TLS_ALERT_DECRYPT_ERROR;
+			return -1;
+		}
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (buflen != data_len || os_memcmp(decrypted, data, data_len) != 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
+		os_free(buf);
+		*alert = TLS_ALERT_DECRYPT_ERROR;
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}

+ 3 - 0
src/tls/tlsv1_common.h

@@ -265,5 +265,8 @@ 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);
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+			 const u8 *data, size_t data_len,
+			 const u8 *pos, size_t len, u8 *alert);
 
 #endif /* TLSV1_COMMON_H */

+ 6 - 84
src/tls/tlsv1_server_read.c

@@ -769,10 +769,10 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
 	const u8 *pos, *end;
 	size_t left, len;
 	u8 type;
-	size_t hlen, buflen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
+	size_t hlen;
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
 	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
-	u16 slen;
+	u8 alert;
 
 	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
 		if (conn->verify_peer) {
@@ -917,90 +917,12 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
 
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
-	if (end - pos < 2) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	slen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < slen) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
-	if (conn->client_rsa_key == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
-			   "signature");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	buflen = end - pos;
-	buf = os_malloc(end - pos);
-	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
-					    pos, end - pos, buf, &buflen) < 0)
-	{
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
-		os_free(buf);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
+	if (tls_verify_signature(conn->rl.tls_version, conn->client_rsa_key,
+				 hash, hlen, pos, end - pos, &alert) < 0) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 		return -1;
 	}
 
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
-			buf, 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(buf, "\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(buf, buf + 19, buflen - 19);
-			buflen -= 19;
-		} else {
-			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
-				   "DigestInfo");
-			os_free(buf);
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_DECRYPT_ERROR);
-			return -1;
-		}
-	}
-#endif /* CONFIG_TLSV12 */
-
-	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
-			   "CertificateVerify - did not match with calculated "
-			   "hash");
-		os_free(buf);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-
-	os_free(buf);
-
 	*in_len = end - in_data;
 
 	conn->state = CHANGE_CIPHER_SPEC;