Coverage Report

Created: 2025-06-13 06:58

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