DECODER: Allow precise result type for OSSL_DECODER_CTX_new_by_EVP_PKEY()
[openssl.git] / crypto / encode_decode / decoder_pkey.c
index 92c0d5a6ea8b6e5999f1ca35435254e2c132316e..75c491f4acb65434e6ba9a2db0015443b44a72a3 100644 (file)
@@ -14,6 +14,7 @@
 #include <openssl/decoder.h>
 #include <openssl/safestack.h>
 #include "crypto/evp.h"
+#include "crypto/decoder.h"
 #include "encoder_local.h"
 
 int OSSL_DECODER_CTX_set_passphrase(OSSL_DECODER_CTX *ctx,
@@ -36,6 +37,13 @@ int OSSL_DECODER_CTX_set_pem_password_cb(OSSL_DECODER_CTX *ctx,
     return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
 }
 
+int OSSL_DECODER_CTX_set_passphrase_cb(OSSL_DECODER_CTX *ctx,
+                                       OSSL_PASSPHRASE_CALLBACK *cb,
+                                       void *cbarg)
+{
+    return ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, cb, cbarg);
+}
+
 /*
  * Support for OSSL_DECODER_CTX_new_by_EVP_PKEY:
  * The construct data, and collecting keymgmt information for it
@@ -54,9 +62,8 @@ static int decoder_construct_EVP_PKEY(OSSL_DECODER_INSTANCE *decoder_inst,
                                       void *construct_data)
 {
     struct decoder_EVP_PKEY_data_st *data = construct_data;
-    OSSL_DECODER *decoder =
-        OSSL_DECODER_INSTANCE_decoder(decoder_inst);
-    void *deserctx = OSSL_DECODER_INSTANCE_decoder_ctx(decoder_inst);
+    OSSL_DECODER *decoder = OSSL_DECODER_INSTANCE_get_decoder(decoder_inst);
+    void *decoderctx = OSSL_DECODER_INSTANCE_get_decoder_ctx(decoder_inst);
     size_t i, end_i;
     /*
      * |object_ref| points to a provider reference to an object, its exact
@@ -143,7 +150,8 @@ static int decoder_construct_EVP_PKEY(OSSL_DECODER_INSTANCE *decoder_inst,
                  * No need to check for errors here, the value of
                  * |import_data.keydata| is as much an indicator.
                  */
-                (void)decoder->export_object(deserctx, object_ref, object_ref_sz,
+                (void)decoder->export_object(decoderctx,
+                                             object_ref, object_ref_sz,
                                              &evp_keymgmt_util_try_import,
                                              &import_data);
                 keydata = import_data.keydata;
@@ -178,10 +186,9 @@ static void decoder_clean_EVP_PKEY_construct_arg(void *construct_data)
     }
 }
 
-DEFINE_STACK_OF_CSTRING()
-
 struct collected_data_st {
     struct decoder_EVP_PKEY_data_st *process_data;
+    const char *keytype;
     STACK_OF(OPENSSL_CSTRING) *names;
     OSSL_DECODER_CTX *ctx;
 
@@ -192,6 +199,8 @@ static void collect_keymgmt(EVP_KEYMGMT *keymgmt, void *arg)
 {
     struct collected_data_st *data = arg;
 
+    if (data->keytype != NULL && !EVP_KEYMGMT_is_a(keymgmt, data->keytype))
+        return;
     if (data->error_occured)
         return;
 
@@ -200,7 +209,7 @@ static void collect_keymgmt(EVP_KEYMGMT *keymgmt, void *arg)
     if (!EVP_KEYMGMT_up_ref(keymgmt) /* ref++ */)
         return;
     if (sk_EVP_KEYMGMT_push(data->process_data->keymgmts, keymgmt) <= 0) {
-        EVP_KEYMGMT_free(keymgmt); /* ref-- */
+        EVP_KEYMGMT_free(keymgmt);   /* ref-- */
         return;
     }
 
@@ -246,28 +255,26 @@ static void collect_decoder(OSSL_DECODER *decoder, void *arg)
     data->error_occured = 0;         /* All is good now */
 }
 
-OSSL_DECODER_CTX *OSSL_DECODER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
-                                                   const char *input_type,
-                                                   OPENSSL_CTX *libctx,
-                                                   const char *propquery)
+int ossl_decoder_ctx_setup_for_EVP_PKEY(OSSL_DECODER_CTX *ctx,
+                                        EVP_PKEY **pkey, const char *keytype,
+                                        OPENSSL_CTX *libctx,
+                                        const char *propquery)
 {
-    OSSL_DECODER_CTX *ctx = NULL;
     struct collected_data_st *data = NULL;
     size_t i, end_i;
+    int ok = 0;
 
-    if ((ctx = OSSL_DECODER_CTX_new()) == NULL
-        || (data = OPENSSL_zalloc(sizeof(*data))) == NULL
+    if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL
         || (data->process_data =
             OPENSSL_zalloc(sizeof(*data->process_data))) == NULL
-        || (data->process_data->keymgmts
-            = sk_EVP_KEYMGMT_new_null()) == NULL
+        || (data->process_data->keymgmts = sk_EVP_KEYMGMT_new_null()) == NULL
         || (data->names = sk_OPENSSL_CSTRING_new_null()) == NULL) {
         ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
         goto err;
     }
     data->process_data->object = (void **)pkey;
     data->ctx = ctx;
-    OSSL_DECODER_CTX_set_input_type(ctx, input_type);
+    data->keytype = keytype;
 
     /* First, find all keymgmts to form goals */
     EVP_KEYMGMT_do_all_provided(libctx, collect_keymgmt, data);
@@ -296,25 +303,43 @@ OSSL_DECODER_CTX *OSSL_DECODER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
     if (data->error_occured)
         goto err;
 
-    /* If we found no decoders to match the keymgmts, we err */
-    if (OSSL_DECODER_CTX_num_decoders(ctx) == 0)
-        goto err;
-
-    /* Finally, collect extra decoders based on what we already have */
-    (void)OSSL_DECODER_CTX_add_extra(ctx, libctx, propquery);
+    if (OSSL_DECODER_CTX_get_num_decoders(ctx) != 0) {
+        if (!OSSL_DECODER_CTX_set_construct(ctx, decoder_construct_EVP_PKEY)
+            || !OSSL_DECODER_CTX_set_construct_data(ctx, data->process_data)
+            || !OSSL_DECODER_CTX_set_cleanup(ctx,
+                                             decoder_clean_EVP_PKEY_construct_arg))
+            goto err;
 
-    if (!OSSL_DECODER_CTX_set_construct(ctx, decoder_construct_EVP_PKEY)
-        || !OSSL_DECODER_CTX_set_construct_data(ctx, data->process_data)
-        || !OSSL_DECODER_CTX_set_cleanup(ctx,
-                                         decoder_clean_EVP_PKEY_construct_arg))
-        goto err;
+        data->process_data = NULL; /* Avoid it being freed */
+    }
 
-    data->process_data = NULL;
+    ok = 1;
  err:
     if (data != NULL) {
         decoder_clean_EVP_PKEY_construct_arg(data->process_data);
         sk_OPENSSL_CSTRING_free(data->names);
         OPENSSL_free(data);
     }
-    return ctx;
+    return ok;
+}
+
+OSSL_DECODER_CTX *
+OSSL_DECODER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
+                                 const char *input_type, const char *keytype,
+                                 OPENSSL_CTX *libctx, const char *propquery)
+{
+    OSSL_DECODER_CTX *ctx = NULL;
+
+    if ((ctx = OSSL_DECODER_CTX_new()) == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    if (OSSL_DECODER_CTX_set_input_type(ctx, input_type)
+        && ossl_decoder_ctx_setup_for_EVP_PKEY(ctx, pkey, keytype,
+                                               libctx, propquery)
+        && OSSL_DECODER_CTX_add_extra(ctx, libctx, propquery))
+        return ctx;
+
+    OSSL_DECODER_CTX_free(ctx);
+    return NULL;
 }