From: slontis Date: Tue, 4 Feb 2025 03:35:38 +0000 (+1100) Subject: SLH_DSA: Add support for generating X509 certs via the openssl X-Git-Tag: openssl-3.5.0-alpha1~178 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7389cca07961871320afeae46d5ed8a45fe23145;p=thirdparty%2Fopenssl.git SLH_DSA: Add support for generating X509 certs via the openssl command line app. Reviewed-by: Viktor Dukhovni Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/26625) --- diff --git a/.gitignore b/.gitignore index 231e1765c2b..aaf09dcae90 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ doc/man1/openssl-*.pod # Auto generated der files +providers/common/der/der_slh_dsa_gen.c providers/common/der/der_digests_gen.c providers/common/der/der_dsa_gen.c providers/common/der/der_ec_gen.c @@ -75,6 +76,7 @@ providers/common/der/der_rsa_gen.c providers/common/der/der_wrap_gen.c providers/common/der/der_sm2_gen.c providers/common/der/der_ml_dsa_gen.c +providers/common/include/prov/der_slh_dsa.h providers/common/include/prov/der_dsa.h providers/common/include/prov/der_ec.h providers/common/include/prov/der_ecx.h diff --git a/crypto/slh_dsa/slh_dsa_key.c b/crypto/slh_dsa/slh_dsa_key.c index ebe1dc07546..93d77dfd123 100644 --- a/crypto/slh_dsa/slh_dsa_key.c +++ b/crypto/slh_dsa/slh_dsa_key.c @@ -433,6 +433,10 @@ const char *ossl_slh_dsa_key_get_name(const SLH_DSA_KEY *key) { return key->params->alg; } +int ossl_slh_dsa_key_get_type(const SLH_DSA_KEY *key) +{ + return key->params->type; +} int ossl_slh_dsa_set_priv(SLH_DSA_KEY *key, const uint8_t *priv, size_t priv_len) { diff --git a/crypto/slh_dsa/slh_params.c b/crypto/slh_dsa/slh_params.c index 24a87aa1520..93e6087b7c9 100644 --- a/crypto/slh_dsa/slh_params.c +++ b/crypto/slh_dsa/slh_params.c @@ -9,6 +9,7 @@ #include #include #include "slh_params.h" +#include /* H(), T() use this to calculate the number of zeros for security cat 3 & 5 */ #define OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2 128 @@ -94,18 +95,18 @@ static const SLH_DSA_PARAMS slh_dsa_params[] = { - {"SLH-DSA-SHA2-128s", 0, OSSL_SLH_PARAMS(128S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1}, - {"SLH-DSA-SHAKE-128s", 1, OSSL_SLH_PARAMS(128S)}, - {"SLH-DSA-SHA2-128f", 0, OSSL_SLH_PARAMS(128F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1}, - {"SLH-DSA-SHAKE-128f", 1, OSSL_SLH_PARAMS(128F)}, - {"SLH-DSA-SHA2-192s", 0, OSSL_SLH_PARAMS(192S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, - {"SLH-DSA-SHAKE-192s", 1, OSSL_SLH_PARAMS(192S)}, - {"SLH-DSA-SHA2-192f", 0, OSSL_SLH_PARAMS(192F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, - {"SLH-DSA-SHAKE-192f", 1, OSSL_SLH_PARAMS(192F)}, - {"SLH-DSA-SHA2-256s", 0, OSSL_SLH_PARAMS(256S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, - {"SLH-DSA-SHAKE-256s", 1, OSSL_SLH_PARAMS(256S)}, - {"SLH-DSA-SHA2-256f", 0, OSSL_SLH_PARAMS(256F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, - {"SLH-DSA-SHAKE-256f", 1, OSSL_SLH_PARAMS(256F)}, + {"SLH-DSA-SHA2-128s", NID_SLH_DSA_SHA2_128s, 0, OSSL_SLH_PARAMS(128S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1}, + {"SLH-DSA-SHAKE-128s", NID_SLH_DSA_SHAKE_128s, 1, OSSL_SLH_PARAMS(128S)}, + {"SLH-DSA-SHA2-128f", NID_SLH_DSA_SHA2_128f, 0, OSSL_SLH_PARAMS(128F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1}, + {"SLH-DSA-SHAKE-128f", NID_SLH_DSA_SHAKE_128f, 1, OSSL_SLH_PARAMS(128F)}, + {"SLH-DSA-SHA2-192s", NID_SLH_DSA_SHA2_192s, 0, OSSL_SLH_PARAMS(192S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, + {"SLH-DSA-SHAKE-192s", NID_SLH_DSA_SHAKE_192s, 1, OSSL_SLH_PARAMS(192S)}, + {"SLH-DSA-SHA2-192f", NID_SLH_DSA_SHA2_192f, 0, OSSL_SLH_PARAMS(192F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, + {"SLH-DSA-SHAKE-192f", NID_SLH_DSA_SHAKE_192f, 1, OSSL_SLH_PARAMS(192F)}, + {"SLH-DSA-SHA2-256s", NID_SLH_DSA_SHA2_256s, 0, OSSL_SLH_PARAMS(256S), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, + {"SLH-DSA-SHAKE-256s", NID_SLH_DSA_SHAKE_256s, 1, OSSL_SLH_PARAMS(256S)}, + {"SLH-DSA-SHA2-256f", NID_SLH_DSA_SHA2_256f, 0, OSSL_SLH_PARAMS(256F), OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND2}, + {"SLH-DSA-SHAKE-256f", NID_SLH_DSA_SHAKE_256f, 1, OSSL_SLH_PARAMS(256F)}, {NULL}, }; diff --git a/crypto/slh_dsa/slh_params.h b/crypto/slh_dsa/slh_params.h index 6ba7c3d12f4..81adf4c6d0d 100644 --- a/crypto/slh_dsa/slh_params.h +++ b/crypto/slh_dsa/slh_params.h @@ -21,6 +21,7 @@ */ typedef struct slh_dsa_params_st { const char *alg; + int type; int is_shake; uint32_t n; /* Security parameter (Hash output size in bytes) (16, 24, 32) */ uint32_t h; /* The total height of the tree (63, 64, 66, 68). #keypairs = 2^h */ diff --git a/doc/designs/slh-dsa.md b/doc/designs/slh-dsa.md index f8abf4793eb..d45e6d46627 100644 --- a/doc/designs/slh-dsa.md +++ b/doc/designs/slh-dsa.md @@ -81,7 +81,7 @@ where `ctx` is some optional value of size 0x00..0xFF. ACVP Testing requires the ability for the message to not be encoded also. This will be controlled by settable parameters. -Pre Hash SLH-DSA Signature Generation encode the message as +Pre Hash SLH-DSA Signature Generation encodes the message as ```c 0x01 || len(ctx) || ctx || digest_OID || H(message). @@ -102,6 +102,17 @@ the API's used should be EVP_PKEY_sign_message_init(), EVP_PKEY_sign(), EVP_PKEY_verify_message_init(), EVP_PKEY_verify(). +OpenSSL command line support +---------------------------- + +For backwards compatibility reasons EVP_DigestSignInit_ex(), EVP_DigestSign(), +EVP_DigestVerifyInit_ex() and EVP_DigestVerify() may also be used, but the digest +passed in `mdname` must be NULL (i.e. it effectively behaves the same as above). +Passing a non NULL digest results in an error. + +OSSL_PKEY_PARAM_MANDATORY_DIGEST must return "" in the key manager getter and +OSSL_SIGNATURE_PARAM_ALGORITHM_ID in the signature context getter. + Buffers ------- diff --git a/doc/man7/EVP_SIGNATURE-SLH-DSA.pod b/doc/man7/EVP_SIGNATURE-SLH-DSA.pod index e3f7020f413..9ca1e077484 100644 --- a/doc/man7/EVP_SIGNATURE-SLH-DSA.pod +++ b/doc/man7/EVP_SIGNATURE-SLH-DSA.pod @@ -81,6 +81,12 @@ instead. This value is ignored if "test-entropy" is set. See L for information related to B keys. +=head1 NOTES + +For backwards compatibility reasons EVP_DigestSignInit_ex(), EVP_DigestSign(), +EVP_DigestVerifyInit_ex() and EVP_DigestVerify() may also be used, but the digest +passed in I must be NULL. + =head1 EXAMPLES To sign a message using an SLH-DSA EVP_PKEY structure: diff --git a/include/crypto/slh_dsa.h b/include/crypto/slh_dsa.h index 15ea92f99d5..72390783bbe 100644 --- a/include/crypto/slh_dsa.h +++ b/include/crypto/slh_dsa.h @@ -47,6 +47,7 @@ __owur size_t ossl_slh_dsa_key_get_priv_len(const SLH_DSA_KEY *key); __owur size_t ossl_slh_dsa_key_get_n(const SLH_DSA_KEY *key); __owur size_t ossl_slh_dsa_key_get_sig_len(const SLH_DSA_KEY *key); __owur const char *ossl_slh_dsa_key_get_name(const SLH_DSA_KEY *key); +__owur int ossl_slh_dsa_key_get_type(const SLH_DSA_KEY *key); __owur int ossl_slh_dsa_key_type_matches(const SLH_DSA_KEY *key, const char *alg); __owur SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_new(const SLH_DSA_KEY *key); void ossl_slh_dsa_hash_ctx_free(SLH_DSA_HASH_CTX *ctx); diff --git a/providers/common/der/SLH_DSA.asn1 b/providers/common/der/SLH_DSA.asn1 new file mode 100644 index 00000000000..3747c2dec84 --- /dev/null +++ b/providers/common/der/SLH_DSA.asn1 @@ -0,0 +1,24 @@ +-- Copyright 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 +-- in the file LICENSE in the source distribution or at +-- https://www.openssl.org/source/license.html + +-- ------------------------------------------------------------------- +-- Taken from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration + +sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 } + +id-slh-dsa-sha2-128s OBJECT IDENTIFIER ::= { sigAlgs 20 } +id-slh-dsa-sha2-128f OBJECT IDENTIFIER ::= { sigAlgs 21 } +id-slh-dsa-sha2-192s OBJECT IDENTIFIER ::= { sigAlgs 22 } +id-slh-dsa-sha2-192f OBJECT IDENTIFIER ::= { sigAlgs 23 } +id-slh-dsa-sha2-256s OBJECT IDENTIFIER ::= { sigAlgs 24 } +id-slh-dsa-sha2-256f OBJECT IDENTIFIER ::= { sigAlgs 25 } +id-slh-dsa-shake-128s OBJECT IDENTIFIER ::= { sigAlgs 26 } +id-slh-dsa-shake-128f OBJECT IDENTIFIER ::= { sigAlgs 27 } +id-slh-dsa-shake-192s OBJECT IDENTIFIER ::= { sigAlgs 28 } +id-slh-dsa-shake-192f OBJECT IDENTIFIER ::= { sigAlgs 29 } +id-slh-dsa-shake-256s OBJECT IDENTIFIER ::= { sigAlgs 30 } +id-slh-dsa-shake-256f OBJECT IDENTIFIER ::= { sigAlgs 31 } diff --git a/providers/common/der/build.info b/providers/common/der/build.info index 3e8904d54a6..cc881be85bd 100644 --- a/providers/common/der/build.info +++ b/providers/common/der/build.info @@ -112,6 +112,21 @@ IF[{- !$disabled{sm2} -}] DEPEND[$DER_SM2_H]=oids_to_c.pm SM2.asn1 ENDIF +#----- SLH-DSA +IF[{- !$disabled{'slh-dsa'} -}] + $DER_SLH_DSA_H=$INCDIR/der_slh_dsa.h + $DER_SLH_DSA_GEN=der_slh_dsa_gen.c + $DER_SLH_DSA_AUX=der_slh_dsa_key.c + + GENERATE[$DER_SLH_DSA_GEN]=der_slh_dsa_gen.c.in + DEPEND[$DER_SLH_DSA_GEN]=oids_to_c.pm SLH_DSA.asn1 + + DEPEND[${DER_SLH_DSA_GEN/.c/.o}]=$DER_SLH_DSA_H + DEPEND[${DER_SLH_DSA_AUX/.c/.o}]=$DER_SLH_DSA_H + GENERATE[$DER_SLH_DSA_H]=$INCDIR/der_slh_dsa.h.in + DEPEND[$DER_SLH_DSA_H]=oids_to_c.pm SLH_DSA.asn1 +ENDIF + #----- Conclusion $COMMON= $DER_RSA_COMMON $DER_DIGESTS_GEN $DER_WRAP_GEN @@ -135,6 +150,10 @@ IF[{- !$disabled{sm2} -}] $NONFIPS = $NONFIPS $DER_SM2_GEN $DER_SM2_AUX ENDIF +IF[{- !$disabled{'slh-dsa'} -}] + $COMMON = $COMMON $DER_SLH_DSA_GEN $DER_SLH_DSA_AUX +ENDIF + SOURCE[../../libcommon.a]= $COMMON SOURCE[../../libfips.a]= $DER_RSA_FIPSABLE SOURCE[../../libdefault.a]= $DER_RSA_FIPSABLE $NONFIPS diff --git a/providers/common/der/der_slh_dsa_gen.c.in b/providers/common/der/der_slh_dsa_gen.c.in new file mode 100644 index 00000000000..c337c9e50dc --- /dev/null +++ b/providers/common/der/der_slh_dsa_gen.c.in @@ -0,0 +1,19 @@ +/* + * {- join("\n * ", @autowarntext) -} + * + * Copyright 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/der_slh_dsa.h" + +/* Well known OIDs precompiled */ +{- + $OUT = oids_to_c::process_leaves('providers/common/der/SLH_DSA.asn1', + { dir => $config{sourcedir}, + filter => \&oids_to_c::filter_to_C }); +-} diff --git a/providers/common/der/der_slh_dsa_key.c b/providers/common/der/der_slh_dsa_key.c new file mode 100644 index 00000000000..1dbb9e1de00 --- /dev/null +++ b/providers/common/der/der_slh_dsa_key.c @@ -0,0 +1,42 @@ +/* + * SLH-DSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include +#include +#include "internal/packet.h" +#include "prov/der_slh_dsa.h" + +#define CASE_OID(nid, name) \ + case nid: \ + alg = ossl_der_oid_##name; \ + len = sizeof(ossl_der_oid_##name); \ + break + +int ossl_DER_w_algorithmIdentifier_SLH_DSA(WPACKET *pkt, int tag, SLH_DSA_KEY *key) +{ + const uint8_t *alg; + size_t len; + int nid = ossl_slh_dsa_key_get_type(key); + + switch (nid) { + CASE_OID(NID_SLH_DSA_SHA2_128s, id_slh_dsa_sha2_128s); + CASE_OID(NID_SLH_DSA_SHA2_128f, id_slh_dsa_sha2_128f); + CASE_OID(NID_SLH_DSA_SHA2_192s, id_slh_dsa_sha2_192s); + CASE_OID(NID_SLH_DSA_SHA2_192f, id_slh_dsa_sha2_192f); + CASE_OID(NID_SLH_DSA_SHA2_256s, id_slh_dsa_sha2_256s); + CASE_OID(NID_SLH_DSA_SHA2_256f, id_slh_dsa_sha2_256f); + CASE_OID(NID_SLH_DSA_SHAKE_128s, id_slh_dsa_shake_128s); + CASE_OID(NID_SLH_DSA_SHAKE_128f, id_slh_dsa_shake_128f); + CASE_OID(NID_SLH_DSA_SHAKE_192s, id_slh_dsa_shake_192s); + CASE_OID(NID_SLH_DSA_SHAKE_192f, id_slh_dsa_shake_192f); + CASE_OID(NID_SLH_DSA_SHAKE_256s, id_slh_dsa_shake_256s); + CASE_OID(NID_SLH_DSA_SHAKE_256f, id_slh_dsa_shake_256f); + default: + return 0; + } + return ossl_DER_w_begin_sequence(pkt, tag) + /* No parameters */ + && ossl_DER_w_precompiled(pkt, -1, alg, len) + && ossl_DER_w_end_sequence(pkt, tag); +} diff --git a/providers/common/include/prov/der_slh_dsa.h.in b/providers/common/include/prov/der_slh_dsa.h.in new file mode 100644 index 00000000000..017a3daa183 --- /dev/null +++ b/providers/common/include/prov/der_slh_dsa.h.in @@ -0,0 +1,22 @@ +/* + * {- join("\n * ", @autowarntext) -} + * + * Copyright 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/der.h" +#include "crypto/slh_dsa.h" + +/* Well known OIDs precompiled */ +{- + $OUT = oids_to_c::process_leaves('providers/common/der/SLH_DSA.asn1', + { dir => $config{sourcedir}, + filter => \&oids_to_c::filter_to_H }); +-} + +int ossl_DER_w_algorithmIdentifier_SLH_DSA(WPACKET *pkt, int tag, SLH_DSA_KEY *key); diff --git a/providers/implementations/keymgmt/slh_dsa_kmgmt.c b/providers/implementations/keymgmt/slh_dsa_kmgmt.c index 198622a7005..f9b223cc4ad 100644 --- a/providers/implementations/keymgmt/slh_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/slh_dsa_kmgmt.c @@ -126,6 +126,7 @@ static const OSSL_PARAM slh_dsa_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0), SLH_DSA_IMEXPORTABLE_PARAMETERS, OSSL_PARAM_END }; @@ -190,6 +191,13 @@ static int slh_dsa_get_params(void *keydata, OSSL_PARAM params[]) ossl_slh_dsa_key_get_pub_len(key))) return 0; } + /* + * This allows apps to use an empty digest, so that the old API + * for digest signing can be used. + */ + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MANDATORY_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, "")) + return 0; return 1; } diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info index c01e69f84ea..0fd39841f34 100644 --- a/providers/implementations/signature/build.info +++ b/providers/implementations/signature/build.info @@ -27,6 +27,7 @@ ENDIF SOURCE[$RSA_GOAL]=rsa_sig.c DEPEND[ml_dsa_sig.o]=../../common/include/prov/der_ml_dsa.h +DEPEND[slh_dsa_sig.o]=../../common/include/prov/der_slh_dsa.h DEPEND[rsa_sig.o]=../../common/include/prov/der_rsa.h DEPEND[dsa_sig.o]=../../common/include/prov/der_dsa.h DEPEND[ecdsa_sig.o]=../../common/include/prov/der_ec.h diff --git a/providers/implementations/signature/slh_dsa_sig.c b/providers/implementations/signature/slh_dsa_sig.c index e78776dbf67..c93e0f4792f 100644 --- a/providers/implementations/signature/slh_dsa_sig.c +++ b/providers/implementations/signature/slh_dsa_sig.c @@ -17,20 +17,25 @@ #include "prov/implementations.h" #include "prov/providercommon.h" #include "prov/provider_ctx.h" +#include "prov/der_slh_dsa.h" #include "crypto/slh_dsa.h" +#include "internal/sizes.h" #define SLH_DSA_MAX_ADD_RANDOM_LEN 32 #define SLH_DSA_MESSAGE_ENCODE_RAW 0 #define SLH_DSA_MESSAGE_ENCODE_PURE 1 -static OSSL_FUNC_signature_sign_message_init_fn slh_sign_msg_init; -static OSSL_FUNC_signature_sign_fn slh_sign; -static OSSL_FUNC_signature_verify_message_init_fn slh_verify_msg_init; -static OSSL_FUNC_signature_verify_fn slh_verify; -static OSSL_FUNC_signature_freectx_fn slh_freectx; -static OSSL_FUNC_signature_set_ctx_params_fn slh_set_ctx_params; -static OSSL_FUNC_signature_settable_ctx_params_fn slh_settable_ctx_params; +static OSSL_FUNC_signature_sign_message_init_fn slh_dsa_sign_msg_init; +static OSSL_FUNC_signature_sign_fn slh_dsa_sign; +static OSSL_FUNC_signature_verify_message_init_fn slh_dsa_verify_msg_init; +static OSSL_FUNC_signature_verify_fn slh_dsa_verify; +static OSSL_FUNC_signature_digest_sign_init_fn slh_dsa_digest_signverify_init; +static OSSL_FUNC_signature_digest_sign_fn slh_dsa_digest_sign; +static OSSL_FUNC_signature_digest_verify_fn slh_dsa_digest_verify; +static OSSL_FUNC_signature_freectx_fn slh_dsa_freectx; +static OSSL_FUNC_signature_set_ctx_params_fn slh_dsa_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn slh_dsa_settable_ctx_params; typedef struct { SLH_DSA_KEY *key; /* Note that the key is not owned by this object */ @@ -44,11 +49,14 @@ typedef struct { OSSL_LIB_CTX *libctx; char *propq; const char *alg; -} PROV_SLH_DSA_HASH_CTX; + /* The Algorithm Identifier of the signature algorithm */ + uint8_t aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + size_t aid_len; +} PROV_SLH_DSA_CTX; -static void slh_freectx(void *vctx) +static void slh_dsa_freectx(void *vctx) { - PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx; + PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx; ossl_slh_dsa_hash_ctx_free(ctx->hash_ctx); OPENSSL_free(ctx->propq); @@ -56,14 +64,14 @@ static void slh_freectx(void *vctx) OPENSSL_free(ctx); } -static void *slh_newctx(void *provctx, const char *alg, const char *propq) +static void *slh_dsa_newctx(void *provctx, const char *alg, const char *propq) { - PROV_SLH_DSA_HASH_CTX *ctx; + PROV_SLH_DSA_CTX *ctx; if (!ossl_prov_is_running()) return NULL; - ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_HASH_CTX)); + ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_CTX)); if (ctx == NULL) return NULL; @@ -74,15 +82,41 @@ static void *slh_newctx(void *provctx, const char *alg, const char *propq) ctx->msg_encode = SLH_DSA_MESSAGE_ENCODE_PURE; return ctx; err: - slh_freectx(ctx); + slh_dsa_freectx(ctx); return NULL; } -static int slh_signverify_msg_init(void *vctx, void *vkey, - const OSSL_PARAM params[], int operation, - const char *desc) +static int slh_dsa_set_alg_id_buffer(PROV_SLH_DSA_CTX *ctx) { - PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx; + int ret; + WPACKET pkt; + uint8_t *aid = NULL; + + /* + * We do not care about DER writing errors. + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + ctx->aid_len = 0; + ret = WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)); + ret = ret && ossl_DER_w_algorithmIdentifier_SLH_DSA(&pkt, -1, ctx->key); + if (ret && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &ctx->aid_len); + aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + if (aid != NULL && ctx->aid_len != 0) + memmove(ctx->aid_buf, aid, ctx->aid_len); + return 1; +} + +static int slh_dsa_signverify_msg_init(void *vctx, void *vkey, + const OSSL_PARAM params[], int operation, + const char *desc) +{ + PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx; SLH_DSA_KEY *key = vkey; if (!ossl_prov_is_running() @@ -103,22 +137,41 @@ static int slh_signverify_msg_init(void *vctx, void *vkey, ctx->key = vkey; } - if (!slh_set_ctx_params(ctx, params)) + slh_dsa_set_alg_id_buffer(ctx); + if (!slh_dsa_set_ctx_params(ctx, params)) return 0; return 1; } -static int slh_sign_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +static int slh_dsa_sign_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]) { - return slh_signverify_msg_init(vctx, vkey, params, - EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init"); + return slh_dsa_signverify_msg_init(vctx, vkey, params, + EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init"); } -static int slh_sign(void *vctx, unsigned char *sig, size_t *siglen, - size_t sigsize, const unsigned char *msg, size_t msg_len) +static int slh_dsa_digest_signverify_init(void *vctx, const char *mdname, + void *vkey, const OSSL_PARAM params[]) +{ + PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx; + + if (mdname != NULL && mdname[0] != '\0') { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "Explicit digest not supported for SLH-DSA operations"); + return 0; + } + + if (vkey == NULL && ctx->key != NULL) + return slh_dsa_set_ctx_params(ctx, params); + + return slh_dsa_signverify_msg_init(vctx, vkey, params, + EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init"); +} + +static int slh_dsa_sign(void *vctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *msg, size_t msg_len) { int ret = 0; - PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx; + PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx; uint8_t add_rand[SLH_DSA_MAX_ADD_RANDOM_LEN], *opt_rand = NULL; size_t n = 0; @@ -144,29 +197,38 @@ static int slh_sign(void *vctx, unsigned char *sig, size_t *siglen, return ret; } -static int slh_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +static int slh_dsa_digest_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize, + const uint8_t *tbs, size_t tbslen) { - return slh_signverify_msg_init(vctx, vkey, params, EVP_PKEY_OP_VERIFY, - "SLH_DSA Verify Init"); + return slh_dsa_sign(vctx, sig, siglen, sigsize, tbs, tbslen); } -static int slh_verify(void *vctx, const unsigned char *sig, size_t siglen, - const unsigned char *msg, size_t msg_len) +static int slh_dsa_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]) { - PROV_SLH_DSA_HASH_CTX *ctx = (PROV_SLH_DSA_HASH_CTX *)vctx; + return slh_dsa_signverify_msg_init(vctx, vkey, params, EVP_PKEY_OP_VERIFY, + "SLH_DSA Verify Init"); +} + +static int slh_dsa_verify(void *vctx, const uint8_t *sig, size_t siglen, + const uint8_t *msg, size_t msg_len) +{ + PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx; if (!ossl_prov_is_running()) return 0; return ossl_slh_dsa_verify(ctx->hash_ctx, msg, msg_len, ctx->context_string, ctx->context_string_len, ctx->msg_encode, sig, siglen); - - return 0; +} +static int slh_dsa_digest_verify(void *vctx, const uint8_t *sig, size_t siglen, + const uint8_t *tbs, size_t tbslen) +{ + return slh_dsa_verify(vctx, sig, siglen, tbs, tbslen); } -static int slh_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +static int slh_dsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { - PROV_SLH_DSA_HASH_CTX *pctx = (PROV_SLH_DSA_HASH_CTX *)vctx; + PROV_SLH_DSA_CTX *pctx = (PROV_SLH_DSA_CTX *)vctx; const OSSL_PARAM *p; if (pctx == NULL) @@ -206,8 +268,8 @@ static int slh_set_ctx_params(void *vctx, const OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *slh_settable_ctx_params(void *vctx, - ossl_unused void *provctx) +static const OSSL_PARAM *slh_dsa_settable_ctx_params(void *vctx, + ossl_unused void *provctx) { static const OSSL_PARAM settable_ctx_params[] = { OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0), @@ -220,24 +282,65 @@ static const OSSL_PARAM *slh_settable_ctx_params(void *vctx, return settable_ctx_params; } +static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *slh_dsa_gettable_ctx_params(ossl_unused void *vctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int slh_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params) +{ + PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx; + OSSL_PARAM *p; + + if (ctx == NULL) + return 0; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL + && !OSSL_PARAM_set_octet_string(p, + ctx->aid_len == 0 ? NULL : ctx->aid_buf, + ctx->aid_len)) + return 0; + + return 1; +} + #define MAKE_SIGNATURE_FUNCTIONS(alg, fn) \ - static OSSL_FUNC_signature_newctx_fn slh_##fn##_newctx; \ - static void *slh_##fn##_newctx(void *provctx, const char *propq) \ + static OSSL_FUNC_signature_newctx_fn slh_dsa_##fn##_newctx; \ + static void *slh_dsa_##fn##_newctx(void *provctx, const char *propq) \ { \ - return slh_newctx(provctx, alg, propq); \ + return slh_dsa_newctx(provctx, alg, propq); \ } \ const OSSL_DISPATCH ossl_slh_dsa_##fn##_signature_functions[] = { \ - { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))slh_##fn##_newctx }, \ + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))slh_dsa_##fn##_newctx }, \ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \ - (void (*)(void))slh_sign_msg_init }, \ - { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))slh_sign }, \ + (void (*)(void))slh_dsa_sign_msg_init }, \ + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))slh_dsa_sign }, \ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \ - (void (*)(void))slh_verify_msg_init }, \ - { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))slh_verify }, \ - { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))slh_freectx }, \ - { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))slh_set_ctx_params },\ + (void (*)(void))slh_dsa_verify_msg_init }, \ + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))slh_dsa_verify }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \ + (void (*)(void))slh_dsa_digest_signverify_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \ + (void (*)(void))slh_dsa_digest_sign }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \ + (void (*)(void))slh_dsa_digest_signverify_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \ + (void (*)(void))slh_dsa_digest_verify }, \ + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))slh_dsa_freectx }, \ + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))slh_dsa_set_ctx_params },\ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ - (void (*)(void))slh_settable_ctx_params }, \ + (void (*)(void))slh_dsa_settable_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \ + (void (*)(void))slh_dsa_get_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \ + (void (*)(void))slh_dsa_gettable_ctx_params }, \ OSSL_DISPATCH_END \ } diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t index 078932f461e..281c8f51777 100644 --- a/test/recipes/25-test_req.t +++ b/test/recipes/25-test_req.t @@ -15,7 +15,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_req"); -plan tests => 112; +plan tests => 113; require_ok(srctop_file('test', 'recipes', 'tconversion.pl')); @@ -454,6 +454,43 @@ subtest "generating certificate requests with -cipher flag" => sub { "Check that the key file is encrypted (AES-128-CBC)"); }; +subtest "generating certificate requests with SLH-DSA" => sub { + plan tests => 3; + + SKIP: { + skip "SLH-DSA is not supported by this OpenSSL build", 3 + if disabled("slh-dsa"); + + ok(run(app(["openssl", "req", + "-config", srctop_file("test", "test.cnf"), + "-x509", "-sha256", "-nodes", "-days", "365", + "-newkey", "SLH-DSA-SHA2-128f", + "-keyout", "privatekey_slh_dsa_sha2_128f.pem", + "-out", "cert_slh_dsa_sha2_128f.pem", + "-subj", "/CN=test-self-signed", + "-addext","keyUsage=digitalSignature"])), + "Generating self signed SLH-DSA-SHA2-128f cert and private key"); + ok(run(app(["openssl", "req", + "-config", srctop_file("test", "test.cnf"), + "-x509", "-sha256", "-nodes", "-days", "365", + "-newkey", "SLH-DSA-SHA2-256s", + "-keyout", "privatekey_slh_dsa_sha2_256s.pem", + "-out", "cert_slh_dsa_sha2_256s.pem", + "-subj", "/CN=test-self-signed", + "-addext","keyUsage=digitalSignature"])), + "Generating self signed SLH-DSA-SHA2-256s cert and private key"); + ok(run(app(["openssl", "req", + "-config", srctop_file("test", "test.cnf"), + "-x509", "-sha256", "-nodes", "-days", "365", + "-newkey", "SLH-DSA-SHAKE-256f", + "-keyout", "privatekey_slh_dsa_shake_256f.pem", + "-out", "cert_slh_dsa_shake_256f.pem", + "-subj", "/CN=test-self-signed", + "-addext","keyUsage=digitalSignature"])), + "Generating self signed SLH-DSA-SHAKE-256f cert and private key"); + } +}; + my @openssl_args = ("req", "-config", srctop_file("apps", "openssl.cnf")); run_conversion('req conversions', diff --git a/test/slh_dsa_test.c b/test/slh_dsa_test.c index 3378299b351..d39b1146ee3 100644 --- a/test/slh_dsa_test.c +++ b/test/slh_dsa_test.c @@ -500,6 +500,59 @@ err: return ret; } +static int slh_dsa_digest_sign_verify_test(void) +{ + int ret = 0; + EVP_PKEY *key = NULL; + uint8_t *sig = NULL; + size_t sig_len = 0; + OSSL_PARAM params[3], *p = params; + const char *alg = "SLH-DSA-SHA2-128s"; + EVP_MD_CTX *mctx = NULL; + static uint8_t context[] = "A context String"; + static uint8_t msg[] = "Hello World"; + size_t msg_len = sizeof(msg); + + if (!TEST_ptr(key = do_gen_key(alg, NULL, 0))) + goto err; + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, + context, sizeof(context)); + *p++ = OSSL_PARAM_construct_end(); + + if (!TEST_ptr(mctx = EVP_MD_CTX_new()) + || !TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, "SHA256", + lib_ctx, "?fips=true", + key, params), 0) + || !TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, NULL, lib_ctx, + "?fips=true", key, params), 1)) + goto err; + if (!TEST_int_eq(EVP_DigestSign(mctx, NULL, &sig_len, msg, msg_len), 1) + || !TEST_ptr(sig = OPENSSL_zalloc(sig_len))) + goto err; + sig_len--; + if (!TEST_int_eq(EVP_DigestSign(mctx, sig, &sig_len, msg, msg_len), 0)) + goto err; + sig_len++; + if (!TEST_int_eq(EVP_DigestSignInit_ex(mctx, NULL, NULL, lib_ctx, "?fips=true", + key, params), 1) + || !TEST_int_eq(EVP_DigestSign(mctx, sig, &sig_len, msg, msg_len), 1) + || !TEST_int_eq(EVP_DigestVerifyInit_ex(mctx, NULL, "SHA256", + lib_ctx, "?fips=true", + key, params), 0) + || !TEST_int_eq(EVP_DigestVerifyInit_ex(mctx, NULL, NULL, + lib_ctx, "?fips=true", + key, params), 1) + || !TEST_int_eq(EVP_DigestVerify(mctx, sig, sig_len, msg, msg_len), 1)) + goto err; + ret = 1; +err: + EVP_PKEY_free(key); + EVP_MD_CTX_free(mctx); + OPENSSL_free(sig); + return ret; +} + const OPTIONS *test_get_options(void) { static const OPTIONS options[] = { @@ -539,6 +592,7 @@ int setup_tests(void) ADD_TEST(slh_dsa_deterministic_usage_test); ADD_ALL_TESTS(slh_dsa_sign_verify_test, OSSL_NELEM(slh_dsa_sig_testdata)); ADD_ALL_TESTS(slh_dsa_keygen_test, OSSL_NELEM(slh_dsa_keygen_testdata)); + ADD_TEST(slh_dsa_digest_sign_verify_test); return 1; }