diff --git a/src/digests.c b/src/digests.c index 9ccbe725..632994ca 100644 --- a/src/digests.c +++ b/src/digests.c @@ -1,4 +1,5 @@ /* Copyright (C) 2022 Simo Sorce + Copyright 2026 NXP SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" @@ -8,57 +9,69 @@ /* General Digest Mapping functions */ static struct { CK_MECHANISM_TYPE digest; + CK_MECHANISM_TYPE hmac; size_t block_size; size_t digest_size; const char *names[5]; /* must give a size for initialization ... */ } digest_map[] = { { CKM_SHA_1, + CKM_SHA_1_HMAC, 64, 20, { "SHA1", "SHA-1", "SSL3-SHA1", "1.3.14.3.2.26", NULL } }, { CKM_SHA224, + CKM_SHA224_HMAC, 64, 28, { "SHA2-224", "SHA-224", "SHA224", "2.16.840.1.101.3.4.2.4", NULL } }, { CKM_SHA256, + CKM_SHA256_HMAC, 64, 32, { "SHA2-256", "SHA-256", "SHA256", "2.16.840.1.101.3.4.2.1", NULL } }, { CKM_SHA384, + CKM_SHA384_HMAC, 128, 48, { "SHA2-384", "SHA-384", "SHA384", "2.16.840.1.101.3.4.2.2", NULL } }, { CKM_SHA512, + CKM_SHA512_HMAC, 128, 64, { "SHA2-512", "SHA-512", "SHA512", "2.16.840.1.101.3.4.2.3", NULL } }, { CKM_SHA512_224, + CKM_SHA512_224_HMAC, 128, 28, { "SHA2-512/224", "SHA-512/224", "SHA512-224", "2.16.840.1.101.3.4.2.5", NULL } }, { CKM_SHA512_256, + CKM_SHA512_256_HMAC, 128, 32, { "SHA2-512/256", "SHA-512/256", "SHA512-256", "2.16.840.1.101.3.4.2.6", NULL } }, { CKM_SHA3_224, + CKM_SHA3_224_HMAC, (1600 - 224 * 2) / 8, 28, { "SHA3-224", "2.16.840.1.101.3.4.2.7", NULL } }, { CKM_SHA3_256, + CKM_SHA3_256_HMAC, (1600 - 256 * 2) / 8, 32, { "SHA3-256", "2.16.840.1.101.3.4.2.8", NULL } }, { CKM_SHA3_384, + CKM_SHA3_384_HMAC, (1600 - 384 * 2) / 8, 48, { "SHA3-384", "2.16.840.1.101.3.4.2.9", NULL } }, { CKM_SHA3_512, + CKM_SHA3_512_HMAC, (1600 - 512 * 2) / 8, 64, { "SHA3-512", "2.16.840.1.101.3.4.2.10", NULL } }, - { CK_UNAVAILABLE_INFORMATION, 0, 0, { NULL } }, + { CK_UNAVAILABLE_INFORMATION, CK_UNAVAILABLE_INFORMATION, 0, 0, { NULL } }, }; CK_RV p11prov_digest_get_block_size(CK_MECHANISM_TYPE digest, @@ -109,6 +122,29 @@ CK_RV p11prov_digest_get_by_name(const char *name, CK_MECHANISM_TYPE *digest) return CKR_MECHANISM_INVALID; } +CK_RV p11prov_digest_to_hmac(CK_MECHANISM_TYPE digest, CK_MECHANISM_TYPE *hmac) +{ + for (int i = 0; digest_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { + if (digest_map[i].digest == digest) { + *hmac = digest_map[i].hmac; + return CKR_OK; + } + } + return CKR_MECHANISM_INVALID; +} + +CK_RV p11prov_digest_from_hmac(CK_MECHANISM_TYPE hmac, + CK_MECHANISM_TYPE *digest) +{ + for (int i = 0; digest_map[i].hmac != CK_UNAVAILABLE_INFORMATION; i++) { + if (digest_map[i].hmac == hmac) { + *digest = digest_map[i].digest; + return CKR_OK; + } + } + return CKR_MECHANISM_INVALID; +} + struct p11prov_digest_ctx { P11PROV_CTX *provctx; CK_MECHANISM_TYPE mechtype; diff --git a/src/digests.h b/src/digests.h index a96b7a63..ba25f1d9 100644 --- a/src/digests.h +++ b/src/digests.h @@ -1,4 +1,5 @@ /* Copyright (C) 2022 Simo Sorce + Copyright 2026 NXP SPDX-License-Identifier: Apache-2.0 */ #ifndef _DIGESTS_H @@ -60,5 +61,7 @@ CK_RV p11prov_digest_get_digest_size(CK_MECHANISM_TYPE digest, size_t *digest_size); CK_RV p11prov_digest_get_name(CK_MECHANISM_TYPE digest, const char **name); CK_RV p11prov_digest_get_by_name(const char *name, CK_MECHANISM_TYPE *digest); - +CK_RV p11prov_digest_to_hmac(CK_MECHANISM_TYPE digest, CK_MECHANISM_TYPE *hmac); +CK_RV p11prov_digest_from_hmac(CK_MECHANISM_TYPE hmac, + CK_MECHANISM_TYPE *digest); #endif /* _DIGESTS_H */ diff --git a/src/mac.c b/src/mac.c new file mode 100644 index 00000000..178080b8 --- /dev/null +++ b/src/mac.c @@ -0,0 +1,351 @@ + +/* Copyright 2026 NXP + SPDX-License-Identifier: Apache-2.0 */ + +#include "provider.h" +#include + +#if SKEY_SUPPORT == 1 + +struct p11prov_mac_ctx { + P11PROV_CTX *provctx; + + P11PROV_OBJ *key; + P11PROV_SESSION *session; + + CK_MECHANISM_TYPE hmac; +}; + +typedef struct p11prov_mac_ctx P11PROV_MAC_CTX; + +static void *p11prov_mac_newctx(void *provctx) +{ + P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; + P11PROV_MAC_CTX *macctx; + + P11PROV_debug("mac newctx"); + + if (p11prov_ctx_status(ctx) != CKR_OK) { + return NULL; + } + + macctx = OPENSSL_zalloc(sizeof(*macctx)); + if (macctx == NULL) { + return NULL; + } + + macctx->provctx = ctx; + macctx->hmac = CK_UNAVAILABLE_INFORMATION; + + return macctx; +} + +static void p11prov_mac_freectx(void *ctx) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + + P11PROV_debug("mac freectx (ctx:%p)", ctx); + + p11prov_obj_free(macctx->key); + + if (macctx->session) { + p11prov_return_session(macctx->session); + } + + OPENSSL_clear_free(macctx, sizeof(*macctx)); +} + +static int p11prov_hmac_get_ctx_params(void *ctx, OSSL_PARAM params[]) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + OSSL_PARAM *p; + CK_RV rv; + size_t digest_size = 0; + size_t block_size = 0; + CK_MECHANISM_TYPE digest; + + P11PROV_debug("mac get ctx params (ctx=%p, params=%p)", macctx, params); + + if (params == NULL) { + return RET_OSSL_OK; + } + + rv = p11prov_digest_from_hmac(macctx->hmac, &digest); + if (rv != CKR_OK || digest == CK_UNAVAILABLE_INFORMATION) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC); + return RET_OSSL_ERR; + } + + p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE); + if (p) { + rv = p11prov_digest_get_digest_size(digest, &digest_size); + if (rv != CKR_OK || digest_size == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return RET_OSSL_ERR; + } + + OSSL_PARAM_set_size_t(p, digest_size); + } + + p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE); + if (p) { + rv = p11prov_digest_get_block_size(digest, &block_size); + if (rv != CKR_OK || block_size == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return RET_OSSL_ERR; + } + + OSSL_PARAM_set_size_t(p, block_size); + } + + return RET_OSSL_OK; +} + +static const OSSL_PARAM *p11prov_hmac_gettable_ctx_params(void *ctx, + void *provctx) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static CK_RV import_mac_key(P11PROV_MAC_CTX *macctx, const uint8_t *key, + size_t keylen, P11PROV_OBJ **keyobj) +{ + CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; + CK_RV rv; + + if (macctx->session == NULL) { + rv = p11prov_get_session(macctx->provctx, &slotid, NULL, NULL, + macctx->hmac, NULL, NULL, true, false, + &macctx->session); + if (rv != CKR_OK) { + return rv; + } + } + if (macctx->session == NULL) { + return CKR_SESSION_HANDLE_INVALID; + } + + *keyobj = p11prov_create_secret_key(macctx->provctx, macctx->session, true, + (unsigned char *)key, keylen); + if (*keyobj == NULL) { + return CKR_KEY_HANDLE_INVALID; + } + return CKR_OK; +} + +static int p11prov_hmac_set_ctx_params(void *ctx, const OSSL_PARAM params[]) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + const OSSL_PARAM *p; + int ret; + + P11PROV_debug("mac set ctx params (ctx=%p, params=%p)", macctx, params); + + p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_TLS_DATA_SIZE); + if (p) { + /* + * TLS_DATA_SIZE parameter should activate some special handling + * for TLS records that are mac-then-encrypt and have variable length + * padding (i.e. CBC ciphersuites). + * + * For now, just raise "not supported" error. + */ + P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, + "TLS_DATA_SIZE is not supported!"); + return RET_OSSL_ERR; + } + + p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_SIZE); + if (p) { + P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, + "TLS_DATA_SIZE is not supported!"); + return RET_OSSL_ERR; + } + + p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_DIGEST); + if (p) { + const char *digest_name = NULL; + CK_ULONG digest = CK_UNAVAILABLE_INFORMATION; + CK_RV rv; + + ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest_name); + if (ret != RET_OSSL_OK) { + return ret; + } + + rv = p11prov_digest_get_by_name(digest_name, &digest); + if (rv != CKR_OK) { + P11PROV_raise(ctx, rv, "Unknown digest"); + return RET_OSSL_ERR; + } + P11PROV_debug("set digest to %lu", digest); + + rv = p11prov_digest_to_hmac(digest, &macctx->hmac); + if (rv != CKR_OK || macctx->hmac == CK_UNAVAILABLE_INFORMATION) { + P11PROV_raise(ctx, rv, "No associated HMAC mechanism"); + return RET_OSSL_ERR; + } + + P11PROV_debug("set MAC to %lu", macctx->hmac); + } + + p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY); + if (p) { + const void *key = NULL; + size_t key_len; + CK_RV rv; + + ret = OSSL_PARAM_get_octet_string_ptr(p, &key, &key_len); + if (ret != RET_OSSL_OK) { + return ret; + } + + /* Create Session and key from key material */ + p11prov_obj_free(macctx->key); + rv = import_mac_key(macctx, key, key_len, &macctx->key); + if (rv != CKR_OK) { + return RET_OSSL_ERR; + } + P11PROV_debug("set key (len:%lu)", key_len); + } + + return RET_OSSL_OK; +} + +static const OSSL_PARAM *p11prov_hmac_settable_ctx_params(void *ctx, + void *provctx) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_TLS_DATA_SIZE, NULL), OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int p11prov_hmac_op_init(P11PROV_MAC_CTX *macctx, + const OSSL_PARAM params[]) +{ + P11PROV_debug("hmac op_init (ctx:%p, params:%p)", macctx, params); + CK_RV rv = CKR_OK; + CK_MECHANISM mech = { 0 }; + + if (!macctx->key) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return RET_OSSL_ERR; + } + + if (!macctx->session) { + rv = p11prov_try_session_ref(macctx->key, macctx->hmac, false, false, + &macctx->session); + } + if (rv != CKR_OK) { + P11PROV_raise(macctx->provctx, rv, "Failed to get session"); + return RET_OSSL_ERR; + } + + rv = p11prov_hmac_set_ctx_params(macctx, params); + if (rv != RET_OSSL_OK) { + P11PROV_raise(macctx->provctx, rv, "Invalid params"); + return RET_OSSL_ERR; + } + + mech.mechanism = macctx->hmac; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + rv = p11prov_SignInit(macctx->provctx, + p11prov_session_handle(macctx->session), &mech, + p11prov_obj_get_handle(macctx->key)); + if (rv != CKR_OK) { + return RET_OSSL_ERR; + } + + return RET_OSSL_OK; +} + +static int p11prov_hmac_legacy_init(void *ctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + CK_RV rv = CKR_OK; + + if (key) { + p11prov_obj_free(macctx->key); + + rv = import_mac_key(macctx, key, keylen, &macctx->key); + if (rv != CKR_OK) { + return RET_OSSL_ERR; + } + P11PROV_debug("set key (len:%lu)", keylen); + } + + return p11prov_hmac_op_init(macctx, params); +} + +static int p11prov_hmac_init_skey(void *ctx, void *keydata, + const OSSL_PARAM params[]) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + + if (keydata) { + macctx->key = p11prov_obj_ref((P11PROV_OBJ *)keydata); + } + + return p11prov_hmac_op_init(macctx, params); +} + +static int p11prov_hmac_update(void *ctx, const unsigned char *in, size_t inl) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + CK_RV rv = CKR_OK; + + rv = p11prov_SignUpdate(macctx->provctx, + p11prov_session_handle(macctx->session), + (CK_BYTE_PTR)in, inl); + if (rv != CKR_OK) { + return RET_OSSL_ERR; + } + + return RET_OSSL_OK; +} + +static int p11prov_hmac_final(void *ctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + P11PROV_MAC_CTX *macctx = (P11PROV_MAC_CTX *)ctx; + CK_RV rv = CKR_OK; + CK_ULONG siglen = outsize; + + rv = p11prov_SignFinal( + macctx->provctx, p11prov_session_handle(macctx->session), out, &siglen); + if (rv != CKR_OK) { + return RET_OSSL_ERR; + } + + *outl = siglen; + return RET_OSSL_OK; +} + +const OSSL_DISPATCH p11prov_hmac_mac_functions[] = { + DISPATCH_MAC_ELEM(mac, NEWCTX, newctx), + DISPATCH_MAC_ELEM(mac, FREECTX, freectx), + DISPATCH_MAC_ELEM(hmac, GET_CTX_PARAMS, get_ctx_params), + DISPATCH_MAC_ELEM(hmac, GETTABLE_CTX_PARAMS, gettable_ctx_params), + DISPATCH_MAC_ELEM(hmac, SET_CTX_PARAMS, set_ctx_params), + DISPATCH_MAC_ELEM(hmac, SETTABLE_CTX_PARAMS, settable_ctx_params), + DISPATCH_MAC_ELEM(hmac, INIT, legacy_init), +#ifdef OSSL_FUNC_MAC_INIT_SKEY + DISPATCH_MAC_ELEM(hmac, INIT_SKEY, init_skey), +#endif + DISPATCH_MAC_ELEM(hmac, UPDATE, update), + DISPATCH_MAC_ELEM(hmac, FINAL, final), + { 0, NULL }, +}; + +#endif diff --git a/src/mac.h b/src/mac.h new file mode 100644 index 00000000..03893006 --- /dev/null +++ b/src/mac.h @@ -0,0 +1,12 @@ +/* Copyright 2026 NXP + SPDX-License-Identifier: Apache-2.0 */ + +#ifndef _MAC_H +#define _MAC_H + +/* MAC fns */ +#define DISPATCH_MAC_ELEM(prefix, NAME, name) \ + { OSSL_FUNC_MAC_##NAME, (void (*)(void))p11prov_##prefix##_##name } +extern const OSSL_DISPATCH p11prov_hmac_mac_functions[]; + +#endif /* _MAC_H */ diff --git a/src/meson.build b/src/meson.build index 3237ca05..0ffad03a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -14,6 +14,7 @@ pkcs11_provider_sources = [ 'kmgmt/mldsa.c', 'kmgmt/mlkem.c', 'kmgmt/rsa.c', + 'mac.c', 'pk11_uri.c', 'interface.c', 'obj/create.c', diff --git a/src/obj/create.c b/src/obj/create.c index 89471a2a..fcdc2d3c 100644 --- a/src/obj/create.c +++ b/src/obj/create.c @@ -20,6 +20,7 @@ P11PROV_OBJ *p11prov_create_secret_key(P11PROV_CTX *provctx, { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, { CKA_TOKEN, &val_token, sizeof(val_token) }, { CKA_DERIVE, &val_true, sizeof(val_true) }, + { CKA_SIGN, &val_true, sizeof(val_true) }, { CKA_VALUE, (void *)secret, secretlen }, }; CK_ULONG tcount = sizeof(template) / sizeof(CK_ATTRIBUTE); diff --git a/src/provider.c b/src/provider.c index a2517b1c..947c8bd8 100644 --- a/src/provider.c +++ b/src/provider.c @@ -1,5 +1,5 @@ /* Copyright (C) 2022 Simo Sorce - Copyright 2025 NXP + Copyright 2025-2026 NXP SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" @@ -63,6 +63,7 @@ struct p11prov_ctx { #if SKEY_SUPPORT == 1 OSSL_ALGORITHM *op_cipher; OSSL_ALGORITHM *op_skeymgmt; + OSSL_ALGORITHM *op_mac; #endif pthread_rwlock_t quirk_lock; @@ -554,6 +555,7 @@ static void p11prov_ctx_free(P11PROV_CTX *ctx) #if SKEY_SUPPORT == 1 OPENSSL_free(ctx->op_cipher); OPENSSL_free(ctx->op_skeymgmt); + OPENSSL_free(ctx->op_mac); #endif OSSL_LIB_CTX_free(ctx->libctx); @@ -867,6 +869,11 @@ static CK_RV alg_set_op(OSSL_ALGORITHM **op, int idx, OSSL_ALGORITHM *alg) CKM_AES_OFB, CKM_AES_CFB8, CKM_AES_CFB128, CKM_AES_CFB1, CKM_AES_GCM #endif +#define HMAC(hash) CKM_##hash##_HMAC, CKM_##hash##_HMAC_GENERAL +#define HMAC_MECHS \ + HMAC(SHA_1), HMAC(SHA224), HMAC(SHA256), HMAC(SHA384), HMAC(SHA512), \ + HMAC(SHA3_224), HMAC(SHA3_256), HMAC(SHA3_384), HMAC(SHA3_512) + static void alg_rm_mechs(CK_ULONG *checklist, CK_ULONG *rmlist, int *clsize, int rmsize) { @@ -923,7 +930,8 @@ static CK_RV operations_init(P11PROV_CTX *ctx) CKM_EDDSA, PQC_MECHS, #if SKEY_SUPPORT == 1 - AES_MECHS + AES_MECHS, + HMAC_MECHS #endif }; bool add_rsasig = false; @@ -939,6 +947,7 @@ static CK_RV operations_init(P11PROV_CTX *ctx) int kem_idx = 0; #if SKEY_SUPPORT == 1 int cipher_idx = 0; + int mac_idx = 0; #endif int slot_idx = 0; const char *prop = get_default_properties(ctx); @@ -1301,6 +1310,27 @@ static CK_RV operations_init(P11PROV_CTX *ctx) ADD_ALGO(AES_128_GCM, aes128gcm, cipher, prop); UNCHECK_MECHS(CKM_AES_GCM); break; + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA3_224_HMAC: + case CKM_SHA3_224_HMAC_GENERAL: + case CKM_SHA3_256_HMAC: + case CKM_SHA3_256_HMAC_GENERAL: + case CKM_SHA3_384_HMAC: + case CKM_SHA3_384_HMAC_GENERAL: + case CKM_SHA3_512_HMAC: + case CKM_SHA3_512_HMAC_GENERAL: + ADD_ALGO(HMAC, hmac, mac, prop); + UNCHECK_MECHS(HMAC_MECHS); + break; #endif default: P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Unhandled mechanism %lu", @@ -1330,6 +1360,7 @@ static CK_RV operations_init(P11PROV_CTX *ctx) TERM_ALGO(kem); #if SKEY_SUPPORT == 1 TERM_ALGO(cipher); + TERM_ALGO(mac); #endif /* handle random */ @@ -1350,6 +1381,7 @@ static CK_RV static_operations_init(P11PROV_CTX *ctx) int keymgmt_idx = 0; #if SKEY_SUPPORT == 1 int skeymgmt_idx = 0; + int mac_idx = 0; #endif const char *prop = get_default_properties(ctx); @@ -1523,6 +1555,9 @@ static CK_RV static_operations_init(P11PROV_CTX *ctx) ADD_ALGO(AES, aes, skeymgmt, prop); ADD_ALGO(GENERIC_SECRET, generic_secret, skeymgmt, prop); TERM_ALGO(skeymgmt); + /* mac */ + ADD_ALGO(HMAC, hmac, mac, prop); + TERM_ALGO(mac); #endif return CKR_OK; @@ -1607,6 +1642,9 @@ p11prov_query_operation(void *provctx, int operation_id, int *no_cache) case OSSL_OP_SKEYMGMT: *no_cache = 0; return ctx->op_skeymgmt; + case OSSL_OP_MAC: + *no_cache = 0; + return ctx->op_mac; #endif } *no_cache = 0; diff --git a/src/provider.h b/src/provider.h index e020204b..2a6bb008 100644 --- a/src/provider.h +++ b/src/provider.h @@ -1,5 +1,5 @@ /* Copyright (C) 2022 Simo Sorce - Copyright 2025 NXP + Copyright 2025-2026 NXP SPDX-License-Identifier: Apache-2.0 */ #ifndef _PROVIDER_H @@ -237,6 +237,8 @@ #define P11PROV_NAME_GENERIC_SECRET "GENERIC-SECRET" #define P11PROV_NAMES_GENERIC_SECRET P11PROV_NAME_GENERIC_SECRET #define P11PROV_DESCS_GENERIC_SECRET "PKCS11 Generic Secret Implementation" +#define P11PROV_NAMES_HMAC "HMAC" +#define P11PROV_DESCS_HMAC "PKCS11 HMAC Implementation" #endif @@ -340,6 +342,7 @@ int p11prov_pop_error_to_mark(P11PROV_CTX *ctx); #if SKEY_SUPPORT == 1 #include "cipher.h" #include "kmgmt/skey.h" +#include "mac.h" #endif /* TLS */ diff --git a/tests/meson.build b/tests/meson.build index 2e4a91ac..384748e4 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -117,6 +117,7 @@ test_programs = { 'tecx': ['tecx.c', 'util.c'], 'tskey-kdf': ['tskey_kdf.c', 'util.c'], 'taead': ['taead.c', 'util.c'], + 'tskey-mac': ['tskey_mac.c', 'util.c'], } test_executables = [] diff --git a/tests/tskey b/tests/tskey index c8e98f10..0f4c7ef5 100755 --- a/tests/tskey +++ b/tests/tskey @@ -162,6 +162,17 @@ if [ $FAIL -ne 0 ]; then exit 1 fi +title PARA "Test Skey MAC" +FAIL=0 +output=$($CHECKER "${TESTBLDDIR}"/tskey-mac 2>&1) || FAIL=1 +if [ $FAIL -ne 0 ]; then + echo + echo "Original command output:" + echo "$output" + echo + exit 1 +fi + OPENSSL_CONF=${ORIG_OPENSSL_CONF} exit 0 diff --git a/tests/tskey_mac.c b/tests/tskey_mac.c new file mode 100644 index 00000000..2c6bf81e --- /dev/null +++ b/tests/tskey_mac.c @@ -0,0 +1,167 @@ +/* Copyright 2026 NXP + SPDX-License-Identifier: Apache-2.0 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +#if defined(OSSL_FUNC_MAC_INIT_SKEY) + +struct hmac_test_vector { + const char *name; + const char *digest; + const unsigned char *ikm; + size_t ikm_len; + const unsigned char *input; + size_t input_len; + + const unsigned char *expected; + size_t out_len; +}; + +static const unsigned char ikm_tc1[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, +}; + +static const unsigned char input_tc1[] = { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, +}; + +unsigned char expected_sha224[] = { + 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, 0x68, 0x32, + 0x10, 0x7c, 0xd4, 0x9d, 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, + 0x99, 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22, +}; + +static const unsigned char expected_sha256[] = { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, + 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, + 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 +}; + +static const unsigned char expected_sha384[] = { + 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4, + 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9, + 0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 +}; + +static const unsigned char expected_sha512[] = { + 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, + 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, + 0xc2, 0x78, 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, + 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, 0x03, 0x8b, 0x27, 0x4e, + 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, + 0x70, 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 +}; + +static struct hmac_test_vector hmac_tests[] = { + { "HMAC", "SHA224", ikm_tc1, sizeof(ikm_tc1), input_tc1, sizeof(input_tc1), + expected_sha224 }, + { "HMAC", "SHA256", ikm_tc1, sizeof(ikm_tc1), input_tc1, sizeof(input_tc1), + expected_sha256 }, + { "HMAC", "SHA384", ikm_tc1, sizeof(ikm_tc1), input_tc1, sizeof(input_tc1), + expected_sha384 }, + { "HMAC", "SHA512", ikm_tc1, sizeof(ikm_tc1), input_tc1, sizeof(input_tc1), + expected_sha512 }, +}; + +static int test_mac_sign(struct hmac_test_vector *tv, bool skey) +{ + EVP_MAC *mac = NULL; + EVP_MAC_CTX *mctx = NULL; + EVP_SKEY *skey_obj = NULL; + int status = EXIT_FAILURE; + + unsigned char output[EVP_MAX_MD_SIZE] = { 0 }; + + mac = EVP_MAC_fetch(NULL, tv->name, "provider=pkcs11"); + if (!mac) { + fprintf(stderr, "EVP_MAC_fetch() failed\n"); + goto end; + } + mctx = EVP_MAC_CTX_new(mac); + if (!mctx) { + fprintf(stderr, "EVP_MAC_CTX_new() failed\n"); + goto end; + } + + OSSL_PARAM params[] = { OSSL_PARAM_construct_utf8_string( + OSSL_MAC_PARAM_DIGEST, (char *)tv->digest, 0), + OSSL_PARAM_construct_end() }; + + if (skey) { + skey_obj = EVP_SKEY_import_raw_key(NULL, "GENERIC-SECRET", + (unsigned char *)tv->ikm, + tv->ikm_len, "provider=pkcs11"); + if (!skey_obj) { + fprintf(stderr, "EVP_SKEY_import_raw_key failed!\n"); + goto end; + } + if (!EVP_MAC_init_SKEY(mctx, skey_obj, params)) { + fprintf(stderr, "EVP_MAC_init_SKEY() failed\n"); + goto end; + }; + } else { + if (!EVP_MAC_init(mctx, tv->ikm, tv->ikm_len, params)) { + fprintf(stderr, "EVP_MAC_init() failed\n"); + goto end; + }; + } + + if (!EVP_MAC_update(mctx, tv->input, tv->input_len) + || !EVP_MAC_final(mctx, output, &tv->out_len, sizeof(output))) { + fprintf(stderr, "EVP_MAC_update/final() failed\n"); + goto end; + } + + if (memcmp(output, tv->expected, tv->out_len) != 0) { + fprintf(stderr, "Output mismatch for %s %s!\n", tv->name, tv->digest); + goto end; + } + + fprintf(stderr, "test_mac_sign %s: OK!\n", (skey) ? "SKEY" : "Legacy"); + status = EXIT_SUCCESS; + +end: + if (skey_obj) { + EVP_SKEY_free(skey_obj); + } + if (mctx) { + EVP_MAC_CTX_free(mctx); + } + if (mac) { + EVP_MAC_free(mac); + } + + return status; +} +#endif + +int main(int argc, char *argv[]) +{ + int status = EXIT_SUCCESS; + +#if defined(OSSL_FUNC_MAC_INIT_SKEY) + for (size_t i = 0; i < sizeof(hmac_tests) / sizeof(hmac_tests[0]); i++) { + status = test_mac_sign(&hmac_tests[i], true); + if (status == EXIT_FAILURE) { + return status; + } + status = test_mac_sign(&hmac_tests[i], false); + if (status == EXIT_FAILURE) { + return status; + } + } +#endif + + return status; +}