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
kdf_sshkdf_new(void * provctx)56 static void *kdf_sshkdf_new(void *provctx)
57 {
58 KDF_SSHKDF *ctx;
59
60 if (!ossl_prov_is_running())
61 return NULL;
62
63 if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) {
64 ctx->provctx = provctx;
65 OSSL_FIPS_IND_INIT(ctx)
66 }
67 return ctx;
68 }
69
kdf_sshkdf_free(void * vctx)70 static void kdf_sshkdf_free(void *vctx)
71 {
72 KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
73
74 if (ctx != NULL) {
75 kdf_sshkdf_reset(ctx);
76 OPENSSL_free(ctx);
77 }
78 }
79
kdf_sshkdf_reset(void * vctx)80 static void kdf_sshkdf_reset(void *vctx)
81 {
82 KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
83 void *provctx = ctx->provctx;
84
85 ossl_prov_digest_reset(&ctx->digest);
86 OPENSSL_clear_free(ctx->key, ctx->key_len);
87 OPENSSL_clear_free(ctx->xcghash, ctx->xcghash_len);
88 OPENSSL_clear_free(ctx->session_id, ctx->session_id_len);
89 memset(ctx, 0, sizeof(*ctx));
90 ctx->provctx = provctx;
91 }
92
kdf_sshkdf_dup(void * vctx)93 static void *kdf_sshkdf_dup(void *vctx)
94 {
95 const KDF_SSHKDF *src = (const KDF_SSHKDF *)vctx;
96 KDF_SSHKDF *dest;
97
98 dest = kdf_sshkdf_new(src->provctx);
99 if (dest != NULL) {
100 if (!ossl_prov_memdup(src->key, src->key_len,
101 &dest->key, &dest->key_len)
102 || !ossl_prov_memdup(src->xcghash, src->xcghash_len,
103 &dest->xcghash , &dest->xcghash_len)
104 || !ossl_prov_memdup(src->session_id, src->session_id_len,
105 &dest->session_id , &dest->session_id_len)
106 || !ossl_prov_digest_copy(&dest->digest, &src->digest))
107 goto err;
108 dest->type = src->type;
109 OSSL_FIPS_IND_COPY(dest, src)
110 }
111 return dest;
112
113 err:
114 kdf_sshkdf_free(dest);
115 return NULL;
116 }
117
sshkdf_set_membuf(unsigned char ** dst,size_t * dst_len,const OSSL_PARAM * p)118 static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len,
119 const OSSL_PARAM *p)
120 {
121 OPENSSL_clear_free(*dst, *dst_len);
122 *dst = NULL;
123 *dst_len = 0;
124 return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
125 }
126
127 #ifdef FIPS_MODULE
fips_digest_check_passed(KDF_SSHKDF * ctx,const EVP_MD * md)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
fips_key_check_passed(KDF_SSHKDF * ctx)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
kdf_sshkdf_derive(void * vctx,unsigned char * key,size_t keylen,const OSSL_PARAM params[])172 static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen,
173 const OSSL_PARAM params[])
174 {
175 KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
176 const EVP_MD *md;
177
178 if (!ossl_prov_is_running() || !kdf_sshkdf_set_ctx_params(ctx, params))
179 return 0;
180
181 md = ossl_prov_digest_md(&ctx->digest);
182 if (md == NULL) {
183 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
184 return 0;
185 }
186 if (ctx->key == NULL) {
187 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
188 return 0;
189 }
190 if (ctx->xcghash == NULL) {
191 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_XCGHASH);
192 return 0;
193 }
194 if (ctx->session_id == NULL) {
195 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID);
196 return 0;
197 }
198 if (ctx->type == 0) {
199 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE);
200 return 0;
201 }
202
203 return SSHKDF(md, ctx->key, ctx->key_len,
204 ctx->xcghash, ctx->xcghash_len,
205 ctx->session_id, ctx->session_id_len,
206 ctx->type, key, keylen);
207 }
208
kdf_sshkdf_set_ctx_params(void * vctx,const OSSL_PARAM params[])209 static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
210 {
211 const OSSL_PARAM *p;
212 KDF_SSHKDF *ctx = vctx;
213 OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx);
214
215 if (ossl_param_is_empty(params))
216 return 1;
217
218 if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params,
219 OSSL_KDF_PARAM_FIPS_DIGEST_CHECK))
220 return 0;
221 if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE1, params,
222 OSSL_KDF_PARAM_FIPS_KEY_CHECK))
223 return 0;
224
225 if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) {
226 const EVP_MD *md = NULL;
227
228 if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
229 return 0;
230
231 md = ossl_prov_digest_md(&ctx->digest);
232 if (EVP_MD_xof(md)) {
233 ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
234 return 0;
235 }
236
237 #ifdef FIPS_MODULE
238 if (!fips_digest_check_passed(ctx, md))
239 return 0;
240 #endif
241 }
242
243 if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) {
244 if (!sshkdf_set_membuf(&ctx->key, &ctx->key_len, p))
245 return 0;
246
247 #ifdef FIPS_MODULE
248 if (!fips_key_check_passed(ctx))
249 return 0;
250 #endif
251 }
252
253 if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_XCGHASH))
254 != NULL)
255 if (!sshkdf_set_membuf(&ctx->xcghash, &ctx->xcghash_len, p))
256 return 0;
257
258 if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_SESSION_ID))
259 != NULL)
260 if (!sshkdf_set_membuf(&ctx->session_id, &ctx->session_id_len, p))
261 return 0;
262
263 if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SSHKDF_TYPE))
264 != NULL) {
265 const char *kdftype;
266
267 if (!OSSL_PARAM_get_utf8_string_ptr(p, &kdftype))
268 return 0;
269 /* Expect one character (byte in this case) */
270 if (kdftype == NULL || p->data_size != 1)
271 return 0;
272 if (kdftype[0] < 65 || kdftype[0] > 70) {
273 ERR_raise(ERR_LIB_PROV, PROV_R_VALUE_ERROR);
274 return 0;
275 }
276 ctx->type = kdftype[0];
277 }
278 return 1;
279 }
280
kdf_sshkdf_settable_ctx_params(ossl_unused void * ctx,ossl_unused void * p_ctx)281 static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx,
282 ossl_unused void *p_ctx)
283 {
284 static const OSSL_PARAM known_settable_ctx_params[] = {
285 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
286 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
287 OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
288 OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_XCGHASH, NULL, 0),
289 OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_SESSION_ID, NULL, 0),
290 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_SSHKDF_TYPE, NULL, 0),
291 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)
292 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_KEY_CHECK)
293 OSSL_PARAM_END
294 };
295 return known_settable_ctx_params;
296 }
297
kdf_sshkdf_get_ctx_params(void * vctx,OSSL_PARAM params[])298 static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
299 {
300 OSSL_PARAM *p;
301
302 if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
303 if (!OSSL_PARAM_set_size_t(p, SIZE_MAX))
304 return 0;
305 }
306 if (!OSSL_FIPS_IND_GET_CTX_PARAM(((KDF_SSHKDF *)vctx), params))
307 return 0;
308 return 1;
309 }
310
kdf_sshkdf_gettable_ctx_params(ossl_unused void * ctx,ossl_unused void * p_ctx)311 static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx,
312 ossl_unused void *p_ctx)
313 {
314 static const OSSL_PARAM known_gettable_ctx_params[] = {
315 OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
316 OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
317 OSSL_PARAM_END
318 };
319 return known_gettable_ctx_params;
320 }
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
SSHKDF(const EVP_MD * evp_md,const unsigned char * key,size_t key_len,const unsigned char * xcghash,size_t xcghash_len,const unsigned char * session_id,size_t session_id_len,char type,unsigned char * okey,size_t okey_len)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 {
343 EVP_MD_CTX *md = NULL;
344 unsigned char digest[EVP_MAX_MD_SIZE];
345 unsigned int dsize = 0;
346 size_t cursize = 0;
347 int ret = 0;
348
349 md = EVP_MD_CTX_new();
350 if (md == NULL)
351 return 0;
352
353 if (!EVP_DigestInit_ex(md, evp_md, NULL))
354 goto out;
355
356 if (!EVP_DigestUpdate(md, key, key_len))
357 goto out;
358
359 if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
360 goto out;
361
362 if (!EVP_DigestUpdate(md, &type, 1))
363 goto out;
364
365 if (!EVP_DigestUpdate(md, session_id, session_id_len))
366 goto out;
367
368 if (!EVP_DigestFinal_ex(md, digest, &dsize))
369 goto out;
370
371 if (okey_len < dsize) {
372 memcpy(okey, digest, okey_len);
373 ret = 1;
374 goto out;
375 }
376
377 memcpy(okey, digest, dsize);
378
379 for (cursize = dsize; cursize < okey_len; cursize += dsize) {
380
381 if (!EVP_DigestInit_ex(md, evp_md, NULL))
382 goto out;
383
384 if (!EVP_DigestUpdate(md, key, key_len))
385 goto out;
386
387 if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
388 goto out;
389
390 if (!EVP_DigestUpdate(md, okey, cursize))
391 goto out;
392
393 if (!EVP_DigestFinal_ex(md, digest, &dsize))
394 goto out;
395
396 if (okey_len < cursize + dsize) {
397 memcpy(okey + cursize, digest, okey_len - cursize);
398 ret = 1;
399 goto out;
400 }
401
402 memcpy(okey + cursize, digest, dsize);
403 }
404
405 ret = 1;
406
407 out:
408 EVP_MD_CTX_free(md);
409 OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE);
410 return ret;
411 }
412