]> git.feebdaed.xyz Git - 0xmirror/openssl.git/commitdiff
New -encopt option for pkey(1) and genpkey(1)
authorViktor Dukhovni <openssl-users@dukhovni.org>
Wed, 10 Dec 2025 02:52:37 +0000 (13:52 +1100)
committerNorbert Pocs <norbertp@openssl.org>
Wed, 17 Dec 2025 12:40:17 +0000 (13:40 +0100)
This allows setting the ML-KEM and ML-DSA output formats.
At the same fixing surprising lack of password encryption
of PKCS#8 private keys in DER output form in the CLI apps.

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/29324)

16 files changed:
apps/genpkey.c
apps/include/apps.h
apps/lib/apps.c
apps/pkey.c
crypto/encode_decode/encoder_err.c
crypto/encode_decode/encoder_meth.c
crypto/err/openssl.txt
doc/man1/openssl-genpkey.pod.in
doc/man1/openssl-pkey.pod.in
doc/man3/OSSL_ENCODER_CTX.pod
include/crypto/encodererr.h
include/openssl/encoder.h
include/openssl/encodererr.h
test/recipes/15-test_ml_dsa_codecs.t
test/recipes/15-test_ml_kem_codecs.t
util/libcrypto.num

index 19fc788b23fea85fb39f460c392e8c9b9d0233ee..aa8089b301e598881f8074005c46c286461c0f75 100644 (file)
@@ -22,6 +22,7 @@ static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file,
 typedef enum OPTION_choice {
     OPT_COMMON,
     OPT_OUTFORM,
+    OPT_ENCOPT,
     OPT_OUT,
     OPT_PASS,
     OPT_PARAMFILE,
@@ -53,6 +54,7 @@ const OPTIONS genpkey_options[] = {
     { "out", OPT_OUT, '>', "Output (private key) file" },
     { "outpubkey", OPT_OUTPUBKEY, '>', "Output public key file" },
     { "outform", OPT_OUTFORM, 'F', "output format (DER or PEM)" },
+    { "encopt", OPT_ENCOPT, 's', "Private key encoder parameter" },
     { "pass", OPT_PASS, 's', "Output file pass phrase source" },
     { "genparam", OPT_GENPARAM, '-', "Generate parameters, not key" },
     { "text", OPT_TEXT, '-', "Print the private key in text" },
@@ -130,6 +132,7 @@ int genpkey_main(int argc, char **argv)
     OPTION_CHOICE o;
     int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
     int private = 0, i;
+    STACK_OF(OPENSSL_STRING) *encopt = NULL;
     OSSL_LIB_CTX *libctx = app_get0_libctx();
     STACK_OF(OPENSSL_STRING) *keyopt = NULL;
 
@@ -154,6 +157,12 @@ int genpkey_main(int argc, char **argv)
             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
                 goto opthelp;
             break;
+        case OPT_ENCOPT:
+            if (encopt == NULL)
+                encopt = sk_OPENSSL_STRING_new_null();
+            if (!sk_OPENSSL_STRING_push(encopt, opt_arg()))
+                goto end;
+            break;
         case OPT_OUT:
             outfile = opt_arg();
             break;
@@ -272,12 +281,12 @@ int genpkey_main(int argc, char **argv)
         rv = PEM_write_bio_Parameters(mem_out, pkey);
     } else if (outformat == FORMAT_PEM) {
         assert(private);
-        rv = PEM_write_bio_PrivateKey(mem_out, pkey, cipher, NULL, 0, NULL, pass);
+        rv = encode_private_key(mem_out, "PEM", pkey, encopt, cipher, pass);
         if (rv > 0 && mem_outpubkey != NULL)
             rv = PEM_write_bio_PUBKEY(mem_outpubkey, pkey);
     } else if (outformat == FORMAT_ASN1) {
         assert(private);
-        rv = i2d_PrivateKey_bio(mem_out, pkey);
+        rv = encode_private_key(mem_out, "DER", pkey, encopt, cipher, pass);
         if (rv > 0 && mem_outpubkey != NULL)
             rv = i2d_PUBKEY_bio(mem_outpubkey, pkey);
     } else {
@@ -322,6 +331,7 @@ end:
                     outfile, strerror(errno));
         }
     }
+    sk_OPENSSL_STRING_free(encopt);
     EVP_PKEY_free(pkey);
     EVP_PKEY_CTX_free(ctx);
     EVP_CIPHER_free(cipher);
index 2113669f5d762ba5f7f56edeee2ae9038cc27d66..74fca51a2ccd042888a33a0786054aa1c5165741 100644 (file)
@@ -102,6 +102,10 @@ int wrap_password_callback(char *buf, int bufsiz, int verify, void *cb_data);
 int progress_cb(EVP_PKEY_CTX *ctx);
 
 void dump_cert_text(BIO *out, X509 *x);
+int encode_private_key(
+    BIO *out, const char *output_type, const EVP_PKEY *pkey,
+    const STACK_OF(OPENSSL_STRING) *encopt, const EVP_CIPHER *cipher,
+    const char *pass);
 void print_name(BIO *out, const char *title, const X509_NAME *nm);
 void print_bignum_var(BIO *, const BIGNUM *, const char *,
     int, unsigned char *);
index 77c70586ec5b7a0929f2b5abe55692faa69c0f72..c922b43761f9628aad7121d5550561bc1a2384b5 100644 (file)
@@ -39,6 +39,7 @@
 #include <openssl/bn.h>
 #include <openssl/ssl.h>
 #include <openssl/core_names.h>
+#include <openssl/encoder.h>
 #include "s_apps.h"
 #include "apps.h"
 
@@ -2109,6 +2110,65 @@ err:
     return rv;
 }
 
+static int
+encoder_ctrl_string(OSSL_ENCODER_CTX *ctx, const char *value)
+{
+    int rv = 0;
+    char *stmp, *vtmp = NULL;
+
+    stmp = OPENSSL_strdup(value);
+    if (stmp == NULL)
+        return -1;
+    vtmp = strchr(stmp, ':');
+    if (vtmp == NULL) {
+        BIO_printf(bio_err,
+            "Missing encoder option value: %s\n", value);
+        goto end;
+    }
+
+    *vtmp = 0;
+    vtmp++;
+    rv = OSSL_ENCODER_CTX_ctrl_string(ctx, stmp, vtmp);
+
+end:
+    OPENSSL_free(stmp);
+    return rv;
+}
+
+int encode_private_key(BIO *out, const char *output_type, const EVP_PKEY *pkey,
+    const STACK_OF(OPENSSL_STRING) *encopt,
+    const EVP_CIPHER *cipher, const char *pass)
+{
+    int ret = 0;
+    OSSL_ENCODER_CTX *ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, EVP_PKEY_PRIVATE_KEY,
+        output_type, "PrivateKeyInfo", NULL);
+
+    if (ectx == NULL)
+        return 0;
+
+    if (cipher != NULL)
+        if (!OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(cipher), NULL)
+            || !OSSL_ENCODER_CTX_set_passphrase(ectx, (const unsigned char *)pass,
+                strlen(pass)))
+            goto end;
+
+    if (encopt != NULL) {
+        int i, n = sk_OPENSSL_STRING_num(encopt);
+
+        for (i = 0; i < n; ++i) {
+            const char *opt = sk_OPENSSL_STRING_value(encopt, i);
+
+            if (encoder_ctrl_string(ectx, opt) <= 0)
+                goto end;
+        }
+    }
+
+    ret = OSSL_ENCODER_to_bio(ectx, out);
+end:
+    OSSL_ENCODER_CTX_free(ectx);
+    return ret;
+}
+
 static void nodes_print(const char *name, STACK_OF(X509_POLICY_NODE) *nodes)
 {
     X509_POLICY_NODE *node;
index 13160f9d8a4ea6320d69a4cf47900b5106e49d9e..0436332dec303304c7bf8ebd510d30c22529601f 100644 (file)
@@ -14,6 +14,7 @@
 #include "ec_common.h"
 #include <openssl/pem.h>
 #include <openssl/err.h>
+#include <openssl/encoder.h>
 #include <openssl/evp.h>
 #include <openssl/core_names.h>
 
@@ -21,6 +22,7 @@ typedef enum OPTION_choice {
     OPT_COMMON,
     OPT_INFORM,
     OPT_OUTFORM,
+    OPT_ENCOPT,
     OPT_PASSIN,
     OPT_PASSOUT,
     OPT_IN,
@@ -57,6 +59,7 @@ const OPTIONS pkey_options[] = {
     OPT_SECTION("Output"),
     { "out", OPT_OUT, '>', "Output file for encoded and/or text output" },
     { "outform", OPT_OUTFORM, 'F', "Output encoding format (DER or PEM)" },
+    { "encopt", OPT_ENCOPT, 's', "Private key encoder parameter" },
     { "", OPT_CIPHER, '-', "Any supported cipher to be used for encryption" },
     { "passout", OPT_PASSOUT, 's', "Output PEM file pass phrase source" },
     { "traditional", OPT_TRADITIONAL, '-',
@@ -86,6 +89,7 @@ int pkey_main(int argc, char **argv)
     int informat = FORMAT_UNDEF, outformat = FORMAT_PEM;
     int pubin = 0, pubout = 0, text_pub = 0, text = 0, noout = 0, ret = 1;
     int private = 0, traditional = 0, check = 0, pub_check = 0;
+    STACK_OF(OPENSSL_STRING) *encopt = NULL;
 #ifndef OPENSSL_NO_EC
     char *asn1_encoding = NULL;
     char *point_format = NULL;
@@ -112,6 +116,12 @@ int pkey_main(int argc, char **argv)
             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
                 goto opthelp;
             break;
+        case OPT_ENCOPT:
+            if (encopt == NULL)
+                encopt = sk_OPENSSL_STRING_new_null();
+            if (!sk_OPENSSL_STRING_push(encopt, opt_arg()))
+                goto end;
+            break;
         case OPT_PASSIN:
             passinarg = opt_arg();
             break;
@@ -201,10 +211,21 @@ int pkey_main(int argc, char **argv)
         if (passoutarg != NULL)
             BIO_printf(bio_err,
                 "Warning: The -passout option is ignored without a cipher option\n");
+    } else if (noout) {
+        EVP_CIPHER_free(cipher);
+        cipher = NULL;
     } else {
-        if (noout || outformat != FORMAT_PEM) {
+        switch (outformat) {
+        case FORMAT_PEM:
+            break;
+        case FORMAT_ASN1:
+            if (!traditional)
+                break;
+            /* FALLTHROUGH */
+        default:
             BIO_printf(bio_err,
-                "Error: Cipher options are supported only for PEM output\n");
+                "Error: Cipher options are supported only in PEM "
+                "and non-traditional DER output forms\n");
             goto end;
         }
     }
@@ -284,8 +305,7 @@ int pkey_main(int argc, char **argv)
                             passout))
                         goto end;
                 } else {
-                    if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
-                            NULL, 0, NULL, passout))
+                    if (!encode_private_key(out, "PEM", pkey, encopt, cipher, passout))
                         goto end;
                 }
             }
@@ -304,8 +324,7 @@ int pkey_main(int argc, char **argv)
                     if (!i2d_PrivateKey_bio(out, pkey))
                         goto end;
                 } else {
-                    if (!i2d_PKCS8PrivateKey_bio(out, pkey, NULL, NULL, 0,
-                            NULL, NULL))
+                    if (!encode_private_key(out, "DER", pkey, encopt, cipher, passout))
                         goto end;
                 }
             }
@@ -329,6 +348,7 @@ int pkey_main(int argc, char **argv)
 end:
     if (ret != 0)
         ERR_print_errors(bio_err);
+    sk_OPENSSL_STRING_free(encopt);
     EVP_PKEY_CTX_free(ctx);
     EVP_PKEY_free(pkey);
     EVP_CIPHER_free(cipher);
index 79b12f9c31df2d04ed2bfee111366c8a36d1f10e..1def566f00fa1f995d9f373260d9a417b145660b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #ifndef OPENSSL_NO_ERR
 
 static const ERR_STRING_DATA OSSL_ENCODER_str_reasons[] = {
+    { ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_BAD_PARAMETER_VALUE),
+        "bad parameter value" },
     { ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_ENCODER_NOT_FOUND),
         "encoder not found" },
     { ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY),
         "incorrect property query" },
     { ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_MISSING_GET_PARAMS),
         "missing get params" },
+    { ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, OSSL_ENCODER_R_UNKNOWN_PARAMETER_NAME),
+        "unknown parameter name" },
     { 0, NULL }
 };
 
index 0bae49fa90d2563393e520ce18f1867d4d0aeea6..d71df816bea88405f222f4ab342dfb86d0d43097 100644 (file)
@@ -10,6 +10,7 @@
 #include <openssl/core.h>
 #include <openssl/core_dispatch.h>
 #include <openssl/encoder.h>
+#include <openssl/encodererr.h>
 #include <openssl/ui.h>
 #include "internal/core.h"
 #include "internal/namemap.h"
@@ -642,6 +643,55 @@ int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
     return ok;
 }
 
+int OSSL_ENCODER_CTX_ctrl_string(OSSL_ENCODER_CTX *ctx,
+    const char *name, const char *value)
+{
+    const OSSL_PARAM *settable = NULL;
+    int i, n, ok = 0;
+
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if (ctx->encoder_insts == NULL)
+        return 1;
+
+    n = OSSL_ENCODER_CTX_get_num_encoders(ctx);
+    for (i = 0; i < n; i++) {
+        OSSL_ENCODER_INSTANCE *encoder_inst = sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
+        OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
+        void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
+        OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+        int good = 0;
+
+        if (encoderctx == NULL || encoder->set_ctx_params == NULL)
+            continue;
+
+        settable = OSSL_ENCODER_settable_ctx_params(encoder);
+        if (settable == NULL)
+            continue;
+        if (!OSSL_PARAM_allocate_from_text(params, settable, name, value,
+                strlen(value), &good)) {
+            if (!good)
+                continue;
+            ERR_raise_data(ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_BAD_PARAMETER_VALUE,
+                "bad encoder parameter value: %s:%s", name, value);
+            return 0;
+        }
+        good = encoder->set_ctx_params(encoderctx, params);
+        OPENSSL_free(params[0].data);
+        if (!good)
+            return 0;
+        ++ok;
+    }
+    if (!ok) {
+        ERR_raise_data(ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_UNKNOWN_PARAMETER_NAME,
+            "unknown encoder parameter name: %s", name);
+    }
+    return ok;
+}
+
 void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx)
 {
     if (ctx != NULL) {
index 28f8b4fd61952a5b072878b621ede0853821d3af..922cecbaa50d07e2360a7feaa9921bd207fa33cc 100644 (file)
@@ -882,9 +882,11 @@ OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type
 OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT:101:could not decode object
 OSSL_DECODER_R_DECODER_NOT_FOUND:102:decoder not found
 OSSL_DECODER_R_MISSING_GET_PARAMS:100:missing get params
+OSSL_ENCODER_R_BAD_PARAMETER_VALUE:103:bad parameter value
 OSSL_ENCODER_R_ENCODER_NOT_FOUND:101:encoder not found
 OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY:100:incorrect property query
 OSSL_ENCODER_R_MISSING_GET_PARAMS:102:missing get params
+OSSL_ENCODER_R_UNKNOWN_PARAMETER_NAME:104:unknown parameter name
 OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
 OSSL_STORE_R_BAD_PASSWORD_READ:115:bad password read
 OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac
index 76fc3ac134e62d5cc9fca74038a580946f08a54d..434ed2a8b5ddd59e2833ed30ebb961cd973f9f0f 100644 (file)
@@ -23,6 +23,7 @@ B<openssl> B<genpkey>
 [B<-paramfile> I<file>]
 [B<-algorithm> I<alg>]
 [B<-pkeyopt> I<opt>:I<value>]
+[B<-encopt> I<opt>:I<value>]
 [B<-genparam>]
 [B<-text>]
 {- $OpenSSL::safe::opt_r_synopsis -}
@@ -96,14 +97,28 @@ PKCS#3 refers to DH Keys. Some options are not shared between DH and DHX keys.
 
 =item B<-pkeyopt> I<opt>:I<value>
 
-Set the public key algorithm option I<opt> to I<value>. The precise set of
-options supported depends on the public key algorithm used and its
+Set the public key algorithm option I<opt> to I<value>.
+The precise set of
+supported options depends on the public key algorithm used and its
 implementation. See L</KEY GENERATION OPTIONS> and
 L</PARAMETER GENERATION OPTIONS> below for more details.
 
 To list the possible I<opt> values for an algorithm use:
 B<openssl> B<genpkey> -algorithm XXX -help
 
+=item B<-encopt> I<opt>:I<value>
+
+Set the private key encoder parameter I<opt> to I<value>.
+In order to set multiple parameters, multiple B<-encopt> options can be
+specified, each specifying a single parameter.
+The precise set of supported parameters depends on the public key algorithm
+involved and its implementation.
+This is primarily applicable to B<ML-DSA> and B<ML-KEM>, whose private key
+encoding to a B<PKCS#8> object can take a number of different forms.
+The C<output_formats> parameter can be used to select the preferred output
+forms.
+See L<EVP_PKEY-ML-DSA(7)> and L<EVP_PKEY-ML-KEM(7)> for details.
+
 =item B<-genparam>
 
 Generate a set of parameters instead of a private key. If used this option must
@@ -553,6 +568,12 @@ Support for B<ML-DSA> and B<ML-KEM> was added in OpenSSL 3.5.
 
 The B<-engine> option was removed in OpenSSL 4.0.
 
+The B<-encopt> option was added in OpenSSL 4.0.
+
+As of OpenSSL 4.0 the B<-pass> and B<-I<cipher>> options apply when
+private keys are output in either B<DER> or B<PEM> form.
+Previously, these private key encryption options were ignored in B<DER> form.
+
 =head1 COPYRIGHT
 
 Copyright 2006-2025 The OpenSSL Project Authors. All Rights Reserved.
index 238d0c812adf0ab00a8c9a844af249ae9e4207b8..1bd0cdfb6dbb2a7778f0a2f0bf842d9f6816cf57 100644 (file)
@@ -22,6 +22,7 @@ B<openssl> B<pkey>
 [B<-pubin>]
 [B<-out> I<filename>]
 [B<-outform> B<DER>|B<PEM>]
+[B<-encopt> I<opt>:I<value>]
 [B<-I<cipher>>]
 [B<-passout> I<arg>]
 [B<-traditional>]
@@ -114,11 +115,25 @@ When password input is interrupted, the output file is not touched.
 The key output format; the default is B<PEM>.
 See L<openssl-format-options(1)> for details.
 
+=item B<-encopt> I<opt>:I<value>
+
+Set the private key encoder parameter I<opt> to I<value>.
+In order to set multiple parameters, multiple B<-encopt> options can be
+specified, each specifying a single parameter.
+The precise set of supported parameters depends on the public key algorithm
+involved and its implementation.
+This is primarily applicable to B<ML-DSA> and B<ML-KEM>, whose private key
+encoding to a B<PKCS#8> object can take a number of different forms.
+The C<output_formats> parameter can be used to select the preferred output
+forms.
+See L<EVP_PKEY-ML-DSA(7)> and L<EVP_PKEY-ML-KEM(7)> for details.
+
 =item B<-I<cipher>>
 
 Encrypt the PEM encoded private key with the supplied cipher. Any algorithm
 name accepted by EVP_get_cipherbyname() is acceptable such as B<aes128>.
-Encryption is not supported for DER output.
+In B<DER> output form encryption is supported only in the default B<PKCS#8>
+form and and is not available when the B<-traditional> option is used.
 
 =item B<-passout> I<arg>
 
@@ -130,8 +145,9 @@ see L<openssl-passphrase-options(1)>.
 =item B<-traditional>
 
 Normally a private key is written using standard format: this is PKCS#8 form
-with the appropriate encryption algorithm (if any). If the B<-traditional>
-option is specified then the older "traditional" format is used instead.
+with the appropriate encryption algorithm (if any).
+If the B<-traditional> option is specified then the older "traditional" format
+is used instead, and in B<DER> output form encryption is not available.
 
 =item B<-pubout>
 
@@ -230,6 +246,13 @@ L<openssl-gendsa(1)>
 
 The B<-engine> option was removed in OpenSSL 4.0.
 
+The B<-encopt> option was added in OpenSSL 4.0.
+
+As of OpenSSL 4.0 the B<-pass> and B<-I<cipher>> options apply when private
+keys are output in both B<PEM> and B<DER> (except with B<-traditional>) forms.
+Previously, these private key encryption options were rejected in combination
+with the B<DER> output form.
+
 =head1 COPYRIGHT
 
 Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved.
index f06b9fd86f62c57e356637d3ecc7ab038e2ce521..23291f8e188bce04021ba7d267cd463d4a3a5c37 100644 (file)
@@ -6,6 +6,7 @@ OSSL_ENCODER_CTX,
 OSSL_ENCODER_CTX_new,
 OSSL_ENCODER_settable_ctx_params,
 OSSL_ENCODER_CTX_set_params,
+OSSL_ENCODER_CTX_ctrl_string,
 OSSL_ENCODER_CTX_free,
 OSSL_ENCODER_CTX_set_selection,
 OSSL_ENCODER_CTX_set_output_type,
@@ -35,6 +36,8 @@ OSSL_ENCODER_CTX_set_cleanup
  const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder);
  int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
                                  const OSSL_PARAM params[]);
+ int OSSL_ENCODER_CTX_ctrl_string(OSSL_ENCODER_CTX *ctx,
+                                  const char *name, const char *val);
  void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx);
 
  int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection);
@@ -101,6 +104,13 @@ OSSL_ENCODER_CTX_set_params() attempts to set parameters specified
 with an L<OSSL_PARAM(3)> array I<params>.  Parameters that the
 implementation doesn't recognise should be ignored.
 
+OSSL_ENCODER_CTX_ctrl_string() attempts to set a single parameter named I<name>
+by parsing the specified string I<value> to the type of a settable parameter
+associated with one of the underlying encoders.
+An error is reported if no parameter named I<name> is a settable in any of the
+underlying encoders, the I<value> fails to parse, or the encoder implementation
+rejects the parsed value.
+
 OSSL_ENCODER_CTX_free() frees the given context I<ctx>.
 If the argument is NULL, nothing is done.
 
@@ -182,6 +192,8 @@ OSSL_ENCODER_CTX_set_params() returns 1 if all recognised parameters were
 valid, or 0 if one of them was invalid or caused some other failure in the
 implementation.
 
+OSSL_ENCODER_CTX_ctrl_string() returns 1 on success and 0 on error.
+
 OSSL_ENCODER_CTX_add_encoder(),
 OSSL_ENCODER_CTX_add_extra(),
 OSSL_ENCODER_CTX_set_cleanup(),
index db930a5dc2d06c846338487e7fc06b43b6d3b161..71fddeb50c6336816170f938748306e047e839fb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
index 9138c07276b6983f551200c68286c9fec026767a..20545309bef5b27c78aa220f6b983f25d930a827 100644 (file)
@@ -50,6 +50,8 @@ const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder);
 OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(void);
 int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
     const OSSL_PARAM params[]);
+int OSSL_ENCODER_CTX_ctrl_string(OSSL_ENCODER_CTX *ctx,
+    const char *name, const char *val);
 void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx);
 
 /* Utilities that help set specific parameters */
index e07174c3acd23020fec8edcb8d541a0e34fa430f..b895b6be322d8b050675e868e737fb33f39dded3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 /*
  * OSSL_ENCODER reason codes.
  */
+#define OSSL_ENCODER_R_BAD_PARAMETER_VALUE 103
 #define OSSL_ENCODER_R_ENCODER_NOT_FOUND 101
 #define OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY 100
 #define OSSL_ENCODER_R_MISSING_GET_PARAMS 102
+#define OSSL_ENCODER_R_UNKNOWN_PARAMETER_NAME 104
 
 #endif
index 3c1e9e1bbcd4c42b38ace1a504c9924d894d147c..07f0b37b7c086e9ebfb0dd298ffd37af629d6df7 100644 (file)
@@ -63,7 +63,7 @@ foreach my $alg (@algs) {
         my $pem = sprintf("prv-%s-%s.%d.pem", $alg, $f, $i++);
         ok(run(app(['openssl', 'genpkey', '-out', $pem,
                     '-pkeyopt', "hexseed:$seed", '-algorithm', "ml-dsa-$alg",
-                    '-provparam', "ml-dsa.output_formats=$f"])));
+                    '-encopt', "output_formats:$f"])));
         ok(!compare_text($in, $pem),
             sprintf("prvkey PEM match: %s, %s", $alg, $f));
 
index bebb8b8e851bdcef7452b3cdd05be7537b958458..25d92571c543b020871688d3d32ffa5964eb56e9 100644 (file)
@@ -59,7 +59,7 @@ foreach my $alg (@algs) {
         my $pem = sprintf("prv-%s-%s.%d.pem", $alg, $f, $i++);
         ok(run(app(['openssl', 'genpkey', '-out', $pem,
                     '-pkeyopt', "hexseed:$seed", '-algorithm', "ml-kem-$alg",
-                    '-provparam', "ml-kem.output_formats=$f"])));
+                    '-encopt', "output_formats:$f"])));
         ok(!compare_text($in, $pem),
             sprintf("prvkey PEM match: %s, %s", $alg, $f));
 
index 4cc9795ed02e788d4f83b34f9fab300d3ac25ed7..46452b2f7e153150ec4925bb5f122b60b1bb7c07 100644 (file)
@@ -5776,3 +5776,4 @@ CMS_SignerInfo_verify_ex                ? 4_0_0   EXIST::FUNCTION:CMS
 EVP_SIGNATURE_has_message_update        ?      4_0_0   EXIST::FUNCTION:
 EVP_MD_CTX_serialize                    ?      4_0_0   EXIST::FUNCTION:
 EVP_MD_CTX_deserialize                  ?      4_0_0   EXIST::FUNCTION:
+OSSL_ENCODER_CTX_ctrl_string            ?      4_0_0   EXIST::FUNCTION: