From 1dca95b0fbe3c02ce573746351eadd09763d9f3d Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 24 Sep 2024 17:41:14 -0400 Subject: [PATCH] Add the TLS13-KDF OpenSSL Key Derivation Function OpenSSL has a special TLS 1.3 KDF that perform TLS 1.3 specific and limited actions using an underlying HKDF implementation. Implement it the way OpenSSL expect it to work. Signed-off-by: Simo Sorce --- src/kdf.c | 601 ++++++++++++++++++++++++++++++++++++++++--------- src/kdf.h | 1 + src/provider.c | 1 + src/provider.h | 3 + 4 files changed, 496 insertions(+), 110 deletions(-) diff --git a/src/kdf.c b/src/kdf.c index 609d924d..14703c8b 100644 --- a/src/kdf.c +++ b/src/kdf.c @@ -2,6 +2,7 @@ SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" +#include "platform/endian.h" #include #include @@ -12,9 +13,23 @@ struct p11prov_kdf_ctx { CK_MECHANISM_TYPE mechtype; - CK_HKDF_PARAMS params; + int mode; + CK_MECHANISM_TYPE hash_mech; + CK_ULONG salt_type; + uint8_t *salt; + size_t saltlen; + uint8_t *info; + size_t infolen; + uint8_t *prefix; + uint8_t *label; + uint8_t *data; + size_t prefixlen; + size_t labellen; + size_t datalen; P11PROV_SESSION *session; + + bool is_tls13_kdf; }; typedef struct p11prov_kdf_ctx P11PROV_KDF_CTX; @@ -48,7 +63,7 @@ static void *p11prov_hkdf_newctx(void *provctx) hkdfctx->provctx = ctx; /* default mechanism */ - hkdfctx->mechtype = CKM_HKDF_DERIVE; + hkdfctx->mechtype = CKM_HKDF_DATA; return hkdfctx; } @@ -76,44 +91,146 @@ static void p11prov_hkdf_reset(void *ctx) hkdfctx->session = NULL; } - OPENSSL_clear_free(hkdfctx->params.pSalt, hkdfctx->params.ulSaltLen); - OPENSSL_clear_free(hkdfctx->params.pInfo, hkdfctx->params.ulInfoLen); + OPENSSL_clear_free(hkdfctx->salt, hkdfctx->saltlen); + OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); + OPENSSL_clear_free(hkdfctx->prefix, hkdfctx->prefixlen); + OPENSSL_clear_free(hkdfctx->label, hkdfctx->labellen); + OPENSSL_clear_free(hkdfctx->data, hkdfctx->datalen); /* zero all */ memset(hkdfctx, 0, sizeof(*hkdfctx)); /* restore defaults */ hkdfctx->provctx = provctx; - hkdfctx->mechtype = CKM_HKDF_DERIVE; + hkdfctx->mechtype = CKM_HKDF_DATA; } -static int p11prov_hkdf_derive(void *ctx, unsigned char *key, size_t keylen, - const OSSL_PARAM params[]) +static CK_RV inner_pkcs11_key(P11PROV_KDF_CTX *hkdfctx, const uint8_t *key, + size_t keylen, P11PROV_OBJ **keyobj) { - P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; - CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; - CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; - CK_BBOOL val_true = CK_TRUE; + CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; + CK_RV ret; + + if (hkdfctx->session == NULL) { + ret = p11prov_get_session(hkdfctx->provctx, &slotid, NULL, NULL, + hkdfctx->mechtype, NULL, NULL, false, false, + &hkdfctx->session); + if (ret != CKR_OK) { + return ret; + } + } + if (hkdfctx->session == NULL) { + return CKR_SESSION_HANDLE_INVALID; + } + + *keyobj = p11prov_create_secret_key(hkdfctx->provctx, hkdfctx->session, + true, (void *)key, keylen); + if (*keyobj == NULL) { + return CKR_KEY_HANDLE_INVALID; + } + return CKR_OK; +} + +static int inner_extract_key_value(P11PROV_CTX *ctx, P11PROV_SESSION *session, + CK_OBJECT_HANDLE dkey_handle, + unsigned char *key, size_t keylen) +{ + CK_ULONG key_size; + struct fetch_attrs attrs[1]; + int num = 0; + CK_RV ret; + + P11PROV_debug("HKDF derived hey handle: %lu", dkey_handle); + FA_SET_BUF_VAL(attrs, num, CKA_VALUE, key, keylen, true); + ret = p11prov_fetch_attributes(ctx, session, dkey_handle, attrs, num); + if (ret != CKR_OK) { + P11PROV_raise(ctx, ret, "Failed to retrieve derived key"); + return ret; + } + FA_GET_LEN(attrs, 0, key_size); + if (key_size != keylen) { + ret = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, ret, "Expected derived key of len %zu, but got %lu", + keylen, key_size); + return ret; + } + + return CKR_OK; +} + +static int inner_derive_key(P11PROV_CTX *ctx, P11PROV_OBJ *key, + P11PROV_SESSION **session, CK_MECHANISM *mechanism, + size_t keylen, CK_OBJECT_HANDLE *dkey_handle) +{ + CK_OBJECT_CLASS class = CKO_DATA; CK_BBOOL val_false = CK_FALSE; CK_ULONG key_size = keylen; - CK_ATTRIBUTE key_template[5] = { - { CKA_CLASS, &key_class, sizeof(key_class) }, - { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, - { CKA_SENSITIVE, &val_false, sizeof(val_false) }, - { CKA_EXTRACTABLE, &val_true, sizeof(val_true) }, + CK_ATTRIBUTE key_template[3] = { + { CKA_CLASS, &class, sizeof(class) }, + { CKA_TOKEN, &val_false, sizeof(val_false) }, { CKA_VALUE_LEN, &key_size, sizeof(key_size) }, }; - CK_MECHANISM mechanism; CK_OBJECT_HANDLE pkey_handle; - CK_OBJECT_HANDLE dkey_handle; CK_SLOT_ID slotid; - struct fetch_attrs attrs[1]; - int num = 0; + CK_RV ret; + + pkey_handle = p11prov_obj_get_handle(key); + if (pkey_handle == CK_INVALID_HANDLE) { + ret = CKR_KEY_HANDLE_INVALID; + P11PROV_raise(ctx, ret, "Invalid key handle"); + return ret; + } + + slotid = p11prov_obj_get_slotid(key); + if (slotid == CK_UNAVAILABLE_INFORMATION) { + ret = CKR_SLOT_ID_INVALID; + P11PROV_raise(ctx, ret, "Invalid key slotid"); + return ret; + } + + return p11prov_derive_key(ctx, slotid, mechanism, pkey_handle, key_template, + 3, session, dkey_handle); +} + +static int p11prov_hkdf_derive(void *ctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; + CK_HKDF_PARAMS ck_params = { + .bExtract = (hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND + || hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_ONLY) + ? CK_TRUE + : CK_FALSE, + .bExpand = (hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND + || hkdfctx->mode == EVP_KDF_HKDF_MODE_EXPAND_ONLY) + ? CK_TRUE + : CK_FALSE, + .prfHashMechanism = hkdfctx->hash_mech, + .ulSaltType = hkdfctx->salt_type, + .pSalt = hkdfctx->salt, + .ulSaltLen = hkdfctx->saltlen, + .hSaltKey = CK_INVALID_HANDLE, + .pInfo = hkdfctx->info, + .ulInfoLen = hkdfctx->infolen, + }; + CK_MECHANISM mechanism = { + .mechanism = hkdfctx->mechtype, + .pParameter = &ck_params, + .ulParameterLen = sizeof(ck_params), + }; + + CK_OBJECT_HANDLE dkey_handle; CK_RV ret; P11PROV_debug("hkdf derive (ctx:%p, key:%p[%zu], params:%p)", ctx, key, keylen, params); + ret = p11prov_hkdf_set_ctx_params(ctx, params); + if (ret != RET_OSSL_OK) { + P11PROV_raise(hkdfctx->provctx, ret, "Invalid params"); + return RET_OSSL_ERR; + } + if (hkdfctx->key == NULL || key == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return RET_OSSL_ERR; @@ -124,49 +241,245 @@ static int p11prov_hkdf_derive(void *ctx, unsigned char *key, size_t keylen, return RET_OSSL_ERR; } - mechanism.mechanism = hkdfctx->mechtype; - mechanism.pParameter = &hkdfctx->params; - mechanism.ulParameterLen = sizeof(hkdfctx->params); + /* no salt ? */ + if (hkdfctx->salt_type == 0) { + ck_params.ulSaltType = CKF_HKDF_SALT_NULL; + } - pkey_handle = p11prov_obj_get_handle(hkdfctx->key); - if (pkey_handle == CK_INVALID_HANDLE) { - P11PROV_raise(hkdfctx->provctx, CKR_KEY_HANDLE_INVALID, - "Provided key has invalid handle"); + ret = inner_derive_key(hkdfctx->provctx, hkdfctx->key, &hkdfctx->session, + &mechanism, keylen, &dkey_handle); + if (ret != CKR_OK) { return RET_OSSL_ERR; } - /* no salt ? */ - if (hkdfctx->params.ulSaltType == 0) { - hkdfctx->params.ulSaltType = CKF_HKDF_SALT_NULL; + ret = inner_extract_key_value(hkdfctx->provctx, hkdfctx->session, + dkey_handle, key, keylen); + if (ret != CKR_OK) { + return RET_OSSL_ERR; } - slotid = p11prov_obj_get_slotid(hkdfctx->key); - if (slotid == CK_UNAVAILABLE_INFORMATION) { - P11PROV_raise(hkdfctx->provctx, CKR_SLOT_ID_INVALID, - "Provided key has invalid slot"); - return RET_OSSL_ERR; + return RET_OSSL_OK; +} + +static CK_RV p11prov_tls13_expand_label(P11PROV_KDF_CTX *hkdfctx, + P11PROV_OBJ *keyobj, uint8_t *prefix, + size_t prefixlen, uint8_t *label, + size_t labellen, uint8_t *data, + size_t datalen, size_t keylen, + CK_OBJECT_HANDLE *dkey_handle) +{ + CK_HKDF_PARAMS params = { + .bExtract = CK_FALSE, + .bExpand = CK_TRUE, + .prfHashMechanism = hkdfctx->hash_mech, + .ulSaltType = 0, + .pSalt = NULL, + .ulSaltLen = 0, + .hSaltKey = CK_INVALID_HANDLE, + }; + CK_MECHANISM mechanism = { + .mechanism = hkdfctx->mechtype, + .pParameter = ¶ms, + .ulParameterLen = sizeof(params), + }; + uint8_t info[2 + 1 + 255 + 1 + 255]; + size_t infolen, i; + uint16_t keysize; + CK_RV ret; + + P11PROV_debug( + "tls13 expand label (prefix:%p[%zu], label:%p[%zu], data:%p[%zu])", + prefix, prefixlen, label, labellen, data, datalen); + + if (prefix == NULL || prefixlen == 0 || label == NULL || labellen == 0 + || (prefixlen + labellen > 255) || (datalen > 0 && data == NULL) + || (datalen == 0 && data != NULL) || (datalen > 255) + || (keylen > 65535)) { + return CKR_ARGUMENTS_BAD; + } + + /* ref: RFC 8446 - 7.1 Key Schedule */ + infolen = 2 + 1 + prefixlen + labellen + 1 + datalen; + i = 0; + keysize = htobe16(keylen); + memcpy(&info[i], &keysize, sizeof(uint16_t)); + i += sizeof(uint16_t); + info[i] = (uint8_t)(prefixlen + labellen); + i += 1; + memcpy(&info[i], prefix, prefixlen); + i += prefixlen; + memcpy(&info[i], label, labellen); + i += labellen; + info[i] = (uint8_t)(datalen); + i += 1; + if (datalen > 0) { + memcpy(&info[i], data, datalen); + i += datalen; } + if (infolen != i) { + OPENSSL_cleanse(&info, i); + return CKR_HOST_MEMORY; + } + + params.pInfo = info; + params.ulInfoLen = infolen; - ret = p11prov_derive_key(hkdfctx->provctx, slotid, &mechanism, pkey_handle, - key_template, 5, &hkdfctx->session, &dkey_handle); + ret = inner_derive_key(hkdfctx->provctx, keyobj, &hkdfctx->session, + &mechanism, keylen, dkey_handle); + + OPENSSL_cleanse(&info, infolen); + return ret; +} + +static CK_RV p11prov_tls13_derive_secret(P11PROV_KDF_CTX *hkdfctx, + P11PROV_OBJ *keyobj, size_t keylen, + CK_OBJECT_HANDLE *dkey_handle) +{ + P11PROV_OBJ *zerokey = NULL; + CK_HKDF_PARAMS params = { + .bExtract = CK_TRUE, + .bExpand = CK_FALSE, + .prfHashMechanism = hkdfctx->hash_mech, + .ulSaltType = CKF_HKDF_SALT_DATA, + .hSaltKey = CK_INVALID_HANDLE, + .pInfo = NULL, + .ulInfoLen = 0, + }; + CK_MECHANISM mechanism = { + .mechanism = CKM_HKDF_DATA, + .pParameter = ¶ms, + .ulParameterLen = sizeof(params), + }; + uint8_t saltbuf[EVP_MAX_MD_SIZE] = { 0 }; + uint8_t zerobuf[EVP_MAX_MD_SIZE] = { 0 }; + size_t saltlen; + size_t hashlen; + CK_RV ret; + + ret = p11prov_digest_get_digest_size(hkdfctx->hash_mech, &hashlen); if (ret != CKR_OK) { + return ret; + } + saltlen = hashlen; + + if (hkdfctx->salt) { + P11PROV_OBJ *ek = NULL; + unsigned char info[hashlen]; + const char *mdname; + data_buffer digest_data[1] = { 0 }; /* intentionally empty */ + data_buffer digest = { .data = info, .length = hashlen }; + CK_OBJECT_HANDLE skey_handle; + + /* OpenSSL special cases this in an odd way and regenerates a hash as + * if an empty message was received. */ + ret = p11prov_digest_get_name(hkdfctx->hash_mech, &mdname); + if (ret != CKR_OK) { + return ret; + } + + ret = p11prov_digest_util(hkdfctx->provctx, mdname, NULL, digest_data, + &digest); + if (ret != CKR_OK) { + return ret; + } + + /* In OpenSSL the salt is used as the derivation key */ + /* FIXME: OpenSSL sets the length to hashlen w/o checks, + * this may be a bug or intentional, further investigation needed + * [opened https://github.com/openssl/openssl/issues/25557] */ + ret = inner_pkcs11_key(hkdfctx, hkdfctx->salt, hkdfctx->saltlen, &ek); + if (ret != CKR_OK) { + return ret; + } + + ret = p11prov_tls13_expand_label( + hkdfctx, ek, hkdfctx->prefix, hkdfctx->prefixlen, hkdfctx->label, + hkdfctx->labellen, info, hashlen, hashlen, &skey_handle); + p11prov_obj_free(ek); + if (ret != CKR_OK) { + return ret; + } + + ret = inner_extract_key_value(hkdfctx->provctx, hkdfctx->session, + skey_handle, saltbuf, saltlen); + if (ret != CKR_OK) { + return ret; + } + } + + params.pSalt = saltbuf; + params.ulSaltLen = saltlen; + + if (!keyobj) { + ret = inner_pkcs11_key(hkdfctx, zerobuf, hashlen, &zerokey); + if (ret != CKR_OK) { + return ret; + } + keyobj = zerokey; + } + + ret = inner_derive_key(hkdfctx->provctx, keyobj, &hkdfctx->session, + &mechanism, keylen, dkey_handle); + + p11prov_obj_free(zerokey); + return ret; +} + +static int p11prov_tls13_kdf_derive(void *ctx, unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; + CK_OBJECT_HANDLE dkey_handle; + CK_RV ret; + + P11PROV_debug("tls13 hkdf derive (ctx:%p, key:%p[%zu], params:%p)", ctx, + key, keylen, params); + + ret = p11prov_hkdf_set_ctx_params(ctx, params); + if (ret != RET_OSSL_OK) { + P11PROV_raise(hkdfctx->provctx, ret, "Invalid params"); return RET_OSSL_ERR; } - P11PROV_debug("HKDF derived hey handle: %lu", dkey_handle); - FA_SET_BUF_VAL(attrs, num, CKA_VALUE, key, keylen, true); - ret = p11prov_fetch_attributes(hkdfctx->provctx, hkdfctx->session, - dkey_handle, attrs, num); - if (ret != CKR_OK) { - P11PROV_raise(hkdfctx->provctx, ret, "Failed to retrieve derived key"); + if (key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return RET_OSSL_ERR; } - FA_GET_LEN(attrs, 0, key_size); - if (key_size != keylen) { - ret = CKR_GENERAL_ERROR; - P11PROV_raise(hkdfctx->provctx, ret, - "Expected derived key of len %zu, but got %lu", keylen, - key_size); + + if (keylen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return RET_OSSL_ERR; + } + + switch (hkdfctx->mode) { + case EVP_KDF_HKDF_MODE_EXPAND_ONLY: + if (hkdfctx->key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return RET_OSSL_ERR; + } + ret = p11prov_tls13_expand_label( + hkdfctx, hkdfctx->key, hkdfctx->prefix, hkdfctx->prefixlen, + hkdfctx->label, hkdfctx->labellen, hkdfctx->data, hkdfctx->datalen, + keylen, &dkey_handle); + if (ret != CKR_OK) { + return RET_OSSL_ERR; + } + break; + case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: + /* key can be null here */ + ret = p11prov_tls13_derive_secret(hkdfctx, hkdfctx->key, keylen, + &dkey_handle); + if (ret != CKR_OK) { + return RET_OSSL_ERR; + } + break; + default: + return RET_OSSL_ERR; + } + + ret = inner_extract_key_value(hkdfctx->provctx, hkdfctx->session, + dkey_handle, key, keylen); + if (ret != CKR_OK) { return RET_OSSL_ERR; } @@ -185,6 +498,8 @@ static int p11prov_hkdf_set_ctx_params(void *ctx, const OSSL_PARAM params[]) return RET_OSSL_OK; } + /* params common to HKDF and TLS13_KDF first */ + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST); if (p) { const char *digest = NULL; @@ -195,108 +510,136 @@ static int p11prov_hkdf_set_ctx_params(void *ctx, const OSSL_PARAM params[]) return ret; } - rv = p11prov_digest_get_by_name(digest, - &hkdfctx->params.prfHashMechanism); + rv = p11prov_digest_get_by_name(digest, &hkdfctx->hash_mech); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } - P11PROV_debug("set digest to %lu", hkdfctx->params.prfHashMechanism); + P11PROV_debug("set digest to %lu", hkdfctx->hash_mech); } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); if (p) { - int mode; if (p->data_type == OSSL_PARAM_UTF8_STRING) { if (OPENSSL_strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) { - mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; + hkdfctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; } else if (OPENSSL_strcasecmp(p->data, "EXTRACT_ONLY") == 0) { - mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; + hkdfctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; } else if (OPENSSL_strcasecmp(p->data, "EXPAND_ONLY") == 0) { - mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; + hkdfctx->mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; } else { - mode = 1; + hkdfctx->mode = 1; } } else { - ret = OSSL_PARAM_get_int(p, &mode); + ret = OSSL_PARAM_get_int(p, &hkdfctx->mode); if (ret != RET_OSSL_OK) { return ret; } } - switch (mode) { + switch (hkdfctx->mode) { case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: - hkdfctx->params.bExtract = CK_TRUE; - hkdfctx->params.bExpand = CK_TRUE; break; case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: - hkdfctx->params.bExtract = CK_TRUE; - hkdfctx->params.bExpand = CK_FALSE; break; case EVP_KDF_HKDF_MODE_EXPAND_ONLY: - hkdfctx->params.bExtract = CK_FALSE; - hkdfctx->params.bExpand = CK_TRUE; break; default: ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); return RET_OSSL_ERR; } - P11PROV_debug("set mode to extract:%d expand:%d", - (int)hkdfctx->params.bExtract, - (int)hkdfctx->params.bExpand); + P11PROV_debug("set mode to mode:%d", hkdfctx->mode); } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); if (p) { - CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; - void *secret = NULL; + const void *secret = NULL; size_t secret_len; - /* TODO: import into a pkcs11 key? */ - ret = OSSL_PARAM_get_octet_string(p, &secret, 0, &secret_len); + + ret = OSSL_PARAM_get_octet_string_ptr(p, &secret, &secret_len); if (ret != RET_OSSL_OK) { return ret; } - /* Create Session and key from key material */ - if (hkdfctx->session == NULL) { - ret = p11prov_get_session(hkdfctx->provctx, &slotid, NULL, NULL, - hkdfctx->mechtype, NULL, NULL, false, - false, &hkdfctx->session); - if (ret != CKR_OK) { - return RET_OSSL_ERR; - } - } - if (hkdfctx->session == NULL) { - return RET_OSSL_ERR; - } - - hkdfctx->key = p11prov_create_secret_key( - hkdfctx->provctx, hkdfctx->session, true, secret, secret_len); - OPENSSL_clear_free(secret, secret_len); - if (hkdfctx->key == NULL) { + /* Create Session and key from key material */ + p11prov_obj_free(hkdfctx->key); + ret = inner_pkcs11_key(hkdfctx, secret, secret_len, &hkdfctx->key); + if (ret != CKR_OK) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT); if (p) { - void *ptr = NULL; - size_t len; - OPENSSL_cleanse(hkdfctx->params.pSalt, hkdfctx->params.ulSaltLen); - hkdfctx->params.pSalt = NULL; - ret = OSSL_PARAM_get_octet_string(p, &ptr, 0, &len); + OPENSSL_clear_free(hkdfctx->salt, hkdfctx->saltlen); + hkdfctx->salt = NULL; + ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->salt, 0, + &hkdfctx->saltlen); if (ret != RET_OSSL_OK) { return ret; } - hkdfctx->params.ulSaltType = CKF_HKDF_SALT_DATA; - hkdfctx->params.pSalt = ptr; - hkdfctx->params.ulSaltLen = len; - P11PROV_debug("set salt (len:%lu)", hkdfctx->params.ulSaltLen); + hkdfctx->salt_type = CKF_HKDF_SALT_DATA; + P11PROV_debug("set salt (len:%lu)", hkdfctx->saltlen); } + if (hkdfctx->is_tls13_kdf) { + + if (hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return RET_OSSL_ERR; + } + + OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); + hkdfctx->info = NULL; + hkdfctx->infolen = 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PREFIX); + if (p) { + OPENSSL_clear_free(hkdfctx->prefix, hkdfctx->prefixlen); + hkdfctx->prefix = NULL; + hkdfctx->prefixlen = 0; + ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->prefix, 0, + &hkdfctx->prefixlen); + if (ret != RET_OSSL_OK) { + return ret; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_LABEL); + if (p) { + OPENSSL_clear_free(hkdfctx->label, hkdfctx->labellen); + hkdfctx->label = NULL; + hkdfctx->labellen = 0; + ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->label, 0, + &hkdfctx->labellen); + if (ret != RET_OSSL_OK) { + return ret; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DATA); + if (p) { + OPENSSL_clear_free(hkdfctx->data, hkdfctx->datalen); + hkdfctx->data = NULL; + hkdfctx->datalen = 0; + ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->data, 0, + &hkdfctx->datalen); + if (ret != RET_OSSL_OK) { + return ret; + } + } + + return RET_OSSL_OK; + } + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); + if (p) { + OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); + hkdfctx->info = NULL; + hkdfctx->infolen = 0; + } /* can be multiple parameters, which will be all concatenated */ - for (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); p != NULL; - p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_INFO)) { + for (; p; p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_INFO)) { uint8_t *ptr; size_t len; @@ -304,16 +647,18 @@ static int p11prov_hkdf_set_ctx_params(void *ctx, const OSSL_PARAM params[]) return RET_OSSL_ERR; } - len = hkdfctx->params.ulInfoLen + p->data_size; - ptr = OPENSSL_realloc(hkdfctx->params.pInfo, len); + len = hkdfctx->infolen + p->data_size; + ptr = OPENSSL_realloc(hkdfctx->info, len); if (ptr == NULL) { - OPENSSL_cleanse(hkdfctx->params.pInfo, hkdfctx->params.ulInfoLen); + OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); + hkdfctx->info = NULL; + hkdfctx->infolen = 0; return RET_OSSL_ERR; } - memcpy(ptr + hkdfctx->params.ulInfoLen, p->data, p->data_size); - hkdfctx->params.pInfo = ptr; - hkdfctx->params.ulInfoLen = len; - P11PROV_debug("set info (len:%lu)", hkdfctx->params.ulInfoLen); + memcpy(ptr + hkdfctx->infolen, p->data, p->data_size); + hkdfctx->info = ptr; + hkdfctx->infolen = len; + P11PROV_debug("set info (len:%lu)", hkdfctx->infolen); } return RET_OSSL_OK; @@ -348,13 +693,12 @@ static int p11prov_hkdf_get_ctx_params(void *ctx, OSSL_PARAM *params) p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); if (p) { size_t ret_size = 0; - if (hkdfctx->params.bExpand != CK_FALSE) { + if (hkdfctx->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY) { ret_size = SIZE_MAX; } else { CK_RV rv; - rv = p11prov_digest_get_digest_size( - hkdfctx->params.prfHashMechanism, &ret_size); + rv = p11prov_digest_get_digest_size(hkdfctx->hash_mech, &ret_size); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; @@ -390,3 +734,40 @@ const OSSL_DISPATCH p11prov_hkdf_kdf_functions[] = { DISPATCH_HKDF_ELEM(hkdf, GETTABLE_CTX_PARAMS, gettable_ctx_params), { 0, NULL }, }; + +static void *p11prov_tls13_kdf_newctx(void *provctx) +{ + P11PROV_KDF_CTX *ctx = (P11PROV_KDF_CTX *)p11prov_hkdf_newctx(provctx); + ctx->is_tls13_kdf = true; + return ctx; +} + +static const OSSL_PARAM *p11prov_tls13_kdf_settable_ctx_params(void *ctx, + void *prov) +{ + static const OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), + OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL), + 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_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PREFIX, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_LABEL, NULL, 0), + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_DATA, NULL, 0), + OSSL_PARAM_END, + }; + return params; +} + +const OSSL_DISPATCH p11prov_tls13_kdf_functions[] = { + DISPATCH_HKDF_ELEM(tls13_kdf, NEWCTX, newctx), + DISPATCH_HKDF_ELEM(hkdf, FREECTX, freectx), + DISPATCH_HKDF_ELEM(hkdf, RESET, reset), + DISPATCH_HKDF_ELEM(tls13_kdf, DERIVE, derive), + DISPATCH_HKDF_ELEM(hkdf, SET_CTX_PARAMS, set_ctx_params), + DISPATCH_HKDF_ELEM(tls13_kdf, SETTABLE_CTX_PARAMS, settable_ctx_params), + DISPATCH_HKDF_ELEM(hkdf, GET_CTX_PARAMS, get_ctx_params), + DISPATCH_HKDF_ELEM(hkdf, GETTABLE_CTX_PARAMS, gettable_ctx_params), + { 0, NULL }, +}; diff --git a/src/kdf.h b/src/kdf.h index cc938780..dfd3cb20 100644 --- a/src/kdf.h +++ b/src/kdf.h @@ -12,5 +12,6 @@ } extern const void *p11prov_hkdf_static_ctx; extern const OSSL_DISPATCH p11prov_hkdf_kdf_functions[]; +extern const OSSL_DISPATCH p11prov_tls13_kdf_functions[]; #endif /* _KDF_H */ diff --git a/src/provider.c b/src/provider.c index a41d0ea7..199659c9 100644 --- a/src/provider.c +++ b/src/provider.c @@ -985,6 +985,7 @@ static CK_RV operations_init(P11PROV_CTX *ctx) break; case CKM_HKDF_DERIVE: ADD_ALGO(HKDF, hkdf, kdf); + ADD_ALGO(TLS13_KDF, tls13, kdf); ADD_ALGO(HKDF, hkdf, exchange); UNCHECK_MECHS(CKM_HKDF_DERIVE); break; diff --git a/src/provider.h b/src/provider.h index b1f1643e..418f9d00 100644 --- a/src/provider.h +++ b/src/provider.h @@ -58,6 +58,9 @@ #define P11PROV_NAMES_RAND "PKCS11-RAND" #define P11PROV_DESCS_RAND "PKCS11 Random Generator" #define P11PROV_NAME_CERTIFICATE "CERTIFICATE" +#define P11PROV_NAME_TLS13_KDF "TLS13-KDF" +#define P11PROV_NAMES_TLS13_KDF P11PROV_NAME_TLS13_KDF +#define P11PROV_DESCS_TLS13_KDF "PKCS11 TLS 1.3 HKDF Implementation" #define P11PROV_PARAM_URI "pkcs11_uri" #define P11PROV_PARAM_KEY_USAGE "pkcs11_key_usage"