From 6b51b630dd07d9e2b63d4faa9085a47606a35e7c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 27 Sep 2024 14:44:58 -0400 Subject: [PATCH 1/4] Add a generic digest utility function In preparation to reuse outside of the specific object.c use case. Also adds a better and more flexible interface. Signed-off-by: Simo Sorce --- src/objects.c | 168 +++++++++++++++++--------------------------------- src/util.c | 89 ++++++++++++++++++++++++++ src/util.h | 10 +++ 3 files changed, 154 insertions(+), 113 deletions(-) diff --git a/src/objects.c b/src/objects.c index ab7d61ff..ef625fa7 100644 --- a/src/objects.c +++ b/src/objects.c @@ -2663,100 +2663,12 @@ static CK_RV param_to_attr(P11PROV_CTX *ctx, const OSSL_PARAM params[], return CKR_OK; } -static CK_RV digest(P11PROV_CTX *ctx, const uint8_t *prefx, size_t plen, - const uint8_t *data1, size_t len1, const uint8_t *data2, - size_t len2, const uint8_t *data3, size_t len3, - uint8_t **out, size_t *outlen) -{ - EVP_MD_CTX *mdctx = NULL; - EVP_MD *md = NULL; - unsigned char *dgst = NULL; - unsigned int dlen = 0; - CK_RV rv; - int err; - - md = EVP_MD_fetch(p11prov_ctx_get_libctx(ctx), "sha256", NULL); - if (!md) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "Failed to fetch sha256 digest"); - goto done; - } - dlen = EVP_MD_get_size(md); - if (dlen == -1) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "Failed to get sha256 digest length"); - goto done; - } - dgst = OPENSSL_malloc(dlen); - if (!dgst) { - rv = CKR_HOST_MEMORY; - goto done; - } - mdctx = EVP_MD_CTX_new(); - if (!mdctx) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "EVP_MD_CTX_new failed"); - goto done; - } - err = EVP_DigestInit(mdctx, md); - if (err != RET_OSSL_OK) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "EVP_DigestInit failed"); - goto done; - } - if (len1 > 0) { - err = EVP_DigestUpdate(mdctx, data1, len1); - if (err != RET_OSSL_OK) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "EVP_DigestUpdate(1) failed"); - goto done; - } - } - if (len2 > 0) { - err = EVP_DigestUpdate(mdctx, data2, len2); - if (err != RET_OSSL_OK) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "EVP_DigestUpdate(2) failed"); - goto done; - } - } - if (len3 > 0) { - err = EVP_DigestUpdate(mdctx, data3, len3); - if (err != RET_OSSL_OK) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "EVP_DigestUpdate(3) failed"); - goto done; - } - } - err = EVP_DigestFinal(mdctx, dgst, &dlen); - if (err != RET_OSSL_OK || dlen == 0) { - rv = CKR_GENERAL_ERROR; - P11PROV_raise(ctx, rv, "EVP_DigestFinal(2) failed"); - goto done; - } - - *out = dgst; - *outlen = dlen; - dgst = NULL; - rv = CKR_OK; - -done: - OPENSSL_free(dgst); - EVP_MD_CTX_free(mdctx); - EVP_MD_free(md); - return rv; -} - static CK_RV prep_rsa_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], struct pool_find_ctx *findctx) { - const OSSL_PARAM *pn; - const OSSL_PARAM *pe; - const OSSL_PARAM *pd; - const char *prefix = "PrivKey"; - size_t prefix_len = 7; - uint8_t *attr_data = NULL; - size_t attr_size = 0; + data_buffer digest_data[5]; + data_buffer digest = { 0 }; + const OSSL_PARAM *p; size_t key_size; CK_RV rv; @@ -2786,39 +2698,50 @@ static CK_RV prep_rsa_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], /* A Token would never allow us to search by private exponent, * so we store a hash of the private key in CKA_ID */ - pn = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N); - if (!pn) { + /* prefix */ + digest_data[0].data = (uint8_t *)"PrivKey"; + digest_data[0].length = 7; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N); + if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_RSA_N); return CKR_KEY_INDIGESTIBLE; } + digest_data[1].data = p->data; + digest_data[1].length = p->data_size; + key_size = p->data_size; - pe = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); - if (!pe) { + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); + if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_RSA_E); return CKR_KEY_INDIGESTIBLE; } + digest_data[2].data = p->data; + digest_data[2].length = p->data_size; - pd = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D); - if (!pd) { + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D); + if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_RSA_D); return CKR_KEY_INDIGESTIBLE; } + digest_data[3].data = p->data; + digest_data[3].length = p->data_size; + + digest_data[4].data = NULL; + + rv = p11prov_digest_util(ctx, "sha256", NULL, digest_data, &digest); - rv = digest(ctx, (uint8_t *)prefix, prefix_len, pn->data, pn->data_size, - pe->data, pe->data_size, pd->data, pd->data_size, - &attr_data, &attr_size); if (rv != CKR_OK) { return rv; } findctx->attrs[0].type = CKA_ID; - findctx->attrs[0].pValue = attr_data; - findctx->attrs[0].ulValueLen = attr_size; + findctx->attrs[0].pValue = digest.data; + findctx->attrs[0].ulValueLen = digest.length; findctx->numattrs++; - key_size = pn->data_size; break; default: return CKR_GENERAL_ERROR; @@ -2844,15 +2767,13 @@ static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], OSSL_PARAM pub_key[2] = { 0 }; uint8_t pub_data[MAX_EC_PUB_KEY_SIZE]; - const char *prefix = "PrivKey"; - size_t prefix_len = 7; - uint8_t *attr_data = NULL; - size_t attr_size = 0; + data_buffer digest_data[5]; + data_buffer digest = { 0 }; const char *curve_name = NULL; int curve_nid; unsigned char *ecparams = NULL; - int len; + int len, i; CK_RV rv; if (findctx->numattrs != MAX_ATTRS_SIZE) { @@ -2956,15 +2877,36 @@ static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], return CKR_KEY_INDIGESTIBLE; } - rv = digest(ctx, (uint8_t *)prefix, prefix_len, (uint8_t *)curve_name, - curve_name ? strlen(curve_name) : 0, ecparams, len, p->data, - p->data_size, &attr_data, &attr_size); + i = 0; + + /* prefix */ + digest_data[i].data = (uint8_t *)"PrivKey"; + digest_data[i].length = 7; + i++; + + if (curve_name) { + digest_data[i].data = (uint8_t *)curve_name; + digest_data[i].length = strlen(curve_name); + i++; + } + + digest_data[i].data = ecparams; + digest_data[i].length = len; + i++; + + digest_data[i].data = p->data; + digest_data[i].length = p->data_size; + i++; + + digest_data[i].data = NULL; + + rv = p11prov_digest_util(ctx, "sha256", NULL, digest_data, &digest); if (rv != CKR_OK) { return rv; } findctx->attrs[0].type = CKA_ID; - findctx->attrs[0].pValue = attr_data; - findctx->attrs[0].ulValueLen = attr_size; + findctx->attrs[0].pValue = digest.data; + findctx->attrs[0].ulValueLen = digest.length; findctx->numattrs++; break; diff --git a/src/util.c b/src/util.c index 273c2bbd..66a3bd0f 100644 --- a/src/util.c +++ b/src/util.c @@ -1170,3 +1170,92 @@ void p11prov_force_rwlock_reinit(pthread_rwlock_t *lock) pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; memcpy(lock, &rwlock, sizeof(rwlock)); } + +CK_RV p11prov_digest_util(P11PROV_CTX *ctx, const char *digest, + const char *properties, data_buffer data[], + data_buffer *output) +{ + EVP_MD_CTX *mdctx = NULL; + EVP_MD *md = NULL; + unsigned char *dgst = NULL; + unsigned int dlen = 0; + CK_RV rv; + int err; + + if (!data || !output) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "Invalid function arguments"); + return rv; + } + + md = EVP_MD_fetch(p11prov_ctx_get_libctx(ctx), digest, properties); + if (!md) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "Failed to fetch %s digest", digest); + goto done; + } + + dlen = EVP_MD_get_size(md); + if (dlen == -1) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "Failed to get %s digest length", digest); + goto done; + } + + if (output->data) { + if (output->length < dlen) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "Invalid function arguments"); + goto done; + } + dgst = output->data; + } else { + dgst = OPENSSL_malloc(dlen); + if (!dgst) { + rv = CKR_HOST_MEMORY; + goto done; + } + } + + mdctx = EVP_MD_CTX_new(); + if (!mdctx) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "EVP_MD_CTX_new failed"); + goto done; + } + + err = EVP_DigestInit(mdctx, md); + if (err != RET_OSSL_OK) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "EVP_DigestInit failed"); + goto done; + } + + for (int i = 0; data[i].data; i++) { + err = EVP_DigestUpdate(mdctx, data[i].data, data[i].length); + if (err != RET_OSSL_OK) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "EVP_DigestUpdate(%d) failed", i); + goto done; + } + } + + err = EVP_DigestFinal(mdctx, dgst, &dlen); + if (err != RET_OSSL_OK || dlen == 0) { + rv = CKR_GENERAL_ERROR; + P11PROV_raise(ctx, rv, "EVP_DigestFinal failed"); + goto done; + } + + output->data = dgst; + output->length = dlen; + rv = CKR_OK; + +done: + if (output->data != dgst) { + OPENSSL_free(dgst); + } + EVP_MD_CTX_free(mdctx); + EVP_MD_free(md); + return rv; +} diff --git a/src/util.h b/src/util.h index aef8f4a4..a96eec72 100644 --- a/src/util.h +++ b/src/util.h @@ -132,4 +132,14 @@ static inline void constant_select_buf(CK_ULONG cond, CK_ULONG size, } } +struct data_buffer { + uint8_t *data; + size_t length; +}; +typedef struct data_buffer data_buffer; + +CK_RV p11prov_digest_util(P11PROV_CTX *provctx, const char *digest, + const char *properties, data_buffer data[], + data_buffer *output); + #endif /* _UTIL_H */ From bc17192db7c083cfa566160e6f5d621a21db7d1b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 27 Sep 2024 13:14:42 -0400 Subject: [PATCH 2/4] Implement support for ec point compression query OpenSSL TLS code needs to know if the EC public key is in compressed or uncompressed representation, for peer keys. Add support to return this information from public keys. Signed-off-by: Simo Sorce --- src/keymgmt.c | 15 ++++++++++++++- src/objects.c | 14 ++++++++++++++ src/objects.h | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/keymgmt.c b/src/keymgmt.c index f6fd9cc6..54652686 100644 --- a/src/keymgmt.c +++ b/src/keymgmt.c @@ -1640,6 +1640,18 @@ static int p11prov_ec_get_params(void *keydata, OSSL_PARAM params[]) memcpy(p->data, pub_key->pValue, pub_key->ulValueLen); } } + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT); + if (p) { + bool compressed = p11prov_obj_get_ec_compressed(key); + if (compressed) { + ret = OSSL_PARAM_set_utf8_string(p, "compressed"); + } else { + ret = OSSL_PARAM_set_utf8_string(p, "uncompressed"); + } + if (ret != RET_OSSL_OK) { + return ret; + } + } return RET_OSSL_OK; } @@ -1655,10 +1667,11 @@ static const OSSL_PARAM *p11prov_ec_gettable_params(void *provctx) OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, NULL, + 0), /* * OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAM * OSSL_PKEY_PARAM_EC_ENCODING - * OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT * OSSL_PKEY_PARAM_EC_FIELD_TYPE * OSSL_PKEY_PARAM_EC_P * OSSL_PKEY_PARAM_EC_A diff --git a/src/objects.c b/src/objects.c index ef625fa7..7800c292 100644 --- a/src/objects.c +++ b/src/objects.c @@ -1728,6 +1728,20 @@ const char *p11prov_obj_get_ec_group_name(P11PROV_OBJ *obj) return (const char *)attr->pValue; } +bool p11prov_obj_get_ec_compressed(P11PROV_OBJ *obj) +{ + CK_ATTRIBUTE *pub_key; + uint8_t *buf; + + pub_key = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY); + if (!pub_key) { + return false; + } + buf = pub_key->pValue; + + return (buf[0] & 0x01) == 0x01; +} + static int ossl_param_construct_bn(P11PROV_CTX *provctx, OSSL_PARAM *param, const char *key, const BIGNUM *val) { diff --git a/src/objects.h b/src/objects.h index 4a06cc30..c6ee04ff 100644 --- a/src/objects.h +++ b/src/objects.h @@ -52,6 +52,7 @@ CK_RV p11prov_obj_set_attributes(P11PROV_CTX *ctx, P11PROV_SESSION *session, P11PROV_OBJ *obj, CK_ATTRIBUTE *template, CK_ULONG tsize); const char *p11prov_obj_get_ec_group_name(P11PROV_OBJ *obj); +bool p11prov_obj_get_ec_compressed(P11PROV_OBJ *obj); int p11prov_obj_export_public_key(P11PROV_OBJ *obj, CK_KEY_TYPE key_type, bool search_related, OSSL_CALLBACK *cb_fn, void *cb_arg); From 4f034a24c2fe9b5d3d837f22e74e3e8dde288b44 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 24 Sep 2024 17:41:14 -0400 Subject: [PATCH 3/4] 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 | 623 ++++++++++++++++++++++++++++++++++++++++--------- src/kdf.h | 1 + src/provider.c | 1 + src/provider.h | 3 + 4 files changed, 518 insertions(+), 110 deletions(-) diff --git a/src/kdf.c b/src/kdf.c index 609d924d..a9b890c5 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 key 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,266 @@ 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; +} + +/* ref: RFC 8446 - 7.1 Key Schedule + * Citation: + * HKDF-Expand-Label(Secret, Label, Context, Length) = + HKDF-Expand(Secret, HkdfLabel, Length) + * + * Where HkdfLabel is specified as: + * + * struct { + * uint16 length = Length; + * opaque label<7..255> = "tls13 " + Label; + * opaque context<0..255> = Context; + * } HkdfLabel; + */ +#define TLS13_HL_KEY_SIZE 2 +#define TLS13_HL_KEY_MAX_LENGTH 65535 +#define TLS13_HL_LABEL_SIZE 1 +#define TLS13_HL_LABEL_MAX_LENGTH 255 +#define TLS13_HL_CONTEXT_SIZE 1 +#define TLS13_HL_CONTEXT_MAX_LENGTH 255 +#define TLS13_HKDF_LABEL_MAX_SIZE \ + (TLS13_HL_KEY_SIZE + TLS13_HL_LABEL_SIZE + TLS13_HL_LABEL_MAX_LENGTH \ + + TLS13_HL_CONTEXT_SIZE + TLS13_HL_CONTEXT_MAX_LENGTH) + +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[TLS13_HKDF_LABEL_MAX_SIZE]; + size_t 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 > TLS13_HL_LABEL_MAX_LENGTH) + || (datalen > 0 && data == NULL) || (datalen == 0 && data != NULL) + || (datalen > TLS13_HL_CONTEXT_MAX_LENGTH) + || (keylen > TLS13_HL_KEY_MAX_LENGTH)) { + return CKR_ARGUMENTS_BAD; } - ret = p11prov_derive_key(hkdfctx->provctx, slotid, &mechanism, pkey_handle, - key_template, 5, &hkdfctx->session, &dkey_handle); + params.pInfo = info; + params.ulInfoLen = 2 + 1 + prefixlen + labellen + 1 + datalen; + if (params.ulInfoLen > TLS13_HKDF_LABEL_MAX_SIZE) { + return CKR_ARGUMENTS_BAD; + } + i = 0; + keysize = htobe16(keylen); + memcpy(&info[i], &keysize, sizeof(keysize)); + i += sizeof(keysize); + info[i] = prefixlen + labellen; + i += 1; + memcpy(&info[i], prefix, prefixlen); + i += prefixlen; + memcpy(&info[i], label, labellen); + i += labellen; + info[i] = datalen; + i += 1; + if (datalen > 0) { + memcpy(&info[i], data, datalen); + i += datalen; + } + if (params.ulInfoLen != i) { + OPENSSL_cleanse(params.pInfo, TLS13_HKDF_LABEL_MAX_SIZE); + return CKR_HOST_MEMORY; + } + + ret = inner_derive_key(hkdfctx->provctx, keyobj, &hkdfctx->session, + &mechanism, keylen, dkey_handle); + + OPENSSL_cleanse(params.pInfo, params.ulInfoLen); + 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 */ + 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 +519,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 +531,137 @@ 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; + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); + return RET_OSSL_ERR; } } 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 +669,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 +715,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 +756,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" From b7c9bb60fc9b65cdb0e707c2ba7ed9dec09b07a0 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 27 Sep 2024 13:13:36 -0400 Subject: [PATCH 4/4] Test TLS1.3 connection forcing all ops on token This is used primarily to test TLS13-KDF. Note that we have to disable digest ops on the token as OpenSSL requires context duplication to work, and most tokens do not really offer it. Signed-off-by: Simo Sorce --- tests/ttls | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/ttls b/tests/ttls index a3ea93f4..6ec20721 100755 --- a/tests/ttls +++ b/tests/ttls @@ -93,4 +93,18 @@ run_test "$ECPRIURI" "$ECCRTURI" "" "-tls1_2" title PARA "Run test with TLS 1.2 and ECDH" run_test "$ECPRIURI" "$ECCRTURI" "" "-tls1_2 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 -groups secp256r1" +#Try again forcing all operations on the token +#We need to disable digest operations as OpenSSL depends on context duplication working +ORIG_OPENSSL_CONF=${OPENSSL_CONF} +sed -e "s/#MORECONF/alg_section = algorithm_sec\n\n[algorithm_sec]\ndefault_properties = ?provider=pkcs11/" \ + -e "s/#pkcs11-module-block-operations/pkcs11-module-block-operations = digest/" \ + "${OPENSSL_CONF}" > "${OPENSSL_CONF}.forcetoken" +OPENSSL_CONF=${OPENSSL_CONF}.forcetoken + +title PARA "Run test with TLS 1.3 preferring token functions" +run_test "$ECPRIURI" "$ECCRTURI" "" "-tls1_3" + +OPENSSL_CONF=${ORIG_OPENSSL_CONF} + + exit 0;