Coverage Report

Created: 2025-10-28 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/providers/implementations/kdfs/sshkdf.c
Line
Count
Source
1
/*
2
 * Copyright 2018-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 <stdlib.h>
11
#include <stdarg.h>
12
#include <string.h>
13
#include <openssl/evp.h>
14
#include <openssl/kdf.h>
15
#include <openssl/core_names.h>
16
#include <openssl/proverr.h>
17
#include "internal/cryptlib.h"
18
#include "internal/numbers.h"
19
#include "crypto/evp.h"
20
#include "prov/provider_ctx.h"
21
#include "prov/providercommon.h"
22
#include "prov/implementations.h"
23
#include "prov/provider_util.h"
24
#include "prov/securitycheck.h"
25
#include "providers/implementations/kdfs/sshkdf.inc"
26
27
/* See RFC 4253, Section 7.2 */
28
static OSSL_FUNC_kdf_newctx_fn kdf_sshkdf_new;
29
static OSSL_FUNC_kdf_dupctx_fn kdf_sshkdf_dup;
30
static OSSL_FUNC_kdf_freectx_fn kdf_sshkdf_free;
31
static OSSL_FUNC_kdf_reset_fn kdf_sshkdf_reset;
32
static OSSL_FUNC_kdf_derive_fn kdf_sshkdf_derive;
33
static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_sshkdf_settable_ctx_params;
34
static OSSL_FUNC_kdf_set_ctx_params_fn kdf_sshkdf_set_ctx_params;
35
static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_sshkdf_gettable_ctx_params;
36
static OSSL_FUNC_kdf_get_ctx_params_fn kdf_sshkdf_get_ctx_params;
37
38
static int SSHKDF(const EVP_MD *evp_md,
39
                  const unsigned char *key, size_t key_len,
40
                  const unsigned char *xcghash, size_t xcghash_len,
41
                  const unsigned char *session_id, size_t session_id_len,
42
                  char type, unsigned char *okey, size_t okey_len);
43
44
typedef struct {
45
    void *provctx;
46
    PROV_DIGEST digest;
47
    unsigned char *key; /* K */
48
    size_t key_len;
49
    unsigned char *xcghash; /* H */
50
    size_t xcghash_len;
51
    char type; /* X */
52
    unsigned char *session_id;
53
    size_t session_id_len;
54
    OSSL_FIPS_IND_DECLARE
55
} KDF_SSHKDF;
56
57
static void *kdf_sshkdf_new(void *provctx)
58
0
{
59
0
    KDF_SSHKDF *ctx;
60
61
0
    if (!ossl_prov_is_running())
62
0
        return NULL;
63
64
0
    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) {
65
0
        ctx->provctx = provctx;
66
0
        OSSL_FIPS_IND_INIT(ctx)
67
0
    }
68
0
    return ctx;
69
0
}
70
71
static void kdf_sshkdf_free(void *vctx)
72
0
{
73
0
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
74
75
0
    if (ctx != NULL) {
76
0
        kdf_sshkdf_reset(ctx);
77
0
        OPENSSL_free(ctx);
78
0
    }
79
0
}
80
81
static void kdf_sshkdf_reset(void *vctx)
82
0
{
83
0
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
84
0
    void *provctx = ctx->provctx;
85
86
0
    ossl_prov_digest_reset(&ctx->digest);
87
0
    OPENSSL_clear_free(ctx->key, ctx->key_len);
88
0
    OPENSSL_clear_free(ctx->xcghash, ctx->xcghash_len);
89
0
    OPENSSL_clear_free(ctx->session_id, ctx->session_id_len);
90
0
    memset(ctx, 0, sizeof(*ctx));
91
0
    ctx->provctx = provctx;
92
0
}
93
94
static void *kdf_sshkdf_dup(void *vctx)
95
0
{
96
0
    const KDF_SSHKDF *src = (const KDF_SSHKDF *)vctx;
97
0
    KDF_SSHKDF *dest;
98
99
0
    dest = kdf_sshkdf_new(src->provctx);
100
0
    if (dest != NULL) {
101
0
        if (!ossl_prov_memdup(src->key, src->key_len,
102
0
                              &dest->key, &dest->key_len)
103
0
                || !ossl_prov_memdup(src->xcghash, src->xcghash_len,
104
0
                                     &dest->xcghash , &dest->xcghash_len)
105
0
                || !ossl_prov_memdup(src->session_id, src->session_id_len,
106
0
                                     &dest->session_id , &dest->session_id_len)
107
0
                || !ossl_prov_digest_copy(&dest->digest, &src->digest))
108
0
            goto err;
109
0
        dest->type = src->type;
110
0
        OSSL_FIPS_IND_COPY(dest, src)
111
0
    }
112
0
    return dest;
113
114
0
 err:
115
0
    kdf_sshkdf_free(dest);
116
0
    return NULL;
117
0
}
118
119
static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len,
120
                             const OSSL_PARAM *p)
121
0
{
122
0
    OPENSSL_clear_free(*dst, *dst_len);
123
0
    *dst = NULL;
124
0
    *dst_len = 0;
125
0
    return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
126
0
}
127
128
#ifdef FIPS_MODULE
129
static int fips_digest_check_passed(KDF_SSHKDF *ctx, const EVP_MD *md)
130
{
131
    OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
132
    /*
133
     * Perform digest check
134
     *
135
     * According to NIST SP 800-135r1 section 5.2, the valid hash functions are
136
     * specified in FIPS 180-3. ACVP also only lists the same set of hash
137
     * functions.
138
     */
139
    int digest_unapproved = !EVP_MD_is_a(md, SN_sha1)
140
        && !EVP_MD_is_a(md, SN_sha224)
141
        && !EVP_MD_is_a(md, SN_sha256)
142
        && !EVP_MD_is_a(md, SN_sha384)
143
        && !EVP_MD_is_a(md, SN_sha512);
144
145
    if (digest_unapproved) {
146
        if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0,
147
                                         libctx, "SSHKDF", "Digest",
148
                                         ossl_fips_config_sshkdf_digest_check)) {
149
            ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
150
            return 0;
151
        }
152
    }
153
    return 1;
154
}
155
156
static int fips_key_check_passed(KDF_SSHKDF *ctx)
157
{
158
    OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
159
    int key_approved = ossl_kdf_check_key_size(ctx->key_len);
160
161
    if (!key_approved) {
162
        if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE1,
163
                                         libctx, "SSHKDF", "Key size",
164
                                         ossl_fips_config_sshkdf_key_check)) {
165
            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
166
            return 0;
167
        }
168
    }
169
    return 1;
170
}
171
#endif
172
173
static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen,
174
                             const OSSL_PARAM params[])
175
0
{
176
0
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
177
0
    const EVP_MD *md;
178
179
0
    if (!ossl_prov_is_running() || !kdf_sshkdf_set_ctx_params(ctx, params))
180
0
        return 0;
181
182
0
    md = ossl_prov_digest_md(&ctx->digest);
183
0
    if (md == NULL) {
184
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
185
0
        return 0;
186
0
    }
187
0
    if (ctx->key == NULL) {
188
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
189
0
        return 0;
190
0
    }
191
0
    if (ctx->xcghash == NULL) {
192
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_XCGHASH);
193
0
        return 0;
194
0
    }
195
0
    if (ctx->session_id == NULL) {
196
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID);
197
0
        return 0;
198
0
    }
199
0
    if (ctx->type == 0) {
200
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE);
201
0
        return 0;
202
0
    }
203
204
0
    return SSHKDF(md, ctx->key, ctx->key_len,
205
0
                  ctx->xcghash, ctx->xcghash_len,
206
0
                  ctx->session_id, ctx->session_id_len,
207
0
                  ctx->type, key, keylen);
208
0
}
209
210
static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
211
0
{
212
0
    struct sshkdf_set_ctx_params_st p;
213
0
    KDF_SSHKDF *ctx = vctx;
214
0
    OSSL_LIB_CTX *provctx;
215
216
0
    if (ctx == NULL || !sshkdf_set_ctx_params_decoder(params, &p))
217
0
        return 0;
218
219
0
    provctx = PROV_LIBCTX_OF(ctx->provctx);
220
221
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, p.ind_d))
222
0
        return 0;
223
0
    if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(ctx, OSSL_FIPS_IND_SETTABLE1, p.ind_k))
224
0
        return 0;
225
226
0
    if (p.digest != NULL) {
227
0
        const EVP_MD *md = NULL;
228
229
0
        if (!ossl_prov_digest_load(&ctx->digest, p.digest,
230
0
                                   p.propq, p.engine, provctx))
231
0
            return 0;
232
233
0
        md = ossl_prov_digest_md(&ctx->digest);
234
0
        if (EVP_MD_xof(md)) {
235
0
            ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
236
0
            return 0;
237
0
        }
238
239
#ifdef FIPS_MODULE
240
        if (!fips_digest_check_passed(ctx, md))
241
            return 0;
242
#endif
243
0
    }
244
245
0
    if (p.key != NULL) {
246
0
        if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p.key))
247
0
            return 0;
248
249
#ifdef FIPS_MODULE
250
        if (!fips_key_check_passed(ctx))
251
            return 0;
252
#endif
253
0
    }
254
255
0
    if (p.xcg != NULL
256
0
            && !sshkdf_set_membuf(&ctx->xcghash, &ctx->xcghash_len, p.xcg))
257
0
        return 0;
258
259
0
    if (p.sid != NULL
260
0
            && !sshkdf_set_membuf(&ctx->session_id, &ctx->session_id_len, p.sid))
261
0
        return 0;
262
263
0
    if (p.type != NULL) {
264
0
        const char *kdftype;
265
266
0
        if (!OSSL_PARAM_get_utf8_string_ptr(p.type, &kdftype))
267
0
            return 0;
268
        /* Expect one character (byte in this case) */
269
0
        if (kdftype == NULL || p.type->data_size != 1)
270
0
            return 0;
271
0
        if (kdftype[0] < 65 || kdftype[0] > 70) {
272
0
            ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR);
273
0
            return 0;
274
0
        }
275
0
        ctx->type = kdftype[0];
276
0
    }
277
0
    return 1;
278
0
}
279
280
static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx,
281
                                                        ossl_unused void *p_ctx)
282
0
{
283
0
    return sshkdf_set_ctx_params_list;
284
0
}
285
286
static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
287
0
{
288
0
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
289
0
    struct sshkdf_get_ctx_params_st p;
290
291
0
    if (ctx == NULL || !sshkdf_get_ctx_params_decoder(params, &p))
292
0
        return 0;
293
294
0
    if (p.size != NULL && !OSSL_PARAM_set_size_t(p.size, SIZE_MAX))
295
0
        return 0;
296
297
0
    if (!OSSL_FIPS_IND_GET_CTX_FROM_PARAM(ctx, p.ind))
298
0
        return 0;
299
0
    return 1;
300
0
}
301
302
static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx,
303
                                                        ossl_unused void *p_ctx)
304
0
{
305
0
    return sshkdf_get_ctx_params_list;
306
0
}
307
308
const OSSL_DISPATCH ossl_kdf_sshkdf_functions[] = {
309
    { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_sshkdf_new },
310
    { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_sshkdf_dup },
311
    { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_sshkdf_free },
312
    { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_sshkdf_reset },
313
    { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_sshkdf_derive },
314
    { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
315
      (void(*)(void))kdf_sshkdf_settable_ctx_params },
316
    { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_set_ctx_params },
317
    { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
318
      (void(*)(void))kdf_sshkdf_gettable_ctx_params },
319
    { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_get_ctx_params },
320
    OSSL_DISPATCH_END
321
};
322
323
static int SSHKDF(const EVP_MD *evp_md,
324
                  const unsigned char *key, size_t key_len,
325
                  const unsigned char *xcghash, size_t xcghash_len,
326
                  const unsigned char *session_id, size_t session_id_len,
327
                  char type, unsigned char *okey, size_t okey_len)
328
0
{
329
0
    EVP_MD_CTX *md = NULL;
330
0
    unsigned char digest[EVP_MAX_MD_SIZE];
331
0
    unsigned int dsize = 0;
332
0
    size_t cursize = 0;
333
0
    int ret = 0;
334
335
0
    md = EVP_MD_CTX_new();
336
0
    if (md == NULL)
337
0
        return 0;
338
339
0
    if (!EVP_DigestInit_ex(md, evp_md, NULL))
340
0
        goto out;
341
342
0
    if (!EVP_DigestUpdate(md, key, key_len))
343
0
        goto out;
344
345
0
    if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
346
0
        goto out;
347
348
0
    if (!EVP_DigestUpdate(md, &type, 1))
349
0
        goto out;
350
351
0
    if (!EVP_DigestUpdate(md, session_id, session_id_len))
352
0
        goto out;
353
354
0
    if (!EVP_DigestFinal_ex(md, digest, &dsize))
355
0
        goto out;
356
357
0
    if (okey_len < dsize) {
358
0
        memcpy(okey, digest, okey_len);
359
0
        ret = 1;
360
0
        goto out;
361
0
    }
362
363
0
    memcpy(okey, digest, dsize);
364
365
0
    for (cursize = dsize; cursize < okey_len; cursize += dsize) {
366
367
0
        if (!EVP_DigestInit_ex(md, evp_md, NULL))
368
0
            goto out;
369
370
0
        if (!EVP_DigestUpdate(md, key, key_len))
371
0
            goto out;
372
373
0
        if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
374
0
            goto out;
375
376
0
        if (!EVP_DigestUpdate(md, okey, cursize))
377
0
            goto out;
378
379
0
        if (!EVP_DigestFinal_ex(md, digest, &dsize))
380
0
            goto out;
381
382
0
        if (okey_len < cursize + dsize) {
383
0
            memcpy(okey + cursize, digest, okey_len - cursize);
384
0
            ret = 1;
385
0
            goto out;
386
0
        }
387
388
0
        memcpy(okey + cursize, digest, dsize);
389
0
    }
390
391
0
    ret = 1;
392
393
0
out:
394
0
    EVP_MD_CTX_free(md);
395
0
    OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE);
396
0
    return ret;
397
0
}