1 /*
2 * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <openssl/core_names.h>
11 #include <openssl/err.h>
12 #include <openssl/rand.h>
13 #include <openssl/proverr.h>
14 #include "prov/implementations.h"
15 #include "prov/providercommon.h"
16 #include "prov/provider_ctx.h"
17 #include "prov/der_slh_dsa.h"
18 #include "crypto/slh_dsa.h"
19 #include "internal/sizes.h"
20
21 #define SLH_DSA_MAX_ADD_RANDOM_LEN 32
22
23 #define SLH_DSA_MESSAGE_ENCODE_RAW 0
24 #define SLH_DSA_MESSAGE_ENCODE_PURE 1
25
26 static OSSL_FUNC_signature_sign_message_init_fn slh_dsa_sign_msg_init;
27 static OSSL_FUNC_signature_sign_fn slh_dsa_sign;
28 static OSSL_FUNC_signature_verify_message_init_fn slh_dsa_verify_msg_init;
29 static OSSL_FUNC_signature_verify_fn slh_dsa_verify;
30 static OSSL_FUNC_signature_digest_sign_init_fn slh_dsa_digest_signverify_init;
31 static OSSL_FUNC_signature_digest_sign_fn slh_dsa_digest_sign;
32 static OSSL_FUNC_signature_digest_verify_fn slh_dsa_digest_verify;
33 static OSSL_FUNC_signature_freectx_fn slh_dsa_freectx;
34 static OSSL_FUNC_signature_dupctx_fn slh_dsa_dupctx;
35 static OSSL_FUNC_signature_set_ctx_params_fn slh_dsa_set_ctx_params;
36 static OSSL_FUNC_signature_settable_ctx_params_fn slh_dsa_settable_ctx_params;
37
38 /*
39 * NOTE: Any changes to this structure may require updating slh_dsa_dupctx().
40 */
41 typedef struct {
42 SLH_DSA_KEY *key; /* Note that the key is not owned by this object */
43 SLH_DSA_HASH_CTX *hash_ctx;
44 uint8_t context_string[SLH_DSA_MAX_CONTEXT_STRING_LEN];
45 size_t context_string_len;
46 uint8_t add_random[SLH_DSA_MAX_ADD_RANDOM_LEN];
47 size_t add_random_len;
48 int msg_encode;
49 int deterministic;
50 OSSL_LIB_CTX *libctx;
51 char *propq;
52 const char *alg;
53 /* The Algorithm Identifier of the signature algorithm */
54 uint8_t aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
55 size_t aid_len;
56 } PROV_SLH_DSA_CTX;
57
slh_dsa_freectx(void * vctx)58 static void slh_dsa_freectx(void *vctx)
59 {
60 PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
61
62 ossl_slh_dsa_hash_ctx_free(ctx->hash_ctx);
63 OPENSSL_free(ctx->propq);
64 OPENSSL_cleanse(ctx->add_random, ctx->add_random_len);
65 OPENSSL_free(ctx);
66 }
67
slh_dsa_newctx(void * provctx,const char * alg,const char * propq)68 static void *slh_dsa_newctx(void *provctx, const char *alg, const char *propq)
69 {
70 PROV_SLH_DSA_CTX *ctx;
71
72 if (!ossl_prov_is_running())
73 return NULL;
74
75 ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_CTX));
76 if (ctx == NULL)
77 return NULL;
78
79 ctx->libctx = PROV_LIBCTX_OF(provctx);
80 if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)
81 goto err;
82 ctx->alg = alg;
83 ctx->msg_encode = SLH_DSA_MESSAGE_ENCODE_PURE;
84 return ctx;
85 err:
86 slh_dsa_freectx(ctx);
87 return NULL;
88 }
89
slh_dsa_dupctx(void * vctx)90 static void *slh_dsa_dupctx(void *vctx)
91 {
92 PROV_SLH_DSA_CTX *src = (PROV_SLH_DSA_CTX *)vctx;
93 PROV_SLH_DSA_CTX *ret;
94
95 if (!ossl_prov_is_running())
96 return NULL;
97
98 /*
99 * Note that the SLH_DSA_KEY is ref counted via EVP_PKEY so we can just copy
100 * the key here.
101 */
102 ret = OPENSSL_memdup(src, sizeof(*src));
103 if (ret == NULL)
104 return NULL;
105 ret->propq = NULL;
106 ret->hash_ctx = NULL;
107 if (src->propq != NULL && (ret->propq = OPENSSL_strdup(src->propq)) == NULL)
108 goto err;
109 ret->hash_ctx = ossl_slh_dsa_hash_ctx_dup(src->hash_ctx);
110 if (ret->hash_ctx == NULL)
111 goto err;
112
113 return ret;
114 err:
115 slh_dsa_freectx(ret);
116 return NULL;
117 }
118
slh_dsa_set_alg_id_buffer(PROV_SLH_DSA_CTX * ctx)119 static int slh_dsa_set_alg_id_buffer(PROV_SLH_DSA_CTX *ctx)
120 {
121 int ret;
122 WPACKET pkt;
123 uint8_t *aid = NULL;
124
125 /*
126 * We do not care about DER writing errors.
127 * All it really means is that for some reason, there's no
128 * AlgorithmIdentifier to be had, but the operation itself is
129 * still valid, just as long as it's not used to construct
130 * anything that needs an AlgorithmIdentifier.
131 */
132 ctx->aid_len = 0;
133 ret = WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf));
134 ret = ret && ossl_DER_w_algorithmIdentifier_SLH_DSA(&pkt, -1, ctx->key);
135 if (ret && WPACKET_finish(&pkt)) {
136 WPACKET_get_total_written(&pkt, &ctx->aid_len);
137 aid = WPACKET_get_curr(&pkt);
138 }
139 WPACKET_cleanup(&pkt);
140 if (aid != NULL && ctx->aid_len != 0)
141 memmove(ctx->aid_buf, aid, ctx->aid_len);
142 return 1;
143 }
144
slh_dsa_signverify_msg_init(void * vctx,void * vkey,const OSSL_PARAM params[],int operation,const char * desc)145 static int slh_dsa_signverify_msg_init(void *vctx, void *vkey,
146 const OSSL_PARAM params[], int operation,
147 const char *desc)
148 {
149 PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
150 SLH_DSA_KEY *key = vkey;
151
152 if (!ossl_prov_is_running()
153 || ctx == NULL)
154 return 0;
155
156 if (vkey == NULL && ctx->key == NULL) {
157 ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
158 return 0;
159 }
160
161 if (key != NULL) {
162 if (!ossl_slh_dsa_key_type_matches(key, ctx->alg))
163 return 0;
164 ctx->hash_ctx = ossl_slh_dsa_hash_ctx_new(key);
165 if (ctx->hash_ctx == NULL)
166 return 0;
167 ctx->key = vkey;
168 }
169
170 slh_dsa_set_alg_id_buffer(ctx);
171 if (!slh_dsa_set_ctx_params(ctx, params))
172 return 0;
173 return 1;
174 }
175
slh_dsa_sign_msg_init(void * vctx,void * vkey,const OSSL_PARAM params[])176 static int slh_dsa_sign_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
177 {
178 return slh_dsa_signverify_msg_init(vctx, vkey, params,
179 EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init");
180 }
181
slh_dsa_digest_signverify_init(void * vctx,const char * mdname,void * vkey,const OSSL_PARAM params[])182 static int slh_dsa_digest_signverify_init(void *vctx, const char *mdname,
183 void *vkey, const OSSL_PARAM params[])
184 {
185 PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
186
187 if (mdname != NULL && mdname[0] != '\0') {
188 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
189 "Explicit digest not supported for SLH-DSA operations");
190 return 0;
191 }
192
193 if (vkey == NULL && ctx->key != NULL)
194 return slh_dsa_set_ctx_params(ctx, params);
195
196 return slh_dsa_signverify_msg_init(vctx, vkey, params,
197 EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init");
198 }
199
slh_dsa_sign(void * vctx,unsigned char * sig,size_t * siglen,size_t sigsize,const unsigned char * msg,size_t msg_len)200 static int slh_dsa_sign(void *vctx, unsigned char *sig, size_t *siglen,
201 size_t sigsize, const unsigned char *msg, size_t msg_len)
202 {
203 int ret = 0;
204 PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
205 uint8_t add_rand[SLH_DSA_MAX_ADD_RANDOM_LEN], *opt_rand = NULL;
206 size_t n = 0;
207
208 if (!ossl_prov_is_running())
209 return 0;
210
211 if (sig != NULL) {
212 if (ctx->add_random_len != 0) {
213 opt_rand = ctx->add_random;
214 } else if (ctx->deterministic == 0) {
215 n = ossl_slh_dsa_key_get_n(ctx->key);
216 if (RAND_priv_bytes_ex(ctx->libctx, add_rand, n, 0) <= 0)
217 return 0;
218 opt_rand = add_rand;
219 }
220 }
221 ret = ossl_slh_dsa_sign(ctx->hash_ctx, msg, msg_len,
222 ctx->context_string, ctx->context_string_len,
223 opt_rand, ctx->msg_encode,
224 sig, siglen, sigsize);
225 if (opt_rand != add_rand)
226 OPENSSL_cleanse(opt_rand, n);
227 return ret;
228 }
229
slh_dsa_digest_sign(void * vctx,uint8_t * sig,size_t * siglen,size_t sigsize,const uint8_t * tbs,size_t tbslen)230 static int slh_dsa_digest_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize,
231 const uint8_t *tbs, size_t tbslen)
232 {
233 return slh_dsa_sign(vctx, sig, siglen, sigsize, tbs, tbslen);
234 }
235
slh_dsa_verify_msg_init(void * vctx,void * vkey,const OSSL_PARAM params[])236 static int slh_dsa_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
237 {
238 return slh_dsa_signverify_msg_init(vctx, vkey, params, EVP_PKEY_OP_VERIFY,
239 "SLH_DSA Verify Init");
240 }
241
slh_dsa_verify(void * vctx,const uint8_t * sig,size_t siglen,const uint8_t * msg,size_t msg_len)242 static int slh_dsa_verify(void *vctx, const uint8_t *sig, size_t siglen,
243 const uint8_t *msg, size_t msg_len)
244 {
245 PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
246
247 if (!ossl_prov_is_running())
248 return 0;
249 return ossl_slh_dsa_verify(ctx->hash_ctx, msg, msg_len,
250 ctx->context_string, ctx->context_string_len,
251 ctx->msg_encode, sig, siglen);
252 }
slh_dsa_digest_verify(void * vctx,const uint8_t * sig,size_t siglen,const uint8_t * tbs,size_t tbslen)253 static int slh_dsa_digest_verify(void *vctx, const uint8_t *sig, size_t siglen,
254 const uint8_t *tbs, size_t tbslen)
255 {
256 return slh_dsa_verify(vctx, sig, siglen, tbs, tbslen);
257 }
258
slh_dsa_set_ctx_params(void * vctx,const OSSL_PARAM params[])259 static int slh_dsa_set_ctx_params(void *vctx, const OSSL_PARAM params[])
260 {
261 PROV_SLH_DSA_CTX *pctx = (PROV_SLH_DSA_CTX *)vctx;
262 const OSSL_PARAM *p;
263
264 if (pctx == NULL)
265 return 0;
266 if (ossl_param_is_empty(params))
267 return 1;
268
269 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_CONTEXT_STRING);
270 if (p != NULL) {
271 void *vp = pctx->context_string;
272
273 if (!OSSL_PARAM_get_octet_string(p, &vp, sizeof(pctx->context_string),
274 &(pctx->context_string_len))) {
275 pctx->context_string_len = 0;
276 return 0;
277 }
278 }
279 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_TEST_ENTROPY);
280 if (p != NULL) {
281 void *vp = pctx->add_random;
282 size_t n = ossl_slh_dsa_key_get_n(pctx->key);
283
284 if (!OSSL_PARAM_get_octet_string(p, &vp, n, &(pctx->add_random_len))
285 || pctx->add_random_len != n) {
286 pctx->add_random_len = 0;
287 return 0;
288 }
289 }
290 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DETERMINISTIC);
291 if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->deterministic))
292 return 0;
293
294 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING);
295 if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->msg_encode))
296 return 0;
297 return 1;
298 }
299
slh_dsa_settable_ctx_params(void * vctx,ossl_unused void * provctx)300 static const OSSL_PARAM *slh_dsa_settable_ctx_params(void *vctx,
301 ossl_unused void *provctx)
302 {
303 static const OSSL_PARAM settable_ctx_params[] = {
304 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
305 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY, NULL, 0),
306 OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, 0),
307 OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, 0),
308 OSSL_PARAM_END
309 };
310
311 return settable_ctx_params;
312 }
313
314 static const OSSL_PARAM known_gettable_ctx_params[] = {
315 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
316 OSSL_PARAM_END
317 };
318
slh_dsa_gettable_ctx_params(ossl_unused void * vctx,ossl_unused void * provctx)319 static const OSSL_PARAM *slh_dsa_gettable_ctx_params(ossl_unused void *vctx,
320 ossl_unused void *provctx)
321 {
322 return known_gettable_ctx_params;
323 }
324
slh_dsa_get_ctx_params(void * vctx,OSSL_PARAM * params)325 static int slh_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params)
326 {
327 PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
328 OSSL_PARAM *p;
329
330 if (ctx == NULL)
331 return 0;
332
333 p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
334 if (p != NULL
335 && !OSSL_PARAM_set_octet_string(p,
336 ctx->aid_len == 0 ? NULL : ctx->aid_buf,
337 ctx->aid_len))
338 return 0;
339
340 return 1;
341 }
342
343 #define MAKE_SIGNATURE_FUNCTIONS(alg, fn) \
344 static OSSL_FUNC_signature_newctx_fn slh_dsa_##fn##_newctx; \
345 static void *slh_dsa_##fn##_newctx(void *provctx, const char *propq) \
346 { \
347 return slh_dsa_newctx(provctx, alg, propq); \
348 } \
349 const OSSL_DISPATCH ossl_slh_dsa_##fn##_signature_functions[] = { \
350 { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))slh_dsa_##fn##_newctx }, \
351 { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \
352 (void (*)(void))slh_dsa_sign_msg_init }, \
353 { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))slh_dsa_sign }, \
354 { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
355 (void (*)(void))slh_dsa_verify_msg_init }, \
356 { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))slh_dsa_verify }, \
357 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \
358 (void (*)(void))slh_dsa_digest_signverify_init }, \
359 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \
360 (void (*)(void))slh_dsa_digest_sign }, \
361 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \
362 (void (*)(void))slh_dsa_digest_signverify_init }, \
363 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \
364 (void (*)(void))slh_dsa_digest_verify }, \
365 { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))slh_dsa_freectx }, \
366 { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))slh_dsa_dupctx }, \
367 { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))slh_dsa_set_ctx_params },\
368 { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
369 (void (*)(void))slh_dsa_settable_ctx_params }, \
370 { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
371 (void (*)(void))slh_dsa_get_ctx_params }, \
372 { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
373 (void (*)(void))slh_dsa_gettable_ctx_params }, \
374 OSSL_DISPATCH_END \
375 }
376
377 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-128s", sha2_128s);
378 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-128f", sha2_128f);
379 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-192s", sha2_192s);
380 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-192f", sha2_192f);
381 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-256s", sha2_256s);
382 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-256f", sha2_256f);
383 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-128s", shake_128s);
384 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-128f", shake_128f);
385 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-192s", shake_192s);
386 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-192f", shake_192f);
387 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-256s", shake_256s);
388 MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-256f", shake_256f);
389