mirror of
https://github.com/openssl/openssl.git
synced 2026-01-25 02:56:43 +00:00
Per-key encoding formats for ML-KEM and ML-DSA
We support selection of ML-KEM and ML-DSA key formats on input and output at the provider level, these are essentially global defaults, in effect for the lifetime of the process. Unfortunately, the JAVA interface in openssl-jostle needs to be able to output a specific key in seed-only form. To that end, this PR introduces a new "output-formats" PKEY encoding parameter, that can be used with OSSL_ENCODER_CTX_set_params(3) when encoding a key to PKCS#8, after using OSSL_ENCODER_CTX_new_for_key(3), rather than i2d_PrivateKey(3), i2d_PKCS8PrivateKey(3) or PEM equivalents. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org> Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/29206)
This commit is contained in:
@@ -454,10 +454,6 @@ static int keygen_internal(ML_DSA_KEY *out)
|
||||
&& ossl_ml_dsa_sk_encode(out);
|
||||
|
||||
err:
|
||||
if (out->seed != NULL && (out->prov_flags & ML_DSA_KEY_RETAIN_SEED) == 0) {
|
||||
OPENSSL_clear_free(out->seed, ML_DSA_SEED_BYTES);
|
||||
out->seed = NULL;
|
||||
}
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
OPENSSL_cleanse(augmented_seed, sizeof(augmented_seed));
|
||||
OPENSSL_cleanse(expanded_seed, sizeof(expanded_seed));
|
||||
|
||||
@@ -1418,14 +1418,9 @@ int genkey(const uint8_t seed[ML_KEM_SEED_BYTES],
|
||||
/* Save |z| portion of seed for "implicit rejection" on failure. */
|
||||
memcpy(key->z, seed + ML_KEM_RANDOM_BYTES, ML_KEM_RANDOM_BYTES);
|
||||
|
||||
/* Optionally save the |d| portion of the seed */
|
||||
/* Save the |d| portion of the seed */
|
||||
key->d = key->z + ML_KEM_RANDOM_BYTES;
|
||||
if (key->prov_flags & ML_KEM_KEY_RETAIN_SEED) {
|
||||
memcpy(key->d, seed, ML_KEM_RANDOM_BYTES);
|
||||
} else {
|
||||
OPENSSL_cleanse(key->d, ML_KEM_RANDOM_BYTES);
|
||||
key->d = NULL;
|
||||
}
|
||||
memcpy(key->d, seed, ML_KEM_RANDOM_BYTES);
|
||||
|
||||
ret = 1;
|
||||
end:
|
||||
|
||||
@@ -53,6 +53,25 @@ ML-DSA hashing operations.
|
||||
|
||||
Use L<EVP_PKEY_CTX_set_params(3)> after calling L<EVP_PKEY_keygen_init(3)>.
|
||||
|
||||
=head2 Encoder Parameters
|
||||
|
||||
=over 4
|
||||
|
||||
=item "output_formats" (B<OSSL_PKEY_PARAM_OUTPUT_FORMATS>) <UTF8 string>
|
||||
|
||||
This parameter can be used with L<OSSL_ENCODER_CTX_new_for_pkey(3)>
|
||||
and L<OSSL_ENCODER_CTX_set_params(3)> to select the preferred B<PKCS#8> output
|
||||
formats of a private key.
|
||||
When this parameter is either not specified or empty, the behaviour is
|
||||
determined by the provider configuration parameters described below.
|
||||
Otherwise, it has the same syntax and behaviour as the provider configuration
|
||||
B<ml-dsa.output_formats> parameter, except that the B<ml-dsa.retain-seed>
|
||||
parameter is then ignored, i.e. the C<seed-only> and C<seed-priv> formats
|
||||
remain available so long as the seed was initially known, regardless of any
|
||||
setting of B<ml-dsa.retain-seed>.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Common ML-DSA parameters
|
||||
|
||||
In addition to the common parameters that all keytypes should support (see
|
||||
@@ -91,10 +110,10 @@ configuration options programmatically.
|
||||
=item C<ml-dsa.retain_seed> (B<OSSL_PKEY_PARAM_ML_DSA_RETAIN_SEED>) <UTF8 string>
|
||||
|
||||
When set to a string representing a false boolean value (see
|
||||
L<OSSL_PROVIDER_conf_get_bool(3)>), the seed will not be retained after key
|
||||
generation or key import from a seed value.
|
||||
If the resulting key is then written to a PKCS#8 object, it will contain
|
||||
only the FIPS 204 C<sk> key.
|
||||
L<OSSL_PROVIDER_conf_get_bool(3)>), the seed will not be included when
|
||||
keys are encoded to B<PKCS#8> form, unless the C<output_formats> encoder
|
||||
parameter is set to a nonempty value, as described above.
|
||||
The output B<PKCS#8> object will contain only the FIPS 204 C<sk> key.
|
||||
|
||||
=item C<ml-dsa.prefer_seed> (B<OSSL_PKEY_PARAM_ML_DSA_PREFER_SEED>) <UTF8 string>
|
||||
|
||||
@@ -285,6 +304,8 @@ L<provider-keymgmt(7)>,
|
||||
L<EVP_PKEY_get_raw_private_key(3)>,
|
||||
L<EVP_PKEY_get_raw_public_key(3)>,
|
||||
L<EVP_PKEY_get1_encoded_public_key(3)>,
|
||||
L<OSSL_ENCODER_CTX_new_for_pkey(3)>,
|
||||
L<OSSL_ENCODER_CTX_set_params(3)>,
|
||||
L<OSSL_PROVIDER_add_conf_parameter(3)>,
|
||||
L<provider-keymgmt(7)>,
|
||||
L<EVP_SIGNATURE-ML-DSA(7)>
|
||||
@@ -292,6 +313,7 @@ L<EVP_SIGNATURE-ML-DSA(7)>
|
||||
=head1 HISTORY
|
||||
|
||||
This functionality was added in OpenSSL 3.5.
|
||||
The C<output_formats> B<OSSL_ENCODER_CTX> parameter was added in OpenSSL 4.0.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
|
||||
@@ -53,11 +53,30 @@ Use L<EVP_PKEY_CTX_set_params(3)> after calling L<EVP_PKEY_keygen_init(3)>.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Encoder Parameters
|
||||
|
||||
=over 4
|
||||
|
||||
=item "output_formats" (B<OSSL_PKEY_PARAM_OUTPUT_FORMATS>) <UTF8 string>
|
||||
|
||||
This parameter can be used with L<OSSL_ENCODER_CTX_new_for_pkey(3)>
|
||||
and L<OSSL_ENCODER_CTX_set_params(3)> to select the preferred B<PKCS#8> output
|
||||
formats of a private key.
|
||||
When this parameter is either not specified or empty, the behaviour is
|
||||
determined by the provider configuration parameters described below.
|
||||
Otherwise, it has the same syntax and behaviour as the provider configuration
|
||||
B<ml-kem.output_formats> parameter, except that the B<ml-kem.retain-seed>
|
||||
parameter is then ignored, i.e. the C<seed-only> and C<seed-priv> formats
|
||||
remain available so long as the seed was initially known, regardless of any
|
||||
setting of B<ml-kem.retain-seed>.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Common parameters
|
||||
|
||||
In addition to the common parameters that all keytypes should support (see
|
||||
L<provider-keymgmt(7)/Common Information Parameters>), B<ML-KEM> keys
|
||||
keys support the parameters listed below.
|
||||
support the parameters listed below.
|
||||
These are gettable using
|
||||
L<EVP_PKEY_get_octet_string_param(3)> or L<EVP_PKEY_get_params(3)>.
|
||||
They can be initialised via L<EVP_PKEY_fromdata(3)>, and are returned by
|
||||
@@ -122,10 +141,10 @@ Specifying any other value of the parameter, e.g. C<none>, skips the test.
|
||||
=item C<ml-kem.retain_seed> (B<OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED>) <UTF8 string>
|
||||
|
||||
When set to a string representing a false boolean value (see
|
||||
L<OSSL_PROVIDER_conf_get_bool(3)>), the seed will not be retained after key
|
||||
generation or key import from a seed value.
|
||||
If the resulting key is then written to a PKCS#8 object, it will contain
|
||||
only the FIPS 203 C<dk> key.
|
||||
L<OSSL_PROVIDER_conf_get_bool(3)>), the seed will not be included when
|
||||
keys are encoded to B<PKCS#8> form, unless the C<output_formats> encoder
|
||||
parameter is set to a nonempty value, as described above.
|
||||
The output B<PKCS#8> object will contain only the FIPS 203 C<dk> key.
|
||||
|
||||
=item C<ml-kem.prefer_seed> (B<OSSL_PKEY_PARAM_ML_KEM_PREFER_SEED>) <UTF8 string>
|
||||
|
||||
@@ -193,14 +212,14 @@ recognised on input.
|
||||
=item C<bare-seed>:
|
||||
|
||||
This format represents B<PKCS#8> objects in which the private key contains
|
||||
the 64-byte FIPS 204 seed B<(d, z)> without any ASN.1 encapsulation.
|
||||
the 64-byte FIPS 203 seed B<(d, z)> without any ASN.1 encapsulation.
|
||||
If the C<bare-seed> format is not included in the list, this format will not be
|
||||
recognised on input.
|
||||
|
||||
=item C<bare-priv>:
|
||||
|
||||
This format represents B<PKCS#8> objects in which the private key contains
|
||||
the FIPS 204 decapsulation key B<dk> without any ASN.1 encapsulation.
|
||||
the FIPS 203 decapsulation key B<dk> without any ASN.1 encapsulation.
|
||||
If the C<bare-priv> format is not included in the list, this format will not be
|
||||
recognised on input.
|
||||
|
||||
@@ -305,6 +324,8 @@ L<EVP_PKEY(3)>,
|
||||
L<EVP_PKEY_get_raw_private_key(3)>,
|
||||
L<EVP_PKEY_get_raw_public_key(3)>,
|
||||
L<EVP_PKEY_get1_encoded_public_key(3)>,
|
||||
L<OSSL_ENCODER_CTX_new_for_pkey(3)>,
|
||||
L<OSSL_ENCODER_CTX_set_params(3)>,
|
||||
L<OSSL_PROVIDER_add_conf_parameter(3)>,
|
||||
L<provider-keymgmt(7)>,
|
||||
L<EVP_KEM-ML-KEM(7)>
|
||||
@@ -312,6 +333,7 @@ L<EVP_KEM-ML-KEM(7)>
|
||||
=head1 HISTORY
|
||||
|
||||
This functionality was added in OpenSSL 3.5.
|
||||
The C<output_formats> B<OSSL_ENCODER_CTX> parameter was added in OpenSSL 4.0.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
|
||||
@@ -116,9 +116,6 @@ extern "C" {
|
||||
#define OSSL_KEM_PARAM_OPERATION_RSASVE "RSASVE"
|
||||
#define OSSL_KEM_PARAM_OPERATION_DHKEM "DHKEM"
|
||||
|
||||
/* Provider configuration variables */
|
||||
#define OSSL_PKEY_RETAIN_SEED "pkey_retain_seed"
|
||||
|
||||
/* Parameter name definitions - generated by util/perl/OpenSSL/paramnames.pm */
|
||||
{- generate_public_macros(); -}
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ typedef struct key2any_ctx_st {
|
||||
EVP_CIPHER *cipher;
|
||||
|
||||
struct ossl_passphrase_data_st pwdata;
|
||||
|
||||
/* Just-in-time ML-KEM and ML-DSA output format override */
|
||||
char *output_formats;
|
||||
} KEY2ANY_CTX;
|
||||
|
||||
typedef int check_key_type_fn(const void *key, int nid);
|
||||
@@ -864,7 +867,8 @@ static int ml_dsa_pki_priv_to_der(const void *vkey, unsigned char **pder,
|
||||
{
|
||||
KEY2ANY_CTX *ctx = vctx;
|
||||
|
||||
return ossl_ml_dsa_i2d_prvkey(vkey, pder, ctx->provctx);
|
||||
return ossl_ml_dsa_i2d_prvkey(vkey, pder,
|
||||
ctx->provctx, ctx->output_formats);
|
||||
}
|
||||
|
||||
# define ml_dsa_epki_priv_to_der ml_dsa_pki_priv_to_der
|
||||
@@ -894,7 +898,8 @@ static int ml_kem_pki_priv_to_der(const void *vkey, unsigned char **pder,
|
||||
{
|
||||
KEY2ANY_CTX *ctx = vctx;
|
||||
|
||||
return ossl_ml_kem_i2d_prvkey(vkey, pder, ctx->provctx);
|
||||
return ossl_ml_kem_i2d_prvkey(vkey, pder,
|
||||
ctx->provctx, ctx->output_formats);
|
||||
}
|
||||
|
||||
# define ml_kem_epki_priv_to_der ml_kem_pki_priv_to_der
|
||||
@@ -1130,6 +1135,7 @@ static void key2any_freectx(void *vctx)
|
||||
|
||||
ossl_pw_clear_passphrase_data(&ctx->pwdata);
|
||||
EVP_CIPHER_free(ctx->cipher);
|
||||
OPENSSL_free(ctx->output_formats);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
@@ -1169,6 +1175,15 @@ static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[])
|
||||
if (p.svprm != NULL && !OSSL_PARAM_get_int(p.svprm, &ctx->save_parameters))
|
||||
return 0;
|
||||
|
||||
if (p.output_formats != NULL) {
|
||||
char *val = NULL;
|
||||
|
||||
if (!OSSL_PARAM_get_utf8_string(p.output_formats, &val, 0))
|
||||
return 0;
|
||||
OPENSSL_free(ctx->output_formats);
|
||||
ctx->output_formats = *val != '\0' ? val : NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ use OpenSSL::paramnames qw(produce_param_decoder);
|
||||
-}
|
||||
|
||||
{- produce_param_decoder('key2any_set_ctx_params',
|
||||
(['OSSL_ENCODER_PARAM_CIPHER', 'cipher', 'utf8_string'],
|
||||
['OSSL_ENCODER_PARAM_PROPERTIES', 'propq', 'utf8_string'],
|
||||
['OSSL_ENCODER_PARAM_SAVE_PARAMETERS', 'svprm', 'int'],
|
||||
(['OSSL_ENCODER_PARAM_CIPHER', 'cipher', 'utf8_string'],
|
||||
['OSSL_ENCODER_PARAM_PROPERTIES', 'propq', 'utf8_string'],
|
||||
['OSSL_ENCODER_PARAM_SAVE_PARAMETERS', 'svprm', 'int'],
|
||||
['OSSL_PKEY_PARAM_OUTPUT_FORMATS', 'output_formats', 'utf8_string'],
|
||||
)); -}
|
||||
|
||||
@@ -283,14 +283,13 @@ int ossl_ml_dsa_i2d_pubkey(const ML_DSA_KEY *key, unsigned char **out)
|
||||
|
||||
/* Allocate and encode PKCS#8 private key payload. */
|
||||
int ossl_ml_dsa_i2d_prvkey(const ML_DSA_KEY *key, uint8_t **out,
|
||||
PROV_CTX *provctx)
|
||||
PROV_CTX *provctx, const char *formats)
|
||||
{
|
||||
const ML_DSA_PARAMS *params = ossl_ml_dsa_key_params(key);
|
||||
const ML_COMMON_CODEC *codec;
|
||||
ML_COMMON_PKCS8_FMT_PREF *fmt_slots, *slot;
|
||||
const ML_COMMON_PKCS8_FMT *p8fmt;
|
||||
uint8_t *buf = NULL, *pos;
|
||||
const char *formats;
|
||||
int len = ML_DSA_SEED_BYTES;
|
||||
int ret = 0;
|
||||
const uint8_t *seed = ossl_ml_dsa_key_get_seed(key);
|
||||
@@ -307,8 +306,13 @@ int ossl_ml_dsa_i2d_prvkey(const ML_DSA_KEY *key, uint8_t **out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
formats = ossl_prov_ctx_get_param(
|
||||
provctx, OSSL_PKEY_PARAM_ML_DSA_OUTPUT_FORMATS, NULL);
|
||||
if (formats == NULL) {
|
||||
if ((ossl_ml_dsa_key_get_prov_flags(key) & ML_DSA_KEY_RETAIN_SEED) == 0)
|
||||
seed = NULL;
|
||||
formats = ossl_prov_ctx_get_param(provctx,
|
||||
OSSL_PKEY_PARAM_ML_DSA_OUTPUT_FORMATS,
|
||||
NULL);
|
||||
}
|
||||
fmt_slots = ossl_ml_common_pkcs8_fmt_order(params->alg, codec->p8fmt,
|
||||
"output", formats);
|
||||
if (fmt_slots == NULL)
|
||||
|
||||
@@ -302,15 +302,15 @@ int ossl_ml_kem_i2d_pubkey(const ML_KEM_KEY *key, unsigned char **out)
|
||||
|
||||
/* Allocate and encode PKCS#8 private key payload. */
|
||||
int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
|
||||
PROV_CTX *provctx)
|
||||
PROV_CTX *provctx, const char *formats)
|
||||
{
|
||||
const ML_KEM_VINFO *v = key->vinfo;
|
||||
const ML_COMMON_CODEC *codec;
|
||||
ML_COMMON_PKCS8_FMT_PREF *fmt_slots, *slot;
|
||||
const ML_COMMON_PKCS8_FMT *p8fmt;
|
||||
uint8_t *buf = NULL, *pos;
|
||||
const char *formats;
|
||||
int len = ML_KEM_SEED_BYTES;
|
||||
int have_seed = ossl_ml_kem_have_seed(key);
|
||||
int ret = 0;
|
||||
|
||||
/* Not ours to handle */
|
||||
@@ -324,8 +324,13 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
formats = ossl_prov_ctx_get_param(
|
||||
provctx, OSSL_PKEY_PARAM_ML_KEM_OUTPUT_FORMATS, NULL);
|
||||
if (formats == NULL) {
|
||||
if ((key->prov_flags & ML_KEM_KEY_RETAIN_SEED) == 0)
|
||||
have_seed = 0;
|
||||
formats = ossl_prov_ctx_get_param(provctx,
|
||||
OSSL_PKEY_PARAM_ML_KEM_OUTPUT_FORMATS,
|
||||
NULL);
|
||||
}
|
||||
fmt_slots = ossl_ml_common_pkcs8_fmt_order(v->algorithm_name, codec->p8fmt,
|
||||
"output", formats);
|
||||
if (fmt_slots == NULL)
|
||||
@@ -333,7 +338,7 @@ int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, uint8_t **out,
|
||||
|
||||
/* If we don't have a seed, skip seedful entries */
|
||||
for (slot = fmt_slots; (p8fmt = slot->fmt) != NULL; ++slot)
|
||||
if (ossl_ml_kem_have_seed(key) || p8fmt->seed_length == 0)
|
||||
if (have_seed || p8fmt->seed_length == 0)
|
||||
break;
|
||||
/* No matching table entries, give up */
|
||||
if (p8fmt == NULL
|
||||
|
||||
@@ -33,7 +33,7 @@ int ossl_ml_dsa_i2d_pubkey(const ML_DSA_KEY *key, unsigned char **out);
|
||||
__owur
|
||||
__owur
|
||||
int ossl_ml_dsa_i2d_prvkey(const ML_DSA_KEY *key, unsigned char **out,
|
||||
PROV_CTX *provctx);
|
||||
PROV_CTX *provctx, const char *formats);
|
||||
|
||||
# endif /* OPENSSL_NO_ML_DSA */
|
||||
#endif /* PROV_ML_DSA_CODECS_H */
|
||||
|
||||
@@ -33,7 +33,7 @@ int ossl_ml_kem_i2d_pubkey(const ML_KEM_KEY *key, unsigned char **out);
|
||||
__owur
|
||||
__owur
|
||||
int ossl_ml_kem_i2d_prvkey(const ML_KEM_KEY *key, unsigned char **out,
|
||||
PROV_CTX *provctx);
|
||||
PROV_CTX *provctx, const char *formats);
|
||||
|
||||
# endif /* OPENSSL_NO_ML_KEM */
|
||||
#endif /* PROV_ML_KEM_CODECS_H */
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/decoder.h>
|
||||
#include <openssl/encoder.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/proverr.h>
|
||||
#include <openssl/rand.h>
|
||||
@@ -737,6 +738,39 @@ static const unsigned char kExampleDHKeyDER[] = {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_ML_KEM
|
||||
/*
|
||||
* openssl genpkey -provparam ml-kem.output_formats=seed-only \
|
||||
* -algorithm ml-kem-512 -outform DER |
|
||||
* xxd -i
|
||||
*/
|
||||
static const unsigned char kMLKEMSeedOnlyDER[] = {
|
||||
0x30, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
|
||||
0x01, 0x65, 0x03, 0x04, 0x04, 0x01, 0x04, 0x42, 0x80, 0x40, 0x21, 0xe4,
|
||||
0x30, 0x56, 0x08, 0x64, 0xd3, 0xd4, 0x37, 0x33, 0x1c, 0xe5, 0xc9, 0xd8,
|
||||
0x26, 0x10, 0x9b, 0x4d, 0x58, 0xb4, 0xe2, 0x57, 0x70, 0x0f, 0x28, 0xe2,
|
||||
0xd2, 0xa8, 0x6b, 0xb6, 0x2b, 0x85, 0x1b, 0x25, 0x39, 0x29, 0xca, 0x6d,
|
||||
0x9a, 0xf0, 0x11, 0x5d, 0xca, 0xf4, 0xf7, 0x9a, 0x50, 0x39, 0xa7, 0x52,
|
||||
0x39, 0x5d, 0x84, 0xa9, 0xb9, 0x84, 0x4c, 0xa2, 0xe5, 0x49, 0xd7, 0x81,
|
||||
0xd1, 0x6d
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_ML_DSA
|
||||
/*
|
||||
* openssl genpkey -provparam ml-dsa.output_formats=seed-only \
|
||||
* -algorithm ml-dsa-44 -outform DER |
|
||||
* xxd -i
|
||||
*/
|
||||
static const unsigned char kMLDSASeedOnlyDER[] = {
|
||||
0x30, 0x34, 0x02, 0x01, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
|
||||
0x01, 0x65, 0x03, 0x04, 0x03, 0x11, 0x04, 0x22, 0x80, 0x20, 0xc5, 0xbb,
|
||||
0x12, 0x9c, 0x76, 0xac, 0x6f, 0x03, 0x6c, 0x56, 0x32, 0xf4, 0x66, 0xb8,
|
||||
0x8c, 0x77, 0x4b, 0xe0, 0xaa, 0x4a, 0xd6, 0xa0, 0x96, 0x12, 0xc3, 0x8c,
|
||||
0xe7, 0x71, 0xbe, 0xf8, 0xba, 0xbe
|
||||
};
|
||||
#endif
|
||||
|
||||
static const unsigned char kCFBDefaultKey[] = {
|
||||
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
|
||||
0x09, 0xCF, 0x4F, 0x3C
|
||||
@@ -926,6 +960,140 @@ static EVP_PKEY *load_example_ec_key(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(OPENSSL_NO_ML_KEM) || !defined(OPENSSL_NO_ML_DSA)
|
||||
static EVP_PKEY *load_ml_key(const char *keytype, const char *input_type,
|
||||
const unsigned char *data, size_t data_len)
|
||||
{
|
||||
const unsigned char **pdata = &data;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
OSSL_DECODER_CTX *dctx =
|
||||
OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, "PrivateKeyInfo",
|
||||
keytype, 0, testctx, testpropq);
|
||||
|
||||
if (!TEST_ptr(dctx))
|
||||
return NULL;
|
||||
/* |pkey| will be NULL on error */
|
||||
(void)OSSL_DECODER_from_data(dctx, pdata, &data_len);
|
||||
OSSL_DECODER_CTX_free(dctx);
|
||||
return pkey;
|
||||
}
|
||||
|
||||
static int
|
||||
store_ml_key(EVP_PKEY *pkey, const char *input_type, const char *fmts,
|
||||
const unsigned char *expect, size_t expectlen)
|
||||
{
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
OSSL_ENCODER_CTX *ectx = NULL;
|
||||
unsigned char *buf = NULL, *der = NULL;
|
||||
size_t len = 0;
|
||||
long derlen;
|
||||
int ret = 0;
|
||||
|
||||
/* Just-in-time encoding format selection */
|
||||
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_OUTPUT_FORMATS,
|
||||
(char *)fmts, 0);
|
||||
|
||||
ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, EVP_PKEY_KEYPAIR, input_type,
|
||||
"PrivateKeyInfo", testpropq);
|
||||
if (!TEST_ptr(ectx))
|
||||
return 0;
|
||||
if (!TEST_true(OSSL_ENCODER_CTX_set_params(ectx, params))
|
||||
|| !TEST_true(OSSL_ENCODER_to_data(ectx, &buf, &len)))
|
||||
goto end;
|
||||
|
||||
if (strcmp(input_type, "PEM") == 0) {
|
||||
BIO *pembio = BIO_new_mem_buf(buf, len);
|
||||
char *name = NULL, *header = NULL;
|
||||
|
||||
if (!TEST_ptr(pembio))
|
||||
goto end;
|
||||
ret = PEM_read_bio(pembio, &name, &header, &der, &derlen);
|
||||
BIO_free(pembio);
|
||||
if (TEST_true(ret)) {
|
||||
if (!TEST_int_eq(strcmp(name, PEM_STRING_PKCS8INF), 0)
|
||||
|| !TEST_true(header == NULL || *header == '\0'))
|
||||
ret = 0;
|
||||
OPENSSL_free(name);
|
||||
OPENSSL_free(header);
|
||||
if (!ret)
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
der = buf;
|
||||
derlen = len;
|
||||
}
|
||||
ret = expect != NULL ?
|
||||
TEST_mem_eq(der, (size_t) derlen, expect, expectlen) :
|
||||
TEST_size_t_eq((size_t) derlen, expectlen);
|
||||
|
||||
end:
|
||||
OSSL_ENCODER_CTX_free(ectx);
|
||||
if (der != buf)
|
||||
OPENSSL_free(der);
|
||||
OPENSSL_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_ml_seed_only(int idx)
|
||||
{
|
||||
const char *alg;
|
||||
const unsigned char *seedonly;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
size_t seedonlysz, privonlysz;
|
||||
const char *outform = (idx & 1) ? "DER" : "PEM";
|
||||
int ret = 0;
|
||||
|
||||
if (idx & 2) {
|
||||
# ifndef OPENSSL_NO_ML_DSA
|
||||
alg = "ML-DSA-44";
|
||||
seedonly = kMLDSASeedOnlyDER;
|
||||
seedonlysz = sizeof(kMLDSASeedOnlyDER);
|
||||
privonlysz = 2588;
|
||||
# else
|
||||
return 0;
|
||||
# endif
|
||||
} else {
|
||||
# ifndef OPENSSL_NO_ML_KEM
|
||||
alg = "ML-KEM-512";
|
||||
seedonly = kMLKEMSeedOnlyDER;
|
||||
seedonlysz = sizeof(kMLKEMSeedOnlyDER);
|
||||
privonlysz = 1660;
|
||||
# else
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
pkey = load_ml_key(alg, "DER", seedonly, seedonlysz);
|
||||
if (!TEST_ptr(pkey))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Check that the "output_formats" parameter is behaving as expected.
|
||||
* With "seed-only" check full payload, otherwise just the DER length.
|
||||
*/
|
||||
if (store_ml_key(pkey, outform, "seed-only", seedonly, seedonlysz)
|
||||
&& store_ml_key(pkey, outform, "bare-seed", NULL, seedonlysz - 2)
|
||||
&& store_ml_key(pkey, outform, "priv-only", NULL, privonlysz))
|
||||
ret = 1;
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_ML_KEM
|
||||
static int test_ml_kem_seed_only(int idx)
|
||||
{
|
||||
return test_ml_seed_only(idx);
|
||||
}
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ML_DSA
|
||||
static int test_ml_dsa_seed_only(int idx)
|
||||
{
|
||||
return test_ml_seed_only(idx + 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
# ifndef OPENSSL_NO_DH
|
||||
static EVP_PKEY *load_example_dh_key(void)
|
||||
@@ -6910,6 +7078,13 @@ int setup_tests(void)
|
||||
|
||||
ADD_TEST(test_evp_cipher_pipeline);
|
||||
|
||||
#ifndef OPENSSL_NO_ML_KEM
|
||||
ADD_ALL_TESTS(test_ml_kem_seed_only, 2);
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ML_DSA
|
||||
ADD_ALL_TESTS(test_ml_dsa_seed_only, 2);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -307,6 +307,7 @@ my %params = (
|
||||
'OSSL_PKEY_PARAM_DIST_ID' => "distid",
|
||||
'OSSL_PKEY_PARAM_PUB_KEY' => "pub",
|
||||
'OSSL_PKEY_PARAM_PRIV_KEY' => "priv",
|
||||
'OSSL_PKEY_PARAM_OUTPUT_FORMATS' => "output_formats",
|
||||
# PKEY_PARAM_IMPLICIT_REJECTION isn't actually used, or meaningful. We keep
|
||||
# it for API stability, but please use ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
|
||||
# instead.
|
||||
|
||||
Reference in New Issue
Block a user