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 "internal/deprecated.h" 11 12 #include <assert.h> 13 #include <string.h> /* memset */ 14 #include <openssl/core_names.h> 15 #include <openssl/err.h> 16 #include <openssl/rand.h> 17 #include <openssl/proverr.h> 18 #include "prov/implementations.h" 19 #include "prov/providercommon.h" 20 #include "prov/provider_ctx.h" 21 #include "prov/der_ml_dsa.h" 22 #include "crypto/ml_dsa.h" 23 #include "internal/packet.h" 24 #include "internal/sizes.h" 25 26 #define ML_DSA_MESSAGE_ENCODE_RAW 0 27 #define ML_DSA_MESSAGE_ENCODE_PURE 1 28 29 static OSSL_FUNC_signature_sign_message_init_fn ml_dsa_sign_msg_init; 30 static OSSL_FUNC_signature_sign_fn ml_dsa_sign; 31 static OSSL_FUNC_signature_verify_message_init_fn ml_dsa_verify_msg_init; 32 static OSSL_FUNC_signature_verify_fn ml_dsa_verify; 33 static OSSL_FUNC_signature_digest_sign_init_fn ml_dsa_digest_signverify_init; 34 static OSSL_FUNC_signature_digest_sign_fn ml_dsa_digest_sign; 35 static OSSL_FUNC_signature_digest_verify_fn ml_dsa_digest_verify; 36 static OSSL_FUNC_signature_freectx_fn ml_dsa_freectx; 37 static OSSL_FUNC_signature_set_ctx_params_fn ml_dsa_set_ctx_params; 38 static OSSL_FUNC_signature_settable_ctx_params_fn ml_dsa_settable_ctx_params; 39 static OSSL_FUNC_signature_get_ctx_params_fn ml_dsa_get_ctx_params; 40 static OSSL_FUNC_signature_gettable_ctx_params_fn ml_dsa_gettable_ctx_params; 41 static OSSL_FUNC_signature_dupctx_fn ml_dsa_dupctx; 42 43 typedef struct { 44 ML_DSA_KEY *key; 45 OSSL_LIB_CTX *libctx; 46 uint8_t context_string[ML_DSA_MAX_CONTEXT_STRING_LEN]; 47 size_t context_string_len; 48 uint8_t test_entropy[ML_DSA_ENTROPY_LEN]; 49 size_t test_entropy_len; 50 int msg_encode; 51 int deterministic; 52 int evp_type; 53 /* The Algorithm Identifier of the signature algorithm */ 54 uint8_t aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; 55 size_t aid_len; 56 int mu; /* Flag indicating we should begin from \mu, not the message */ 57 } PROV_ML_DSA_CTX; 58 59 static void ml_dsa_freectx(void *vctx) 60 { 61 PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx; 62 63 OPENSSL_cleanse(ctx->test_entropy, ctx->test_entropy_len); 64 OPENSSL_free(ctx); 65 } 66 67 static void *ml_dsa_newctx(void *provctx, int evp_type, const char *propq) 68 { 69 PROV_ML_DSA_CTX *ctx; 70 71 if (!ossl_prov_is_running()) 72 return NULL; 73 74 ctx = OPENSSL_zalloc(sizeof(PROV_ML_DSA_CTX)); 75 if (ctx == NULL) 76 return NULL; 77 78 ctx->libctx = PROV_LIBCTX_OF(provctx); 79 ctx->msg_encode = ML_DSA_MESSAGE_ENCODE_PURE; 80 ctx->evp_type = evp_type; 81 return ctx; 82 } 83 84 static void *ml_dsa_dupctx(void *vctx) 85 { 86 PROV_ML_DSA_CTX *srcctx = (PROV_ML_DSA_CTX *)vctx; 87 88 if (!ossl_prov_is_running()) 89 return NULL; 90 91 /* 92 * Note that the ML_DSA_KEY is ref counted via EVP_PKEY so we can just copy 93 * the key here. 94 */ 95 return OPENSSL_memdup(srcctx, sizeof(*srcctx)); 96 } 97 98 static int set_alg_id_buffer(PROV_ML_DSA_CTX *ctx) 99 { 100 int ret; 101 WPACKET pkt; 102 uint8_t *aid = NULL; 103 104 /* 105 * We do not care about DER writing errors. 106 * All it really means is that for some reason, there's no 107 * AlgorithmIdentifier to be had, but the operation itself is 108 * still valid, just as long as it's not used to construct 109 * anything that needs an AlgorithmIdentifier. 110 */ 111 ctx->aid_len = 0; 112 ret = WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)); 113 ret = ret && ossl_DER_w_algorithmIdentifier_ML_DSA(&pkt, -1, ctx->key); 114 if (ret && WPACKET_finish(&pkt)) { 115 WPACKET_get_total_written(&pkt, &ctx->aid_len); 116 aid = WPACKET_get_curr(&pkt); 117 } 118 WPACKET_cleanup(&pkt); 119 if (aid != NULL && ctx->aid_len != 0) 120 memmove(ctx->aid_buf, aid, ctx->aid_len); 121 return 1; 122 } 123 124 static int ml_dsa_signverify_msg_init(void *vctx, void *vkey, 125 const OSSL_PARAM params[], int operation, 126 const char *desc) 127 { 128 PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx; 129 ML_DSA_KEY *key = vkey; 130 131 if (!ossl_prov_is_running() 132 || ctx == NULL) 133 return 0; 134 135 if (vkey == NULL && ctx->key == NULL) { 136 ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); 137 return 0; 138 } 139 140 if (key != NULL) 141 ctx->key = vkey; 142 if (!ossl_ml_dsa_key_matches(ctx->key, ctx->evp_type)) 143 return 0; 144 145 set_alg_id_buffer(ctx); 146 ctx->mu = 0; 147 148 return ml_dsa_set_ctx_params(ctx, params); 149 } 150 151 static int ml_dsa_sign_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]) 152 { 153 return ml_dsa_signverify_msg_init(vctx, vkey, params, 154 EVP_PKEY_OP_SIGN, "ML_DSA Sign Init"); 155 } 156 157 static int ml_dsa_digest_signverify_init(void *vctx, const char *mdname, 158 void *vkey, const OSSL_PARAM params[]) 159 { 160 PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx; 161 162 if (mdname != NULL && mdname[0] != '\0') { 163 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, 164 "Explicit digest not supported for ML-DSA operations"); 165 return 0; 166 } 167 168 ctx->mu = 0; 169 170 if (vkey == NULL && ctx->key != NULL) 171 return ml_dsa_set_ctx_params(ctx, params); 172 173 return ml_dsa_signverify_msg_init(vctx, vkey, params, 174 EVP_PKEY_OP_SIGN, "ML_DSA Sign Init"); 175 } 176 177 static int ml_dsa_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize, 178 const uint8_t *msg, size_t msg_len) 179 { 180 int ret = 0; 181 PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx; 182 uint8_t rand_tmp[ML_DSA_ENTROPY_LEN], *rnd = NULL; 183 184 if (!ossl_prov_is_running()) 185 return 0; 186 187 if (sig != NULL) { 188 if (ctx->test_entropy_len != 0) { 189 rnd = ctx->test_entropy; 190 } else { 191 rnd = rand_tmp; 192 193 if (ctx->deterministic == 1) 194 memset(rnd, 0, sizeof(rand_tmp)); 195 else if (RAND_priv_bytes_ex(ctx->libctx, rnd, sizeof(rand_tmp), 0) <= 0) 196 return 0; 197 } 198 } 199 ret = ossl_ml_dsa_sign(ctx->key, ctx->mu, msg, msg_len, 200 ctx->context_string, ctx->context_string_len, 201 rnd, sizeof(rand_tmp), ctx->msg_encode, 202 sig, siglen, sigsize); 203 if (rnd != ctx->test_entropy) 204 OPENSSL_cleanse(rand_tmp, sizeof(rand_tmp)); 205 return ret; 206 } 207 208 static int ml_dsa_digest_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize, 209 const uint8_t *tbs, size_t tbslen) 210 { 211 return ml_dsa_sign(vctx, sig, siglen, sigsize, tbs, tbslen); 212 } 213 214 static int ml_dsa_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]) 215 { 216 return ml_dsa_signverify_msg_init(vctx, vkey, params, EVP_PKEY_OP_VERIFY, 217 "ML_DSA Verify Init"); 218 } 219 220 static int ml_dsa_verify(void *vctx, const uint8_t *sig, size_t siglen, 221 const uint8_t *msg, size_t msg_len) 222 { 223 PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx; 224 225 if (!ossl_prov_is_running()) 226 return 0; 227 return ossl_ml_dsa_verify(ctx->key, ctx->mu, msg, msg_len, 228 ctx->context_string, ctx->context_string_len, 229 ctx->msg_encode, sig, siglen); 230 } 231 static int ml_dsa_digest_verify(void *vctx, 232 const uint8_t *sig, size_t siglen, 233 const uint8_t *tbs, size_t tbslen) 234 { 235 return ml_dsa_verify(vctx, sig, siglen, tbs, tbslen); 236 } 237 238 static int ml_dsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) 239 { 240 PROV_ML_DSA_CTX *pctx = (PROV_ML_DSA_CTX *)vctx; 241 const OSSL_PARAM *p; 242 243 if (pctx == NULL) 244 return 0; 245 if (ossl_param_is_empty(params)) 246 return 1; 247 248 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_CONTEXT_STRING); 249 if (p != NULL) { 250 void *vp = pctx->context_string; 251 252 if (!OSSL_PARAM_get_octet_string(p, &vp, sizeof(pctx->context_string), 253 &(pctx->context_string_len))) { 254 pctx->context_string_len = 0; 255 return 0; 256 } 257 } 258 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_TEST_ENTROPY); 259 if (p != NULL) { 260 void *vp = pctx->test_entropy; 261 262 pctx->test_entropy_len = 0; 263 if (!OSSL_PARAM_get_octet_string(p, &vp, sizeof(pctx->test_entropy), 264 &(pctx->test_entropy_len))) 265 return 0; 266 if (pctx->test_entropy_len != sizeof(pctx->test_entropy)) { 267 pctx->test_entropy_len = 0; 268 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); 269 return 0; 270 } 271 } 272 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DETERMINISTIC); 273 if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->deterministic)) 274 return 0; 275 276 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING); 277 if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->msg_encode)) 278 return 0; 279 280 p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MU); 281 if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->mu)) 282 return 0; 283 284 return 1; 285 } 286 287 static const OSSL_PARAM *ml_dsa_settable_ctx_params(void *vctx, 288 ossl_unused void *provctx) 289 { 290 static const OSSL_PARAM settable_ctx_params[] = { 291 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0), 292 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY, NULL, 0), 293 OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, 0), 294 OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MU, 0), 295 OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, 0), 296 OSSL_PARAM_END 297 }; 298 299 return settable_ctx_params; 300 } 301 302 static const OSSL_PARAM known_gettable_ctx_params[] = { 303 OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), 304 OSSL_PARAM_END 305 }; 306 307 static const OSSL_PARAM *ml_dsa_gettable_ctx_params(ossl_unused void *vctx, 308 ossl_unused void *provctx) 309 { 310 return known_gettable_ctx_params; 311 } 312 313 static int ml_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params) 314 { 315 PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx; 316 OSSL_PARAM *p; 317 318 if (ctx == NULL) 319 return 0; 320 321 p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); 322 if (p != NULL 323 && !OSSL_PARAM_set_octet_string(p, 324 ctx->aid_len == 0 ? NULL : ctx->aid_buf, 325 ctx->aid_len)) 326 return 0; 327 328 return 1; 329 } 330 331 #define MAKE_SIGNATURE_FUNCTIONS(alg) \ 332 static OSSL_FUNC_signature_newctx_fn ml_dsa_##alg##_newctx; \ 333 static void *ml_dsa_##alg##_newctx(void *provctx, const char *propq) \ 334 { \ 335 return ml_dsa_newctx(provctx, EVP_PKEY_ML_DSA_##alg, propq); \ 336 } \ 337 const OSSL_DISPATCH ossl_ml_dsa_##alg##_signature_functions[] = { \ 338 { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ml_dsa_##alg##_newctx }, \ 339 { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \ 340 (void (*)(void))ml_dsa_sign_msg_init }, \ 341 { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ml_dsa_sign }, \ 342 { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \ 343 (void (*)(void))ml_dsa_verify_msg_init }, \ 344 { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))ml_dsa_verify }, \ 345 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \ 346 (void (*)(void))ml_dsa_digest_signverify_init }, \ 347 { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \ 348 (void (*)(void))ml_dsa_digest_sign }, \ 349 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \ 350 (void (*)(void))ml_dsa_digest_signverify_init }, \ 351 { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \ 352 (void (*)(void))ml_dsa_digest_verify }, \ 353 { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ml_dsa_freectx }, \ 354 { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \ 355 (void (*)(void))ml_dsa_set_ctx_params }, \ 356 { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ 357 (void (*)(void))ml_dsa_settable_ctx_params }, \ 358 { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \ 359 (void (*)(void))ml_dsa_get_ctx_params }, \ 360 { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \ 361 (void (*)(void))ml_dsa_gettable_ctx_params }, \ 362 { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))ml_dsa_dupctx }, \ 363 OSSL_DISPATCH_END \ 364 } 365 366 MAKE_SIGNATURE_FUNCTIONS(44); 367 MAKE_SIGNATURE_FUNCTIONS(65); 368 MAKE_SIGNATURE_FUNCTIONS(87); 369