diff options
Diffstat (limited to 'crypto/asn1/a_verify.c')
-rw-r--r-- | crypto/asn1/a_verify.c | 162 |
1 files changed, 105 insertions, 57 deletions
diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c index 4b5f54234fa5..66809bd6d2ff 100644 --- a/crypto/asn1/a_verify.c +++ b/crypto/asn1/a_verify.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -20,8 +20,9 @@ #include <openssl/evp.h> #include "crypto/asn1.h" #include "crypto/evp.h" +#include "crypto/rsa.h" -#ifndef NO_ASN1_OLD +#ifndef OPENSSL_NO_DEPRECATED_3_0 int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey) @@ -32,29 +33,29 @@ int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature, int ret = -1, i, inl; if (ctx == NULL) { - ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); goto err; } i = OBJ_obj2nid(a->algorithm); type = EVP_get_digestbyname(OBJ_nid2sn(i)); if (type == NULL) { - ASN1err(ASN1_F_ASN1_VERIFY, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); goto err; } if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) { - ASN1err(ASN1_F_ASN1_VERIFY, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); goto err; } inl = i2d(data, NULL); if (inl <= 0) { - ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR); goto err; } buf_in = OPENSSL_malloc((unsigned int)inl); if (buf_in == NULL) { - ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); goto err; } p = buf_in; @@ -66,14 +67,14 @@ int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature, OPENSSL_clear_free(buf_in, (unsigned int)inl); if (!ret) { - ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_EVP_LIB); + ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); goto err; } ret = -1; if (EVP_VerifyFinal(ctx, (unsigned char *)signature->data, (unsigned int)signature->length, pkey) <= 0) { - ASN1err(ASN1_F_ASN1_VERIFY, ERR_R_EVP_LIB); + ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); ret = 0; goto err; } @@ -85,81 +86,129 @@ int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature, #endif -int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, - ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) +int ASN1_item_verify(const ASN1_ITEM *it, const X509_ALGOR *alg, + const ASN1_BIT_STRING *signature, const void *data, + EVP_PKEY *pkey) { - EVP_MD_CTX *ctx = NULL; + return ASN1_item_verify_ex(it, alg, signature, data, NULL, pkey, NULL, NULL); +} + +int ASN1_item_verify_ex(const ASN1_ITEM *it, const X509_ALGOR *alg, + const ASN1_BIT_STRING *signature, const void *data, + const ASN1_OCTET_STRING *id, EVP_PKEY *pkey, + OSSL_LIB_CTX *libctx, const char *propq) +{ + EVP_MD_CTX *ctx; + int rv = -1; + + if ((ctx = evp_md_ctx_new_ex(pkey, id, libctx, propq)) != NULL) { + rv = ASN1_item_verify_ctx(it, alg, signature, data, ctx); + EVP_PKEY_CTX_free(EVP_MD_CTX_get_pkey_ctx(ctx)); + EVP_MD_CTX_free(ctx); + } + return rv; +} + +int ASN1_item_verify_ctx(const ASN1_ITEM *it, const X509_ALGOR *alg, + const ASN1_BIT_STRING *signature, const void *data, + EVP_MD_CTX *ctx) +{ + EVP_PKEY *pkey; unsigned char *buf_in = NULL; int ret = -1, inl = 0; int mdnid, pknid; size_t inll = 0; - if (!pkey) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER); + pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx)); + + if (pkey == NULL) { + ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER); return -1; } if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); return -1; } - ctx = EVP_MD_CTX_new(); - if (ctx == NULL) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE); - goto err; - } - /* Convert signature OID into digest and public key OIDs */ - if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid)) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); + if (!OBJ_find_sigid_algs(OBJ_obj2nid(alg->algorithm), &mdnid, &pknid)) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } - if (mdnid == NID_undef) { - if (!pkey->ameth || !pkey->ameth->item_verify) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, - ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); + + if (mdnid == NID_undef && evp_pkey_is_legacy(pkey)) { + if (pkey->ameth == NULL || pkey->ameth->item_verify == NULL) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } - ret = pkey->ameth->item_verify(ctx, it, asn, a, signature, pkey); + ret = pkey->ameth->item_verify(ctx, it, data, alg, signature, pkey); /* - * Return value of 2 means carry on, anything else means we exit - * straight away: either a fatal error of the underlying verification - * routine handles all verification. + * Return values meaning: + * <=0: error. + * 1: method does everything. + * 2: carry on as normal, method has called EVP_DigestVerifyInit() */ - if (ret != 2) + if (ret <= 0) + ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); + if (ret <= 1) goto err; - ret = -1; } else { - const EVP_MD *type = EVP_get_digestbynid(mdnid); - - if (type == NULL) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, - ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); - goto err; - } - - /* Check public key OID matches public key type */ - if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_WRONG_PUBLIC_KEY_TYPE); - goto err; - } + const EVP_MD *type = NULL; - if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); - ret = 0; - goto err; + /* + * We don't yet have the ability for providers to be able to handle + * X509_ALGOR style parameters. Fortunately the only one that needs this + * so far is RSA-PSS, so we just special case this for now. In some + * future version of OpenSSL we should push this to the provider. + */ + if (mdnid == NID_undef && pknid == EVP_PKEY_RSA_PSS) { + if (!EVP_PKEY_is_a(pkey, "RSA") && !EVP_PKEY_is_a(pkey, "RSA-PSS")) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE); + goto err; + } + /* This function also calls EVP_DigestVerifyInit */ + if (ossl_rsa_pss_to_ctx(ctx, NULL, alg, pkey) <= 0) { + ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR); + goto err; + } + } else { + /* Check public key OID matches public key type */ + if (!EVP_PKEY_is_a(pkey, OBJ_nid2sn(pknid))) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE); + goto err; + } + + if (mdnid != NID_undef) { + type = EVP_get_digestbynid(mdnid); + if (type == NULL) { + ERR_raise(ERR_LIB_ASN1, + ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + goto err; + } + } + + /* + * Note that some algorithms (notably Ed25519 and Ed448) may allow + * a NULL digest value. + */ + if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) { + ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); + ret = 0; + goto err; + } } - } - inl = ASN1_item_i2d(asn, &buf_in, it); + inl = ASN1_item_i2d(data, &buf_in, it); if (inl <= 0) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_INTERNAL_ERROR); + ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR); + ret = -1; goto err; } if (buf_in == NULL) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); + ret = -1; goto err; } inll = inl; @@ -167,12 +216,11 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ret = EVP_DigestVerify(ctx, signature->data, (size_t)signature->length, buf_in, inl); if (ret <= 0) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); + ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); goto err; } ret = 1; err: OPENSSL_clear_free(buf_in, inll); - EVP_MD_CTX_free(ctx); return ret; } |