/*
- * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
-#include "internal/cryptlib.h"
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
#include <openssl/params.h>
+#include "internal/cryptlib.h"
+#include "internal/numbers.h"
#include "internal/evp_int.h"
-#include "kdf_local.h"
-
-static void kdf_tls1_prf_reset(EVP_KDF_IMPL *impl);
-static int tls1_prf_alg(const EVP_MD *md,
+#include "internal/provider_ctx.h"
+#include "internal/providercommonerr.h"
+#include "internal/provider_algs.h"
+#include "internal/provider_util.h"
+#include "e_os.h"
+
+static OSSL_OP_kdf_newctx_fn kdf_tls1_prf_new;
+static OSSL_OP_kdf_freectx_fn kdf_tls1_prf_free;
+static OSSL_OP_kdf_reset_fn kdf_tls1_prf_reset;
+static OSSL_OP_kdf_derive_fn kdf_tls1_prf_derive;
+static OSSL_OP_kdf_settable_ctx_params_fn kdf_tls1_prf_settable_ctx_params;
+static OSSL_OP_kdf_set_ctx_params_fn kdf_tls1_prf_set_ctx_params;
+
+static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx,
const unsigned char *sec, size_t slen,
const unsigned char *seed, size_t seed_len,
unsigned char *out, size_t olen);
#define TLS1_PRF_MAXBUF 1024
/* TLS KDF kdf context structure */
+typedef struct {
+ void *provctx;
+
+ /* MAC context for the main digest */
+ EVP_MAC_CTX *P_hash;
+ /* MAC context for SHA1 for the MD5/SHA-1 combined PRF */
+ EVP_MAC_CTX *P_sha1;
-struct evp_kdf_impl_st {
- /* Digest to use for PRF */
- const EVP_MD *md;
/* Secret value to use for PRF */
unsigned char *sec;
size_t seclen;
/* Buffer of concatenated seed data */
unsigned char seed[TLS1_PRF_MAXBUF];
size_t seedlen;
-};
+} TLS1_PRF;
-static EVP_KDF_IMPL *kdf_tls1_prf_new(void)
+static void *kdf_tls1_prf_new(void *provctx)
{
- EVP_KDF_IMPL *impl;
+ TLS1_PRF *ctx;
- if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL)
- KDFerr(KDF_F_KDF_TLS1_PRF_NEW, ERR_R_MALLOC_FAILURE);
- return impl;
+ if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ ctx->provctx = provctx;
+ return ctx;
}
-static void kdf_tls1_prf_free(EVP_KDF_IMPL *impl)
+static void kdf_tls1_prf_free(void *vctx)
{
- kdf_tls1_prf_reset(impl);
- OPENSSL_free(impl);
-}
+ TLS1_PRF *ctx = (TLS1_PRF *)vctx;
-static void kdf_tls1_prf_reset(EVP_KDF_IMPL *impl)
-{
- OPENSSL_clear_free(impl->sec, impl->seclen);
- OPENSSL_cleanse(impl->seed, impl->seedlen);
- memset(impl, 0, sizeof(*impl));
+ kdf_tls1_prf_reset(ctx);
+ OPENSSL_free(ctx);
}
-static int kdf_tls1_prf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
+static void kdf_tls1_prf_reset(void *vctx)
{
- const unsigned char *p;
- size_t len;
- const EVP_MD *md;
-
- switch (cmd) {
- case EVP_KDF_CTRL_SET_MD:
- md = va_arg(args, const EVP_MD *);
- if (md == NULL)
- return 0;
-
- impl->md = md;
- return 1;
+ TLS1_PRF *ctx = (TLS1_PRF *)vctx;
- case EVP_KDF_CTRL_SET_TLS_SECRET:
- p = va_arg(args, const unsigned char *);
- len = va_arg(args, size_t);
- OPENSSL_clear_free(impl->sec, impl->seclen);
- impl->sec = OPENSSL_memdup(p, len);
- if (impl->sec == NULL)
- return 0;
+ EVP_MAC_CTX_free(ctx->P_hash);
+ EVP_MAC_CTX_free(ctx->P_sha1);
+ OPENSSL_clear_free(ctx->sec, ctx->seclen);
+ OPENSSL_cleanse(ctx->seed, ctx->seedlen);
+ memset(ctx, 0, sizeof(*ctx));
+}
- impl->seclen = len;
- return 1;
+static int kdf_tls1_prf_derive(void *vctx, unsigned char *key,
+ size_t keylen)
+{
+ TLS1_PRF *ctx = (TLS1_PRF *)vctx;
- /* TODO: This is only ever called from pkey_kdf and only as part of setting the TLS secret
- consider merging the twe two?? */
- case EVP_KDF_CTRL_RESET_TLS_SEED:
- OPENSSL_cleanse(impl->seed, impl->seedlen);
- impl->seedlen = 0;
- return 1;
+ if (ctx->P_hash == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ if (ctx->sec == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET);
+ return 0;
+ }
+ if (ctx->seedlen == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SEED);
+ return 0;
+ }
- case EVP_KDF_CTRL_ADD_TLS_SEED:
- p = va_arg(args, const unsigned char *);
- len = va_arg(args, size_t);
- if (len == 0 || p == NULL)
- return 1;
+ return tls1_prf_alg(ctx->P_hash, ctx->P_sha1,
+ ctx->sec, ctx->seclen,
+ ctx->seed, ctx->seedlen,
+ key, keylen);
+}
- if (len > (TLS1_PRF_MAXBUF - impl->seedlen))
- return 0;
+static EVP_MAC_CTX *kdf_tls1_prf_mkmacctx(OPENSSL_CTX *libctx,
+ const char *mdname,
+ const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ OSSL_PARAM mac_params[5], *mp = mac_params;
+ const char *properties = NULL;
+ /* TODO(3.0) rethink "flags", also see hmac.c in providers */
+ int mac_flags = EVP_MD_CTX_FLAG_NON_FIPS_ALLOW;
+ EVP_MAC_CTX *macctx = NULL;
+
+ *mp++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
+ (char *)mdname, 0);
+#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE)
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ENGINE)) != NULL)
+ *mp++ = *p;
+#endif
+ if ((p = OSSL_PARAM_locate_const(params,
+ OSSL_KDF_PARAM_PROPERTIES)) != NULL) {
+ properties = p->data;
+ *mp++ = *p;
+ }
+ *mp++ = OSSL_PARAM_construct_int(OSSL_MAC_PARAM_FLAGS, &mac_flags);
+ *mp = OSSL_PARAM_construct_end();
- memcpy(impl->seed + impl->seedlen, p, len);
- impl->seedlen += len;
- return 1;
+ /* Implicit fetch */
+ {
+ EVP_MAC *mac = EVP_MAC_fetch(libctx, OSSL_MAC_NAME_HMAC, properties);
- default:
- return -2;
+ macctx = EVP_MAC_CTX_new(mac);
+ /* The context holds on to the MAC */
+ EVP_MAC_free(mac);
+ if (macctx == NULL)
+ goto err;
}
+
+ if (EVP_MAC_CTX_set_params(macctx, mac_params))
+ goto done;
+ err:
+ EVP_MAC_CTX_free(macctx);
+ macctx = NULL;
+ done:
+ return macctx;
}
-static int kdf_tls1_prf_ctrl_str(EVP_KDF_IMPL *impl,
- const char *type, const char *value)
+static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
- if (value == NULL) {
- KDFerr(KDF_F_KDF_TLS1_PRF_CTRL_STR, KDF_R_VALUE_MISSING);
- return 0;
+ const OSSL_PARAM *p;
+ TLS1_PRF *ctx = vctx;
+ OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) {
+ EVP_MAC_CTX_free(ctx->P_hash);
+ EVP_MAC_CTX_free(ctx->P_sha1);
+ if (strcasecmp(p->data, SN_md5_sha1) == 0) {
+ ctx->P_hash = kdf_tls1_prf_mkmacctx(libctx, SN_md5, params);
+ ctx->P_sha1 = kdf_tls1_prf_mkmacctx(libctx, SN_sha1, params);
+ } else {
+ ctx->P_hash = kdf_tls1_prf_mkmacctx(libctx, p->data, params);
+ }
}
- if (strcmp(type, "digest") == 0)
- return kdf_md2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_SET_MD, value);
-
- if (strcmp(type, "secret") == 0)
- return kdf_str2ctrl(impl, kdf_tls1_prf_ctrl,
- EVP_KDF_CTRL_SET_TLS_SECRET, value);
- if (strcmp(type, "hexsecret") == 0)
- return kdf_hex2ctrl(impl, kdf_tls1_prf_ctrl,
- EVP_KDF_CTRL_SET_TLS_SECRET, value);
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) {
+ OPENSSL_clear_free(ctx->sec, ctx->seclen);
+ ctx->sec = NULL;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->sec, 0, &ctx->seclen))
+ return 0;
+ }
+ /* The seed fields concatenate, so process them all */
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED)) != NULL) {
+ OPENSSL_cleanse(ctx->seed, ctx->seedlen);
+ ctx->seedlen = 0;
+
+ for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1,
+ OSSL_KDF_PARAM_SEED)) {
+ const void *q = ctx->seed + ctx->seedlen;
+ size_t sz = 0;
+
+ if (p->data_size != 0
+ && p->data != NULL
+ && !OSSL_PARAM_get_octet_string(p, (void **)&q,
+ TLS1_PRF_MAXBUF - ctx->seedlen,
+ &sz))
+ return 0;
+ ctx->seedlen += sz;
+ }
+ }
+ return 1;
+}
- if (strcmp(type, "seed") == 0)
- return kdf_str2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_ADD_TLS_SEED,
- value);
+static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params(void)
+{
+ static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0),
+ OSSL_PARAM_END
+ };
+ return known_settable_ctx_params;
+}
- if (strcmp(type, "hexseed") == 0)
- return kdf_hex2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_ADD_TLS_SEED,
- value);
+static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
+ return OSSL_PARAM_set_size_t(p, SIZE_MAX);
return -2;
}
-static int kdf_tls1_prf_derive(EVP_KDF_IMPL *impl, unsigned char *key,
- size_t keylen)
+static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params(void)
{
- if (impl->md == NULL) {
- KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
- return 0;
- }
- if (impl->sec == NULL) {
- KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SECRET);
- return 0;
- }
- if (impl->seedlen == 0) {
- KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SEED);
- return 0;
- }
- return tls1_prf_alg(impl->md, impl->sec, impl->seclen,
- impl->seed, impl->seedlen,
- key, keylen);
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+ OSSL_PARAM_END
+ };
+ return known_gettable_ctx_params;
}
-const EVP_KDF tls1_prf_kdf_meth = {
- EVP_KDF_TLS1_PRF,
- kdf_tls1_prf_new,
- kdf_tls1_prf_free,
- kdf_tls1_prf_reset,
- kdf_tls1_prf_ctrl,
- kdf_tls1_prf_ctrl_str,
- NULL,
- kdf_tls1_prf_derive
+const OSSL_DISPATCH kdf_tls1_prf_functions[] = {
+ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_tls1_prf_new },
+ { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_tls1_prf_free },
+ { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_tls1_prf_reset },
+ { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_tls1_prf_derive },
+ { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+ (void(*)(void))kdf_tls1_prf_settable_ctx_params },
+ { OSSL_FUNC_KDF_SET_CTX_PARAMS,
+ (void(*)(void))kdf_tls1_prf_set_ctx_params },
+ { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+ (void(*)(void))kdf_tls1_prf_gettable_ctx_params },
+ { OSSL_FUNC_KDF_GET_CTX_PARAMS,
+ (void(*)(void))kdf_tls1_prf_get_ctx_params },
+ { 0, NULL }
};
/*
* A(0) = seed
* A(i) = HMAC_<hash>(secret, A(i-1))
*/
-static int tls1_prf_P_hash(const EVP_MD *md,
+static int tls1_prf_P_hash(EVP_MAC_CTX *ctx_init,
const unsigned char *sec, size_t sec_len,
const unsigned char *seed, size_t seed_len,
unsigned char *out, size_t olen)
{
size_t chunk;
- EVP_MAC *mac = NULL;
- EVP_MAC_CTX *ctx = NULL, *ctx_Ai = NULL, *ctx_init = NULL;
+ EVP_MAC_CTX *ctx = NULL, *ctx_Ai = NULL;
unsigned char Ai[EVP_MAX_MD_SIZE];
size_t Ai_len;
int ret = 0;
- OSSL_PARAM params[4];
- int mac_flags;
- const char *mdname = EVP_MD_name(md);
+ OSSL_PARAM params[2], *p = params;
- mac = EVP_MAC_fetch(NULL, OSSL_MAC_NAME_HMAC, NULL); /* Implicit fetch */
- ctx_init = EVP_MAC_CTX_new(mac);
- if (ctx_init == NULL)
- goto err;
-
- /* TODO(3.0) rethink "flags", also see hmac.c in providers */
- mac_flags = EVP_MD_CTX_FLAG_NON_FIPS_ALLOW;
- params[0] = OSSL_PARAM_construct_int(OSSL_MAC_PARAM_FLAGS, &mac_flags);
- params[1] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
- (char *)mdname, 0);
- params[2] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
- (void *)sec, sec_len);
- params[3] = OSSL_PARAM_construct_end();
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+ (void *)sec, sec_len);
+ *p = OSSL_PARAM_construct_end();
if (!EVP_MAC_CTX_set_params(ctx_init, params))
goto err;
if (!EVP_MAC_init(ctx_init))
err:
EVP_MAC_CTX_free(ctx);
EVP_MAC_CTX_free(ctx_Ai);
- EVP_MAC_CTX_free(ctx_init);
- EVP_MAC_free(mac);
OPENSSL_cleanse(Ai, sizeof(Ai));
return ret;
}
*
* PRF(secret, label, seed) = P_<hash>(secret, label + seed)
*/
-static int tls1_prf_alg(const EVP_MD *md,
+static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx,
const unsigned char *sec, size_t slen,
const unsigned char *seed, size_t seed_len,
unsigned char *out, size_t olen)
{
- if (EVP_MD_type(md) == NID_md5_sha1) {
+ if (sha1ctx != NULL) {
/* TLS v1.0 and TLS v1.1 */
size_t i;
unsigned char *tmp;
size_t L_S1 = (slen + 1) / 2;
size_t L_S2 = L_S1;
- if (!tls1_prf_P_hash(EVP_md5(), sec, L_S1,
+ if (!tls1_prf_P_hash(mdctx, sec, L_S1,
seed, seed_len, out, olen))
return 0;
if ((tmp = OPENSSL_malloc(olen)) == NULL) {
- KDFerr(KDF_F_TLS1_PRF_ALG, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
}
- if (!tls1_prf_P_hash(EVP_sha1(), sec + slen - L_S2, L_S2,
+
+ if (!tls1_prf_P_hash(sha1ctx, sec + slen - L_S2, L_S2,
seed, seed_len, tmp, olen)) {
OPENSSL_clear_free(tmp, olen);
return 0;
}
/* TLS v1.2 */
- if (!tls1_prf_P_hash(md, sec, slen, seed, seed_len, out, olen))
+ if (!tls1_prf_P_hash(mdctx, sec, slen, seed, seed_len, out, olen))
return 0;
return 1;