Coverage Report

Created: 2025-08-28 06:41

/src/openssl/providers/implementations/kem/ml_kem_kem.c
Line
Count
Source (jump to first uncovered line)
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
11
#include <string.h>
12
#include <openssl/crypto.h>
13
#include <openssl/evp.h>
14
#include <openssl/core_dispatch.h>
15
#include <openssl/core_names.h>
16
#include <openssl/params.h>
17
#include <openssl/err.h>
18
#include <openssl/proverr.h>
19
#include "crypto/ml_kem.h"
20
#include "internal/cryptlib.h"
21
#include "prov/provider_ctx.h"
22
#include "prov/implementations.h"
23
#include "prov/securitycheck.h"
24
#include "prov/providercommon.h"
25
26
static OSSL_FUNC_kem_newctx_fn ml_kem_newctx;
27
static OSSL_FUNC_kem_freectx_fn ml_kem_freectx;
28
static OSSL_FUNC_kem_encapsulate_init_fn ml_kem_encapsulate_init;
29
static OSSL_FUNC_kem_encapsulate_fn ml_kem_encapsulate;
30
static OSSL_FUNC_kem_decapsulate_init_fn ml_kem_decapsulate_init;
31
static OSSL_FUNC_kem_decapsulate_fn ml_kem_decapsulate;
32
static OSSL_FUNC_kem_set_ctx_params_fn ml_kem_set_ctx_params;
33
static OSSL_FUNC_kem_settable_ctx_params_fn ml_kem_settable_ctx_params;
34
35
typedef struct {
36
    ML_KEM_KEY *key;
37
    uint8_t entropy_buf[ML_KEM_RANDOM_BYTES];
38
    uint8_t *entropy;
39
    int op;
40
} PROV_ML_KEM_CTX;
41
42
static void *ml_kem_newctx(void *provctx)
43
0
{
44
0
    PROV_ML_KEM_CTX *ctx;
45
46
0
    if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL)
47
0
        return NULL;
48
49
0
    ctx->key = NULL;
50
0
    ctx->entropy = NULL;
51
0
    ctx->op = 0;
52
0
    return ctx;
53
0
}
54
55
static void ml_kem_freectx(void *vctx)
56
0
{
57
0
    PROV_ML_KEM_CTX *ctx = vctx;
58
59
0
    if (ctx->entropy != NULL)
60
0
        OPENSSL_cleanse(ctx->entropy, ML_KEM_RANDOM_BYTES);
61
0
    OPENSSL_free(ctx);
62
0
}
63
64
static int ml_kem_init(void *vctx, int op, void *key,
65
                       const OSSL_PARAM params[])
66
0
{
67
0
    PROV_ML_KEM_CTX *ctx = vctx;
68
69
0
    if (!ossl_prov_is_running())
70
0
        return 0;
71
0
    ctx->key = key;
72
0
    ctx->op = op;
73
0
    return ml_kem_set_ctx_params(vctx, params);
74
0
}
75
76
static int ml_kem_encapsulate_init(void *vctx, void *vkey,
77
                                   const OSSL_PARAM params[])
78
0
{
79
0
    ML_KEM_KEY *key = vkey;
80
81
0
    if (!ossl_ml_kem_have_pubkey(key)) {
82
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
83
0
        return 0;
84
0
    }
85
0
    return ml_kem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, key, params);
86
0
}
87
88
static int ml_kem_decapsulate_init(void *vctx, void *vkey,
89
                                   const OSSL_PARAM params[])
90
0
{
91
0
    ML_KEM_KEY *key = vkey;
92
93
0
    if (!ossl_ml_kem_have_prvkey(key)) {
94
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
95
0
        return 0;
96
0
    }
97
0
    return ml_kem_init(vctx, EVP_PKEY_OP_DECAPSULATE, key, params);
98
0
}
99
100
/* Machine generated by util/perl/OpenSSL/paramnames.pm */
101
#ifndef ml_kem_set_ctx_params_list
102
static const OSSL_PARAM ml_kem_set_ctx_params_list[] = {
103
    OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0),
104
    OSSL_PARAM_END
105
};
106
#endif
107
108
#ifndef ml_kem_set_ctx_params_st
109
struct ml_kem_set_ctx_params_st {
110
    OSSL_PARAM *ikme;
111
};
112
#endif
113
114
#ifndef ml_kem_set_ctx_params_decoder
115
static int ml_kem_set_ctx_params_decoder
116
    (const OSSL_PARAM *p, struct ml_kem_set_ctx_params_st *r)
117
0
{
118
0
    const char *s;
119
120
0
    memset(r, 0, sizeof(*r));
121
0
    if (p != NULL)
122
0
        for (; (s = p->key) != NULL; p++)
123
0
            if (ossl_likely(strcmp("ikme", s + 0) == 0)) {
124
                /* KEM_PARAM_IKME */
125
0
                if (ossl_unlikely(r->ikme != NULL)) {
126
0
                    ERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,
127
0
                                   "param %s is repeated", s);
128
0
                    return 0;
129
0
                }
130
0
                r->ikme = (OSSL_PARAM *)p;
131
0
            }
132
0
    return 1;
133
0
}
134
#endif
135
/* End of machine generated */
136
137
static int ml_kem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
138
0
{
139
0
    PROV_ML_KEM_CTX *ctx = vctx;
140
0
    struct ml_kem_set_ctx_params_st p;
141
142
0
    if (ctx == NULL || !ml_kem_set_ctx_params_decoder(params, &p))
143
0
        return 0;
144
145
0
    if (ctx->op == EVP_PKEY_OP_DECAPSULATE && ctx->entropy != NULL) {
146
        /* Decapsulation is deterministic */
147
0
        OPENSSL_cleanse(ctx->entropy, ML_KEM_RANDOM_BYTES);
148
0
        ctx->entropy = NULL;
149
0
    }
150
151
    /* Encapsulation ephemeral input key material "ikmE" */
152
0
    if (ctx->op == EVP_PKEY_OP_ENCAPSULATE && p.ikme != NULL) {
153
0
        size_t len = ML_KEM_RANDOM_BYTES;
154
155
0
        ctx->entropy = ctx->entropy_buf;
156
0
        if (OSSL_PARAM_get_octet_string(p.ikme, (void **)&ctx->entropy,
157
0
                                        len, &len)
158
0
            && len == ML_KEM_RANDOM_BYTES)
159
0
            return 1;
160
161
        /* Possibly, but much less likely wrong type */
162
0
        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH);
163
0
        ctx->entropy = NULL;
164
0
        return 0;
165
0
    }
166
167
0
    return 1;
168
0
}
169
170
static const OSSL_PARAM *ml_kem_settable_ctx_params(ossl_unused void *vctx,
171
                                                    ossl_unused void *provctx)
172
0
{
173
0
    return ml_kem_set_ctx_params_list;
174
0
}
175
176
static int ml_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen,
177
                              unsigned char *shsec, size_t *slen)
178
0
{
179
0
    PROV_ML_KEM_CTX *ctx = vctx;
180
0
    ML_KEM_KEY *key = ctx->key;
181
0
    const ML_KEM_VINFO *v;
182
0
    size_t encap_clen;
183
0
    size_t encap_slen;
184
0
    int ret = 0;
185
186
0
    if (!ossl_ml_kem_have_pubkey(key)) {
187
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
188
0
        goto end;
189
0
    }
190
0
    v = ossl_ml_kem_key_vinfo(key);
191
0
    encap_clen = v->ctext_bytes;
192
0
    encap_slen = ML_KEM_SHARED_SECRET_BYTES;
193
194
0
    if (ctext == NULL) {
195
0
        if (clen == NULL && slen == NULL)
196
0
            return 0;
197
0
        if (clen != NULL)
198
0
            *clen = encap_clen;
199
0
        if (slen != NULL)
200
0
            *slen = encap_slen;
201
0
        return 1;
202
0
    }
203
0
    if (shsec == NULL) {
204
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_OUTPUT_BUFFER,
205
0
                       "NULL shared-secret buffer");
206
0
        goto end;
207
0
    }
208
209
0
    if (clen == NULL) {
210
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_LENGTH_POINTER,
211
0
                       "null ciphertext input/output length pointer");
212
0
        goto end;
213
0
    } else if (*clen < encap_clen) {
214
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
215
0
                       "ciphertext buffer too small");
216
0
        goto end;
217
0
    } else {
218
0
        *clen = encap_clen;
219
0
    }
220
221
0
    if (slen == NULL) {
222
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_LENGTH_POINTER,
223
0
                       "null shared secret input/output length pointer");
224
0
        goto end;
225
0
    } else if (*slen < encap_slen) {
226
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
227
0
                       "shared-secret buffer too small");
228
0
        goto end;
229
0
    } else {
230
0
        *slen = encap_slen;
231
0
    }
232
233
0
    if (ctx->entropy != NULL)
234
0
        ret = ossl_ml_kem_encap_seed(ctext, encap_clen, shsec, encap_slen,
235
0
                                     ctx->entropy, ML_KEM_RANDOM_BYTES, key);
236
0
    else
237
0
        ret = ossl_ml_kem_encap_rand(ctext, encap_clen, shsec, encap_slen, key);
238
239
0
 end:
240
    /*
241
     * One shot entropy, each encapsulate call must either provide a new
242
     * "ikmE", or else will use a random value.  If a caller sets an explicit
243
     * ikmE once for testing, and later performs multiple encapsulations
244
     * without again calling encapsulate_init(), these should not share the
245
     * original entropy.
246
     */
247
0
    if (ctx->entropy != NULL) {
248
0
        OPENSSL_cleanse(ctx->entropy, ML_KEM_RANDOM_BYTES);
249
0
        ctx->entropy = NULL;
250
0
    }
251
0
    return ret;
252
0
}
253
254
static int ml_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen,
255
                              const uint8_t *ctext, size_t clen)
256
0
{
257
0
    PROV_ML_KEM_CTX *ctx = vctx;
258
0
    ML_KEM_KEY *key = ctx->key;
259
0
    size_t decap_slen = ML_KEM_SHARED_SECRET_BYTES;
260
261
0
    if (!ossl_ml_kem_have_prvkey(key)) {
262
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
263
0
        return 0;
264
0
    }
265
266
0
    if (shsec == NULL) {
267
0
        if (slen == NULL)
268
0
            return 0;
269
0
        *slen = ML_KEM_SHARED_SECRET_BYTES;
270
0
        return 1;
271
0
    }
272
273
    /* For now tolerate newly-deprecated NULL length pointers. */
274
0
    if (slen == NULL) {
275
0
        slen = &decap_slen;
276
0
    } else if (*slen < decap_slen) {
277
0
        ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
278
0
                       "shared-secret buffer too small");
279
0
        return 0;
280
0
    } else {
281
0
        *slen = decap_slen;
282
0
    }
283
284
    /* ML-KEM decap handles incorrect ciphertext lengths internally */
285
0
    return ossl_ml_kem_decap(shsec, decap_slen, ctext, clen, key);
286
0
}
287
288
const OSSL_DISPATCH ossl_ml_kem_asym_kem_functions[] = {
289
    { OSSL_FUNC_KEM_NEWCTX, (OSSL_FUNC) ml_kem_newctx },
290
    { OSSL_FUNC_KEM_ENCAPSULATE_INIT, (OSSL_FUNC) ml_kem_encapsulate_init },
291
    { OSSL_FUNC_KEM_ENCAPSULATE, (OSSL_FUNC) ml_kem_encapsulate },
292
    { OSSL_FUNC_KEM_DECAPSULATE_INIT, (OSSL_FUNC) ml_kem_decapsulate_init },
293
    { OSSL_FUNC_KEM_DECAPSULATE, (OSSL_FUNC) ml_kem_decapsulate },
294
    { OSSL_FUNC_KEM_FREECTX, (OSSL_FUNC) ml_kem_freectx },
295
    { OSSL_FUNC_KEM_SET_CTX_PARAMS, (OSSL_FUNC) ml_kem_set_ctx_params },
296
    { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, (OSSL_FUNC) ml_kem_settable_ctx_params },
297
    OSSL_DISPATCH_END
298
};