Skip to content

Commit

Permalink
Decoding PKCS#8: separate decoding of encrypted and unencrypted PKCS#8
Browse files Browse the repository at this point in the history
This has us switch from the 'structure' "pkcs8" to "PrivateKeyInfo",
which is sensible considering we already have "SubjectPublicKeyInfo".
We also add "EncryptedPrivateKeyInfo", and use it for a special decoder
that detects and decrypts an EncryptedPrivateKeyInfo structured DER
blob into a PrivateKeyInfo structured DER blob and passes that on to
the next decoder implementation.

The result of this change is that PKCS#8 decryption should only happen
once per decoding instead of once for every expected key type.
Furthermore, this new decoder implementation sets the data type to the
OID of the algorithmIdentifier field, thus reducing how many decoder
implementations are tentativaly run further down the call chain.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #15498)
  • Loading branch information
levitte committed Jun 9, 2021
1 parent 320fc03 commit 6a2b8ff
Show file tree
Hide file tree
Showing 18 changed files with 435 additions and 231 deletions.
2 changes: 1 addition & 1 deletion apps/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ int rsa_main(int argc, char **argv)
if (traditional)
output_structure = "pkcs1"; /* "type-specific" would work too */
else
output_structure = "pkcs8";
output_structure = "PrivateKeyInfo";
}
}

Expand Down
2 changes: 1 addition & 1 deletion crypto/asn1/d2i_pr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp,
EVP_PKEY *pkey = NULL, *bak_a = NULL;
EVP_PKEY **ppkey = &pkey;
const char *key_name = NULL;
const char *input_structures[] = { "type-specific", "pkcs8", NULL };
const char *input_structures[] = { "type-specific", "PrivateKeyInfo", NULL };
int i, ret;

if (keytype != EVP_PKEY_NONE) {
Expand Down
2 changes: 1 addition & 1 deletion crypto/asn1/i2d_evp.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp)
if (evp_pkey_is_provided(a)) {
static const struct type_and_structure_st output_info[] = {
{ "DER", "type-specific" },
{ "DER", "pkcs8" },
{ "DER", "PrivateKeyInfo" },
{ NULL, }
};

Expand Down
6 changes: 3 additions & 3 deletions crypto/evp/evp_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ EVP_PKEY *EVP_PKCS82PKEY_ex(const PKCS8_PRIV_KEY_INFO *p8, OSSL_LIB_CTX *libctx,

p8_data = encoded_data;
len = encoded_len;
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "pkcs8", EVP_PKEY_NONE,
0, libctx, propq);
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "PrivateKeyInfo",
EVP_PKEY_NONE, 0, libctx, propq);
if (dctx == NULL
|| !OSSL_DECODER_from_data(dctx, &p8_data, &len))
/* try legacy */
Expand Down Expand Up @@ -115,7 +115,7 @@ PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(const EVP_PKEY *pkey)
const unsigned char *pp;

if ((ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection,
"DER", "pkcs8",
"DER", "PrivateKeyInfo",
NULL)) == NULL
|| !OSSL_ENCODER_to_data(ctx, &der, &derlen))
goto error;
Expand Down
2 changes: 1 addition & 1 deletion crypto/pem/pem_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* Properties, named according to the ASN.1 names used throughout libcrypto.
*/
# define PEM_STRUCTURE_PUBKEY "SubjectPublicKeyInfo"
# define PEM_STRUCTURE_PrivateKey "pkcs8"
# define PEM_STRUCTURE_PrivateKey "PrivateKeyInfo"
# define PEM_STRUCTURE_Parameters "type-specific"

# define PEM_STRUCTURE_RSAPrivateKey "type-specific"
Expand Down
2 changes: 1 addition & 1 deletion crypto/pem/pem_pk8.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static int do_pk8pkey(BIO *bp, const EVP_PKEY *x, int isder, int nid,
const char *outtype = isder ? "DER" : "PEM";
OSSL_ENCODER_CTX *ctx =
OSSL_ENCODER_CTX_new_for_pkey(x, OSSL_KEYMGMT_SELECT_ALL,
outtype, "pkcs8", propq);
outtype, "PrivateKeyInfo", propq);

if (ctx == NULL)
return 0;
Expand Down
4 changes: 2 additions & 2 deletions doc/man3/OSSL_ENCODER_to_bio.pod
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ To encode a pkey as PKCS#8 with PEM format into a bio:

OSSL_ENCODER_CTX *ectx;
const char *format = "PEM";
const char *structure = "pkcs8"; /* PKCS#8 structure */
const char *structure = "PrivateKeyInfo"; /* PKCS#8 structure */
const unsigned char *pass = "my password";

ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey,
Expand All @@ -86,7 +86,7 @@ AES-256-CBC into a buffer:

OSSL_ENCODER_CTX *ectx;
const char *format = "DER";
const char *structure = "pkcs8"; /* PKCS#8 structure */
const char *structure = "PrivateKeyInfo"; /* PKCS#8 structure */
const unsigned char *pass = "my password";
unsigned char *data = NULL;
size_t datalen;
Expand Down
10 changes: 6 additions & 4 deletions doc/man7/openssl-glossary.pod
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,13 @@ This is defined in IETF RFC 1421:

L<https://tools.ietf.org/html/rfc1421>

=item PKCS#8 (also known as "pkcs8" in some parts of OpenSSL)
=item PKCS#8

PKCS#8 is a specification of an ASN.1 structure that OpenSSL uses for
storing or transmitting any private key in a key type agnostic manner, and
has both an unencrypted and an encrypted form.
PKCS#8 is a specification of ASN.1 structures that OpenSSL uses for storing
or transmitting any private key in a key type agnostic manner.
There are two structures worth noting for OpenSSL use, one that contains the
key data in unencrypted form (known as "PrivateKeyInfo") and an encrypted
wrapper structure (known as "EncryptedPrivateKeyInfo").

This is specified in RFC 5208:

Expand Down
31 changes: 19 additions & 12 deletions providers/decoders.inc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#define DECODER_STRUCTURE_type_specific_params "type-specific"
#define DECODER_STRUCTURE_type_specific "type-specific"
#define DECODER_STRUCTURE_type_specific_no_pub "type-specific"
#define DECODER_STRUCTURE_PKCS8 "pkcs8"
#define DECODER_STRUCTURE_EncryptedPrivateKeyInfo "EncryptedPrivateKeyInfo"
#define DECODER_STRUCTURE_PrivateKeyInfo "PrivateKeyInfo"
#define DECODER_STRUCTURE_SubjectPublicKeyInfo "SubjectPublicKeyInfo"
#define DECODER_STRUCTURE_DH "dh"
#define DECODER_STRUCTURE_DHX "dhx"
Expand All @@ -35,48 +36,54 @@
(ossl_##_structure##_##_input##_to_##_output##_decoder_functions) }

#ifndef OPENSSL_NO_DH
DECODER_w_structure("DH", der, PKCS8, dh, yes),
DECODER_w_structure("DH", der, PrivateKeyInfo, dh, yes),
DECODER_w_structure("DH", der, SubjectPublicKeyInfo, dh, yes),
DECODER_w_structure("DH", der, type_specific_params, dh, yes),
DECODER_w_structure("DH", der, DH, dh, yes),
DECODER_w_structure("DHX", der, PKCS8, dhx, yes),
DECODER_w_structure("DHX", der, PrivateKeyInfo, dhx, yes),
DECODER_w_structure("DHX", der, SubjectPublicKeyInfo, dhx, yes),
DECODER_w_structure("DHX", der, type_specific_params, dhx, yes),
DECODER_w_structure("DHX", der, DHX, dhx, yes),
#endif
#ifndef OPENSSL_NO_DSA
DECODER_w_structure("DSA", der, PKCS8, dsa, yes),
DECODER_w_structure("DSA", der, PrivateKeyInfo, dsa, yes),
DECODER_w_structure("DSA", der, SubjectPublicKeyInfo, dsa, yes),
DECODER_w_structure("DSA", der, type_specific, dsa, yes),
DECODER_w_structure("DSA", der, DSA, dsa, yes),
DECODER("DSA", msblob, dsa, yes),
DECODER("DSA", pvk, dsa, yes),
#endif
#ifndef OPENSSL_NO_EC
DECODER_w_structure("EC", der, PKCS8, ec, yes),
DECODER_w_structure("EC", der, PrivateKeyInfo, ec, yes),
DECODER_w_structure("EC", der, SubjectPublicKeyInfo, ec, yes),
DECODER_w_structure("EC", der, type_specific_no_pub, ec, yes),
DECODER_w_structure("EC", der, EC, ec, yes),
DECODER_w_structure("ED25519", der, PKCS8, ed25519, yes),
DECODER_w_structure("ED25519", der, PrivateKeyInfo, ed25519, yes),
DECODER_w_structure("ED25519", der, SubjectPublicKeyInfo, ed25519, yes),
DECODER_w_structure("ED448", der, PKCS8, ed448, yes),
DECODER_w_structure("ED448", der, PrivateKeyInfo, ed448, yes),
DECODER_w_structure("ED448", der, SubjectPublicKeyInfo, ed448, yes),
DECODER_w_structure("X25519", der, PKCS8, x25519, yes),
DECODER_w_structure("X25519", der, PrivateKeyInfo, x25519, yes),
DECODER_w_structure("X25519", der, SubjectPublicKeyInfo, x25519, yes),
DECODER_w_structure("X448", der, PKCS8, x448, yes),
DECODER_w_structure("X448", der, PrivateKeyInfo, x448, yes),
DECODER_w_structure("X448", der, SubjectPublicKeyInfo, x448, yes),
# ifndef OPENSSL_NO_SM2
DECODER_w_structure("SM2", der, PKCS8, sm2, yes),
DECODER_w_structure("SM2", der, PrivateKeyInfo, sm2, yes),
DECODER_w_structure("SM2", der, SubjectPublicKeyInfo, sm2, yes),
# endif
#endif
DECODER_w_structure("RSA", der, PKCS8, rsa, yes),
DECODER_w_structure("RSA", der, PrivateKeyInfo, rsa, yes),
DECODER_w_structure("RSA", der, SubjectPublicKeyInfo, rsa, yes),
DECODER_w_structure("RSA", der, type_specific_keypair, rsa, yes),
DECODER_w_structure("RSA", der, RSA, rsa, yes),
DECODER_w_structure("RSA-PSS", der, PKCS8, rsapss, yes),
DECODER_w_structure("RSA-PSS", der, PrivateKeyInfo, rsapss, yes),
DECODER_w_structure("RSA-PSS", der, SubjectPublicKeyInfo, rsapss, yes),
DECODER("RSA", msblob, rsa, yes),
DECODER("RSA", pvk, rsa, yes),

DECODER("DER", pem, der, yes),
/*
* A decoder that recognises PKCS#8 EncryptedPrivateKeyInfo structure
* and decrypts it, passing on the unencrypted PrivateKeyInfo in DER
* form to the next decoder.
*/
DECODER_w_structure("DER", der, EncryptedPrivateKeyInfo, der, yes),
48 changes: 24 additions & 24 deletions providers/encoders.inc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#define ENCODER_STRUCTURE_type_specific_params "type-specific"
#define ENCODER_STRUCTURE_type_specific "type-specific"
#define ENCODER_STRUCTURE_type_specific_no_pub "type-specific"
#define ENCODER_STRUCTURE_PKCS8 "pkcs8"
#define ENCODER_STRUCTURE_PrivateKeyInfo "PrivateKeyInfo"
#define ENCODER_STRUCTURE_SubjectPublicKeyInfo "SubjectPublicKeyInfo"
#define ENCODER_STRUCTURE_DH "dh"
#define ENCODER_STRUCTURE_DHX "dhx"
Expand Down Expand Up @@ -127,70 +127,70 @@ ENCODER("DSA", dsa, yes, pvk),
#endif

/*
* Entries for PKCS#8 and SubjectPublicKeyInfo.
* Entries for PKCS#8 (PrivateKeyInfo) and SubjectPublicKeyInfo.
* The "der" ones are added convenience for any user that wants to use
* OSSL_ENCODER directly.
* The "pem" ones also support PEM_write_bio_PrivateKey() and
* PEM_write_bio_PUBKEY().
*/
ENCODER_w_structure("RSA", rsa, yes, der, PKCS8),
ENCODER_w_structure("RSA", rsa, yes, pem, PKCS8),
ENCODER_w_structure("RSA", rsa, yes, der, PrivateKeyInfo),
ENCODER_w_structure("RSA", rsa, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("RSA", rsa, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("RSA", rsa, yes, pem, SubjectPublicKeyInfo),

ENCODER_w_structure("RSA-PSS", rsapss, yes, der, PKCS8),
ENCODER_w_structure("RSA-PSS", rsapss, yes, pem, PKCS8),
ENCODER_w_structure("RSA-PSS", rsapss, yes, der, PrivateKeyInfo),
ENCODER_w_structure("RSA-PSS", rsapss, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("RSA-PSS", rsapss, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("RSA-PSS", rsapss, yes, pem, SubjectPublicKeyInfo),

#ifndef OPENSSL_NO_DH
ENCODER_w_structure("DH", dh, yes, der, PKCS8),
ENCODER_w_structure("DH", dh, yes, pem, PKCS8),
ENCODER_w_structure("DH", dh, yes, der, PrivateKeyInfo),
ENCODER_w_structure("DH", dh, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("DH", dh, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("DH", dh, yes, pem, SubjectPublicKeyInfo),

ENCODER_w_structure("DHX", dhx, yes, der, PKCS8),
ENCODER_w_structure("DHX", dhx, yes, pem, PKCS8),
ENCODER_w_structure("DHX", dhx, yes, der, PrivateKeyInfo),
ENCODER_w_structure("DHX", dhx, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("DHX", dhx, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("DHX", dhx, yes, pem, SubjectPublicKeyInfo),
#endif

#ifndef OPENSSL_NO_DSA
ENCODER_w_structure("DSA", dsa, yes, der, PKCS8),
ENCODER_w_structure("DSA", dsa, yes, pem, PKCS8),
ENCODER_w_structure("DSA", dsa, yes, der, PrivateKeyInfo),
ENCODER_w_structure("DSA", dsa, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("DSA", dsa, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("DSA", dsa, yes, pem, SubjectPublicKeyInfo),
#endif

#ifndef OPENSSL_NO_EC
ENCODER_w_structure("EC", ec, yes, der, PKCS8),
ENCODER_w_structure("EC", ec, yes, pem, PKCS8),
ENCODER_w_structure("EC", ec, yes, der, PrivateKeyInfo),
ENCODER_w_structure("EC", ec, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("EC", ec, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("EC", ec, yes, pem, SubjectPublicKeyInfo),

ENCODER_w_structure("X25519", x25519, yes, der, PKCS8),
ENCODER_w_structure("X25519", x25519, yes, pem, PKCS8),
ENCODER_w_structure("X25519", x25519, yes, der, PrivateKeyInfo),
ENCODER_w_structure("X25519", x25519, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("X25519", x25519, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("X25519", x25519, yes, pem, SubjectPublicKeyInfo),

ENCODER_w_structure("X448", x448, yes, der, PKCS8),
ENCODER_w_structure("X448", x448, yes, pem, PKCS8),
ENCODER_w_structure("X448", x448, yes, der, PrivateKeyInfo),
ENCODER_w_structure("X448", x448, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("X448", x448, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("X448", x448, yes, pem, SubjectPublicKeyInfo),

ENCODER_w_structure("ED25519", ed25519, yes, der, PKCS8),
ENCODER_w_structure("ED25519", ed25519, yes, pem, PKCS8),
ENCODER_w_structure("ED25519", ed25519, yes, der, PrivateKeyInfo),
ENCODER_w_structure("ED25519", ed25519, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("ED25519", ed25519, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("ED25519", ed25519, yes, pem, SubjectPublicKeyInfo),

ENCODER_w_structure("ED448", ed448, yes, der, PKCS8),
ENCODER_w_structure("ED448", ed448, yes, pem, PKCS8),
ENCODER_w_structure("ED448", ed448, yes, der, PrivateKeyInfo),
ENCODER_w_structure("ED448", ed448, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("ED448", ed448, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("ED448", ed448, yes, pem, SubjectPublicKeyInfo),

# ifndef OPENSSL_NO_SM2
ENCODER_w_structure("SM2", sm2, yes, der, PKCS8),
ENCODER_w_structure("SM2", sm2, yes, pem, PKCS8),
ENCODER_w_structure("SM2", sm2, yes, der, PrivateKeyInfo),
ENCODER_w_structure("SM2", sm2, yes, pem, PrivateKeyInfo),
ENCODER_w_structure("SM2", sm2, yes, der, SubjectPublicKeyInfo),
ENCODER_w_structure("SM2", sm2, yes, pem, SubjectPublicKeyInfo),
# endif
Expand Down
2 changes: 1 addition & 1 deletion providers/implementations/encode_decode/build.info
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ $DECODER_GOAL=../../libdefault.a

SOURCE[$ENCODER_GOAL]=endecoder_common.c

SOURCE[$DECODER_GOAL]=decode_der2key.c decode_pem2der.c \
SOURCE[$DECODER_GOAL]=decode_der2key.c decode_epki2pki.c decode_pem2der.c \
decode_msblob2key.c decode_pvk2key.c

SOURCE[$ENCODER_GOAL]=encode_key2any.c encode_key2text.c encode_key2ms.c
Expand Down

0 comments on commit 6a2b8ff

Please sign in to comment.