Tolerate PKCS#8 V2 with optional public keys

- Presently any included public key is unused.
- We don't check that v1 PKCS#8 structures omit the public key.

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/27076)
This commit is contained in:
Viktor Dukhovni 2025-03-17 15:24:33 +11:00 committed by Tomas Mraz
parent 58d548d84e
commit 064bb16454
3 changed files with 151 additions and 6 deletions

View file

@ -17,11 +17,25 @@
static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
/* Since the structure must still be valid use ASN1_OP_FREE_PRE */
if (operation == ASN1_OP_FREE_PRE) {
PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
PKCS8_PRIV_KEY_INFO *key;
int version;
switch (operation) {
case ASN1_OP_FREE_PRE:
/* The structure is still valid during ASN1_OP_FREE_PRE */
key = (PKCS8_PRIV_KEY_INFO *)*pval;
if (key->pkey)
OPENSSL_cleanse(key->pkey->data, key->pkey->length);
break;
case ASN1_OP_D2I_POST:
/* Insist on a valid version now that the structure is decoded */
key = (PKCS8_PRIV_KEY_INFO *)*pval;
version = ASN1_INTEGER_get(key->version);
if (version < 0 || version > 1)
return 0;
if (version == 0 && key->kpub != NULL)
return 0;
break;
}
return 1;
}
@ -30,7 +44,8 @@ ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = {
ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_OCTET_STRING),
ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0),
ASN1_IMP_OPT(PKCS8_PRIV_KEY_INFO, kpub, ASN1_BIT_STRING, 1)
} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
@ -40,6 +55,9 @@ int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj,
int ptype, void *pval, unsigned char *penc, int penclen)
{
if (version >= 0) {
/* We only support PKCS#8 v1 (0) and v2 (1). */
if (version > 1)
return 0;
if (!ASN1_INTEGER_set(priv->version, version))
return 0;
}