diff options
author | David Benjamin <davidben@chromium.org> | 2014-10-09 22:50:20 +0400 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2014-10-10 01:52:52 +0400 |
commit | 8f160a680b855328df7c33b03f8e9c9eefd59a84 (patch) | |
tree | e65f2cda2282d84c5b1ab982be6b610d2e531d5d /crypto/evp | |
parent | 2e1594dfb5f4efd9e93f1cc3db04e64f64ace5b4 (diff) |
Add EVP_DigestVerifyInitFromAlgorithm and EVP_DigestSignAlgorithm.
Factor the AlgorithmIdentifier portions of ASN1_item_sign and ASN1_item_verify
out. This makes it possible to initialize a signature context from an
AlgorithmIdentifier without needing the data parsed into an ASN1_ITEM/void*
pair and reserialized.
Change-Id: Idc2e06b1310a3f801aa25de323d39d2b7a44ef50
Reviewed-on: https://boringssl-review.googlesource.com/1916
Reviewed-by: Adam Langley <agl@google.com>
Diffstat (limited to 'crypto/evp')
-rw-r--r-- | crypto/evp/CMakeLists.txt | 1 | ||||
-rw-r--r-- | crypto/evp/algorithm.c | 162 | ||||
-rw-r--r-- | crypto/evp/evp_error.c | 3 | ||||
-rw-r--r-- | crypto/evp/internal.h | 30 | ||||
-rw-r--r-- | crypto/evp/p_rsa_asn1.c | 53 |
5 files changed, 209 insertions, 40 deletions
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt index c3d8d8a3..43e351a7 100644 --- a/crypto/evp/CMakeLists.txt +++ b/crypto/evp/CMakeLists.txt @@ -5,6 +5,7 @@ add_library( OBJECT + algorithm.c asn1.c digestsign.c evp.c diff --git a/crypto/evp/algorithm.c b/crypto/evp/algorithm.c new file mode 100644 index 00000000..4ec111bb --- /dev/null +++ b/crypto/evp/algorithm.c @@ -0,0 +1,162 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include <openssl/evp.h> + +#include <assert.h> + +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/obj.h> +#include <openssl/x509.h> + +#include "internal.h" + + +/* These functions use error codes under the ASN1 and X509 namespaces for + * compatibility with OpenSSL. */ + +int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { + const EVP_MD *digest; + EVP_PKEY *pkey; + int sign_nid, paramtype; + + digest = EVP_MD_CTX_md(ctx); + pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + if (!digest || !pkey) { + OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm, + EVP_R_CONTEXT_NOT_INITIALISED); + return 0; + } + + if (pkey->ameth->digest_sign_algorithm) { + switch (pkey->ameth->digest_sign_algorithm(ctx, algor)) { + case EVP_DIGEST_SIGN_ALGORITHM_ERROR: + return 0; + case EVP_DIGEST_SIGN_ALGORITHM_SUCCESS: + return 1; + case EVP_DIGEST_SIGN_ALGORITHM_DEFAULT: + /* Use default behavior. */ + break; + default: + assert(0); + } + } + + /* Default behavior: look up the OID for the algorithm/hash pair and encode + * that. */ + if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest), + pkey->ameth->pkey_id)) { + OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm, + X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); + return 0; + } + + if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) { + paramtype = V_ASN1_NULL; + } else { + paramtype = V_ASN1_UNDEF; + } + + X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL); + return 1; +} + +int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey) { + int digest_nid, pkey_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + const EVP_MD *digest; + + /* Convert signature OID into digest and public key OIDs */ + if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid, + &pkey_nid)) { + OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm, + ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); + return 0; + } + + /* Check public key OID matches public key type */ + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) { + OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm, + ASN1_R_WRONG_PUBLIC_KEY_TYPE); + return 0; + } + + /* NID_undef signals that there are custom parameters to set. */ + if (digest_nid == NID_undef) { + if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) { + OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm, + ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); + return 0; + } + + return pkey->ameth->digest_verify_init_from_algorithm(ctx, algor, pkey); + } + + /* Otherwise, initialize with the digest from the OID. */ + digest = EVP_get_digestbynid(digest_nid); + if (digest == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm, + ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + return 0; + } + + return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey); +} + diff --git a/crypto/evp/evp_error.c b/crypto/evp/evp_error.c index 76a802ae..fae1aa78 100644 --- a/crypto/evp/evp_error.c +++ b/crypto/evp/evp_error.c @@ -17,6 +17,8 @@ #include <openssl/evp.h> const ERR_STRING_DATA EVP_error_string_data[] = { + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DigestSignAlgorithm, 0), "EVP_DigestSignAlgorithm"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DigestVerifyInitFromAlgorithm, 0), "EVP_DigestVerifyInitFromAlgorithm"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_ctrl, 0), "EVP_PKEY_CTX_ctrl"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_copy_parameters, 0), "EVP_PKEY_copy_parameters"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_decrypt, 0), "EVP_PKEY_decrypt"}, @@ -74,6 +76,7 @@ const ERR_STRING_DATA EVP_error_string_data[] = { {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_pub_decode, 0), "rsa_pub_decode"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BUFFER_TOO_SMALL), "BUFFER_TOO_SMALL"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COMMAND_NOT_SUPPORTED), "COMMAND_NOT_SUPPORTED"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CONTEXT_NOT_INITIALISED), "CONTEXT_NOT_INITIALISED"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DECODE_ERROR), "DECODE_ERROR"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES), "DIFFERENT_KEY_TYPES"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS), "DIFFERENT_PARAMETERS"}, diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h index 36755f0f..d92c9e56 100644 --- a/crypto/evp/internal.h +++ b/crypto/evp/internal.h @@ -67,8 +67,25 @@ extern "C" { /* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */ #define ASN1_PKEY_ALIAS 0x1 #define ASN1_PKEY_DYNAMIC 0x2 + +/* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of + * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the + * AlgorithmIdentifier. */ #define ASN1_PKEY_SIGPARAM_NULL 0x4 +/* evp_digest_sign_algorithm_result_t is the return value of the + * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */ +typedef enum { + /* EVP_DIGEST_SIGN_ALGORITHM_ERROR signals an error. */ + EVP_DIGEST_SIGN_ALGORITHM_ERROR = 0, + /* EVP_DIGEST_SIGN_ALGORITHM_SUCCESS signals that the parameters were + * serialized in the AlgorithmIdentifier. */ + EVP_DIGEST_SIGN_ALGORITHM_SUCCESS = 1, + /* EVP_DIGEST_SIGN_ALGORITHM_DEFAULT signals that the parameters are + * serialized using the default behavior. */ + EVP_DIGEST_SIGN_ALGORITHM_DEFAULT = 2, +} evp_digest_sign_algorithm_result_t; + struct evp_pkey_asn1_method_st { int pkey_id; int pkey_base_id; @@ -113,11 +130,14 @@ struct evp_pkey_asn1_method_st { int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder, int derlen); int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder); - /* Custom ASN1 signature verification */ - int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, - X509_ALGOR *a, ASN1_BIT_STRING *sig, EVP_PKEY *pkey); - int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, - X509_ALGOR *alg1, X509_ALGOR *alg2, ASN1_BIT_STRING *sig); + + /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */ + int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey); + evp_digest_sign_algorithm_result_t (*digest_sign_algorithm)( + EVP_MD_CTX *ctx, + X509_ALGOR *algor); } /* EVP_PKEY_ASN1_METHOD */; diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c index 1bb69f34..ab83a8e6 100644 --- a/crypto/evp/p_rsa_asn1.c +++ b/crypto/evp/p_rsa_asn1.c @@ -649,54 +649,37 @@ err: return ret; } -/* Customised RSA item verification routine. This is called - * when a signature is encountered requiring special handling. We - * currently only handle PSS. */ -static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, - X509_ALGOR *sigalg, ASN1_BIT_STRING *sig, - EVP_PKEY *pkey) { +/* Customised RSA AlgorithmIdentifier handling. This is called when a signature + * is encountered requiring special handling. We currently only handle PSS. */ +static int rsa_digest_verify_init_from_algorithm(EVP_MD_CTX *ctx, + X509_ALGOR *sigalg, + EVP_PKEY *pkey) { /* Sanity check: make sure it is PSS */ if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { OPENSSL_PUT_ERROR(EVP, rsa_item_verify, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); - return -1; - } - if (rsa_pss_to_ctx(ctx, sigalg, pkey)) { - /* Carry on */ - return 2; + return 0; } - - return -1; + return rsa_pss_to_ctx(ctx, sigalg, pkey); } -static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, - X509_ALGOR *alg1, X509_ALGOR *alg2, - ASN1_BIT_STRING *sig) { +static evp_digest_sign_algorithm_result_t rsa_digest_sign_algorithm( + EVP_MD_CTX *ctx, X509_ALGOR *sigalg) { int pad_mode; EVP_PKEY_CTX *pkctx = ctx->pctx; if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0) { - return 0; - } - if (pad_mode == RSA_PKCS1_PADDING) { - return 2; + return EVP_DIGEST_SIGN_ALGORITHM_ERROR; } if (pad_mode == RSA_PKCS1_PSS_PADDING) { ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx); if (!os1) { - return 0; - } - /* Duplicate parameters if we have to */ - if (alg2) { - ASN1_STRING *os2 = ASN1_STRING_dup(os1); - if (!os2) { - ASN1_STRING_free(os1); - return 0; - } - X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os2); + return EVP_DIGEST_SIGN_ALGORITHM_ERROR; } - X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1); - return 3; + X509_ALGOR_set0(sigalg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1); + return EVP_DIGEST_SIGN_ALGORITHM_SUCCESS; } - return 2; + + /* Other padding schemes use the default behavior. */ + return EVP_DIGEST_SIGN_ALGORITHM_DEFAULT; } const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { @@ -730,8 +713,8 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { old_rsa_priv_decode, old_rsa_priv_encode, - rsa_item_verify, - rsa_item_sign, + rsa_digest_verify_init_from_algorithm, + rsa_digest_sign_algorithm, }; const EVP_PKEY_ASN1_METHOD rsa_asn1_meth_2 = { |