| 1 | /* |
| 2 | * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. |
| 3 | * Copyright 2019 Red Hat, Inc. |
| 4 | * |
| 5 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
| 6 | * this file except in compliance with the License. You can obtain a copy |
| 7 | * in the file LICENSE in the source distribution or at |
| 8 | * https://www.openssl.org/source/license.html |
| 9 | */ |
| 10 | |
| 11 | /* |
| 12 | * This implements https://csrc.nist.gov/publications/detail/sp/800-108/final |
| 13 | * section 5.1 ("counter mode") and section 5.2 ("feedback mode") in both HMAC |
| 14 | * and CMAC. That document does not name the KDFs it defines; the name is |
| 15 | * derived from |
| 16 | * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Key-Derivation |
| 17 | * |
| 18 | * Note that section 5.3 ("double-pipeline mode") is not implemented, though |
| 19 | * it would be possible to do so in the future. |
| 20 | * |
| 21 | * These versions all assume the counter is used. It would be relatively |
| 22 | * straightforward to expose a configuration handle should the need arise. |
| 23 | * |
| 24 | * Variable names attempt to match those of SP800-108. |
| 25 | */ |
| 26 | |
| 27 | #include <stdarg.h> |
| 28 | #include <stdlib.h> |
| 29 | #include <string.h> |
| 30 | |
| 31 | #include <openssl/core_names.h> |
| 32 | #include <openssl/evp.h> |
| 33 | #include <openssl/hmac.h> |
| 34 | #include <openssl/kdf.h> |
| 35 | #include <openssl/params.h> |
| 36 | |
| 37 | #include "internal/cryptlib.h" |
| 38 | #include "crypto/evp.h" |
| 39 | #include "internal/numbers.h" |
| 40 | #include "prov/implementations.h" |
| 41 | #include "prov/provider_ctx.h" |
| 42 | #include "prov/provider_util.h" |
| 43 | #include "prov/providercommonerr.h" |
| 44 | |
| 45 | #include "e_os.h" |
| 46 | |
| 47 | #define MIN(a, b) ((a) < (b)) ? (a) : (b) |
| 48 | |
| 49 | typedef enum { |
| 50 | COUNTER = 0, |
| 51 | FEEDBACK |
| 52 | } kbkdf_mode; |
| 53 | |
| 54 | /* Our context structure. */ |
| 55 | typedef struct { |
| 56 | void *provctx; |
| 57 | kbkdf_mode mode; |
| 58 | EVP_MAC_CTX *ctx_init; |
| 59 | |
| 60 | /* Names are lowercased versions of those found in SP800-108. */ |
| 61 | unsigned char *ki; |
| 62 | size_t ki_len; |
| 63 | unsigned char *label; |
| 64 | size_t label_len; |
| 65 | unsigned char *context; |
| 66 | size_t context_len; |
| 67 | unsigned char *iv; |
| 68 | size_t iv_len; |
| 69 | } KBKDF; |
| 70 | |
| 71 | /* Definitions needed for typechecking. */ |
| 72 | static OSSL_OP_kdf_newctx_fn kbkdf_new; |
| 73 | static OSSL_OP_kdf_freectx_fn kbkdf_free; |
| 74 | static OSSL_OP_kdf_reset_fn kbkdf_reset; |
| 75 | static OSSL_OP_kdf_derive_fn kbkdf_derive; |
| 76 | static OSSL_OP_kdf_settable_ctx_params_fn kbkdf_settable_ctx_params; |
| 77 | static OSSL_OP_kdf_set_ctx_params_fn kbkdf_set_ctx_params; |
| 78 | |
| 79 | /* Not all platforms have htobe32(). */ |
| 80 | static uint32_t be32(uint32_t host) |
| 81 | { |
| 82 | uint32_t big = 0; |
| 83 | const union { |
| 84 | long one; |
| 85 | char little; |
| 86 | } is_endian = { 1 }; |
| 87 | |
| 88 | if (!is_endian.little) |
| 89 | return host; |
| 90 | |
| 91 | big |= (host & 0xff000000) >> 24; |
| 92 | big |= (host & 0x00ff0000) >> 8; |
| 93 | big |= (host & 0x0000ff00) << 8; |
| 94 | big |= (host & 0x000000ff) << 24; |
| 95 | return big; |
| 96 | } |
| 97 | |
| 98 | static void *kbkdf_new(void *provctx) |
| 99 | { |
| 100 | KBKDF *ctx; |
| 101 | |
| 102 | ctx = OPENSSL_zalloc(sizeof(*ctx)); |
| 103 | if (ctx == NULL) { |
| 104 | ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); |
| 105 | return NULL; |
| 106 | } |
| 107 | |
| 108 | ctx->provctx = provctx; |
| 109 | return ctx; |
| 110 | } |
| 111 | |
| 112 | static void kbkdf_free(void *vctx) |
| 113 | { |
| 114 | KBKDF *ctx = (KBKDF *)vctx; |
| 115 | |
| 116 | if (ctx != NULL) { |
| 117 | kbkdf_reset(ctx); |
| 118 | OPENSSL_free(ctx); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | static void kbkdf_reset(void *vctx) |
| 123 | { |
| 124 | KBKDF *ctx = (KBKDF *)vctx; |
| 125 | |
| 126 | EVP_MAC_CTX_free(ctx->ctx_init); |
| 127 | OPENSSL_clear_free(ctx->context, ctx->context_len); |
| 128 | OPENSSL_clear_free(ctx->label, ctx->label_len); |
| 129 | OPENSSL_clear_free(ctx->ki, ctx->ki_len); |
| 130 | OPENSSL_clear_free(ctx->iv, ctx->iv_len); |
| 131 | memset(ctx, 0, sizeof(*ctx)); |
| 132 | } |
| 133 | |
| 134 | /* SP800-108 section 5.1 or section 5.2 depending on mode. */ |
| 135 | static int derive(EVP_MAC_CTX *ctx_init, kbkdf_mode mode, unsigned char *iv, |
| 136 | size_t iv_len, unsigned char *label, size_t label_len, |
| 137 | unsigned char *context, size_t context_len, |
| 138 | unsigned char *k_i, size_t h, uint32_t l, unsigned char *ko, |
| 139 | size_t ko_len) |
| 140 | { |
| 141 | int ret = 0; |
| 142 | EVP_MAC_CTX *ctx = NULL; |
| 143 | size_t written = 0, to_write, k_i_len = iv_len; |
| 144 | const unsigned char zero = 0; |
| 145 | uint32_t counter, i; |
| 146 | |
| 147 | /* Setup K(0) for feedback mode. */ |
| 148 | if (iv_len > 0) |
| 149 | memcpy(k_i, iv, iv_len); |
| 150 | |
| 151 | for (counter = 1; written < ko_len; counter++) { |
| 152 | i = be32(counter); |
| 153 | |
| 154 | ctx = EVP_MAC_CTX_dup(ctx_init); |
| 155 | if (ctx == NULL) |
| 156 | goto done; |
| 157 | |
| 158 | /* Perform feedback, if appropriate. */ |
| 159 | if (mode == FEEDBACK && !EVP_MAC_update(ctx, k_i, k_i_len)) |
| 160 | goto done; |
| 161 | |
| 162 | if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4) |
| 163 | || !EVP_MAC_update(ctx, label, label_len) |
| 164 | || !EVP_MAC_update(ctx, &zero, 1) |
| 165 | || !EVP_MAC_update(ctx, context, context_len) |
| 166 | || !EVP_MAC_update(ctx, (unsigned char *)&l, 4) |
| 167 | || !EVP_MAC_final(ctx, k_i, NULL, h)) |
| 168 | goto done; |
| 169 | |
| 170 | to_write = ko_len - written; |
| 171 | memcpy(ko + written, k_i, MIN(to_write, h)); |
| 172 | written += h; |
| 173 | |
| 174 | k_i_len = h; |
| 175 | EVP_MAC_CTX_free(ctx); |
| 176 | ctx = NULL; |
| 177 | } |
| 178 | |
| 179 | ret = 1; |
| 180 | done: |
| 181 | EVP_MAC_CTX_free(ctx); |
| 182 | return ret; |
| 183 | } |
| 184 | |
| 185 | static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen) |
| 186 | { |
| 187 | KBKDF *ctx = (KBKDF *)vctx; |
| 188 | int ret = 0; |
| 189 | unsigned char *k_i = NULL; |
| 190 | uint32_t l = be32(keylen * 8); |
| 191 | size_t h = 0; |
| 192 | |
| 193 | /* label, context, and iv are permitted to be empty. Check everything |
| 194 | * else. */ |
| 195 | if (ctx->ctx_init == NULL) { |
| 196 | if (ctx->ki_len == 0 || ctx->ki == NULL) { |
| 197 | ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET); |
| 198 | return 0; |
| 199 | } |
| 200 | /* Could either be missing MAC or missing message digest or missing |
| 201 | * cipher - arbitrarily, I pick this one. */ |
| 202 | ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC); |
| 203 | return 0; |
| 204 | } |
| 205 | |
| 206 | h = EVP_MAC_size(ctx->ctx_init); |
| 207 | if (h == 0) |
| 208 | goto done; |
| 209 | if (ctx->iv_len != 0 && ctx->iv_len != h) { |
| 210 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); |
| 211 | goto done; |
| 212 | } |
| 213 | |
| 214 | k_i = OPENSSL_zalloc(h); |
| 215 | if (k_i == NULL) |
| 216 | goto done; |
| 217 | |
| 218 | ret = derive(ctx->ctx_init, ctx->mode, ctx->iv, ctx->iv_len, ctx->label, |
| 219 | ctx->label_len, ctx->context, ctx->context_len, k_i, h, l, |
| 220 | key, keylen); |
| 221 | done: |
| 222 | if (ret != 1) |
| 223 | OPENSSL_cleanse(key, keylen); |
| 224 | OPENSSL_clear_free(k_i, h); |
| 225 | return ret; |
| 226 | } |
| 227 | |
| 228 | static int kbkdf_set_buffer(unsigned char **out, size_t *out_len, |
| 229 | const OSSL_PARAM *p) |
| 230 | { |
| 231 | if (p->data == NULL || p->data_size == 0) |
| 232 | return 1; |
| 233 | |
| 234 | OPENSSL_clear_free(*out, *out_len); |
| 235 | *out = NULL; |
| 236 | return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len); |
| 237 | } |
| 238 | |
| 239 | static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) |
| 240 | { |
| 241 | KBKDF *ctx = (KBKDF *)vctx; |
| 242 | OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); |
| 243 | const OSSL_PARAM *p; |
| 244 | OSSL_PARAM mparams[2]; |
| 245 | |
| 246 | if (!ossl_prov_macctx_load_from_params(&ctx->ctx_init, params, NULL, |
| 247 | NULL, NULL, libctx)) |
| 248 | return 0; |
| 249 | else if (ctx->ctx_init != NULL |
| 250 | && !EVP_MAC_is_a(EVP_MAC_CTX_mac(ctx->ctx_init), |
| 251 | OSSL_MAC_NAME_HMAC) |
| 252 | && !EVP_MAC_is_a(EVP_MAC_CTX_mac(ctx->ctx_init), |
| 253 | OSSL_MAC_NAME_CMAC)) { |
| 254 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC); |
| 255 | return 0; |
| 256 | } |
| 257 | |
| 258 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); |
| 259 | if (p != NULL && strncasecmp("counter" , p->data, p->data_size) == 0) { |
| 260 | ctx->mode = COUNTER; |
| 261 | } else if (p != NULL |
| 262 | && strncasecmp("feedback" , p->data, p->data_size) == 0) { |
| 263 | ctx->mode = FEEDBACK; |
| 264 | } else if (p != NULL) { |
| 265 | ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); |
| 266 | return 0; |
| 267 | } |
| 268 | |
| 269 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); |
| 270 | if (p != NULL && !kbkdf_set_buffer(&ctx->ki, &ctx->ki_len, p)) |
| 271 | return 0; |
| 272 | |
| 273 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT); |
| 274 | if (p != NULL && !kbkdf_set_buffer(&ctx->label, &ctx->label_len, p)) |
| 275 | return 0; |
| 276 | |
| 277 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); |
| 278 | if (p != NULL && !kbkdf_set_buffer(&ctx->context, &ctx->context_len, p)) |
| 279 | return 0; |
| 280 | |
| 281 | p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED); |
| 282 | if (p != NULL && !kbkdf_set_buffer(&ctx->iv, &ctx->iv_len, p)) |
| 283 | return 0; |
| 284 | |
| 285 | /* Set up digest context, if we can. */ |
| 286 | if (ctx->ctx_init != NULL && ctx->ki_len != 0) { |
| 287 | mparams[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, |
| 288 | ctx->ki, ctx->ki_len); |
| 289 | mparams[1] = OSSL_PARAM_construct_end(); |
| 290 | |
| 291 | if (!EVP_MAC_CTX_set_params(ctx->ctx_init, mparams) |
| 292 | || !EVP_MAC_init(ctx->ctx_init)) |
| 293 | return 0; |
| 294 | } |
| 295 | |
| 296 | return 1; |
| 297 | } |
| 298 | |
| 299 | static const OSSL_PARAM *kbkdf_settable_ctx_params(void) |
| 300 | { |
| 301 | static const OSSL_PARAM known_settable_ctx_params[] = { |
| 302 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), |
| 303 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), |
| 304 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), |
| 305 | OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), |
| 306 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), |
| 307 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0), |
| 308 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), |
| 309 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), |
| 310 | |
| 311 | OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), |
| 312 | OSSL_PARAM_END, |
| 313 | }; |
| 314 | return known_settable_ctx_params; |
| 315 | } |
| 316 | |
| 317 | static int kbkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) |
| 318 | { |
| 319 | OSSL_PARAM *p; |
| 320 | |
| 321 | p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); |
| 322 | if (p == NULL) |
| 323 | return -2; |
| 324 | |
| 325 | /* KBKDF can produce results as large as you like. */ |
| 326 | return OSSL_PARAM_set_size_t(p, SIZE_MAX); |
| 327 | } |
| 328 | |
| 329 | static const OSSL_PARAM *kbkdf_gettable_ctx_params(void) |
| 330 | { |
| 331 | static const OSSL_PARAM known_gettable_ctx_params[] = |
| 332 | { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), OSSL_PARAM_END }; |
| 333 | return known_gettable_ctx_params; |
| 334 | } |
| 335 | |
| 336 | const OSSL_DISPATCH kdf_kbkdf_functions[] = { |
| 337 | { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kbkdf_new }, |
| 338 | { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kbkdf_free }, |
| 339 | { OSSL_FUNC_KDF_RESET, (void(*)(void))kbkdf_reset }, |
| 340 | { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kbkdf_derive }, |
| 341 | { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, |
| 342 | (void(*)(void))kbkdf_settable_ctx_params }, |
| 343 | { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kbkdf_set_ctx_params }, |
| 344 | { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, |
| 345 | (void(*)(void))kbkdf_gettable_ctx_params }, |
| 346 | { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kbkdf_get_ctx_params }, |
| 347 | { 0, NULL }, |
| 348 | }; |
| 349 | |