Coverage Report

Created: 2025-06-13 06:55

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