From 49ce634ed6fa1fddc2bb34fd0f89c0ea0cc368ee Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Tue, 1 Mar 2022 09:15:15 +0100 Subject: [PATCH 25/34] COMMON/EP11: Add Kyber key type and mechanism Kyber requires an EP11 host library of version 4.0 or later, and a CEX8P crypto card. Signed-off-by: Ingo Franzki --- usr/lib/api/mechtable.inc | 1 + usr/lib/api/policy.c | 2 + usr/lib/common/asn1.c | 563 +++++++++++++++++++++++++++++++++++ usr/lib/common/h_extern.h | 59 ++++ usr/lib/common/key.c | 476 +++++++++++++++++++++++++++++ usr/lib/common/key_mgr.c | 10 + usr/lib/common/mech_ec.c | 3 + usr/lib/common/template.c | 12 + usr/lib/ep11_stdll/ep11_specific.c | 42 ++- usr/lib/ep11_stdll/ep11cpfilter.conf | 2 +- 10 files changed, 1167 insertions(+), 3 deletions(-) diff --git a/usr/lib/api/mechtable.inc b/usr/lib/api/mechtable.inc index e3d14e3e..7aa72fbf 100644 --- a/usr/lib/api/mechtable.inc +++ b/usr/lib/api/mechtable.inc @@ -84,6 +84,7 @@ const struct mechrow mechtable_rows[] = { "CKM_IBM_EC_X448", CKM_IBM_EC_X448, 0, MC_INFORMATION_UNAVAILABLE, MCF_DERIVE }, { "CKM_IBM_ED25519_SHA512", CKM_IBM_ED25519_SHA512, 128, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, { "CKM_IBM_ED448_SHA3", CKM_IBM_ED448_SHA3, 144, MC_KEY_DEPENDENT, MCF_SIGNVERIFY }, + { "CKM_IBM_KYBER", CKM_IBM_KYBER, 0, MC_KEY_DEPENDENT, MCF_KEYGEN | MCF_ENCRYPTDECRYPT | MCF_DERIVE | MCF_NEEDSPARAM}, { "CKM_IBM_SHA3_224", CKM_IBM_SHA3_224, 144, 24, MCF_DIGEST }, { "CKM_IBM_SHA3_224_HMAC", CKM_IBM_SHA3_224_HMAC, 144, 24, MCF_SIGNVERIFY }, { "CKM_IBM_SHA3_256", CKM_IBM_SHA3_256, 136, 32, MCF_DIGEST }, diff --git a/usr/lib/api/policy.c b/usr/lib/api/policy.c index 4bee5180..b513a8a9 100644 --- a/usr/lib/api/policy.c +++ b/usr/lib/api/policy.c @@ -333,6 +333,7 @@ static CK_RV policy_extract_key_data(get_attr_val_f getattr, void *d, *comptarget = COMPARE_SYMMETRIC; break; case CKK_IBM_PQC_DILITHIUM: + case CKK_IBM_PQC_KYBER: rv = policy_get_pqc_args(*(CK_ULONG *)keytype->pValue, getattr, d, free_attr, size, siglen, oid, oidlen); *comptarget = COMPARE_PQC; @@ -1062,6 +1063,7 @@ static CK_RV policy_update_mech_info(policy_t p, CK_MECHANISM_TYPE mech, } break; case CKM_IBM_DILITHIUM: + case CKM_IBM_KYBER: break; case CKM_IBM_SHA3_224: case CKM_IBM_SHA3_256: diff --git a/usr/lib/common/asn1.c b/usr/lib/common/asn1.c index 85d3924c..87cc5dfc 100644 --- a/usr/lib/common/asn1.c +++ b/usr/lib/common/asn1.c @@ -4384,3 +4384,566 @@ cleanup: return rc; } + +/** + * An IBM Kyber public key is given by: + * + * SEQUENCE (2 elem) + * SEQUENCE (2 elem) + * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.5.xxx + * NULL + * BIT STRING (1 elem) + * SEQUENCE (1 elem) + * pk BIT STRING -- public key + */ +CK_RV ber_encode_IBM_KyberPublicKey(CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len, + const CK_BYTE *oid, CK_ULONG oid_len, + CK_ATTRIBUTE *pk) +{ + CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL, *buf4 = NULL; + CK_BYTE *buf5 = NULL, *algid = NULL; + CK_ULONG len, len4, offset, total, total_len, algid_len; + CK_RV rc; + + UNUSED(length_only); + + offset = 0; + rc = 0; + total_len = 0; + total = 0; + + /* Calculate storage for AlgID sequence */ + rc |= ber_encode_SEQUENCE(TRUE, NULL, &total_len, NULL, + oid_len + ber_NULLLen); + + /* Calculate storage for inner sequence */ + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, pk->ulValueLen); + offset += len; + + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + /* Allocate storage for inner sequence */ + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + /** + * SEQUENCE (1 elem) + * BIT STRING -> pk + */ + offset = 0; + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + pk->pValue, pk->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + goto error; + } + free(buf); + buf = NULL; + + /* Calculate length of outer sequence */ + rc = ber_encode_BIT_STRING(TRUE, NULL, &total, buf2, len, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Oct_Str failed with rc=0x%lx\n", __func__, rc); + goto error; + } else { + total_len += total; + } + + /* Allocate storage for outer sequence and bit string */ + buf3 = (CK_BYTE *) malloc(total_len); + if (!buf3) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + rc = CKR_HOST_MEMORY; + goto error; + } + + /* + * SEQUENCE (2 elem) + * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.5.xxx + * NULL <- no parms for this oid + */ + buf5 = (CK_BYTE *) malloc(oid_len + ber_NULLLen); + if (!buf5) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + rc = CKR_HOST_MEMORY; + goto error; + } + memcpy(buf5, oid, oid_len); + memcpy(buf5 + oid_len, ber_NULL, ber_NULLLen); + + rc = ber_encode_SEQUENCE(FALSE, &algid, &algid_len, buf5, + oid_len + ber_NULLLen); + free(buf5); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + total_len = algid_len; + memcpy(buf3, algid, algid_len); + free(algid); + algid = NULL; + + /* + * BIT STRING (1 elem) + * SEQUENCE (1 elem) + * BIT STRING -> pk + */ + rc = ber_encode_BIT_STRING(FALSE, &buf4, &len4, buf2, len, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); + goto error; + } + memcpy(buf3 + total_len, buf4, len4); + total_len += len4; + free(buf4); + buf4 = NULL; + + /** + * SEQUENCE (2 elem) + * SEQUENCE (2 elem) + * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.5.xxx + * NULL -> no parms for this oid + * BIT STRING (1 elem) + * SEQUENCE (2 elem) + * BIT STRING -> pk + */ + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf3, total_len); + if (rc != CKR_OK) + TRACE_ERROR("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + +error: + + if (buf) + free(buf); + if (buf2) + free(buf2); + if (buf3) + free(buf3); + + return rc; +} + +CK_RV ber_decode_IBM_KyberPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **pk_attr, + CK_ATTRIBUTE **value_attr, + const struct pqc_oid **oid) +{ + CK_ATTRIBUTE *pk_attr_temp = NULL; + CK_ATTRIBUTE *value_attr_temp = NULL; + + CK_BYTE *algoid = NULL; + CK_ULONG algoid_len; + CK_BYTE *param = NULL; + CK_ULONG param_len; + CK_BYTE *val = NULL; + CK_ULONG val_len; + CK_BYTE *seq; + CK_ULONG seq_len; + CK_BYTE *pk; + CK_ULONG pk_len; + CK_ULONG field_len, raw_spki_len; + CK_RV rc; + + UNUSED(data_len); // XXX can this parameter be removed ? + + rc = ber_decode_SPKI(data, &algoid, &algoid_len, ¶m, ¶m_len, + &val, &val_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SPKI failed\n"); + return rc; + } + + *oid = find_pqc_by_oid(kyber_oids, algoid, algoid_len); + if (*oid == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + /* Decode sequence: + * SEQUENCE (1 elem) + * BIT STRING = pk + */ + rc = ber_decode_SEQUENCE(val, &seq, &seq_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + /* Decode pk */ + rc = ber_decode_BIT_STRING(seq, &pk, &pk_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + pk++; /* Remove unused-bits byte */ + pk_len--; + + /* Build pk attribute */ + rc = build_attribute(CKA_IBM_KYBER_PK, pk, pk_len, &pk_attr_temp); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + /* Add raw SPKI as CKA_VALUE to public key (z/OS ICSF compatibility) */ + rc = ber_decode_SEQUENCE(data, &val, &val_len, &raw_spki_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); + goto cleanup; + } + rc = build_attribute(CKA_VALUE, data, raw_spki_len, &value_attr_temp); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + *pk_attr = pk_attr_temp; + *value_attr = value_attr_temp; + + return CKR_OK; + +cleanup: + if (pk_attr_temp) + free(pk_attr_temp); + if (value_attr_temp) + free(value_attr_temp); + + return rc; +} + +/** + * An IBM Kyber private key is given by: + * + * KyberPrivateKey ::= SEQUENCE { + * version INTEGER, -- v0, reserved 0 + * sk BIT STRING, -- private key + * pk [0] IMPLICIT OPTIONAL { + * pk||rs BIT STRING -- public key (pk) concatenated with 2x32 bytes rs + * } + * } + */ +CK_RV ber_encode_IBM_KyberPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + const CK_BYTE *oid, CK_ULONG oid_len, + CK_ATTRIBUTE *sk, + CK_ATTRIBUTE *pk) +{ + CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL; + CK_BYTE *algid = NULL, *algid_buf = NULL, *pk_rs = NULL; + CK_ULONG len, len2 = 0, offset, algid_len = 0; + CK_BYTE version[] = { 0 }; + CK_RV rc; + + /* Calculate storage for sequence */ + offset = 0; + rc = 0; + + rc |= ber_encode_SEQUENCE(TRUE, NULL, &algid_len, NULL, + oid_len + ber_NULLLen); + + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); + offset += len; + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, sk->ulValueLen, 0); + offset += len; + if (pk) { + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len2, NULL, + pk->ulValueLen + 64, 0); + rc |= ber_encode_CHOICE(TRUE, 0, NULL, &len, NULL, len2); + offset += len; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("Calculate storage for sequence failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + rc = ber_encode_PrivateKeyInfo(TRUE, + NULL, data_len, + NULL, algid_len, + NULL, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + return rc; + } + return rc; + } + + /* Allocate storage for sequence */ + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + offset = 0; + + /* Version */ + rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_INTEGER of version failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* sk */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + sk->pValue, sk->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of sk failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* (pk) Optional bit-string of public key */ + if (pk && pk->pValue) { + /* append rs to public key */ + pk_rs = (CK_BYTE *)malloc(pk->ulValueLen + 64); + if (!pk_rs) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + + memcpy(pk_rs, pk->pValue, pk->ulValueLen); + memset(pk_rs + pk->ulValueLen, 0x30, 64); + + rc = ber_encode_BIT_STRING(FALSE, &buf3, &len2, + pk_rs, pk->ulValueLen + 64, 0); + rc |= ber_encode_CHOICE(FALSE, 0, &buf2, &len, buf3, len2); + if (rc != CKR_OK) { + TRACE_ERROR("encoding of pk value failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + /* Encode sequence */ + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_SEQUENCE failed\n"); + goto error; + } + + algid_buf = (CK_BYTE *) malloc(oid_len + ber_NULLLen); + if (!algid_buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + rc = CKR_HOST_MEMORY; + goto error; + } + memcpy(algid_buf, oid, oid_len); + memcpy(algid_buf + oid_len, ber_NULL, ber_NULLLen); + + rc = ber_encode_SEQUENCE(FALSE, &algid, &algid_len, algid_buf, + oid_len + ber_NULLLen); + free(algid_buf); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = ber_encode_PrivateKeyInfo(FALSE, + data, data_len, + algid, algid_len, + buf2, len); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); + } + +error: + if (buf3) + free(buf3); + if (buf2) + free(buf2); + if (buf) + free(buf); + if (algid) + free(algid); + if (pk_rs) + free(pk_rs); + + return rc; +} + +/** + * decode an IBM Kyber private key: + * + * KyberPrivateKey ::= SEQUENCE { + * version INTEGER, -- v0, reserved 0 + * sk BIT STRING, -- private key + * pk [0] IMPLICIT OPTIONAL { + * pk||rs BIT STRING -- public key (pk) concatenated with 2x32 bytes rs + * } + * } + */ +CK_RV ber_decode_IBM_KyberPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **sk, + CK_ATTRIBUTE **pk, + CK_ATTRIBUTE **value, + const struct pqc_oid **oid) +{ + CK_ATTRIBUTE *sk_attr = NULL, *pk_attr = NULL, *value_attr = NULL; + CK_BYTE *algoid = NULL; + CK_BYTE *kyber_priv_key = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *tmp = NULL; + CK_ULONG offset, buf_len, field_len, len, option; + CK_RV rc; + + /* Check if this is a Kyber private key */ + rc = ber_decode_PrivateKeyInfo(data, data_len, &algoid, &len, + &kyber_priv_key); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); + return rc; + } + + if (len <= ber_NULLLen || + memcmp(algoid + len - ber_NULLLen, ber_NULL, ber_NULLLen) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + len -= ber_NULLLen; + *oid = find_pqc_by_oid(kyber_oids, algoid, len); + if (*oid == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + /* Decode private Kyber key */ + rc = ber_decode_SEQUENCE(kyber_priv_key, &buf, &buf_len, &field_len); + if (rc != CKR_OK) + return rc; + + /* Now build the attributes */ + offset = 0; + + /* Skip the version */ + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + /* sk */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (sk) failed\n"); + goto cleanup; + } else { + tmp++; /* Remove unused-bits byte */ + len--; + rc = build_attribute(CKA_IBM_KYBER_SK, tmp, len, &sk_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (sk) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* pk (optional, within choice) */ + if (offset < buf_len) { + rc = ber_decode_CHOICE(buf + offset, &tmp, &len, &field_len, &option); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (t1) failed\n"); + goto cleanup; + } + + if (option != 0x00) { + TRACE_DEVEL("ber_decode_CHOICE returned invalid option %ld\n", + option); + goto cleanup; + } + + offset += field_len - len; + + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (pk) failed\n"); + goto cleanup; + } + tmp++; /* Remove unused-bits byte */ + len--; + + if (len > 64) + len -= 64; /* Remove 'rs' */ + + rc = build_attribute(CKA_IBM_KYBER_PK, tmp, len, &pk_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (pk) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* Check if buffer big enough */ + if (offset > buf_len) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto cleanup; + } + + /* Add private key as CKA_VALUE to public key (z/OS ICSF compatibility) */ + rc = ber_decode_SEQUENCE(data, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode_SEQUENCE failed with rc=0x%lx\n", __func__, rc); + goto cleanup; + } + rc = build_attribute(CKA_VALUE, data, field_len, &value_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (t1) failed\n"); + goto cleanup; + } + + *sk = sk_attr; + *pk = pk_attr; + *value = value_attr; + + return CKR_OK; + +cleanup: + + if (sk_attr) + free(sk_attr); + if (pk_attr) + free(pk_attr); + if (value_attr) + free(value_attr); + + return rc; +} + diff --git a/usr/lib/common/h_extern.h b/usr/lib/common/h_extern.h index fdbcacd9..ee1ae08d 100644 --- a/usr/lib/common/h_extern.h +++ b/usr/lib/common/h_extern.h @@ -2505,6 +2505,40 @@ CK_RV ibm_dilithium_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_RV ibm_dilithium_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length, CK_BBOOL add_value); + +// Kyber routines +// +CK_RV ibm_kyber_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_kyber_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_kyber_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV ibm_kyber_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV ibm_kyber_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_kyber_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_kyber_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV ibm_kyber_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV ibm_kyber_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG total_length, CK_BBOOL add_value); +CK_RV ibm_kyber_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length, + CK_BBOOL add_value); + +// PQC helper routines +// +CK_RV ibm_pqc_publ_get_spki(TEMPLATE *tmpl, CK_KEY_TYPE keytype, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV ibm_pqc_priv_wrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV ibm_pqc_priv_unwrap(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data, + CK_ULONG total_length, CK_BBOOL add_value); +CK_RV ibm_pqc_priv_unwrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, + CK_BYTE *data, CK_ULONG total_length, + CK_BBOOL add_value); const struct pqc_oid *ibm_pqc_get_keyform_mode(TEMPLATE *tmpl, CK_MECHANISM_TYPE mech); CK_RV ibm_pqc_add_keyform_mode(TEMPLATE *tmpl, const struct pqc_oid *oid, @@ -2782,6 +2816,31 @@ CK_RV ber_decode_IBM_DilithiumPrivateKey(CK_BYTE *data, CK_ATTRIBUTE **value, const struct pqc_oid **oid); +CK_RV ber_encode_IBM_KyberPublicKey(CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len, + const CK_BYTE *oid, CK_ULONG oid_len, + CK_ATTRIBUTE *pk); + +CK_RV ber_decode_IBM_KyberPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **pk_attr, + CK_ATTRIBUTE **value_attr, + const struct pqc_oid **oid); + +CK_RV ber_encode_IBM_KyberPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + const CK_BYTE *oid, CK_ULONG oid_len, + CK_ATTRIBUTE *sk, + CK_ATTRIBUTE *pk); + +CK_RV ber_decode_IBM_KyberPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **sk, + CK_ATTRIBUTE **pk, + CK_ATTRIBUTE **value, + const struct pqc_oid **oid); + typedef CK_RV (*t_rsa_encrypt)(STDLL_TokData_t *, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj); diff --git a/usr/lib/common/key.c b/usr/lib/common/key.c index ba40cefd..ef329452 100644 --- a/usr/lib/common/key.c +++ b/usr/lib/common/key.c @@ -722,6 +722,9 @@ CK_RV publ_key_get_spki(TEMPLATE *tmpl, CK_ULONG keytype, CK_BBOOL length_only, case CKK_IBM_PQC_DILITHIUM: rc = ibm_dilithium_publ_get_spki(tmpl, length_only, data, data_len); break; + case CKK_IBM_PQC_KYBER: + rc = ibm_kyber_publ_get_spki(tmpl, length_only, data, data_len); + break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; @@ -1053,6 +1056,9 @@ CK_RV priv_key_unwrap(TEMPLATE *tmpl, case CKK_IBM_PQC_DILITHIUM: rc = ibm_dilithium_priv_unwrap(tmpl, data, data_len, TRUE); break; + case CKK_IBM_PQC_KYBER: + rc = ibm_kyber_priv_unwrap(tmpl, data, data_len, TRUE); + break; default: TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID)); return CKR_WRAPPED_KEY_INVALID; @@ -3030,6 +3036,240 @@ error: return rc; } +/* + * Extract the SubjectPublicKeyInfo from the Kyber public key + */ +CK_RV ibm_kyber_publ_get_spki(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *pk = NULL; + const struct pqc_oid *oid; + CK_RV rc; + + oid = ibm_pqc_get_keyform_mode(tmpl, CKM_IBM_KYBER); + if (oid == NULL) + return CKR_TEMPLATE_INCOMPLETE; + + rc = template_attribute_get_non_empty(tmpl, CKA_IBM_KYBER_PK, &pk); + if (rc != CKR_OK) { + TRACE_ERROR("Could not find CKA_IBM_KYBER_PK for the key.\n"); + return rc; + } + + rc = ber_encode_IBM_KyberPublicKey(length_only, data, data_len, + oid->oid, oid->oid_len, pk); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_IBM_KyberPublicKey failed.\n"); + return rc; + } + + return CKR_OK; +} + + +CK_RV ibm_kyber_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *sk = NULL, *pk = NULL; + const struct pqc_oid *oid; + CK_RV rc; + + oid = ibm_pqc_get_keyform_mode(tmpl, CKM_IBM_KYBER); + if (oid == NULL) + return CKR_TEMPLATE_INCOMPLETE; + + rc = template_attribute_get_non_empty(tmpl, CKA_IBM_KYBER_SK, &sk); + if (rc != CKR_OK) { + TRACE_ERROR("Could not find CKA_IBM_KYBER_SK for the key.\n"); + return rc; + } + + rc = template_attribute_get_non_empty(tmpl, CKA_IBM_KYBER_PK, &pk); + if (rc != CKR_OK) { + TRACE_ERROR("Could not find CKA_IBM_KYBER_PK for the key.\n"); + return rc; + } + + rc = ber_encode_IBM_KyberPrivateKey(length_only, data, data_len, + oid->oid, oid->oid_len, sk, pk); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_IBM_KyberPrivateKey failed\n"); + } + + return rc; +} + +CK_RV ibm_kyber_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG total_length, + CK_BBOOL add_value) +{ + CK_ATTRIBUTE *pk = NULL; + CK_ATTRIBUTE *value = NULL; + const struct pqc_oid *oid; + CK_RV rc; + + rc = ber_decode_IBM_KyberPublicKey(data, total_length, &pk, + &value, &oid); + if (rc != CKR_OK) { + TRACE_ERROR("ber_decode_IBM_KyberPublicKey failed\n"); + return rc; + } + + rc = ibm_pqc_add_keyform_mode(tmpl, oid, CKM_IBM_KYBER); + if (rc != CKR_OK) { + TRACE_ERROR("ibm_pqc_add_keyform_mode failed\n"); + return rc; + } + + rc = template_update_attribute(tmpl, pk); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute failed.\n"); + goto error; + } + pk = NULL; + if (add_value) { + rc = template_update_attribute(tmpl, value); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute failed.\n"); + goto error; + } + } else { + free(value); + } + value = NULL; + + return CKR_OK; + +error: + if (pk) + free(pk); + if (value) + free(value); + + return rc; +} + +// +// +CK_RV ibm_kyber_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG total_length, CK_BBOOL add_value) +{ + CK_ATTRIBUTE *sk = NULL, *pk = NULL, *value = NULL; + const struct pqc_oid *oid; + CK_RV rc; + + rc = ber_decode_IBM_KyberPrivateKey(data, total_length, + &sk, &pk, &value, &oid); + if (rc != CKR_OK) { + TRACE_ERROR("ber_decode_IBM_KyberPrivateKey failed\n"); + return rc; + } + + rc = ibm_pqc_add_keyform_mode(tmpl, oid, CKM_IBM_KYBER); + if (rc != CKR_OK) { + TRACE_ERROR("ibm_pqc_add_keyform_mode failed\n"); + return rc; + } + + rc = template_update_attribute(tmpl, sk); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + sk = NULL; + rc = template_update_attribute(tmpl, pk); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + pk = NULL; + if (add_value) { + rc = template_update_attribute(tmpl, value); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute failed.\n"); + goto error; + } + } else { + free(value); + } + value = NULL; + + return CKR_OK; + +error: + if (sk) + free(sk); + if (pk) + free(pk); + if (value) + free(value); + + return rc; +} + +CK_RV ibm_pqc_publ_get_spki(TEMPLATE *tmpl, CK_KEY_TYPE keytype, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + switch (keytype) { + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_publ_get_spki(tmpl, length_only, data, data_len); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_publ_get_spki(tmpl, length_only, data, data_len); + default: + TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); + return CKR_KEY_TYPE_INCONSISTENT; + } +} + +CK_RV ibm_pqc_priv_wrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + switch (keytype) { + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_priv_wrap_get_data(tmpl, length_only, data, + data_len); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_priv_wrap_get_data(tmpl, length_only, data, data_len); + default: + TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); + return CKR_KEY_TYPE_INCONSISTENT; + } +} + +CK_RV ibm_pqc_priv_unwrap(TEMPLATE *tmpl, CK_KEY_TYPE keytype, CK_BYTE *data, + CK_ULONG total_length, CK_BBOOL add_value) +{ + switch (keytype) { + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_priv_unwrap(tmpl, data, total_length, add_value); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_priv_unwrap(tmpl, data, total_length, add_value); + default: + TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); + return CKR_KEY_TYPE_INCONSISTENT; + } +} + +CK_RV ibm_pqc_priv_unwrap_get_data(TEMPLATE *tmpl, CK_KEY_TYPE keytype, + CK_BYTE *data, CK_ULONG total_length, + CK_BBOOL add_value) +{ + switch (keytype) { + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_priv_unwrap_get_data(tmpl, data, total_length, + add_value); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_priv_unwrap_get_data(tmpl, data, total_length, + add_value); + default: + TRACE_DEVEL("Key type 0x%lx not supported.\n", keytype); + return CKR_KEY_TYPE_INCONSISTENT; + } +} + // dsa_publ_check_required_attributes() // CK_RV dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) @@ -4987,6 +5227,152 @@ error: return rc; } +// ibm_dilithium_publ_set_default_attributes() +// +CK_RV ibm_kyber_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *type_attr = NULL; + CK_ATTRIBUTE *pk_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_RV rc; + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + pk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !pk_attr ||!value_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_IBM_PQC_KYBER; + + pk_attr->type = CKA_IBM_KYBER_PK; + pk_attr->ulValueLen = 0; + pk_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + rc = template_update_attribute(tmpl, type_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + type_attr = NULL; + rc = template_update_attribute(tmpl, pk_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + pk_attr = NULL; + rc = template_update_attribute(tmpl, value_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + value_attr = NULL; + + return CKR_OK; + +error: + if (type_attr) + free(type_attr); + if (pk_attr) + free(pk_attr); + if (value_attr) + free(value_attr); + + return rc; +} + +// ibm_dilithium_priv_set_default_attributes() +// +CK_RV ibm_kyber_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *type_attr = NULL; + CK_ATTRIBUTE *sk_attr = NULL; + CK_ATTRIBUTE *pk_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_RV rc; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + sk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + pk_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !sk_attr || !pk_attr || !value_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_IBM_PQC_KYBER; + + sk_attr->type = CKA_IBM_KYBER_SK; + sk_attr->ulValueLen = 0; + sk_attr->pValue = NULL; + + pk_attr->type = CKA_IBM_KYBER_PK; + pk_attr->ulValueLen = 0; + pk_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + rc = template_update_attribute(tmpl, type_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + type_attr = NULL; + rc = template_update_attribute(tmpl, sk_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + sk_attr = NULL; + rc = template_update_attribute(tmpl, pk_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + pk_attr = NULL; + rc = template_update_attribute(tmpl, value_attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto error; + } + value_attr = NULL; + + return CKR_OK; + +error: + if (type_attr) + free(type_attr); + if (sk_attr) + free(sk_attr); + if (pk_attr) + free(pk_attr); + if (value_attr) + free(value_attr); + + return rc; +} + static CK_RV ibm_pqc_check_attributes(TEMPLATE *tmpl, CK_ULONG mode, CK_MECHANISM_TYPE mech, CK_ULONG *req_attrs, @@ -5122,6 +5508,43 @@ CK_RV ibm_dilithium_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode return priv_key_check_required_attributes(tmpl, mode); } +// ibm_kyber_publ_check_required_attributes() +// +CK_RV ibm_kyber_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + static CK_ULONG req_attrs[] = { + CKA_IBM_KYBER_PK, + }; + CK_RV rc; + + rc = ibm_pqc_check_attributes(tmpl, mode, CKM_IBM_KYBER, req_attrs, + sizeof(req_attrs) / sizeof(req_attrs[0])); + if (rc != CKR_OK) + return rc; + + /* All required attrs found, check them */ + return publ_key_check_required_attributes(tmpl, mode); +} + +// ibm_kyber_priv_check_required_attributes() +// +CK_RV ibm_kyber_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + static CK_ULONG req_attrs[] = { + CKA_IBM_KYBER_SK, + CKA_IBM_KYBER_PK, + }; + CK_RV rc; + + rc = ibm_pqc_check_attributes(tmpl, mode, CKM_IBM_KYBER, req_attrs, + sizeof(req_attrs) / sizeof(req_attrs[0])); + if (rc != CKR_OK) + return rc; + + /* All required attrs found, check them */ + return priv_key_check_required_attributes(tmpl, mode); +} + static CK_RV ibm_pqc_validate_keyform_mode(CK_ATTRIBUTE *attr, CK_ULONG mode, CK_MECHANISM_TYPE mech) { @@ -5228,6 +5651,59 @@ CK_RV ibm_dilithium_priv_validate_attribute(STDLL_TokData_t *tokdata, } } +// ibm_kyber_publ_validate_attribute() +// +CK_RV ibm_kyber_publ_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + CK_RV rc; + + switch (attr->type) { + case CKA_IBM_KYBER_KEYFORM: + case CKA_IBM_KYBER_MODE: + rc = ibm_pqc_validate_keyform_mode(attr, mode, CKM_IBM_KYBER); + if (rc != CKR_OK) + return rc; + return CKR_OK; + case CKA_IBM_KYBER_PK: + case CKA_VALUE: + if (mode == MODE_CREATE) + return CKR_OK; + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + +// ibm_kyber_priv_validate_attribute() +// +CK_RV ibm_kyber_priv_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + CK_RV rc; + + switch (attr->type) { + case CKA_IBM_KYBER_KEYFORM: + case CKA_IBM_KYBER_MODE: + rc = ibm_pqc_validate_keyform_mode(attr, mode, CKM_IBM_KYBER); + if (rc != CKR_OK) + return rc; + return CKR_OK; + case CKA_IBM_KYBER_SK: + case CKA_IBM_KYBER_PK: + case CKA_VALUE: + if (mode == MODE_CREATE) + return CKR_OK; + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + // generic_secret_check_required_attributes() // CK_RV generic_secret_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) diff --git a/usr/lib/common/key_mgr.c b/usr/lib/common/key_mgr.c index 01103dc2..8fcdc88e 100644 --- a/usr/lib/common/key_mgr.c +++ b/usr/lib/common/key_mgr.c @@ -1421,6 +1421,16 @@ CK_RV key_mgr_get_private_key_type(CK_BYTE *keydata, return CKR_OK; } } + // Check only the OBJECT IDENTIFIERs for KYBER + // + for (i = 0; kyber_oids[i].oid != NULL; i++) { + if (alg_len == kyber_oids[i].oid_len + ber_NULLLen && + memcmp(alg, kyber_oids[i].oid, kyber_oids[i].oid_len) == 0 && + memcmp(alg + kyber_oids[i].oid_len, ber_NULL, ber_NULLLen) == 0) { + *keytype = CKK_IBM_PQC_KYBER; + return CKR_OK; + } + } TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; diff --git a/usr/lib/common/mech_ec.c b/usr/lib/common/mech_ec.c index 9df53b46..3a642f50 100644 --- a/usr/lib/common/mech_ec.c +++ b/usr/lib/common/mech_ec.c @@ -912,6 +912,9 @@ CK_RV pkcs_get_keytype(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, case CKM_IBM_DILITHIUM: *type = CKK_IBM_PQC_DILITHIUM; break; + case CKM_IBM_KYBER: + *type = CKK_IBM_PQC_KYBER; + break; default: return CKR_MECHANISM_INVALID; } diff --git a/usr/lib/common/template.c b/usr/lib/common/template.c index 3338e847..37831efc 100644 --- a/usr/lib/common/template.c +++ b/usr/lib/common/template.c @@ -164,6 +164,8 @@ CK_RV template_add_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl, return dh_publ_set_default_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_dilithium_publ_set_default_attributes(tmpl, mode); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_publ_set_default_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); @@ -181,6 +183,8 @@ CK_RV template_add_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl, return dh_priv_set_default_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_dilithium_priv_set_default_attributes(tmpl, mode); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_priv_set_default_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); @@ -409,6 +413,8 @@ CK_RV template_check_required_attributes(TEMPLATE *tmpl, CK_ULONG class, return dh_publ_check_required_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_dilithium_publ_check_required_attributes(tmpl, mode); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_publ_check_required_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); @@ -426,6 +432,8 @@ CK_RV template_check_required_attributes(TEMPLATE *tmpl, CK_ULONG class, return dh_priv_check_required_attributes(tmpl, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_dilithium_priv_check_required_attributes(tmpl, mode); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_priv_check_required_attributes(tmpl, mode); default: TRACE_ERROR("%s: %lx\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID), subclass); @@ -1642,6 +1650,8 @@ CK_RV template_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, return dh_publ_validate_attribute(tokdata, tmpl, attr, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_dilithium_publ_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_publ_validate_attribute(tokdata, tmpl, attr, mode); default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type @@ -1658,6 +1668,8 @@ CK_RV template_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, return dh_priv_validate_attribute(tokdata, tmpl, attr, mode); case CKK_IBM_PQC_DILITHIUM: return ibm_dilithium_priv_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_IBM_PQC_KYBER: + return ibm_kyber_priv_validate_attribute(tokdata, tmpl, attr, mode); default: TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c index 479951cb..44796dba 100644 --- a/usr/lib/ep11_stdll/ep11_specific.c +++ b/usr/lib/ep11_stdll/ep11_specific.c @@ -362,6 +362,13 @@ static const version_req_t ibm_dilithium_req_versions[] = { }; #define NUM_DILITHIUM_REQ (sizeof(ibm_dilithium_req_versions) / sizeof(version_req_t)) +static const CK_VERSION ibm_cex8p_kyber_support = { .major = 8, .minor = 9 }; + +static const version_req_t ibm_kyber_req_versions[] = { + { .card_type = 8, .min_firmware_version = &ibm_cex8p_kyber_support } +}; +#define NUM_KYBER_REQ (sizeof(ibm_kyber_req_versions) / sizeof(version_req_t)) + static const CK_VERSION ibm_cex6p_reencrypt_single_support = { .major = 6, .minor = 15 }; static const CK_VERSION ibm_cex7p_reencrypt_single_support = @@ -1809,7 +1816,8 @@ static CK_RV check_key_attributes(STDLL_TokData_t * tokdata, check_types = &check_types_pub[0]; attr_cnt = sizeof(check_types_pub) / sizeof(CK_ULONG); } - /* do nothing for CKM_DH_PKCS_KEY_PAIR_GEN and CKK_IBM_PQC_DILITHIUM */ + /* do nothing for CKM_DH_PKCS_KEY_PAIR_GEN, CKK_IBM_PQC_DILITHIUM, + and CKK_IBM_PQC_KYBER */ break; case CKO_PRIVATE_KEY: if ((kt == CKK_EC) || (kt == CKK_ECDSA) || (kt == CKK_DSA)) { @@ -1824,7 +1832,7 @@ static CK_RV check_key_attributes(STDLL_TokData_t * tokdata, check_types = &check_types_derive[0]; attr_cnt = sizeof(check_types_derive) / sizeof(CK_ULONG); } - /* Do nothing for CKK_IBM_PQC_DILITHIUM */ + /* Do nothing for CKK_IBM_PQC_DILITHIUM and CKK_IBM_PQC_KYBER */ break; default: return CKR_OK; @@ -2029,6 +2037,13 @@ static CK_BBOOL attr_applicable_for_ep11(STDLL_TokData_t * tokdata, attr->type == CKA_IBM_DILITHIUM_MODE) return CK_FALSE; break; + case CKK_IBM_PQC_KYBER: + if (attr->type == CKA_SIGN || attr->type == CKA_VERIFY || + attr->type == CKA_WRAP || attr->type == CKA_UNWRAP || + attr->type == CKA_IBM_KYBER_KEYFORM || + attr->type == CKA_IBM_KYBER_MODE) + return CK_FALSE; + break; default: break; } @@ -9145,6 +9160,10 @@ CK_RV ep11tok_unwrap_key(STDLL_TokData_t * tokdata, SESSION * session, rc = ibm_dilithium_priv_unwrap_get_data(key_obj->template, csum, cslen, FALSE); break; + case CKK_IBM_PQC_KYBER: + rc = ibm_kyber_priv_unwrap_get_data(key_obj->template, + csum, cslen, FALSE); + break; } if (rc != 0) { @@ -9240,6 +9259,7 @@ static const CK_MECHANISM_TYPE ep11_supported_mech_list[] = { CKM_IBM_EC_X448, CKM_IBM_ED25519_SHA512, CKM_IBM_ED448_SHA3, + CKM_IBM_KYBER, CKM_IBM_SHA3_224, CKM_IBM_SHA3_224_HMAC, CKM_IBM_SHA3_256, @@ -9478,6 +9498,7 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, CK_VERSION ver1_3 = { .major = 1, .minor = 3 }; CK_VERSION ver3 = { .major = 3, .minor = 0 }; CK_VERSION ver3_1 = { .major = 3, .minor = 0x10 }; + CK_VERSION ver4 = { .major = 4, .minor = 0 }; CK_BBOOL found = FALSE; CK_ULONG i; int status; @@ -9630,6 +9651,23 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, } break; + case CKM_IBM_KYBER: + if (compare_ck_version(&ep11_data->ep11_lib_version, &ver4) < 0) { + TRACE_INFO("%s Mech '%s' banned due to host library version\n", + __func__, ep11_get_ckm(tokdata, type)); + rc = CKR_MECHANISM_INVALID; + goto out; + } + status = check_required_versions(tokdata, ibm_kyber_req_versions, + NUM_KYBER_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(tokdata, type)); + rc = CKR_MECHANISM_INVALID; + goto out; + } + break; + case CKM_IBM_CPACF_WRAP: if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) <= 0) { TRACE_INFO("%s Mech '%s' banned due to host library version\n", diff --git a/usr/lib/ep11_stdll/ep11cpfilter.conf b/usr/lib/ep11_stdll/ep11cpfilter.conf index 9d6a2fc8..4353ec53 100644 --- a/usr/lib/ep11_stdll/ep11cpfilter.conf +++ b/usr/lib/ep11_stdll/ep11cpfilter.conf @@ -73,7 +73,7 @@ XCP_CPB_ALG_EC_25519: CKM_IBM_EC_X25519, CKM_IBM_ED25519_SHA512, CKM_IBM_EC_X448 XCP_CPB_ALG_NBSI2017: CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA224_RSA_PKCS, CKM_SHA256_RSA_PKCS, CKM_SHA384_RSA_PKCS, CKM_SHA512_RSA_PKCS #enable support of Dilithium -XCP_CPB_ALG_PQC: CKM_IBM_DILITHIUM +XCP_CPB_ALG_PQC: CKM_IBM_DILITHIUM, CKM_IBM_KYBER # enable BTC-related functionality XCP_CPB_BTC: CKM_IBM_BTC_DERIVE -- 2.16.2.windows.1