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