Improve the performance of d2i_AutoPrivateKey and friends

Probe first to see if we have a PKCS8 file to improve decoder performance.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/20416)

(cherry picked from commit dba97d4c71)
This commit is contained in:
Matt Caswell 2023-03-01 17:03:48 +00:00 committed by Pauli
parent f0ea7a51aa
commit fe24a06cfa
1 changed files with 42 additions and 29 deletions

View File

@ -22,6 +22,7 @@
#include "crypto/asn1.h" #include "crypto/asn1.h"
#include "crypto/evp.h" #include "crypto/evp.h"
#include "internal/asn1.h" #include "internal/asn1.h"
#include "internal/sizes.h"
static EVP_PKEY * static EVP_PKEY *
d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp, d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp,
@ -32,8 +33,12 @@ d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp,
EVP_PKEY *pkey = NULL, *bak_a = NULL; EVP_PKEY *pkey = NULL, *bak_a = NULL;
EVP_PKEY **ppkey = &pkey; EVP_PKEY **ppkey = &pkey;
const char *key_name = NULL; const char *key_name = NULL;
const char *input_structures[] = { "type-specific", "PrivateKeyInfo", NULL }; char keytypebuf[OSSL_MAX_NAME_SIZE];
int i, ret; int ret;
const unsigned char *p = *pp;
const char *structure;
PKCS8_PRIV_KEY_INFO *p8info;
const ASN1_OBJECT *algoid;
if (keytype != EVP_PKEY_NONE) { if (keytype != EVP_PKEY_NONE) {
key_name = evp_pkey_type2name(keytype); key_name = evp_pkey_type2name(keytype);
@ -41,34 +46,42 @@ d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp,
return NULL; return NULL;
} }
for (i = 0; i < (int)OSSL_NELEM(input_structures); ++i) { /* This is just a probe. It might fail, so we ignore errors */
const unsigned char *p = *pp; ERR_set_mark();
p8info = d2i_PKCS8_PRIV_KEY_INFO(NULL, pp, len);
if (a != NULL && (bak_a = *a) != NULL) ERR_pop_to_mark();
ppkey = a; if (p8info != NULL) {
dctx = OSSL_DECODER_CTX_new_for_pkey(ppkey, "DER", if (key_name == NULL
input_structures[i], key_name, && PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8info)
EVP_PKEY_KEYPAIR, libctx, propq); && OBJ_obj2txt(keytypebuf, sizeof(keytypebuf), algoid, 0))
if (a != NULL) key_name = keytypebuf;
*a = bak_a; structure = "PrivateKeyInfo";
if (dctx == NULL) PKCS8_PRIV_KEY_INFO_free(p8info);
continue; } else {
structure = "type-specific";
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 */ *pp = p;
err:
if (a != NULL && (bak_a = *a) != NULL)
ppkey = a;
dctx = OSSL_DECODER_CTX_new_for_pkey(ppkey, "DER", structure, key_name,
EVP_PKEY_KEYPAIR, libctx, propq);
if (a != NULL)
*a = bak_a;
if (dctx == NULL)
goto err;
ret = OSSL_DECODER_from_data(dctx, pp, &len);
OSSL_DECODER_CTX_free(dctx);
if (ret
&& *ppkey != NULL
&& evp_keymgmt_util_has(*ppkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) {
if (a != NULL)
*a = *ppkey;
return *ppkey;
}
err:
if (ppkey != a) if (ppkey != a)
EVP_PKEY_free(*ppkey); EVP_PKEY_free(*ppkey);
return NULL; return NULL;