diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 7b79da36d..475a6e903 100644 --- a/src/tls/tlsv1_client_read.c +++ b/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; diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c index dd67d28e0..8a4645bf2 100644 --- a/src/tls/tlsv1_common.c +++ b/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; +} diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h index 4251d3936..26e68af16 100644 --- a/src/tls/tlsv1_common.h +++ b/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 */ diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 137fd3abd..a5b732850 100644 --- a/src/tls/tlsv1_server_read.c +++ b/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,89 +917,11 @@ 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); + 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; } - 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); - 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;