diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c index 133dc0e0c..44a21556b 100644 --- a/src/charon/config/credentials/local_credential_store.c +++ b/src/charon/config/credentials/local_credential_store.c @@ -832,7 +832,7 @@ static status_t verify_signature(private_local_credential_store_t *this, } *issuer_p = issuer; } - sig_status = public_key->verify_emsa_pkcs1_signature(public_key, hash, signature); + sig_status = public_key->verify_emsa_pkcs1_signature(public_key, HASH_UNKNOWN, hash, signature); if (sig_status == SUCCESS) { DBG2(DBG_CFG, "candidate peer certificate has a matching RSA public key"); diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c index b4ae37b2e..214cfb1e6 100755 --- a/src/libstrongswan/crypto/crl.c +++ b/src/libstrongswan/crypto/crl.c @@ -304,6 +304,11 @@ bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl) break; case CRL_OBJ_ALGORITHM: crl->algorithm = parse_algorithmIdentifier(object, level, NULL); + if (crl->algorithm != crl->sigAlg) + { + DBG1(" signature algorithms do not agree"); + return FALSE; + } break; case CRL_OBJ_SIGNATURE: crl->signature = object; @@ -374,7 +379,14 @@ static bool is_newer(const private_crl_t *this, const private_crl_t *other) */ static bool verify(const private_crl_t *this, const rsa_public_key_t *signer) { - return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature) == SUCCESS; + hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->algorithm); + + if (algorithm == HASH_UNKNOWN) + { + DBG1(" unknown signature algorithm"); + return FALSE; + } + return signer->verify_emsa_pkcs1_signature(signer, algorithm, this->tbsCertList, this->signature) == SUCCESS; } /** diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c index 7fa6346d6..f386a3fe3 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -24,12 +24,14 @@ #include "hasher.h" +#include #include #include #include -ENUM(hash_algorithm_names, HASH_MD2, HASH_SHA512, +ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512, + "HASH_UNKNOWN", "HASH_MD2", "HASH_MD5", "HASH_SHA1", @@ -63,3 +65,42 @@ hasher_t *hasher_create(hash_algorithm_t hash_algorithm) return NULL; } } + +/* + * Described in header. + */ +hash_algorithm_t hasher_algorithm_from_oid(int oid) +{ + hash_algorithm_t algorithm; + + switch (oid) + { + case OID_MD2: + case OID_MD2_WITH_RSA: + algorithm = HASH_MD2; + break; + case OID_MD5: + case OID_MD5_WITH_RSA: + algorithm = HASH_MD5; + break; + case OID_SHA1: + case OID_SHA1_WITH_RSA: + algorithm = HASH_SHA1; + break; + case OID_SHA256: + case OID_SHA256_WITH_RSA: + algorithm = HASH_SHA256; + break; + case OID_SHA384: + case OID_SHA384_WITH_RSA: + algorithm = HASH_SHA384; + break; + case OID_SHA512: + case OID_SHA512_WITH_RSA: + algorithm = HASH_SHA512; + break; + default: + algorithm = HASH_UNKNOWN; + } + return algorithm; +} diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index 6c17f892d..4adc22afa 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -42,17 +42,18 @@ typedef struct hasher_t hasher_t; * @ingroup hashers */ enum hash_algorithm_t { - HASH_MD2 = 0, + HASH_UNKNOWN = 0, + HASH_MD2 = 1, /** Implemented in class md5_hasher_t */ - HASH_MD5 = 1, + HASH_MD5 = 2, /** Implemented in class sha1_hasher_t */ - HASH_SHA1 = 2, + HASH_SHA1 = 3, /** Implemented in class sha2_hasher_t */ - HASH_SHA256 = 3, + HASH_SHA256 = 4, /** Implemented in class sha2_hasher_t */ - HASH_SHA384 = 4, + HASH_SHA384 = 5, /** Implemented in class sha2_hasher_t */ - HASH_SHA512 = 5, + HASH_SHA512 = 6, }; #define HASH_SIZE_MD2 16 @@ -68,7 +69,6 @@ enum hash_algorithm_t { */ extern enum_name_t *hash_algorithm_names; - /** * @brief Generic interface for all hash functions. * @@ -156,4 +156,16 @@ struct hasher_t { */ hasher_t *hasher_create(hash_algorithm_t hash_algorithm); +/** + * @brief Conversion of ASN.1 OID to hash algorithm. + * + * @param oid ASN.1 OID + * @return + * - hash algorithm + * - HASH_UNKNOWN if OID unsuported + * + * @ingroup hashers + */ +hash_algorithm_t hasher_algorithm_from_oid(int oid); + #endif /* HASHER_H_ */ diff --git a/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c index dcdab43a4..e4d907188 100644 --- a/src/libstrongswan/crypto/ocsp.c +++ b/src/libstrongswan/crypto/ocsp.c @@ -614,6 +614,13 @@ static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert) rsa_public_key_t *public_key; time_t until = UNDEFINED_TIME; err_t ugh; + hash_algorithm_t algorithm = hasher_algorithm_from_oid(res->algorithm); + + if (algorithm == HASH_UNKNOWN) + { + DBG1("unknown signature algorithm"); + return FALSE; + } DBG2("verifying ocsp response signature:"); DBG2("signer: '%D'", ocsp_cert->get_subject(ocsp_cert)); @@ -626,8 +633,8 @@ static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert) return FALSE; } public_key = ocsp_cert->get_public_key(ocsp_cert); - - return public_key->verify_emsa_pkcs1_signature(public_key, res->tbs, res->signature) == SUCCESS; + + return public_key->verify_emsa_pkcs1_signature(public_key, algorithm, res->tbs, res->signature) == SUCCESS; } /** diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c index 38899670f..6de6a1d6e 100644 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.c +++ b/src/libstrongswan/crypto/rsa/rsa_public_key.c @@ -33,70 +33,10 @@ #include #include -/* - * For simplicity, we use these predefined values for hash algorithm OIDs - * These also contain the length of the appended hash - * These values are also used in rsa_private_key.c. - */ - -const u_int8_t md2_oid[] = { - 0x30,0x20, - 0x30,0x0c, - 0x06,0x08, - 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02, - 0x05,0x00, - 0x04,0x10 -}; - -const u_int8_t md5_oid[] = { - 0x30,0x20, - 0x30,0x0c, - 0x06,0x08, - 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05, - 0x05,0x00, - 0x04,0x10 -}; - -const u_int8_t sha1_oid[] = { - 0x30,0x21, - 0x30,0x09, - 0x06,0x05, - 0x2b,0x0e,0x03,0x02,0x1a, - 0x05,0x00, - 0x04,0x14 -}; - -const u_int8_t sha256_oid[] = { - 0x30,0x31, - 0x30,0x0d, - 0x06,0x09, - 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01, - 0x05,0x00, - 0x04,0x20 -}; - -const u_int8_t sha384_oid[] = { - 0x30,0x41, - 0x30,0x0d, - 0x06,0x09, - 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02, - 0x05,0x00, - 0x04,0x30 -}; - -const u_int8_t sha512_oid[] = { - 0x30,0x51, - 0x30,0x0d, - 0x06,0x09, - 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03, - 0x05,0x00, - 0x04,0x40 -}; - #define LARGEST_HASH_OID_SIZE sizeof(sha512_oid) -/* ASN.1 definition public key */ -static const asn1Object_t pubkey_objects[] = { +/* ASN.1 definition of RSApublicKey */ +static const asn1Object_t pubkeyObjects[] = { { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ @@ -107,6 +47,17 @@ static const asn1Object_t pubkey_objects[] = { #define PUB_KEY_EXPONENT 2 #define PUB_KEY_ROOF 3 +/* ASN.1 definition of digestInfo */ +static const asn1Object_t digestInfoObjects[] = { + { 0, "digestInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ +}; + +#define DIGEST_INFO_ALGORITHM 1 +#define DIGEST_INFO_DIGEST 2 +#define DIGEST_INFO_ROOF 3 + typedef struct private_rsa_public_key_t private_rsa_public_key_t; /** @@ -186,12 +137,11 @@ static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data) /** * Implementation of rsa_public_key.verify_emsa_pkcs1_signature. */ -static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, chunk_t data, chunk_t signature) +static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, + hash_algorithm_t algorithm, + chunk_t data, chunk_t signature) { - hasher_t *hasher = NULL; - chunk_t hash; - chunk_t em; - u_int8_t *pos; + chunk_t em_ori, em; status_t res = FAILED; /* remove any preceding 0-bytes from signature */ @@ -207,7 +157,7 @@ static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this } /* unpack signature */ - em = this->rsavp1(this, signature); + em_ori = em = this->rsavp1(this, signature); /* result should look like this: * EM = 0x00 || 0x01 || PS || 0x00 || T. @@ -216,98 +166,99 @@ static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this */ /* check magic bytes */ - if ((*(em.ptr) != 0x00) || (*(em.ptr+1) != 0x01)) + if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01) { goto end; } + em.ptr += 2; + em.len -= 2; /* find magic 0x00 */ - pos = em.ptr + 2; - while (pos <= em.ptr + em.len) + while (em.len > 0) { - if (*pos == 0x00) + if (*em.ptr == 0x00) { /* found magic byte, stop */ - pos++; + em.ptr++; + em.len--; break; } - else if (*pos != 0xFF) + else if (*em.ptr != 0xFF) { /* bad padding, decryption failed ?!*/ goto end; } - pos++; + em.ptr++; + em.len--; } - if (pos + LARGEST_HASH_OID_SIZE > em.ptr + em.len) + if (em.len == 0) { - /* not enought room for oid compare */ + /* no digestInfo found */ goto end; } - if (memeq(md2_oid, pos, sizeof(md2_oid))) + /* parse ASN.1-based digestInfo */ { - hasher = hasher_create(HASH_MD2); - pos += sizeof(md2_oid); - } - else if (memeq(md5_oid, pos, sizeof(md5_oid))) - { - hasher = hasher_create(HASH_MD5); - pos += sizeof(md5_oid); - } - else if (memeq(sha1_oid, pos, sizeof(sha1_oid))) - { - hasher = hasher_create(HASH_SHA1); - pos += sizeof(sha1_oid); - } - else if (memeq(sha256_oid, pos, sizeof(sha256_oid))) - { - hasher = hasher_create(HASH_SHA256); - pos += sizeof(sha256_oid); - } - else if (memeq(sha384_oid, pos, sizeof(sha384_oid))) - { - hasher = hasher_create(HASH_SHA384); - pos += sizeof(sha384_oid); - } - else if (memeq(sha512_oid, pos, sizeof(sha512_oid))) - { - hasher = hasher_create(HASH_SHA512); - pos += sizeof(sha512_oid); - } + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + hash_algorithm_t hash_algorithm; + + asn1_init(&ctx, em, 0, FALSE, FALSE); + + while (objectID < DIGEST_INFO_ROOF) + { + if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx)) + { + goto end; + } + if (objectID == DIGEST_INFO_ALGORITHM) + { + int hash_oid = parse_algorithmIdentifier(object, level+1, NULL); + + hash_algorithm = hasher_algorithm_from_oid(hash_oid); + if (hash_algorithm == HASH_UNKNOWN + || (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) + { + goto end; + } + } + else if (objectID == DIGEST_INFO_DIGEST) + { + chunk_t hash; + hasher_t *hasher = hasher_create(hash_algorithm); + + if (object.len != hasher->get_hash_size(hasher)) + { + /* wrong hash size */ + hasher->destroy(hasher); + goto end; + } + + /* build our own hash */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); - if (hasher == NULL) - { - /* unsupported hash algorithm */ - res = NOT_SUPPORTED;; - goto end; + /* compare the hashes */ + res = memeq(object.ptr, hash.ptr, hash.len) ? SUCCESS : FAILED; + free(hash.ptr); + } + objectID++; + } } - - if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len) - { - /* bad length */ - hasher->destroy(hasher); - goto end; - } - - /* build our own hash */ - hasher->allocate_hash(hasher, data, &hash); - hasher->destroy(hasher); - - /* compare the hashes */ - res = memeq(hash.ptr, pos, hash.len) ? SUCCESS : FAILED; - free(hash.ptr); end: - free(em.ptr); + free(em_ori.ptr); return res; } - + /** * Implementation of rsa_public_key.get_key. */ static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key) -{ +{ chunk_t n, e; n.len = this->k; @@ -391,7 +342,7 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void) private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t); /* public functions */ - this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature; + this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,hash_algorithm_t,chunk_t,chunk_t))verify_emsa_pkcs1_signature; this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key; this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key; this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus; @@ -447,7 +398,7 @@ rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob) while (objectID < PUB_KEY_ROOF) { - if (!extract_object(pubkey_objects, &objectID, &object, &level, &ctx)) + if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx)) { destroy(this); return FALSE; diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.h b/src/libstrongswan/crypto/rsa/rsa_public_key.h index 1ee54dcc3..f1d45cc4f 100644 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.h +++ b/src/libstrongswan/crypto/rsa/rsa_public_key.h @@ -29,6 +29,7 @@ typedef struct rsa_public_key_t rsa_public_key_t; #include #include +#include /** * @brief RSA public key with associated functions. @@ -58,6 +59,7 @@ struct rsa_public_key_t { * * @param this rsa_public_key to use * @param data data to sign + # @param algorithm hash algorithm the signature is based on * @param signature signature to verify * @return * - SUCCESS, if signature ok @@ -66,7 +68,9 @@ struct rsa_public_key_t { * - INVALID_ARG, if signature is not a signature * - FAILED if signature invalid or unable to verify */ - status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this, chunk_t data, chunk_t signature); + status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this, + hash_algorithm_t algorithm, + chunk_t data, chunk_t signature); /** * @brief Gets the key. diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c index d68fdbf2c..646043b06 100755 --- a/src/libstrongswan/crypto/x509.c +++ b/src/libstrongswan/crypto/x509.c @@ -807,7 +807,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this) case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION) { - DBG2(" unsupported public key algorithm"); + DBG1(" unsupported public key algorithm"); return FALSE; } break; @@ -819,7 +819,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this) } else { - DBG2(" invalid RSA public key format"); + DBG1(" invalid RSA public key format"); return FALSE; } break; @@ -872,6 +872,11 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this) } case X509_OBJ_ALGORITHM: this->algorithm = parse_algorithmIdentifier(object, level, NULL); + if (this->algorithm != this->sigAlg) + { + DBG1(" signature algorithms do not agree"); + return FALSE; + } break; case X509_OBJ_SIGNATURE: this->signature = object; @@ -1129,7 +1134,14 @@ static iterator_t *create_ocspuri_iterator(const private_x509_t *this) */ static bool verify(const private_x509_t *this, const rsa_public_key_t *signer) { - return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertificate, this->signature) == SUCCESS; + hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->algorithm); + + if (algorithm == HASH_UNKNOWN) + { + DBG1(" unknown signature algorithm"); + return FALSE; + } + return signer->verify_emsa_pkcs1_signature(signer, algorithm, this->tbsCertificate, this->signature) == SUCCESS; } /** @@ -1324,8 +1336,15 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level) this->isSelfSigned = FALSE; if (this->subject->equals(this->subject, this->issuer)) { + hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->algorithm); + + if (algorithm == HASH_UNKNOWN) + { + destroy(this); + return NULL; + } this->isSelfSigned = this->public_key->verify_emsa_pkcs1_signature(this->public_key, - this->tbsCertificate, this->signature) == SUCCESS; + algorithm, this->tbsCertificate, this->signature) == SUCCESS; } if (this->isSelfSigned) {