Coverage Report

Created: 2025-06-13 06:58

/src/openssl31/providers/implementations/kdfs/sshkdf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2018-2022 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
25
/* See RFC 4253, Section 7.2 */
26
static OSSL_FUNC_kdf_newctx_fn kdf_sshkdf_new;
27
static OSSL_FUNC_kdf_dupctx_fn kdf_sshkdf_dup;
28
static OSSL_FUNC_kdf_freectx_fn kdf_sshkdf_free;
29
static OSSL_FUNC_kdf_reset_fn kdf_sshkdf_reset;
30
static OSSL_FUNC_kdf_derive_fn kdf_sshkdf_derive;
31
static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_sshkdf_settable_ctx_params;
32
static OSSL_FUNC_kdf_set_ctx_params_fn kdf_sshkdf_set_ctx_params;
33
static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_sshkdf_gettable_ctx_params;
34
static OSSL_FUNC_kdf_get_ctx_params_fn kdf_sshkdf_get_ctx_params;
35
36
static int SSHKDF(const EVP_MD *evp_md,
37
                  const unsigned char *key, size_t key_len,
38
                  const unsigned char *xcghash, size_t xcghash_len,
39
                  const unsigned char *session_id, size_t session_id_len,
40
                  char type, unsigned char *okey, size_t okey_len);
41
42
typedef struct {
43
    void *provctx;
44
    PROV_DIGEST digest;
45
    unsigned char *key; /* K */
46
    size_t key_len;
47
    unsigned char *xcghash; /* H */
48
    size_t xcghash_len;
49
    char type; /* X */
50
    unsigned char *session_id;
51
    size_t session_id_len;
52
} KDF_SSHKDF;
53
54
static void *kdf_sshkdf_new(void *provctx)
55
0
{
56
0
    KDF_SSHKDF *ctx;
57
58
0
    if (!ossl_prov_is_running())
59
0
        return NULL;
60
61
0
    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
62
0
        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
63
0
    else
64
0
        ctx->provctx = provctx;
65
0
    return ctx;
66
0
}
67
68
static void kdf_sshkdf_free(void *vctx)
69
25
{
70
25
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
71
72
25
    if (ctx != NULL) {
73
25
        kdf_sshkdf_reset(ctx);
74
25
        OPENSSL_free(ctx);
75
25
    }
76
25
}
77
78
static void kdf_sshkdf_reset(void *vctx)
79
25
{
80
25
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
81
25
    void *provctx = ctx->provctx;
82
83
25
    ossl_prov_digest_reset(&ctx->digest);
84
25
    OPENSSL_clear_free(ctx->key, ctx->key_len);
85
25
    OPENSSL_clear_free(ctx->xcghash, ctx->xcghash_len);
86
25
    OPENSSL_clear_free(ctx->session_id, ctx->session_id_len);
87
25
    memset(ctx, 0, sizeof(*ctx));
88
25
    ctx->provctx = provctx;
89
25
}
90
91
static void *kdf_sshkdf_dup(void *vctx)
92
0
{
93
0
    const KDF_SSHKDF *src = (const KDF_SSHKDF *)vctx;
94
0
    KDF_SSHKDF *dest;
95
96
0
    dest = kdf_sshkdf_new(src->provctx);
97
0
    if (dest != NULL) {
98
0
        if (!ossl_prov_memdup(src->key, src->key_len,
99
0
                              &dest->key, &dest->key_len)
100
0
                || !ossl_prov_memdup(src->xcghash, src->xcghash_len,
101
0
                                     &dest->xcghash , &dest->xcghash_len)
102
0
                || !ossl_prov_memdup(src->session_id, src->session_id_len,
103
0
                                     &dest->session_id , &dest->session_id_len)
104
0
                || !ossl_prov_digest_copy(&dest->digest, &src->digest))
105
0
            goto err;
106
0
        dest->type = src->type;
107
0
    }
108
0
    return dest;
109
110
0
 err:
111
0
    kdf_sshkdf_free(dest);
112
0
    return NULL;
113
0
}
114
115
static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len,
116
                             const OSSL_PARAM *p)
117
60
{
118
60
    OPENSSL_clear_free(*dst, *dst_len);
119
60
    *dst = NULL;
120
60
    *dst_len = 0;
121
60
    return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
122
60
}
123
124
static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen,
125
                             const OSSL_PARAM params[])
126
0
{
127
0
    KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
128
0
    const EVP_MD *md;
129
130
0
    if (!ossl_prov_is_running() || !kdf_sshkdf_set_ctx_params(ctx, params))
131
0
        return 0;
132
133
0
    md = ossl_prov_digest_md(&ctx->digest);
134
0
    if (md == NULL) {
135
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
136
0
        return 0;
137
0
    }
138
0
    if (ctx->key == NULL) {
139
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
140
0
        return 0;
141
0
    }
142
0
    if (ctx->xcghash == NULL) {
143
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_XCGHASH);
144
0
        return 0;
145
0
    }
146
0
    if (ctx->session_id == NULL) {
147
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID);
148
0
        return 0;
149
0
    }
150
0
    if (ctx->type == 0) {
151
0
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE);
152
0
        return 0;
153
0
    }
154
0
    return SSHKDF(md, ctx->key, ctx->key_len,
155
0
                  ctx->xcghash, ctx->xcghash_len,
156
0
                  ctx->session_id, ctx->session_id_len,
157
0
                  ctx->type, key, keylen);
158
0
}
159
160
static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
161
0
{
162
0
    const OSSL_PARAM *p;
163
0
    KDF_SSHKDF *ctx = vctx;
164
0
    OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx);
165
166
0
    if (params == NULL)
167
0
        return 1;
168
169
0
    if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
170
0
        return 0;
171
172
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
173
0
        if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p))
174
0
            return 0;
175
176
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_XCGHASH))
177
0
        != NULL)
178
0
        if (!sshkdf_set_membuf(&ctx->xcghash, &ctx->xcghash_len, p))
179
0
            return 0;
180
181
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_SESSION_ID))
182
0
        != NULL)
183
0
        if (!sshkdf_set_membuf(&ctx->session_id, &ctx->session_id_len, p))
184
0
            return 0;
185
186
0
    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_TYPE))
187
0
        != NULL) {
188
0
        const char *kdftype;
189
190
0
        if (!OSSL_PARAM_get_utf8_string_ptr(p, &kdftype))
191
0
            return 0;
192
        /* Expect one character (byte in this case) */
193
0
        if (kdftype == NULL || p->data_size != 1)
194
0
            return 0;
195
0
        if (kdftype[0] < 65 || kdftype[0] > 70) {
196
0
            ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR);
197
0
            return 0;
198
0
        }
199
0
        ctx->type = kdftype[0];
200
0
    }
201
0
    return 1;
202
0
}
203
204
static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx,
205
                                                        ossl_unused void *p_ctx)
206
25
{
207
25
    static const OSSL_PARAM known_settable_ctx_params[] = {
208
25
        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
209
25
        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
210
25
        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
211
25
        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_XCGHASH, NULL, 0),
212
25
        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_SESSION_ID, NULL, 0),
213
25
        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_SSHKDF_TYPE, NULL, 0),
214
25
        OSSL_PARAM_END
215
25
    };
216
25
    return known_settable_ctx_params;
217
25
}
218
219
static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
220
0
{
221
0
    OSSL_PARAM *p;
222
223
0
    if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
224
0
        return OSSL_PARAM_set_size_t(p, SIZE_MAX);
225
0
    return -2;
226
0
}
227
228
static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx,
229
                                                        ossl_unused void *p_ctx)
230
0
{
231
0
    static const OSSL_PARAM known_gettable_ctx_params[] = {
232
0
        OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
233
0
        OSSL_PARAM_END
234
0
    };
235
0
    return known_gettable_ctx_params;
236
0
}
237
238
const OSSL_DISPATCH ossl_kdf_sshkdf_functions[] = {
239
    { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_sshkdf_new },
240
    { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_sshkdf_dup },
241
    { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_sshkdf_free },
242
    { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_sshkdf_reset },
243
    { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_sshkdf_derive },
244
    { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
245
      (void(*)(void))kdf_sshkdf_settable_ctx_params },
246
    { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_set_ctx_params },
247
    { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
248
      (void(*)(void))kdf_sshkdf_gettable_ctx_params },
249
    { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_sshkdf_get_ctx_params },
250
    { 0, NULL }
251
};
252
253
static int SSHKDF(const EVP_MD *evp_md,
254
                  const unsigned char *key, size_t key_len,
255
                  const unsigned char *xcghash, size_t xcghash_len,
256
                  const unsigned char *session_id, size_t session_id_len,
257
                  char type, unsigned char *okey, size_t okey_len)
258
0
{
259
0
    EVP_MD_CTX *md = NULL;
260
0
    unsigned char digest[EVP_MAX_MD_SIZE];
261
0
    unsigned int dsize = 0;
262
0
    size_t cursize = 0;
263
0
    int ret = 0;
264
265
0
    md = EVP_MD_CTX_new();
266
0
    if (md == NULL)
267
0
        return 0;
268
269
0
    if (!EVP_DigestInit_ex(md, evp_md, NULL))
270
0
        goto out;
271
272
0
    if (!EVP_DigestUpdate(md, key, key_len))
273
0
        goto out;
274
275
0
    if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
276
0
        goto out;
277
278
0
    if (!EVP_DigestUpdate(md, &type, 1))
279
0
        goto out;
280
281
0
    if (!EVP_DigestUpdate(md, session_id, session_id_len))
282
0
        goto out;
283
284
0
    if (!EVP_DigestFinal_ex(md, digest, &dsize))
285
0
        goto out;
286
287
0
    if (okey_len < dsize) {
288
0
        memcpy(okey, digest, okey_len);
289
0
        ret = 1;
290
0
        goto out;
291
0
    }
292
293
0
    memcpy(okey, digest, dsize);
294
295
0
    for (cursize = dsize; cursize < okey_len; cursize += dsize) {
296
297
0
        if (!EVP_DigestInit_ex(md, evp_md, NULL))
298
0
            goto out;
299
300
0
        if (!EVP_DigestUpdate(md, key, key_len))
301
0
            goto out;
302
303
0
        if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
304
0
            goto out;
305
306
0
        if (!EVP_DigestUpdate(md, okey, cursize))
307
0
            goto out;
308
309
0
        if (!EVP_DigestFinal_ex(md, digest, &dsize))
310
0
            goto out;
311
312
0
        if (okey_len < cursize + dsize) {
313
0
            memcpy(okey + cursize, digest, okey_len - cursize);
314
0
            ret = 1;
315
0
            goto out;
316
0
        }
317
318
0
        memcpy(okey + cursize, digest, dsize);
319
0
    }
320
321
0
    ret = 1;
322
323
0
out:
324
0
    EVP_MD_CTX_free(md);
325
0
    OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE);
326
0
    return ret;
327
0
}
328