diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c index ea3e6171a..381b7a038 100644 --- a/src/tls/pkcs1.c +++ b/src/tls/pkcs1.c @@ -1,6 +1,6 @@ /* * PKCS #1 (RSA Encryption) - * Copyright (c) 2006-2009, Jouni Malinen + * Copyright (c) 2006-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,7 +9,9 @@ #include "includes.h" #include "common.h" +#include "crypto/crypto.h" #include "rsa.h" +#include "asn1.h" #include "pkcs1.h" @@ -189,3 +191,130 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, return 0; } + + +int pkcs1_v15_sig_ver(struct crypto_public_key *pk, + const u8 *s, size_t s_len, + const struct asn1_oid *hash_alg, + const u8 *hash, size_t hash_len) +{ + int res; + u8 *decrypted; + size_t decrypted_len; + const u8 *pos, *end, *next, *da_end; + struct asn1_hdr hdr; + struct asn1_oid oid; + + decrypted = os_malloc(s_len); + if (decrypted == NULL) + return -1; + decrypted_len = s_len; + res = crypto_public_key_decrypt_pkcs1(pk, s, s_len, decrypted, + &decrypted_len); + if (res < 0) { + wpa_printf(MSG_INFO, "PKCS #1: RSA decrypt failed"); + os_free(decrypted); + return -1; + } + wpa_hexdump(MSG_DEBUG, "Decrypted(S)", decrypted, decrypted_len); + + /* + * PKCS #1 v1.5, 10.1.2: + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + * + */ + if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Expected SEQUENCE (DigestInfo) - found class %d tag 0x%x", + hdr.class, hdr.tag); + os_free(decrypted); + return -1; + } + + pos = hdr.payload; + end = pos + hdr.length; + + /* + * X.509: + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + */ + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier) - found class %d tag 0x%x", + hdr.class, hdr.tag); + os_free(decrypted); + return -1; + } + da_end = hdr.payload + hdr.length; + + if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Failed to parse digestAlgorithm"); + os_free(decrypted); + return -1; + } + + if (!asn1_oid_equal(&oid, hash_alg)) { + char txt[100], txt2[100]; + asn1_oid_to_str(&oid, txt, sizeof(txt)); + asn1_oid_to_str(hash_alg, txt2, sizeof(txt2)); + wpa_printf(MSG_DEBUG, + "PKCS #1: Hash alg OID mismatch: was %s, expected %s", + txt, txt2); + os_free(decrypted); + return -1; + } + + /* Digest ::= OCTET STRING */ + pos = da_end; + end = decrypted + decrypted_len; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Expected OCTETSTRING (Digest) - found class %d tag 0x%x", + hdr.class, hdr.tag); + os_free(decrypted); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Decrypted Digest", + hdr.payload, hdr.length); + + if (hdr.length != hash_len || + os_memcmp(hdr.payload, hash, hdr.length) != 0) { + wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash"); + os_free(decrypted); + return -1; + } + + os_free(decrypted); + + if (hdr.payload + hdr.length != end) { + wpa_printf(MSG_INFO, + "PKCS #1: Extra data after signature - reject"); + + wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data", + hdr.payload + hdr.length, + end - hdr.payload - hdr.length); + return -1; + } + + return 0; +} diff --git a/src/tls/pkcs1.h b/src/tls/pkcs1.h index ed64defaa..f37ebf387 100644 --- a/src/tls/pkcs1.h +++ b/src/tls/pkcs1.h @@ -9,6 +9,9 @@ #ifndef PKCS1_H #define PKCS1_H +struct crypto_public_key; +struct asn1_oid; + int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, int use_private, const u8 *in, size_t inlen, u8 *out, size_t *outlen); @@ -18,5 +21,9 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len); +int pkcs1_v15_sig_ver(struct crypto_public_key *pk, + const u8 *s, size_t s_len, + const struct asn1_oid *hash_alg, + const u8 *hash, size_t hash_len); #endif /* PKCS1_H */