PROV: Re-implement all the keypair decoders
authorRichard Levitte <levitte@openssl.org>
Mon, 26 Oct 2020 12:22:54 +0000 (13:22 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 11 Nov 2020 10:42:06 +0000 (11:42 +0100)
The base functionality to implement the keypair decoders doesn't
change much, but this results in a more massive amount of
OSSL_DISPATCH and OSSL_ALGORITHM arrays, to support a fine grained
selection of implementation based on what parts of the keypair
structure (combinations of key parameters, public key and private key)
should be expected as input, the input type ("DER", "PEM", ...) and the
outermost input structure ("pkcs8", "SubjectPublicKeyInfo", key
type specific structures, ...).

We add support for the generic structure name "type-specific", to
allow selecting that without knowing the exact name of that structure.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/13248)

providers/baseprov.c
providers/decoders.inc
providers/defltprov.c
providers/implementations/encode_decode/decode_der2key.c
providers/implementations/encode_decode/decode_ms2key.c
providers/implementations/encode_decode/decode_pem2der.c
providers/implementations/include/prov/implementations.h
providers/implementations/storemgmt/file_store_der2obj.c

index 019caf1..18d664a 100644 (file)
@@ -80,15 +80,11 @@ static const OSSL_ALGORITHM base_encoder[] = {
 #undef ENCODER
 
 static const OSSL_ALGORITHM base_decoder[] = {
-#define DECODER(name, _fips, _input, func_table)                            \
-    { name,                                                                 \
-      "provider=base,fips=" _fips ",input=" _input,                         \
-      (func_table) }
-
+#define DECODER_PROVIDER "base"
 #include "decoders.inc"
     { NULL, NULL, NULL }
+#undef DECODER_PROVIDER
 };
-#undef DECODER
 
 static const OSSL_ALGORITHM base_store[] = {
 #define STORE(name, _fips, func_table)                           \
index 4f56994..a9119ca 100644 (file)
@@ -7,36 +7,78 @@
  * https://www.openssl.org/source/license.html
  */
 
-#ifndef DECODER
-# error Macro DECODER undefined
+#ifndef DECODER_PROVIDER
+# error Macro DECODER_PROVIDER undefined
 #endif
 
+#define DECODER_STRUCTURE_type_specific_keypair         "type-specific"
+#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_SubjectPublicKeyInfo          "SubjectPublicKeyInfo"
+#define DECODER_STRUCTURE_DH                            "dh"
+#define DECODER_STRUCTURE_DHX                           "dhx"
+#define DECODER_STRUCTURE_DSA                           "dsa"
+#define DECODER_STRUCTURE_EC                            "ec"
+#define DECODER_STRUCTURE_RSA                           "rsa"
+
+/* Arguments are prefixed with '_' to avoid build breaks on certain platforms */
+#define DECODER(_name, _input, _output, _fips)                          \
+    { _name,                                                            \
+      "provider=" DECODER_PROVIDER ",fips=" #_fips ",input=" #_input,   \
+      (ossl_##_input##_to_##_output##_decoder_functions) }
+#define DECODER_w_structure(_name, _input, _structure, _output, _fips)  \
+    { _name,                                                            \
+      "provider=" DECODER_PROVIDER ",fips=" #_fips ",input=" #_input    \
+      ",structure=" DECODER_STRUCTURE_##_structure,                     \
+      (ossl_##_structure##_##_input##_to_##_output##_decoder_functions) }
+
 #ifndef OPENSSL_NO_DH
-    DECODER("DH", "yes", "der", ossl_der_to_dh_decoder_functions),
-    DECODER("DHX", "yes", "der", ossl_der_to_dhx_decoder_functions),
+DECODER_w_structure("DH", der, PKCS8, 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, 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("DSA", "yes", "der", ossl_der_to_dsa_decoder_functions),
-    DECODER("DSA", "yes", "mblob", ossl_msblob_to_dsa_decoder_functions),
+DECODER_w_structure("DSA", der, PKCS8, 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),
 # ifndef OPENSSL_NO_RC4
-    DECODER("DSA", "yes", "pvk", ossl_pvk_to_dsa_decoder_functions),
+DECODER("DSA", pvk, dsa, yes),
 # endif
 #endif
 #ifndef OPENSSL_NO_EC
-    DECODER("EC", "yes", "der", ossl_der_to_ec_decoder_functions),
-    DECODER("ED25519", "yes", "der", ossl_der_to_ed25519_decoder_functions),
-    DECODER("ED448", "yes", "der", ossl_der_to_ed448_decoder_functions),
-    DECODER("X25519", "yes", "der", ossl_der_to_x25519_decoder_functions),
-    DECODER("X448", "yes", "der", ossl_der_to_x448_decoder_functions),
+DECODER_w_structure("EC", der, PKCS8, 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, SubjectPublicKeyInfo, ed25519, yes),
+DECODER_w_structure("ED448", der, PKCS8, ed448, yes),
+DECODER_w_structure("ED448", der, SubjectPublicKeyInfo, ed448, yes),
+DECODER_w_structure("X25519", der, PKCS8, x25519, yes),
+DECODER_w_structure("X25519", der, SubjectPublicKeyInfo, x25519, yes),
+DECODER_w_structure("X448", der, PKCS8, x448, yes),
+DECODER_w_structure("X448", der, SubjectPublicKeyInfo, x448, yes),
 #endif
-    DECODER("RSA", "yes", "der", ossl_der_to_rsa_decoder_functions),
-    DECODER("RSA-PSS", "yes", "der", ossl_der_to_rsapss_decoder_functions),
+DECODER_w_structure("RSA", der, PKCS8, 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, SubjectPublicKeyInfo, rsapss, yes),
 #ifndef OPENSSL_NO_DSA
-    DECODER("RSA", "yes", "mblob", ossl_msblob_to_rsa_decoder_functions),
+DECODER("RSA", msblob, rsa, yes),
 # ifndef OPENSSL_NO_RC4
-    DECODER("RSA", "yes", "pvk", ossl_pvk_to_rsa_decoder_functions),
+DECODER("RSA", pvk, rsa, yes),
 # endif
 #endif
 
-    DECODER("DER", "yes", "pem", ossl_pem_to_der_decoder_functions),
-
+DECODER("DER", pem, der, yes),
index 425ec9a..8ce6c92 100644 (file)
@@ -453,15 +453,11 @@ static const OSSL_ALGORITHM deflt_encoder[] = {
 #undef ENCODER
 
 static const OSSL_ALGORITHM deflt_decoder[] = {
-#define DECODER(name, _fips, _input, func_table)                            \
-    { name,                                                                 \
-      "provider=default,fips=" _fips ",input=" _input,                      \
-      (func_table) }
-
+#define DECODER_PROVIDER "default"
 #include "decoders.inc"
     { NULL, NULL, NULL }
+#undef DECODER_PROVIDER
 };
-#undef DECODER
 
 static const OSSL_ALGORITHM deflt_store[] = {
 #define STORE(name, _fips, func_table)                           \
index fed4ae0..17ed162 100644 (file)
@@ -103,23 +103,38 @@ static int der_from_p8(unsigned char **new_der, long *new_der_len,
 /* ---------------------------------------------------------------------- */
 
 static OSSL_FUNC_decoder_freectx_fn der2key_freectx;
-static OSSL_FUNC_decoder_gettable_params_fn der2key_gettable_params;
-static OSSL_FUNC_decoder_get_params_fn der2key_get_params;
 static OSSL_FUNC_decoder_decode_fn der2key_decode;
 static OSSL_FUNC_decoder_export_object_fn der2key_export_object;
 
 typedef void *(extract_key_fn)(EVP_PKEY *);
 typedef void (free_key_fn)(void *);
 struct keytype_desc_st {
-    int type;                 /* EVP key type */
-    const char *name;         /* Keytype */
+    const char *keytype_name;
     const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */
 
+    /* The input structure name */
+    const char *structure_name;
+
+    /*
+     * The EVP_PKEY_xxx type macro.  Should be zero for type specific
+     * structures, non-zero when the outermost structure is PKCS#8 or
+     * SubjectPublicKeyInfo.  This determines which of the function
+     * pointers below will be used.
+     */
+    int evp_type;
+
+    /* The selection mask for OSSL_FUNC_decoder_does_selection() */
+    int selection_mask;
+
+    /* For type specific decoders, we use the corresponding d2i */
+    d2i_of_void *d2i_private_key;
+    d2i_of_void *d2i_public_key;
+    d2i_of_void *d2i_key_params;
     /*
-     * These must be the correct EVP_PKEY_get1_{TYPE}() and {TYPE}_free()
-     * function for the key.
+     * For PKCS#8 decoders, we use EVP_PKEY extractors, EVP_PKEY_get1_{TYPE}()
      */
     extract_key_fn *extract_key;
+    /* {type}_free() */
     free_key_fn *free_key;
 };
 
@@ -150,28 +165,74 @@ static void der2key_freectx(void *vctx)
     OPENSSL_free(ctx);
 }
 
-static const OSSL_PARAM *der2key_gettable_params(void *provctx)
+static const OSSL_PARAM *
+der2key_gettable_params(void *provctx, const struct keytype_desc_st *desc)
 {
     static const OSSL_PARAM gettables[] = {
         { OSSL_DECODER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
         OSSL_PARAM_END,
     };
+    static const OSSL_PARAM gettables_w_structure[] = {
+        { OSSL_DECODER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        { OSSL_DECODER_PARAM_INPUT_STRUCTURE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        OSSL_PARAM_END,
+    };
 
-    return gettables;
+    return desc->structure_name != NULL ? gettables_w_structure :  gettables;
 }
 
-static int der2key_get_params(OSSL_PARAM params[])
+static int der2key_get_params(OSSL_PARAM params[],
+                              const struct keytype_desc_st *desc)
 {
     OSSL_PARAM *p;
 
     p = OSSL_PARAM_locate(params, OSSL_DECODER_PARAM_INPUT_TYPE);
     if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, "DER"))
         return 0;
+    if (desc->structure_name != NULL) {
+        p = OSSL_PARAM_locate(params, OSSL_DECODER_PARAM_INPUT_STRUCTURE);
+        if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, desc->structure_name))
+            return 0;
+    }
 
     return 1;
 }
 
-static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin,
+static int der2key_check_selection(int selection,
+                                   const struct keytype_desc_st *desc)
+{
+    /*
+     * The selections are kinda sorta "levels", i.e. each selection given
+     * here is assumed to include those following.
+     */
+    int checks[] = {
+        OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
+        OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
+        OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
+    };
+    size_t i;
+
+    /* The decoder implementations made here support guessing */
+    if (selection == 0)
+        return 1;
+
+    for (i = 0; i < OSSL_NELEM(checks); i++) {
+        int check1 = (selection & checks[i]) != 0;
+        int check2 = (desc->selection_mask & checks[i]) != 0;
+
+        /*
+         * If the caller asked for the currently checked bit(s), return
+         * whether the decoder description says it's supported.
+         */
+        if (check1)
+            return check2;
+    }
+
+    /* This should be dead code, but just to be safe... */
+    return 0;
+}
+
+static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
                           OSSL_CALLBACK *data_cb, void *data_cbarg,
                           OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
 {
@@ -184,63 +245,110 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin,
     long new_der_len;
     EVP_PKEY *pkey = NULL;
     void *key = NULL;
+    int orig_selection = selection;
     int ok = 0;
 
-    SET_ERR_MARK();
-    if (!read_der(ctx->provctx, cin, &der, &der_len))
-        goto err;
-
     /*
-     * Opportunistic attempt to decrypt.  If it doesn't work, we try to
-     * decode our input unencrypted.
+     * The caller is allowed to specify 0 as a selection mark, to have the
+     * structure and key type guessed.  For type-specific structures, this
+     * is not recommended, as some structures are very similar.
+     * Note that 0 isn't the same as OSSL_KEYMGMT_SELECT_ALL, as the latter
+     * signifies a private key structure, where everything else is assumed
+     * to be present as well.
      */
-    if (der_from_p8(&new_der, &new_der_len, der, der_len, pw_cb, pw_cbarg)) {
-        OPENSSL_free(der);
-        der = new_der;
-        der_len = new_der_len;
+    if (selection == 0)
+        selection = ctx->desc->selection_mask;
+    if ((selection & ctx->desc->selection_mask) == 0) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
     }
-    RESET_ERR_MARK();
 
-    derp = der;
-    pkey = d2i_PrivateKey_ex(ctx->desc->type, NULL, &derp, der_len,
-                             libctx, NULL);
-    if (pkey == NULL) {
-        RESET_ERR_MARK();
-        derp = der;
-        pkey = d2i_PUBKEY_ex(NULL, &derp, der_len, libctx, NULL);
-    }
+    SET_ERR_MARK();
+    if (!read_der(ctx->provctx, cin, &der, &der_len))
+        goto end;
 
-    if (pkey == NULL) {
-        RESET_ERR_MARK();
+    if (ctx->desc->extract_key == NULL) {
+        /*
+         * There's no EVP_PKEY extractor, so we use the type specific
+         * functions.
+         */
         derp = der;
-        pkey = d2i_KeyParams(ctx->desc->type, NULL, &derp, der_len);
-    }
- err:
-    /*
-     * Prune low-level ASN.1 parse errors from error queue, assuming that
-     * this is called by decoder_process() in a loop trying several formats.
-     */
-    CLEAR_ERR_MARK();
-
-    if (pkey != NULL) {
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+            key = ctx->desc->d2i_private_key(NULL, &derp, der_len);
+            if (key == NULL && orig_selection != 0)
+                goto end;
+        }
+        if (key == NULL
+            && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+            key = ctx->desc->d2i_public_key(NULL, &derp, der_len);
+            if (key == NULL && orig_selection != 0)
+                goto end;
+        }
+        if (key == NULL
+            && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) {
+            key = ctx->desc->d2i_key_params(NULL, &derp, der_len);
+        }
+    } else {
         /*
-         * Tear out the low-level key pointer from the pkey,
-         * but only if it matches the expected key type.
-         *
-         * TODO(3.0): The check should be done with EVP_PKEY_is_a(), but
-         * as long as we still have #legacy internal keys, it's safer to
-         * use the type numbers inside the provider.
+         * There is a EVP_PKEY extractor, so we use the more generic
+         * EVP_PKEY functions, since they know how to unpack PKCS#8 and
+         * SubjectPublicKeyInfo.
          */
-        if (EVP_PKEY_id(pkey) == ctx->desc->type)
-            key = ctx->desc->extract_key(pkey);
 
         /*
-         * ctx->desc->extract_key() is expected to have incremented |key|'s
-         * reference count, so it should be safe to free |pkey| now.
+         * Opportunistic attempt to decrypt.  If it doesn't work, we try
+         * to decode our input unencrypted.
          */
-        EVP_PKEY_free(pkey);
+        if (der_from_p8(&new_der, &new_der_len, der, der_len,
+                        pw_cb, pw_cbarg)) {
+            OPENSSL_free(der);
+            der = new_der;
+            der_len = new_der_len;
+        }
+        RESET_ERR_MARK();
+
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+            derp = der;
+            pkey = d2i_PrivateKey_ex(ctx->desc->evp_type, NULL, &derp, der_len,
+                                     libctx, NULL);
+        }
+
+        if (pkey == NULL
+            && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+            RESET_ERR_MARK();
+            derp = der;
+            pkey = d2i_PUBKEY_ex(NULL, &derp, der_len, libctx, NULL);
+        }
+
+        if (pkey != NULL) {
+            /*
+             * Tear out the low-level key pointer from the pkey,
+             * but only if it matches the expected key type.
+             *
+             * TODO: The check should be done with EVP_PKEY_is_a(), but
+             * as long as we still have #legacy internal keys, it's safer
+             * to use the type numbers inside the provider.
+             */
+            if (EVP_PKEY_id(pkey) == ctx->desc->evp_type)
+                key = ctx->desc->extract_key(pkey);
+
+            /*
+             * ctx->desc->extract_key() is expected to have incremented
+             * |key|'s reference count, so it should be safe to free |pkey|
+             * now.
+             */
+            EVP_PKEY_free(pkey);
+        }
     }
 
+ end:
+    /*
+     * Prune low-level ASN.1 parse errors from error queue, assuming
+     * that this is called by decoder_process() in a loop trying several
+     * formats.
+     */
+    CLEAR_ERR_MARK();
+
     OPENSSL_free(der);
 
     if (key != NULL) {
@@ -251,7 +359,8 @@ static int der2key_decode(void *vctx, OSSL_CORE_BIO *cin,
             OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type);
         params[1] =
             OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
-                                             (char *)ctx->desc->name, 0);
+                                             (char *)ctx->desc->keytype_name,
+                                             0);
         /* The address of the key becomes the octet string */
         params[2] =
             OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
@@ -284,26 +393,279 @@ static int der2key_export_object(void *vctx,
     return 0;
 }
 
-#define IMPLEMENT_NEWCTX(KEYTYPEstr, KEYTYPE, keytype, extract, free)   \
-    static const struct keytype_desc_st keytype##_desc =                \
-        { EVP_PKEY_##KEYTYPE, KEYTYPEstr,                               \
-          ossl_##keytype##_keymgmt_functions,                           \
-          (extract_key_fn *)extract,                                    \
-          (free_key_fn *)free };                                        \
-    static OSSL_FUNC_decoder_newctx_fn der2##keytype##_newctx;          \
-    static void *der2##keytype##_newctx(void *provctx)                  \
+/* ---------------------------------------------------------------------- */
+
+#ifndef OPENSSL_NO_DH
+# define dh_evp_type                    EVP_PKEY_DH
+# define dh_evp_extract                 (extract_key_fn *)EVP_PKEY_get1_DH
+# define dh_d2i_private_key             NULL
+# define dh_d2i_public_key              NULL
+# define dh_d2i_key_params              (d2i_of_void *)d2i_DHparams
+# define dh_free                        (free_key_fn *)DH_free
+
+# define dhx_evp_type                   EVP_PKEY_DHX
+# define dhx_evp_extract                (extract_key_fn *)EVP_PKEY_get1_DH
+# define dhx_d2i_private_key            NULL
+# define dhx_d2i_public_key             NULL
+# define dhx_d2i_key_params             (d2i_of_void *)d2i_DHxparams
+# define dhx_free                       (free_key_fn *)DH_free
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+#ifndef OPENSSL_NO_DSA
+# define dsa_evp_type                   EVP_PKEY_DSA
+# define dsa_evp_extract                (extract_key_fn *)EVP_PKEY_get1_DSA
+# define dsa_d2i_private_key            (d2i_of_void *)d2i_DSAPrivateKey
+# define dsa_d2i_public_key             (d2i_of_void *)d2i_DSAPublicKey
+# define dsa_d2i_key_params             (d2i_of_void *)d2i_DSAparams
+# define dsa_free                       (free_key_fn *)DSA_free
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+#ifndef OPENSSL_NO_EC
+# define ec_evp_type                    EVP_PKEY_EC
+# define ec_evp_extract                 (extract_key_fn *)EVP_PKEY_get1_EC_KEY
+# define ec_d2i_private_key             (d2i_of_void *)d2i_ECPrivateKey
+# define ec_d2i_public_key              NULL
+# define ec_d2i_key_params              (d2i_of_void *)d2i_ECParameters
+# define ec_free                        (free_key_fn *)EC_KEY_free
+
+/*
+ * ED25519, ED448, X25519, X448 only implement PKCS#8 and SubjectPublicKeyInfo,
+ * so no d2i functions to be had.
+ */
+# define ed25519_evp_type               EVP_PKEY_ED25519
+# define ed25519_evp_extract            (extract_key_fn *)evp_pkey_get1_ED25519
+# define ed25519_d2i_private_key        NULL
+# define ed25519_d2i_public_key         NULL
+# define ed25519_d2i_key_params         NULL
+# define ed25519_free                   (free_key_fn *)ecx_key_free
+
+# define ed448_evp_type                 EVP_PKEY_ED448
+# define ed448_evp_extract              (extract_key_fn *)evp_pkey_get1_ED448
+# define ed448_d2i_private_key          NULL
+# define ed448_d2i_public_key           NULL
+# define ed448_d2i_key_params           NULL
+# define ed448_free                     (free_key_fn *)ecx_key_free
+
+# define x25519_evp_type                EVP_PKEY_X25519
+# define x25519_evp_extract             (extract_key_fn *)evp_pkey_get1_X25519
+# define x25519_d2i_private_key         NULL
+# define x25519_d2i_public_key          NULL
+# define x25519_d2i_key_params          NULL
+# define x25519_free                    (free_key_fn *)ecx_key_free
+
+# define x448_evp_type                  EVP_PKEY_X448
+# define x448_evp_extract               (extract_key_fn *)evp_pkey_get1_X448
+# define x448_d2i_private_key           NULL
+# define x448_d2i_public_key            NULL
+# define x448_d2i_key_params            NULL
+# define x448_free                      (free_key_fn *)ecx_key_free
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+#define rsa_evp_type                    EVP_PKEY_RSA
+#define rsa_evp_extract                 (extract_key_fn *)EVP_PKEY_get1_RSA
+#define rsa_d2i_private_key             (d2i_of_void *)d2i_RSAPrivateKey
+#define rsa_d2i_public_key              (d2i_of_void *)d2i_RSAPublicKey
+#define rsa_d2i_key_params              NULL
+#define rsa_free                        (free_key_fn *)RSA_free
+
+#define rsapss_evp_type                 EVP_PKEY_RSA_PSS
+#define rsapss_evp_extract              (extract_key_fn *)EVP_PKEY_get1_RSA
+#define rsapss_d2i_private_key          (d2i_of_void *)d2i_RSAPrivateKey
+#define rsapss_d2i_public_key           (d2i_of_void *)d2i_RSAPublicKey
+#define rsapss_d2i_key_params           NULL
+#define rsapss_free                     (free_key_fn *)RSA_free
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * The DO_ macros help define the selection mask and the method functions
+ * for each kind of object we want to decode.
+ */
+#define DO_type_specific_keypair(keytype)               \
+    "type-specific", 0,                                 \
+        ( OSSL_KEYMGMT_SELECT_KEYPAIR ),                \
+        keytype##_d2i_private_key,                      \
+        keytype##_d2i_public_key,                       \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_type_specific_pub(keytype)                   \
+    "type-specific", 0,                                 \
+        ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ),             \
+        NULL,                                           \
+        keytype##_d2i_public_key,                       \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_type_specific_priv(keytype)                  \
+    "type-specific", 0,                                 \
+        ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ),            \
+        keytype##_d2i_private_key,                      \
+        NULL,                                           \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_type_specific_params(keytype)                \
+    "type-specific", 0,                                 \
+        ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ),         \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_type_specific(keytype)                       \
+    "type-specific", 0,                                 \
+        ( OSSL_KEYMGMT_SELECT_ALL ),                    \
+        keytype##_d2i_private_key,                      \
+        keytype##_d2i_public_key,                       \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_type_specific_no_pub(keytype)                \
+    "type-specific", 0,                                 \
+        ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY               \
+          | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ),       \
+        keytype##_d2i_private_key,                      \
+        NULL,                                           \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_PKCS8(keytype)                               \
+    "pkcs8", keytype##_evp_type,                        \
+        ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ),            \
+        NULL,                                           \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_evp_extract,                          \
+        keytype##_free
+
+#define DO_SubjectPublicKeyInfo(keytype)                \
+    "SubjectPublicKeyInfo", keytype##_evp_type,         \
+        ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ),             \
+        NULL,                                           \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_evp_extract,                          \
+        keytype##_free
+
+#define DO_DH(keytype)                                  \
+    "DH", 0,                                            \
+        ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ),         \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_DHX(keytype)                                 \
+    "DHX", 0,                                           \
+        ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ),         \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_DSA(keytype)                                 \
+    "DSA", 0,                                           \
+        ( OSSL_KEYMGMT_SELECT_ALL ),                    \
+        keytype##_d2i_private_key,                      \
+        keytype##_d2i_public_key,                       \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_EC(keytype)                                  \
+    "EC", 0,                                            \
+        ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY               \
+          | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ),       \
+        keytype##_d2i_private_key,                      \
+        NULL,                                           \
+        keytype##_d2i_key_params,                       \
+        NULL,                                           \
+        keytype##_free
+
+#define DO_RSA(keytype)                                 \
+    "RSA", 0,                                           \
+        ( OSSL_KEYMGMT_SELECT_KEYPAIR ),                \
+        keytype##_d2i_private_key,                      \
+        keytype##_d2i_public_key,                       \
+        NULL,                                           \
+        NULL,                                           \
+        keytype##_free
+
+/*
+ * MAKE_DECODER is the single driver for creating OSSL_DISPATCH tables.
+ * It takes the following arguments:
+ *
+ * keytype_name The implementation key type as a string.
+ * keytype      The implementation key type.  This must correspond exactly
+ *              to our existing keymgmt keytype names...  in other words,
+ *              there must exist an ossl_##keytype##_keymgmt_functions.
+ * type         The type name for the set of functions that implement the
+ *              decoder for the key type.  This isn't necessarily the same
+ *              as keytype.  For example, the key types ed25519, ed448,
+ *              x25519 and x448 are all handled by the same functions with
+ *              the common type name ecx.
+ * kind         The kind of support to implement.  This translates into
+ *              the DO_##kind macros above, to populate the keytype_desc_st
+ *              structure.
+ */
+#define MAKE_DECODER(keytype_name, keytype, type, kind)                 \
+    static const struct keytype_desc_st kind##_##keytype##_desc =       \
+        { keytype_name, ossl_##keytype##_keymgmt_functions,             \
+          DO_##kind(keytype) };                                         \
+                                                                        \
+    static OSSL_FUNC_decoder_newctx_fn kind##_der2##keytype##_newctx;   \
+    static OSSL_FUNC_decoder_gettable_params_fn                         \
+    kind##_der2##keytype##_gettable_params;                             \
+    static OSSL_FUNC_decoder_get_params_fn                              \
+    kind##_der2##keytype##_get_params;                                  \
+                                                                        \
+    static void *kind##_der2##keytype##_newctx(void *provctx)           \
+    {                                                                   \
+        return der2key_newctx(provctx, &kind##_##keytype##_desc);       \
+    }                                                                   \
+    static const OSSL_PARAM *                                           \
+    kind##_der2##keytype##_gettable_params(void *provctx)               \
+    {                                                                   \
+        return                                                          \
+            der2key_gettable_params(provctx, &kind##_##keytype##_desc); \
+    }                                                                   \
+    static int kind##_der2##keytype##_get_params(OSSL_PARAM params[])   \
+    {                                                                   \
+        return der2key_get_params(params, &kind##_##keytype##_desc);    \
+    }                                                                   \
+    static int kind##_der2##keytype##_does_selection(void *provctx,     \
+                                                     int selection)     \
     {                                                                   \
-        return der2key_newctx(provctx, &keytype##_desc);                \
+        return der2key_check_selection(selection,                       \
+                                       &kind##_##keytype##_desc);       \
     }                                                                   \
-    const OSSL_DISPATCH ossl_der_to_##keytype##_decoder_functions[] = { \
+    const OSSL_DISPATCH                                                 \
+    ossl_##kind##_der_to_##keytype##_decoder_functions[] = {            \
         { OSSL_FUNC_DECODER_NEWCTX,                                     \
-          (void (*)(void))der2##keytype##_newctx },                     \
+          (void (*)(void))kind##_der2##keytype##_newctx },              \
         { OSSL_FUNC_DECODER_FREECTX,                                    \
           (void (*)(void))der2key_freectx },                            \
         { OSSL_FUNC_DECODER_GETTABLE_PARAMS,                            \
-          (void (*)(void))der2key_gettable_params },                    \
+          (void (*)(void))kind##_der2##keytype##_gettable_params },     \
         { OSSL_FUNC_DECODER_GET_PARAMS,                                 \
-          (void (*)(void))der2key_get_params },                         \
+          (void (*)(void))kind##_der2##keytype##_get_params },          \
+        { OSSL_FUNC_DECODER_DOES_SELECTION,                             \
+          (void (*)(void))kind##_der2##keytype##_does_selection },      \
         { OSSL_FUNC_DECODER_DECODE,                                     \
           (void (*)(void))der2key_decode },                             \
         { OSSL_FUNC_DECODER_EXPORT_OBJECT,                              \
@@ -312,21 +674,38 @@ static int der2key_export_object(void *vctx,
     }
 
 #ifndef OPENSSL_NO_DH
-IMPLEMENT_NEWCTX("DH", DH, dh, EVP_PKEY_get1_DH, DH_free);
-IMPLEMENT_NEWCTX("DHX", DHX, dhx, EVP_PKEY_get1_DH, DH_free);
+MAKE_DECODER("DH", dh, dh, PKCS8);
+MAKE_DECODER("DH", dh, dh, SubjectPublicKeyInfo);
+MAKE_DECODER("DH", dh, dh, type_specific_params);
+MAKE_DECODER("DH", dh, dh, DH);
+MAKE_DECODER("DHX", dhx, dhx, PKCS8);
+MAKE_DECODER("DHX", dhx, dhx, SubjectPublicKeyInfo);
+MAKE_DECODER("DHX", dhx, dhx, type_specific_params);
+MAKE_DECODER("DHX", dhx, dhx, DHX);
 #endif
 #ifndef OPENSSL_NO_DSA
-IMPLEMENT_NEWCTX("DSA", DSA, dsa, EVP_PKEY_get1_DSA, DSA_free);
+MAKE_DECODER("DSA", dsa, dsa, PKCS8);
+MAKE_DECODER("DSA", dsa, dsa, SubjectPublicKeyInfo);
+MAKE_DECODER("DSA", dsa, dsa, type_specific);
+MAKE_DECODER("DSA", dsa, dsa, DSA);
 #endif
 #ifndef OPENSSL_NO_EC
-IMPLEMENT_NEWCTX("EC", EC, ec, EVP_PKEY_get1_EC_KEY, EC_KEY_free);
-IMPLEMENT_NEWCTX("X25519", X25519, x25519,
-                 evp_pkey_get1_X25519, ecx_key_free);
-IMPLEMENT_NEWCTX("X448", X448, x448,
-                 evp_pkey_get1_X448, ecx_key_free);
-IMPLEMENT_NEWCTX("ED25519", ED25519, ed25519,
-                 evp_pkey_get1_ED25519, ecx_key_free);
-IMPLEMENT_NEWCTX("ED448", ED448, ed448, evp_pkey_get1_ED448, ecx_key_free);
+MAKE_DECODER("EC", ec, ec, PKCS8);
+MAKE_DECODER("EC", ec, ec, SubjectPublicKeyInfo);
+MAKE_DECODER("EC", ec, ec, type_specific_no_pub);
+MAKE_DECODER("EC", ec, ec, EC);
+MAKE_DECODER("X25519", x25519, ecx, PKCS8);
+MAKE_DECODER("X25519", x25519, ecx, SubjectPublicKeyInfo);
+MAKE_DECODER("X448", x448, ecx, PKCS8);
+MAKE_DECODER("X448", x448, ecx, SubjectPublicKeyInfo);
+MAKE_DECODER("ED25519", ed25519, ecx, PKCS8);
+MAKE_DECODER("ED25519", ed25519, ecx, SubjectPublicKeyInfo);
+MAKE_DECODER("ED448", ed448, ecx, PKCS8);
+MAKE_DECODER("ED448", ed448, ecx, SubjectPublicKeyInfo);
 #endif
-IMPLEMENT_NEWCTX("RSA", RSA, rsa, EVP_PKEY_get1_RSA, RSA_free);
-IMPLEMENT_NEWCTX("RSA-PSS", RSA_PSS, rsapss, EVP_PKEY_get1_RSA, RSA_free);
+MAKE_DECODER("RSA", rsa, rsa, PKCS8);
+MAKE_DECODER("RSA", rsa, rsa, SubjectPublicKeyInfo);
+MAKE_DECODER("RSA", rsa, rsa, type_specific_keypair);
+MAKE_DECODER("RSA", rsa, rsa, RSA);
+MAKE_DECODER("RSA-PSS", rsapss, rsapss, PKCS8);
+MAKE_DECODER("RSA-PSS", rsapss, rsapss, SubjectPublicKeyInfo);
index deb2cc2..573f9c9 100644 (file)
@@ -188,27 +188,37 @@ static int ms2key_post(struct ms2key_ctx_st *ctx, EVP_PKEY *pkey,
     return ok;
 }
 
-static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin,
+static int msblob2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
                              OSSL_CALLBACK *data_cb, void *data_cbarg,
                              OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
 {
     struct ms2key_ctx_st *ctx = vctx;
     int ispub = -1;
     EVP_PKEY *pkey = read_msblob(ctx->provctx, cin, &ispub);
-    int ok = ms2key_post(ctx, pkey, data_cb, data_cbarg);
+    int ok = 0;
+
+    if (selection == 0
+        || (ispub
+            ? (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0
+            : (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0))
+        ok = ms2key_post(ctx, pkey, data_cb, data_cbarg);
 
     EVP_PKEY_free(pkey);
     return ok;
 }
 
 #ifndef OPENSSL_NO_RC4
-static int pvk2key_decode(void *vctx, OSSL_CORE_BIO *cin,
+static int pvk2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
                           OSSL_CALLBACK *data_cb, void *data_cbarg,
                           OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
 {
     struct ms2key_ctx_st *ctx = vctx;
     EVP_PKEY *pkey = read_pvk(ctx->provctx, cin, pw_cb, pw_cbarg);
-    int ok = ms2key_post(ctx, pkey, data_cb, data_cbarg);
+    int ok = 0;
+
+    if (selection == 0
+        || (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        ok = ms2key_post(ctx, pkey, data_cb, data_cbarg);
 
     EVP_PKEY_free(pkey);
     return ok;
index 9ddc0ae..6c8b108 100644 (file)
@@ -106,7 +106,11 @@ static int pem2der_pass_helper(char *buf, int num, int w, void *data)
     return (int)plen;
 }
 
-static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin,
+/*
+ * The selection parameter in pem2der_decode() is not used by this function
+ * because it's not relevant just to decode PEM to DER.
+ */
+static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
                           OSSL_CALLBACK *data_cb, void *data_cbarg,
                           OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
 {
index fd6b721..23b0f51 100644 (file)
@@ -362,20 +362,50 @@ extern const OSSL_DISPATCH ossl_ec_to_pem_encoder_functions[];
 extern const OSSL_DISPATCH ossl_ec_to_text_encoder_functions[];
 
 /* Decoders */
-extern const OSSL_DISPATCH ossl_der_to_dh_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_dhx_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_dsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_dh_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dh_decoder_functions[];
+extern const OSSL_DISPATCH ossl_type_specific_params_der_to_dh_decoder_functions[];
+extern const OSSL_DISPATCH ossl_DH_der_to_dh_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_dhx_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dhx_decoder_functions[];
+extern const OSSL_DISPATCH ossl_type_specific_params_der_to_dhx_decoder_functions[];
+extern const OSSL_DISPATCH ossl_DHX_der_to_dhx_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_dsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_type_specific_der_to_dsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_DSA_der_to_dsa_decoder_functions[];
 extern const OSSL_DISPATCH ossl_msblob_to_dsa_decoder_functions[];
 extern const OSSL_DISPATCH ossl_pvk_to_dsa_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_ec_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_x25519_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_x448_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_ed25519_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_ed448_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_rsa_decoder_functions[];
-extern const OSSL_DISPATCH ossl_der_to_rsapss_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_ec_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ec_decoder_functions[];
+extern const OSSL_DISPATCH ossl_type_specific_no_pub_der_to_ec_decoder_functions[];
+extern const OSSL_DISPATCH ossl_EC_der_to_ec_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_x25519_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_x25519_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_x448_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_x448_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_ed25519_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ed25519_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_ed448_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ed448_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_rsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_rsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_type_specific_keypair_der_to_rsa_decoder_functions[];
+extern const OSSL_DISPATCH ossl_RSA_der_to_rsa_decoder_functions[];
 extern const OSSL_DISPATCH ossl_msblob_to_rsa_decoder_functions[];
 extern const OSSL_DISPATCH ossl_pvk_to_rsa_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PKCS8_der_to_rsapss_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_rsapss_decoder_functions[];
+
 extern const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[];
 
 extern const OSSL_DISPATCH ossl_file_store_functions[];
index 8c9168b..74a18eb 100644 (file)
@@ -77,7 +77,7 @@ static int der2obj_get_params(OSSL_PARAM params[])
     return 1;
 }
 
-static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin,
+static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection,
                           OSSL_CALLBACK *data_cb, void *data_cbarg,
                           OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
 {