diff options
Diffstat (limited to 'crypto/openssl/crypto/asn1/d2i_pr.c')
-rw-r--r-- | crypto/openssl/crypto/asn1/d2i_pr.c | 170 |
1 files changed, 139 insertions, 31 deletions
diff --git a/crypto/openssl/crypto/asn1/d2i_pr.c b/crypto/openssl/crypto/asn1/d2i_pr.c index 7b127d2092fa..720b7fd6c050 100644 --- a/crypto/openssl/crypto/asn1/d2i_pr.c +++ b/crypto/openssl/crypto/asn1/d2i_pr.c @@ -1,32 +1,89 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 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 */ +/* We need to use some engine deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/bn.h> #include <openssl/evp.h> #include <openssl/objects.h> +#include <openssl/decoder.h> #include <openssl/engine.h> #include <openssl/x509.h> #include <openssl/asn1.h> #include "crypto/asn1.h" #include "crypto/evp.h" +#include "internal/asn1.h" -EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, - long length) +static EVP_PKEY * +d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp, + long length, OSSL_LIB_CTX *libctx, const char *propq) +{ + OSSL_DECODER_CTX *dctx = NULL; + size_t len = length; + EVP_PKEY *pkey = NULL, *bak_a = NULL; + EVP_PKEY **ppkey = &pkey; + const char *key_name = NULL; + const char *input_structures[] = { "type-specific", "PrivateKeyInfo", NULL }; + int i, ret; + + if (keytype != EVP_PKEY_NONE) { + key_name = evp_pkey_type2name(keytype); + if (key_name == NULL) + return NULL; + } + + for (i = 0; i < (int)OSSL_NELEM(input_structures); ++i) { + const unsigned char *p = *pp; + + if (a != NULL && (bak_a = *a) != NULL) + ppkey = a; + dctx = OSSL_DECODER_CTX_new_for_pkey(ppkey, "DER", + input_structures[i], key_name, + EVP_PKEY_KEYPAIR, libctx, propq); + if (a != NULL) + *a = bak_a; + if (dctx == NULL) + continue; + + ret = OSSL_DECODER_from_data(dctx, pp, &len); + OSSL_DECODER_CTX_free(dctx); + if (ret) { + if (*ppkey != NULL + && evp_keymgmt_util_has(*ppkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) { + if (a != NULL) + *a = *ppkey; + return *ppkey; + } + *pp = p; + goto err; + } + } + /* Fall through to error if all decodes failed */ +err: + if (ppkey != a) + EVP_PKEY_free(*ppkey); + return NULL; +} + +EVP_PKEY * +ossl_d2i_PrivateKey_legacy(int keytype, EVP_PKEY **a, const unsigned char **pp, + long length, OSSL_LIB_CTX *libctx, const char *propq) { EVP_PKEY *ret; const unsigned char *p = *pp; - if ((a == NULL) || (*a == NULL)) { + if (a == NULL || *a == NULL) { if ((ret = EVP_PKEY_new()) == NULL) { - ASN1err(ASN1_F_D2I_PRIVATEKEY, ERR_R_EVP_LIB); + ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); return NULL; } } else { @@ -37,35 +94,45 @@ EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, #endif } - if (!EVP_PKEY_set_type(ret, type)) { - ASN1err(ASN1_F_D2I_PRIVATEKEY, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE); + if (!EVP_PKEY_set_type(ret, keytype)) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE); goto err; } + ERR_set_mark(); if (!ret->ameth->old_priv_decode || !ret->ameth->old_priv_decode(ret, &p, length)) { - if (ret->ameth->priv_decode) { + if (ret->ameth->priv_decode != NULL + || ret->ameth->priv_decode_ex != NULL) { EVP_PKEY *tmp; PKCS8_PRIV_KEY_INFO *p8 = NULL; p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length); - if (!p8) + if (p8 == NULL) { + ERR_clear_last_mark(); goto err; - tmp = EVP_PKCS82PKEY(p8); + } + tmp = evp_pkcs82pkey_legacy(p8, libctx, propq); PKCS8_PRIV_KEY_INFO_free(p8); - if (tmp == NULL) + if (tmp == NULL) { + ERR_clear_last_mark(); goto err; + } EVP_PKEY_free(ret); ret = tmp; - if (EVP_PKEY_type(type) != EVP_PKEY_base_id(ret)) + ERR_pop_to_mark(); + if (EVP_PKEY_type(keytype) != EVP_PKEY_get_base_id(ret)) goto err; } else { - ASN1err(ASN1_F_D2I_PRIVATEKEY, ERR_R_ASN1_LIB); + ERR_clear_last_mark(); + ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); goto err; } + } else { + ERR_clear_last_mark(); } *pp = p; if (a != NULL) - (*a) = ret; + *a = ret; return ret; err: if (a == NULL || *a != ret) @@ -73,17 +140,35 @@ EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, return NULL; } -/* - * This works like d2i_PrivateKey() except it automatically works out the - * type - */ +EVP_PKEY *d2i_PrivateKey_ex(int keytype, EVP_PKEY **a, const unsigned char **pp, + long length, OSSL_LIB_CTX *libctx, + const char *propq) +{ + EVP_PKEY *ret; -EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, - long length) + ret = d2i_PrivateKey_decoder(keytype, a, pp, length, libctx, propq); + /* try the legacy path if the decoder failed */ + if (ret == NULL) + ret = ossl_d2i_PrivateKey_legacy(keytype, a, pp, length, libctx, propq); + return ret; +} + +EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, + long length) +{ + return d2i_PrivateKey_ex(type, a, pp, length, NULL, NULL); +} + +static EVP_PKEY *d2i_AutoPrivateKey_legacy(EVP_PKEY **a, + const unsigned char **pp, + long length, + OSSL_LIB_CTX *libctx, + const char *propq) { STACK_OF(ASN1_TYPE) *inkey; const unsigned char *p; int keytype; + p = *pp; /* * Dirty trick: read in the ASN1 data into a STACK_OF(ASN1_TYPE): by @@ -96,32 +181,55 @@ EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, * Since we only need to discern "traditional format" RSA and DSA keys we * can just count the elements. */ - if (sk_ASN1_TYPE_num(inkey) == 6) + if (sk_ASN1_TYPE_num(inkey) == 6) { keytype = EVP_PKEY_DSA; - else if (sk_ASN1_TYPE_num(inkey) == 4) + } else if (sk_ASN1_TYPE_num(inkey) == 4) { keytype = EVP_PKEY_EC; - else if (sk_ASN1_TYPE_num(inkey) == 3) { /* This seems to be PKCS8, not + } else if (sk_ASN1_TYPE_num(inkey) == 3) { /* This seems to be PKCS8, not * traditional format */ PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length); EVP_PKEY *ret; sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); - if (!p8) { - ASN1err(ASN1_F_D2I_AUTOPRIVATEKEY, - ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + if (p8 == NULL) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE); return NULL; } - ret = EVP_PKCS82PKEY(p8); + ret = evp_pkcs82pkey_legacy(p8, libctx, propq); PKCS8_PRIV_KEY_INFO_free(p8); if (ret == NULL) return NULL; *pp = p; - if (a) { + if (a != NULL) { *a = ret; } return ret; - } else + } else { keytype = EVP_PKEY_RSA; + } sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); - return d2i_PrivateKey(keytype, a, pp, length); + return ossl_d2i_PrivateKey_legacy(keytype, a, pp, length, libctx, propq); +} + +/* + * This works like d2i_PrivateKey() except it passes the keytype as + * EVP_PKEY_NONE, which then figures out the type during decoding. + */ +EVP_PKEY *d2i_AutoPrivateKey_ex(EVP_PKEY **a, const unsigned char **pp, + long length, OSSL_LIB_CTX *libctx, + const char *propq) +{ + EVP_PKEY *ret; + + ret = d2i_PrivateKey_decoder(EVP_PKEY_NONE, a, pp, length, libctx, propq); + /* try the legacy path if the decoder failed */ + if (ret == NULL) + ret = d2i_AutoPrivateKey_legacy(a, pp, length, libctx, propq); + return ret; +} + +EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, + long length) +{ + return d2i_AutoPrivateKey_ex(a, pp, length, NULL, NULL); } |