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>
This commit is contained in:
parent
6531963584
commit
129b9b991a
4 changed files with 111 additions and 152 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue