summaryrefslogtreecommitdiffstats
path: root/providers/implementations/encode_decode/encode_key2any.c
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2021-05-27 12:34:03 +0200
committerRichard Levitte <levitte@openssl.org>2021-06-09 17:00:10 +0200
commit6a2b8ff392a304bbb106528653397b864acc53fa (patch)
tree75bd836ad9cec6eec65f270fd4db4b893f73b939 /providers/implementations/encode_decode/encode_key2any.c
parent320fc032b98cc452c5dc96600b16da40b155123b (diff)
Decoding PKCS#8: separate decoding of encrypted and unencrypted PKCS#8
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 https://github.com/openssl/openssl/pull/15498)
Diffstat (limited to 'providers/implementations/encode_decode/encode_key2any.c')
-rw-r--r--providers/implementations/encode_decode/encode_key2any.c228
1 files changed, 149 insertions, 79 deletions
diff --git a/providers/implementations/encode_decode/encode_key2any.c b/providers/implementations/encode_decode/encode_key2any.c
index f986ec124e..855866cbfe 100644
--- a/providers/implementations/encode_decode/encode_key2any.c
+++ b/providers/implementations/encode_decode/encode_key2any.c
@@ -128,12 +128,14 @@ static X509_SIG *key_to_encp8(const void *key, int key_nid,
{
PKCS8_PRIV_KEY_INFO *p8info =
key_to_p8info(key, key_nid, params, params_type, k2d);
- X509_SIG *p8 = p8info_to_encp8(p8info, ctx);
+ X509_SIG *p8 = NULL;
- if (p8info == NULL)
+ if (p8info == NULL) {
free_asn1_data(params_type, params);
-
- PKCS8_PRIV_KEY_INFO_free(p8info);
+ } else {
+ p8 = p8info_to_encp8(p8info, ctx);
+ PKCS8_PRIV_KEY_INFO_free(p8info);
+ }
return p8;
}
@@ -162,81 +164,141 @@ static X509_PUBKEY *key_to_pubkey(const void *key, int key_nid,
}
/*
- * key_to_pkcs8_* produce encoded output with the key data pkcs8
- * in a structure. For private keys, that structure is PKCS#8, and for
- * public keys, it's X.509 SubjectPublicKeyInfo. Parameters don't have
- * any defined envelopment of that kind.
+ * key_to_epki_* produce encoded output with the private key data in a
+ * EncryptedPrivateKeyInfo structure (defined by PKCS#8). They require
+ * that there's an intent to encrypt, anything else is an error.
+ * They are currently only called from the corresponding key_to_pki_ function.
+ *
+ * key_to_pki_* primarly produce encoded output with the private key data
+ * in a PrivateKeyInfo structure (also defined by PKCS#8). However, if
+ * there is an intent to encrypt the data, the corresponding key_to_epki_*
+ * function is used instead.
+ *
+ * key_to_spki_* produce encoded output with the public key data in an
+ * X.509 SubjectPublicKeyInfo.
+ *
+ * Key parameters don't have any defined envelopment of this kind, but are
+ * included in some manner in the output from the functions described above,
+ * either in the AlgorithmIdentifier's parameter field, or as part of the
+ * key data itself.
*/
-static int key_to_pkcs8_der_priv_bio(BIO *out, const void *key,
- int key_nid,
- ossl_unused const char *pemname,
- key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+
+static int key_to_epki_der_priv_bio(BIO *out, const void *key,
+ int key_nid,
+ ossl_unused const char *pemname,
+ key_to_paramstring_fn *p2s,
+ i2d_of_void *k2d,
+ struct key2any_ctx_st *ctx)
{
int ret = 0;
void *str = NULL;
int strtype = V_ASN1_UNDEF;
+ X509_SIG *p8;
+
+ if (!ctx->cipher_intent)
+ return 0;
if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters,
&str, &strtype))
return 0;
- if (ctx->cipher_intent) {
- X509_SIG *p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx);
+ p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx);
+ if (p8 != NULL)
+ ret = i2d_PKCS8_bio(out, p8);
- if (p8 != NULL)
- ret = i2d_PKCS8_bio(out, p8);
+ X509_SIG_free(p8);
- X509_SIG_free(p8);
- } else {
- PKCS8_PRIV_KEY_INFO *p8info =
- key_to_p8info(key, key_nid, str, strtype, k2d);
+ return ret;
+}
- if (p8info != NULL)
- ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info);
- else
- free_asn1_data(strtype, str);
+static int key_to_epki_pem_priv_bio(BIO *out, const void *key,
+ int key_nid,
+ ossl_unused const char *pemname,
+ key_to_paramstring_fn *p2s,
+ i2d_of_void *k2d,
+ struct key2any_ctx_st *ctx)
+{
+ int ret = 0;
+ void *str = NULL;
+ int strtype = V_ASN1_UNDEF;
+ X509_SIG *p8;
- PKCS8_PRIV_KEY_INFO_free(p8info);
- }
+ if (!ctx->cipher_intent)
+ return 0;
+
+ if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters,
+ &str, &strtype))
+ return 0;
+
+ p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx);
+ if (p8 != NULL)
+ ret = PEM_write_bio_PKCS8(out, p8);
+
+ X509_SIG_free(p8);
return ret;
}
-static int key_to_pkcs8_pem_priv_bio(BIO *out, const void *key,
- int key_nid,
- ossl_unused const char *pemname,
- key_to_paramstring_fn *p2s,
- i2d_of_void *k2d,
- struct key2any_ctx_st *ctx)
+static int key_to_pki_der_priv_bio(BIO *out, const void *key,
+ int key_nid,
+ ossl_unused const char *pemname,
+ key_to_paramstring_fn *p2s,
+ i2d_of_void *k2d,
+ struct key2any_ctx_st *ctx)
{
int ret = 0;
void *str = NULL;
int strtype = V_ASN1_UNDEF;
+ PKCS8_PRIV_KEY_INFO *p8info;
+
+ if (ctx->cipher_intent)
+ return key_to_epki_der_priv_bio(out, key, key_nid, pemname,
+ p2s, k2d, ctx);
if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters,
&str, &strtype))
return 0;
- if (ctx->cipher_intent) {
- X509_SIG *p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx);
+ p8info = key_to_p8info(key, key_nid, str, strtype, k2d);
- if (p8 != NULL)
- ret = PEM_write_bio_PKCS8(out, p8);
+ if (p8info != NULL)
+ ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info);
+ else
+ free_asn1_data(strtype, str);
- X509_SIG_free(p8);
- } else {
- PKCS8_PRIV_KEY_INFO *p8info =
- key_to_p8info(key, key_nid, str, strtype, k2d);
+ PKCS8_PRIV_KEY_INFO_free(p8info);
- if (p8info != NULL)
- ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info);
- else
- free_asn1_data(strtype, str);
+ return ret;
+}
- PKCS8_PRIV_KEY_INFO_free(p8info);
- }
+static int key_to_pki_pem_priv_bio(BIO *out, const void *key,
+ int key_nid,
+ ossl_unused const char *pemname,
+ key_to_paramstring_fn *p2s,
+ i2d_of_void *k2d,
+ struct key2any_ctx_st *ctx)
+{
+ int ret = 0;
+ void *str = NULL;
+ int strtype = V_ASN1_UNDEF;
+ PKCS8_PRIV_KEY_INFO *p8info;
+
+ if (ctx->cipher_intent)
+ return key_to_epki_pem_priv_bio(out, key, key_nid, pemname,
+ p2s, k2d, ctx);
+
+ if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters,
+ &str, &strtype))
+ return 0;
+
+ p8info = key_to_p8info(key, key_nid, str, strtype, k2d);
+
+ if (p8info != NULL)
+ ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info);
+ else
+ free_asn1_data(strtype, str);
+
+ PKCS8_PRIV_KEY_INFO_free(p8info);
return ret;
}
@@ -427,7 +489,7 @@ static int dh_spki_pub_to_der(const void *dh, unsigned char **pder)
return ret;
}
-static int dh_pkcs8_priv_to_der(const void *dh, unsigned char **pder)
+static int dh_pki_priv_to_der(const void *dh, unsigned char **pder)
{
const BIGNUM *bn = NULL;
ASN1_INTEGER *priv_key = NULL;
@@ -540,7 +602,7 @@ static int dsa_spki_pub_to_der(const void *dsa, unsigned char **pder)
return ret;
}
-static int dsa_pkcs8_priv_to_der(const void *dsa, unsigned char **pder)
+static int dsa_pki_priv_to_der(const void *dsa, unsigned char **pder)
{
const BIGNUM *bn = NULL;
ASN1_INTEGER *priv_key = NULL;
@@ -639,7 +701,7 @@ static int ec_spki_pub_to_der(const void *eckey, unsigned char **pder)
return i2o_ECPublicKey(eckey, pder);
}
-static int ec_pkcs8_priv_to_der(const void *veckey, unsigned char **pder)
+static int ec_pki_priv_to_der(const void *veckey, unsigned char **pder)
{
EC_KEY *eckey = (EC_KEY *)veckey;
unsigned int old_flags;
@@ -700,7 +762,7 @@ static int ecx_spki_pub_to_der(const void *vecxkey, unsigned char **pder)
return ecxkey->keylen;
}
-static int ecx_pkcs8_priv_to_der(const void *vecxkey, unsigned char **pder)
+static int ecx_pki_priv_to_der(const void *vecxkey, unsigned char **pder)
{
const ECX_KEY *ecxkey = vecxkey;
ASN1_OCTET_STRING oct;
@@ -826,7 +888,7 @@ static int prepare_rsa_params(const void *rsa, int nid, int save,
* RSA is extremely simple, as PKCS#1 is used for the PKCS#8 |privateKey|
* field as well as the SubjectPublicKeyInfo |subjectPublicKey| field.
*/
-#define rsa_pkcs8_priv_to_der rsa_type_specific_priv_to_der
+#define rsa_pki_priv_to_der rsa_type_specific_priv_to_der
#define rsa_spki_pub_to_der rsa_type_specific_pub_to_der
#define rsa_type_specific_priv_to_der (i2d_of_void *)i2d_RSAPrivateKey
#define rsa_type_specific_pub_to_der (i2d_of_void *)i2d_RSAPublicKey
@@ -1041,10 +1103,18 @@ static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout,
* the same.
*/
-/* PKCS#8 is a structure for private keys only */
-#define DO_PKCS8_selection_mask DO_PRIVATE_KEY_selection_mask
-#define DO_PKCS8(impl, type, output) \
- DO_PRIVATE_KEY(impl, type, pkcs8, output)
+/*
+ * PKCS#8 defines two structures for private keys only:
+ * - PrivateKeyInfo (raw unencrypted form)
+ * - EncryptedPrivateKeyInfo (encrypted wrapping)
+ *
+ * To allow a certain amount of flexibility, we allow the routines
+ * for PrivateKeyInfo to also produce EncryptedPrivateKeyInfo if a
+ * passphrase callback has been passed to them.
+ */
+#define DO_PrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask
+#define DO_PrivateKeyInfo(impl, type, output) \
+ DO_PRIVATE_KEY(impl, type, pki, output)
/* SubjectPublicKeyInfo is a structure for public keys only */
#define DO_SubjectPublicKeyInfo_selection_mask DO_PUBLIC_KEY_selection_mask
@@ -1258,55 +1328,55 @@ MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, type_specific_no_pub, pem);
* For PEM, these are expected to be used by PEM_write_bio_PrivateKey(),
* PEM_write_bio_PUBKEY() and PEM_write_bio_Parameters().
*/
-MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS8, der);
-MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS8, pem);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PrivateKeyInfo, der);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PrivateKeyInfo, pem);
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, der);
MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, pem);
-MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS8, der);
-MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS8, pem);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PrivateKeyInfo, der);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PrivateKeyInfo, pem);
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, der);
MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, pem);
#ifndef OPENSSL_NO_DH
-MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS8, der);
-MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS8, pem);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PrivateKeyInfo, der);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PrivateKeyInfo, pem);
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, der);
MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, pem);
-MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PKCS8, der);
-MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PKCS8, pem);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PrivateKeyInfo, der);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PrivateKeyInfo, pem);
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, der);
MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, pem);
#endif
#ifndef OPENSSL_NO_DSA
-MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PKCS8, der);
-MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PKCS8, pem);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PrivateKeyInfo, der);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PrivateKeyInfo, pem);
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, der);
MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, pem);
#endif
#ifndef OPENSSL_NO_EC
-MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PKCS8, der);
-MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PKCS8, pem);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PrivateKeyInfo, der);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PrivateKeyInfo, pem);
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der);
MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem);
# ifndef OPENSSL_NO_SM2
-MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PKCS8, der);
-MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PKCS8, pem);
+MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PrivateKeyInfo, der);
+MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, PrivateKeyInfo, pem);
MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der);
MAKE_ENCODER(sm2, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem);
# endif
-MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PKCS8, der);
-MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PKCS8, pem);
+MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PrivateKeyInfo, der);
+MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PrivateKeyInfo, pem);
MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, der);
MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, pem);
-MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PKCS8, der);
-MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PKCS8, pem);
+MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, der);
+MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, pem);
MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der);
MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem);
-MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PKCS8, der);
-MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PKCS8, pem);
+MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PrivateKeyInfo, der);
+MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PrivateKeyInfo, pem);
MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, der);
MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, pem);
-MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PKCS8, der);
-MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PKCS8, pem);
+MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, der);
+MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PrivateKeyInfo, pem);
MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der);
MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem);
#endif