1
0
mirror of https://github.com/opencryptoki/opencryptoki.git synced 2026-10-24 05:39:17 +03:00
Files
opencryptoki/testcases/crypto/ec_func.c
Alexandre Laroche 7131685d35 TESTCASES: Check CKA_SENSITIVE and CKA_EXTRACTABLE of unwrapped keys
Add check_unwrap_sensitive_extractable() to the common test code. It
unwraps the same data with each combination of CKA_SENSITIVE and
CKA_EXTRACTABLE, and with neither, and checks every new key: the
attributes match the template (any value is accepted when the template
does not set them, since the defaults are token specific);
CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE are FALSE; and the key
value cannot be read from a sensitive key. When the unwrapping key's
CKA_UNWRAP_TEMPLATE sets one of the attributes, a key unwrapped without
it gets that value, and a template asking for the other value must fail
with CKR_TEMPLATE_INCONSISTENT.

CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE are not checked on the
ICSF token, which unwraps on the ICSF server and takes these attributes
from it.

Run it from do_WrapUnwrapAES() for secret keys, from do_WrapUnwrapRSA()
for RSA private keys, and from both EC key transfer tests for EC private
keys, whose transport key's CKA_UNWRAP_TEMPLATE sets CKA_EXTRACTABLE =
FALSE. Add do_UnwrapTemplateAES(), which unwraps under a wrapping key
whose CKA_UNWRAP_TEMPLATE sets CKA_SENSITIVE = TRUE and CKA_EXTRACTABLE =
FALSE, for every AES wrap mechanism.

Signed-off-by: Alexandre Laroche <larochealexandre@hotmail.com>
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
2026-10-19 13:52:53 +02:00

5766 lines
228 KiB
C

/*
* COPYRIGHT (c) International Business Machines Corp. 2011-2017
*
* This program is provided under the terms of the Common Public License,
* version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
* software constitutes recipient's acceptance of CPL-1.0 terms which can be
* found in the file LICENSE file or at
* https://opensource.org/licenses/cpl1.0.php
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <openssl/hmac.h>
#include "pkcs11types.h"
#include "regress.h"
#include "common.c"
#include "ec.h"
#include "defs.h"
#include "ec_curves.h"
#include "mechtable.h"
#include "mech_to_str.h"
/*
* Below is a list for the OIDs and DER encodings of the brainpool.
* Beginning of each DER encoding should be 06 for OID and 09 for the length.
* For example brainpoolP160r1 should be 06092B2403030208010101
* brainpoolP160r1
* 1.3.36.3.3.2.8.1.1.1
* 2B2403030208010101
* brainpoolP160t1
* 1.3.36.3.3.2.8.1.1.2
* 2B2403030208010102
* brainpoolP192r1
* 1.3.36.3.3.2.8.1.1.3
* 2B2403030208010103
* brainpoolP192t1
* 1.3.36.3.3.2.8.1.1.4
* 2B2403030208010104
* brainpoolP224r1
* 1.3.36.3.3.2.8.1.1.5
* 2B2403030208010105
* brainpoolP224t1
* 1.3.36.3.3.2.8.1.1.6
* 2B2403030208010106
* brainpoolP256r1
* 1.3.36.3.3.2.8.1.1.7
* 2B2403030208010107
* brainpoolP256t1
* 1.3.36.3.3.2.8.1.1.8
* 2B2403030208010108
* brainpoolP320r1
* 1.3.36.3.3.2.8.1.1.9
* 2B2403030208010109
* brainpoolP320t1
* 1.3.36.3.3.2.8.1.1.10
* 2B240303020801010A
* brainpoolP384r1
* 1.3.36.3.3.2.8.1.1.11
* 2B240303020801010B
* brainpoolP384t1
* 1.3.36.3.3.2.8.1.1.12
* 2B240303020801010C
* brainpoolP512r1
* 1.3.36.3.3.2.8.1.1.13
* 2B240303020801010D
* brainpoolP512t1
* 1.3.36.3.3.2.8.1.1.14
* 2B240303020801010E
* prime192
* 1.2.840.10045.3.1.1
* 2A8648CE3D030101
* secp224
* 1.3.132.0.33
* 2B81040021
* prime256
* 1.2.840.10045.3.1.7
* 2A8648CE3D030107
* secp384
* 1.3.132.0.34
* 2B81040022
* secp521
* 1.3.132.0.35
* 2B81040023
* secp256k1
* 1.3.132.0.10
* 2B8104000A
* curve25519
* 1.3.101.110
* 06032B656E
* curve448[]
* 1.3.101.111
* 06032B656F
* ed25519[]
* 1.3.101.112
* 06032B6570
* ed448
* 1.3.101.113
* 06032B6571
*/
typedef struct ec_struct {
void const *curve;
CK_ULONG size;
CK_BBOOL twisted;
enum curve_type type;
CK_ULONG bit_len;
char *name;
} _ec_struct;
/* Supported Elliptic Curves */
#define NUMEC 25
const CK_BYTE brainpoolP160r1[] = OCK_BRAINPOOL_P160R1;
const CK_BYTE brainpoolP160t1[] = OCK_BRAINPOOL_P160T1;
const CK_BYTE brainpoolP192r1[] = OCK_BRAINPOOL_P192R1;
const CK_BYTE brainpoolP192t1[] = OCK_BRAINPOOL_P192T1;
const CK_BYTE brainpoolP224r1[] = OCK_BRAINPOOL_P224R1;
const CK_BYTE brainpoolP224t1[] = OCK_BRAINPOOL_P224T1;
const CK_BYTE brainpoolP256r1[] = OCK_BRAINPOOL_P256R1;
const CK_BYTE brainpoolP256t1[] = OCK_BRAINPOOL_P256T1;
const CK_BYTE brainpoolP320r1[] = OCK_BRAINPOOL_P320R1;
const CK_BYTE brainpoolP320t1[] = OCK_BRAINPOOL_P320T1;
const CK_BYTE brainpoolP384r1[] = OCK_BRAINPOOL_P384R1;
const CK_BYTE brainpoolP384t1[] = OCK_BRAINPOOL_P384T1;
const CK_BYTE brainpoolP512r1[] = OCK_BRAINPOOL_P512R1;
const CK_BYTE brainpoolP512t1[] = OCK_BRAINPOOL_P512T1;
const CK_BYTE prime192v1[] = OCK_PRIME192V1;
const CK_BYTE secp224r1[] = OCK_SECP224R1;
const CK_BYTE prime256v1[] = OCK_PRIME256V1;
const CK_BYTE secp384r1[] = OCK_SECP384R1;
const CK_BYTE secp521r1[] = OCK_SECP521R1;
const CK_BYTE secp256k1[] = OCK_SECP256K1;
const CK_BYTE curve25519[] = OCK_CURVE25519;
const CK_BYTE curve448[] = OCK_CURVE448;
const CK_BYTE ed25519[] = OCK_ED25519;
const CK_BYTE ed448[] = OCK_ED448;
const CK_BYTE bls12_381[] = OCK_BLS12_381;
const _ec_struct der_ec_supported[NUMEC] = {
{&brainpoolP160r1, sizeof(brainpoolP160r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE160_LENGTH, "brainpoolP160r1"},
{&brainpoolP160t1, sizeof(brainpoolP160t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE160_LENGTH, "brainpoolP160t1"},
{&brainpoolP192r1, sizeof(brainpoolP192r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE192_LENGTH, "brainpoolP192r1"},
{&brainpoolP192t1, sizeof(brainpoolP192t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE192_LENGTH, "brainpoolP192t1"},
{&brainpoolP224r1, sizeof(brainpoolP224r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE224_LENGTH, "brainpoolP224r1"},
{&brainpoolP224t1, sizeof(brainpoolP224t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE224_LENGTH, "brainpoolP224t1"},
{&brainpoolP256r1, sizeof(brainpoolP256r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE256_LENGTH, "brainpoolP256r1"},
{&brainpoolP256t1, sizeof(brainpoolP256t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE256_LENGTH, "brainpoolP256t1"},
{&brainpoolP320r1, sizeof(brainpoolP320r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE320_LENGTH, "brainpoolP320r1"},
{&brainpoolP320t1, sizeof(brainpoolP320t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE320_LENGTH, "brainpoolP320t1"},
{&brainpoolP384r1, sizeof(brainpoolP384r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE384_LENGTH, "brainpoolP384r1"},
{&brainpoolP384t1, sizeof(brainpoolP384t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE384_LENGTH, "brainpoolP384t1"},
{&brainpoolP512r1, sizeof(brainpoolP512r1), CK_FALSE, CURVE_BRAINPOOL,
CURVE512_LENGTH, "brainpoolP512r1"},
{&brainpoolP512t1, sizeof(brainpoolP512t1), CK_TRUE, CURVE_BRAINPOOL,
CURVE512_LENGTH, "brainpoolP512t1"},
{&prime192v1, sizeof(prime192v1), CK_FALSE, CURVE_PRIME,
CURVE192_LENGTH, "prime192v1"},
{&secp224r1, sizeof(secp224r1), CK_FALSE, CURVE_PRIME,
CURVE224_LENGTH , "secp224r1"},
{&prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME,
CURVE256_LENGTH, "prime256v1"},
{&secp384r1, sizeof(secp384r1), CK_FALSE, CURVE_PRIME,
CURVE384_LENGTH, "secp384r1"},
{&secp521r1, sizeof(secp521r1), CK_FALSE, CURVE_PRIME,
CURVE521_LENGTH + 8, "secp521r1"},
{&secp256k1, sizeof(secp256k1), CK_FALSE, CURVE_KOBLITZ,
CURVE256_LENGTH, "secp256k1"},
{&curve25519, sizeof(curve25519), CK_FALSE, CURVE_MONTGOMERY,
CURVE256_LENGTH, "curve25519"},
{&curve448, sizeof(curve448), CK_FALSE, CURVE_MONTGOMERY,
CURVE448_LENGTH, "curve448"},
{&ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS,
CURVE256_LENGTH, "ed25519"},
{&ed448, sizeof(ed448), CK_FALSE, CURVE_EDWARDS,
CURVE456_LENGTH, "ed448"},
{&bls12_381, sizeof(bls12_381), CK_TRUE, CURVE_BLS12_381,
CURVE384_LENGTH, "bls12_381"},
};
/* Invalid curves */
#define NUMECINVAL 4
const CK_BYTE invalidCurve[] =
{ 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x08, 0x08, 0x01, 0x01, 0x01 };
const CK_BYTE invalidLen1[] =
{ 0x06, 0x0A, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01 };
const CK_BYTE invalidLen2[] =
{ 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01 };
const CK_BYTE invalidOIDfield[] =
{ 0x05, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01 };
const _ec_struct der_ec_notsupported[NUMECINVAL] = {
{&invalidCurve, sizeof(invalidCurve), CK_FALSE, CURVE_BRAINPOOL,
CURVE256_LENGTH, "invalidCurve"},
{&invalidLen1, sizeof(invalidLen1), CK_FALSE, CURVE_BRAINPOOL,
CURVE256_LENGTH, "invalidLen1"},
{&invalidLen2, sizeof(invalidLen2), CK_FALSE, CURVE_BRAINPOOL,
CURVE256_LENGTH, "invalidLen2"},
{&invalidOIDfield, sizeof(invalidOIDfield), CK_FALSE, CURVE_BRAINPOOL,
CURVE256_LENGTH, "invalidOIDfield"}
};
typedef struct signVerifyParam {
CK_MECHANISM mech;
CK_ULONG inputlen;
CK_ULONG parts; /* 0 means process in 1 chunk via C_Sign,
* >0 means process in n chunks via
* C_SignUpdate/C_SignFinal
*/
const char *name;
} _signVerifyParam;
CK_IBM_ECDSA_OTHER_PARAMS other_rand = { .submechanism = CKM_IBM_ECSDSA_RAND };
CK_IBM_ECDSA_OTHER_PARAMS other_compr_multi =
{ .submechanism = CKM_IBM_ECSDSA_COMPR_MULTI };
CK_IBM_ECDSA_OTHER_PARAMS other_bls =
{ .submechanism = CKM_IBM_BLS };
_signVerifyParam signVerifyInput[] = {
{{CKM_ECDSA, NULL, 0}, 20, 0, ""},
{{CKM_ECDSA, NULL, 0}, 32, 0, ""},
{{CKM_ECDSA, NULL, 0}, 48, 0, ""},
{{CKM_ECDSA, NULL, 0}, 64, 0, ""},
{{CKM_ECDSA_SHA1, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA1, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA1, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA1, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA224, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA224, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA224, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA224, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA256, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA256, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA256, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA256, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA384, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA384, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA384, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA384, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA512, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA512, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA512, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA512, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA3_224, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA3_224, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA3_224, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA3_224, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA3_256, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA3_256, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA3_256, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA3_256, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA3_384, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA3_384, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA3_384, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA3_384, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_ECDSA_SHA3_512, NULL, 0}, 100, 0, ""},
{{CKM_ECDSA_SHA3_512, NULL, 0}, 100, 4, ""},
{{CKM_ECDSA_SHA3_512, NULL, 0}, 0, 0, ""}, /* Empty Message via C_Sign */
{{CKM_ECDSA_SHA3_512, NULL, 0}, 0, 1, ""}, /* Empty Message via C_SignInit+C_SignFinal */
{{CKM_IBM_ED25519_SHA512, NULL, 0}, 100, 0, ""},
{{CKM_IBM_ED448_SHA3, NULL, 0}, 100, 0, ""},
{{CKM_IBM_ECDSA_OTHER, &other_rand, sizeof(other_rand)}, 20, 0, ""},
{{CKM_IBM_ECDSA_OTHER, &other_compr_multi, sizeof(other_compr_multi)}, 20, 0, ""},
{{CKM_IBM_ECDSA_OTHER, &other_bls, sizeof(other_bls)}, 20, 0, ""},
};
#define NUM_KDFS sizeof(kdfs)/sizeof(CK_EC_KDF_TYPE)
static CK_EC_KDF_TYPE kdfs[] = {
CKD_NULL,
CKD_SHA1_KDF,
CKD_SHA224_KDF,
CKD_SHA256_KDF,
CKD_SHA384_KDF,
CKD_SHA512_KDF,
CKD_SHA3_224_KDF,
CKD_SHA3_256_KDF,
CKD_SHA3_384_KDF,
CKD_SHA3_512_KDF,
CKD_SHA1_KDF_SP800,
CKD_SHA224_KDF_SP800,
CKD_SHA256_KDF_SP800,
CKD_SHA384_KDF_SP800,
CKD_SHA512_KDF_SP800,
CKD_SHA3_224_KDF_SP800,
CKD_SHA3_256_KDF_SP800,
CKD_SHA3_384_KDF_SP800,
CKD_SHA3_512_KDF_SP800,
};
static const char *p11_get_ckd(CK_EC_KDF_TYPE kdf)
{
switch (kdf) {
case CKD_NULL:
return "CKD_NULL";
case CKD_SHA1_KDF:
return "CKD_SHA1_KDF";
case CKD_SHA224_KDF:
return "CKD_SHA224_KDF";
case CKD_SHA256_KDF:
return "CKD_SHA256_KDF";
case CKD_SHA384_KDF:
return "CKD_SHA384_KDF";
case CKD_SHA512_KDF:
return "CKD_SHA512_KDF";
case CKD_SHA3_224_KDF:
return "CKD_SHA3_224_KDF";
case CKD_SHA3_256_KDF:
return "CKD_SHA3_256_KDF";
case CKD_SHA3_384_KDF:
return "CKD_SHA3_384_KDF";
case CKD_SHA3_512_KDF:
return "CKD_SHA3_512_KDF";
case CKD_SHA1_KDF_SP800:
return "CKD_SHA1_KDF_SP800";
case CKD_SHA224_KDF_SP800:
return "CKD_SHA224_KDF_SP800";
case CKD_SHA256_KDF_SP800:
return "CKD_SHA256_KDF_SP800";
case CKD_SHA384_KDF_SP800:
return "CKD_SHA384_KDF_SP800";
case CKD_SHA512_KDF_SP800:
return "CKD_SHA512_KDF_SP800";
case CKD_SHA3_224_KDF_SP800:
return "CKD_SHA3_224_KDF_SP800";
case CKD_SHA3_256_KDF_SP800:
return "CKD_SHA3_256_KDF_SP800";
case CKD_SHA3_384_KDF_SP800:
return "CKD_SHA3_384_KDF_SP800";
case CKD_SHA3_512_KDF_SP800:
return "CKD_SHA3_512_KDF_SP800";
default:
return "UNKNOWN";
}
}
static unsigned int curve_len(int index)
{
if (index >= NUMEC)
return 0;
return der_ec_supported[index].bit_len / 8;
}
static CK_RV curve_supported(const char *name)
{
if (name[strlen(name) - 2] == 'r' || name[strlen(name) - 2] == 'v' ||
name[strlen(name) - 2] == 'k')
return 1;
return 0;
}
/**
* A test is skipped, when no KDF is used and the derived key length
* shall be bigger than the shared secret (z-value). Without a KDF, max
* z-length key bytes can be derived.
*/
static unsigned int too_many_key_bytes_requested(unsigned int curve,
unsigned int kdf,
unsigned int keylen)
{
if (kdf > 0 || keylen <= curve_len(curve))
return 0;
return 1;
}
/*
* Perform a HMAC sign to verify that the key is usable.
*/
CK_RV run_HMACSign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key,
CK_ULONG key_len, CK_MECHANISM_TYPE hmac_mech,
CK_BYTE *mac, CK_ULONG *mac_len)
{
CK_MECHANISM mech = { .mechanism = hmac_mech,
.pParameter = NULL, .ulParameterLen = 0 };
CK_BYTE data[32] = { 0 };
CK_RV rc = CKR_OK;
if (!mech_supported(SLOT_ID, mech.mechanism)) {
testcase_notice("Mechanism %s is not supported with slot "
"%lu. Skipping key check",
p11_get_ckm(&mechtable_funcs, mech.mechanism),
SLOT_ID);
*mac_len = 0;
return CKR_OK;
}
if (!check_supp_keysize(SLOT_ID, mech.mechanism, key_len * 8)) {
testcase_notice("Mechanism %s can not be used with keys "
"of size %lu. Skipping key check",
p11_get_ckm(&mechtable_funcs, mech.mechanism),
key_len);
*mac_len = 0;
return CKR_OK;
}
rc = funcs->C_SignInit(session, &mech, h_key);
if (rc != CKR_OK) {
testcase_notice("C_SignInit rc=%s", p11_get_ckr(rc));
goto error;
}
/** do signing **/
rc = funcs->C_Sign(session, data, sizeof(data), mac, mac_len);
if (rc != CKR_OK) {
testcase_notice("C_Sign rc=%s", p11_get_ckr(rc));
goto error;
}
error:
return rc;
}
CK_RV run_AESEncrypt(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h_key,
CK_BYTE *enc, CK_ULONG *enc_len)
{
char aes_iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
CK_MECHANISM mech = { .mechanism = CKM_AES_CBC,
.pParameter = &aes_iv,
.ulParameterLen = AES_INIT_VECTOR_SIZE };
CK_BYTE data[AES_BLOCK_SIZE] = { 0 };
CK_RV rc = CKR_OK;
if (!mech_supported(SLOT_ID, mech.mechanism)) {
testcase_notice("Mechanism %s is not supported with slot "
"%lu. Skipping key check",
p11_get_ckm(&mechtable_funcs, mech.mechanism),
SLOT_ID);
*enc_len = 0;
return CKR_OK;
}
rc = funcs->C_EncryptInit(session, &mech, h_key);
if (rc != CKR_OK) {
testcase_notice("C_EncryptInit rc=%s", p11_get_ckr(rc));
goto error;
}
/** do encrypting **/
rc = funcs->C_Encrypt(session, data, sizeof(data), enc, enc_len);
if (rc != CKR_OK) {
testcase_notice("C_Encrypt rc=%s", p11_get_ckr(rc));
goto error;
}
error:
return rc;
}
/*
* Perform a HMAC sign to verify that the key is usable.
*/
CK_RV run_HMACSign_OpenSSL(CK_BYTE *key, CK_ULONG key_len,
CK_MECHANISM_TYPE hmac_mech,
CK_BYTE *mac, CK_ULONG *mac_len)
{
CK_BYTE data[32] = { 0 };
const EVP_MD *md;
unsigned int out_len;
switch (hmac_mech) {
case CKM_SHA_1_HMAC:
md = EVP_sha1();
break;
case CKM_SHA224_HMAC:
md = EVP_sha224();
break;
case CKM_SHA256_HMAC:
md = EVP_sha256();
break;
case CKM_SHA384_HMAC:
md = EVP_sha384();
break;
case CKM_SHA512_HMAC:
md = EVP_sha512();
break;
default:
testcase_notice("Mechanism %s is not supported. Skipping key check",
p11_get_ckm(&mechtable_funcs, hmac_mech));
*mac_len = 0;
return CKR_OK;
}
out_len = *mac_len;
if (HMAC(md, key, key_len, data, sizeof(data), mac, &out_len) == NULL) {
testcase_notice("HMAC (OpenSSL) failed");
return CKR_OK;
}
*mac_len = out_len;
return CKR_OK;
}
/*
* Generate EC key-pairs for parties A and B.
* Derive shared secrets based on Diffie Hellman key agreement defined in PKCS#3
*/
CK_RV run_DeriveECDHKey(CK_BBOOL cofactor_mode)
{
CK_SESSION_HANDLE session;
CK_MECHANISM mech;
CK_FLAGS flags;
CK_OBJECT_HANDLE publ_keyA = CK_INVALID_HANDLE,
priv_keyA = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE publ_keyB = CK_INVALID_HANDLE,
priv_keyB = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE secret_keyA = CK_INVALID_HANDLE,
secret_keyB = CK_INVALID_HANDLE;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len;
CK_RV rc = CKR_OK;
CK_ECDH1_DERIVE_PARAMS ecdh_parmA, ecdh_parmB;
CK_BBOOL true = CK_TRUE;
CK_BBOOL false = CK_FALSE;
CK_BYTE pubkeyA_value[256] = { 0 };
CK_BYTE pubkeyB_value[256] = { 0 };
CK_BYTE secretA_value[80000] = { 0 }; //enough space for lengths in secret_key_len[]
CK_BYTE deriveB_value[80000] = { 0 };
CK_OBJECT_CLASS class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_GENERIC_SECRET;
CK_ULONG i, j, k, m;
CK_MECHANISM_TYPE derive_mech_type;
testcase_begin("starting run_DeriveECDHKey with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_EC_KEY_PAIR_GEN)) {
testcase_skip("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
for (i=0; i<NUMEC; i++) {
CK_ATTRIBUTE cka_derive_tmpl[] = {
{CKA_PRIVATE, &true, sizeof(true)},
{CKA_EXTRACTABLE, &true, sizeof(true)},
};
CK_ULONG derive_key_type = CKK_AES;
CK_ULONG derive_value_len = 256 / 8;
CK_ATTRIBUTE cka_derive_tmpl_cca[] = {
{CKA_PRIVATE, &true, sizeof(true)},
{CKA_EXTRACTABLE, &true, sizeof(true)},
{CKA_KEY_TYPE, &derive_key_type, sizeof(derive_key_type)},
{CKA_VALUE_LEN, &derive_value_len, sizeof(derive_value_len)},
};
CK_ATTRIBUTE prv_attr[] = {
{CKA_SIGN, &true, sizeof(true)},
{CKA_EXTRACTABLE, &true, sizeof(true)},
{CKA_DERIVE, &true, sizeof(true)},
{CKA_DERIVE_TEMPLATE, &cka_derive_tmpl, sizeof(cka_derive_tmpl)},
};
CK_ULONG prv_attr_len = sizeof(prv_attr)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE prv_attr_edwards[] = {
{CKA_SIGN, &true, sizeof(true)},
{CKA_EXTRACTABLE, &true, sizeof(true)},
};
CK_ULONG prv_attr_edwards_len =
sizeof(prv_attr_edwards)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE prv_attr_montgomery[] = {
{CKA_DERIVE, &true, sizeof(true)},
{CKA_EXTRACTABLE, &true, sizeof(true)},
{CKA_DERIVE_TEMPLATE, &cka_derive_tmpl, sizeof(cka_derive_tmpl)},
};
CK_ULONG prv_attr_montgomery_len =
sizeof(prv_attr_montgomery)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE pub_attr[] = {
{CKA_ECDSA_PARAMS, (CK_VOID_PTR)der_ec_supported[i].curve,
der_ec_supported[i].size},
{CKA_VERIFY, &true, sizeof(true)},
{CKA_MODIFIABLE, &true, sizeof(true)},
};
CK_ULONG pub_attr_len = sizeof(pub_attr)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE pub_attr_montgomery[] = {
{CKA_ECDSA_PARAMS, (CK_VOID_PTR)der_ec_supported[i].curve,
der_ec_supported[i].size},
{CKA_MODIFIABLE, &true, sizeof(true)},
{CKA_VERIFY, &true, sizeof(true)},
};
CK_ULONG pub_attr_montgomery_len =
sizeof(pub_attr_montgomery)/sizeof(CK_ATTRIBUTE);
if (is_icsf_token(SLOT_ID))
prv_attr_len -= 1; /* ICSF does not support array attributes */
if (is_cca_token(SLOT_ID)) {
prv_attr[3].pValue = cka_derive_tmpl_cca;
prv_attr[3].ulValueLen = sizeof(cka_derive_tmpl_cca);
}
CK_ATTRIBUTE *prv_attr_gen = prv_attr;
CK_ULONG prv_attr_gen_len = prv_attr_len;
CK_ATTRIBUTE *pub_attr_gen = pub_attr;
CK_ULONG pub_attr_gen_len = pub_attr_len;
CK_ATTRIBUTE extr1_tmpl[] = {
{CKA_EC_POINT, pubkeyA_value, sizeof(pubkeyA_value)},
};
CK_ULONG extr1_tmpl_len = sizeof(extr1_tmpl)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE extr2_tmpl[] = {
{CKA_EC_POINT, pubkeyB_value, sizeof(pubkeyB_value)},
};
CK_ULONG extr2_tmpl_len = sizeof(extr2_tmpl)/sizeof(CK_ATTRIBUTE);
if (der_ec_supported[i].type == CURVE_EDWARDS||
der_ec_supported[i].type == CURVE_BLS12_381) {
/* Edwards/BLS curves can not be used for ECDH derive */
continue;
}
if (is_cca_token(SLOT_ID) || is_icsf_token(SLOT_ID)) {
if (der_ec_supported[i].twisted) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, der_ec_supported[i].name);
continue;
}
if (der_ec_supported[i].type != CURVE_BRAINPOOL &&
der_ec_supported[i].type != CURVE_PRIME &&
der_ec_supported[i].type != CURVE_KOBLITZ) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,der_ec_supported[i].name);
continue;
}
}
derive_mech_type = cofactor_mode ?
CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE;
if (der_ec_supported[i].type == CURVE_MONTGOMERY) {
if (cofactor_mode) {
testcase_skip("No cofactor mode possible for curve: %s",
der_ec_supported[i].name);
continue;
}
if (der_ec_supported[i].curve == curve25519)
derive_mech_type = CKM_IBM_EC_X25519;
if (der_ec_supported[i].curve == curve448)
derive_mech_type = CKM_IBM_EC_X448;
prv_attr_gen = prv_attr_montgomery;
prv_attr_gen_len = prv_attr_montgomery_len;
pub_attr_gen = pub_attr_montgomery;
pub_attr_gen_len = pub_attr_montgomery_len;
} else if (der_ec_supported[i].type == CURVE_EDWARDS) {
if (cofactor_mode) {
testcase_skip("No cofactor mode possible for curve: %s",
der_ec_supported[i].name);
continue;
}
prv_attr_gen = prv_attr_edwards;
prv_attr_gen_len = prv_attr_edwards_len;
}
if (!mech_supported(SLOT_ID, derive_mech_type)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckm(&mechtable_funcs, derive_mech_type));
goto testcase_cleanup;
}
// Testcase #1 - Generate 2 EC key pairs.
// First, generate the EC key pair for party A
mech.mechanism = CKM_EC_KEY_PAIR_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
rc = funcs->C_GenerateKeyPair(session, &mech,
pub_attr_gen, pub_attr_gen_len,
prv_attr_gen, prv_attr_gen_len,
&publ_keyA, &priv_keyA);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
continue;
}
if (rc == CKR_MECHANISM_PARAM_INVALID ||
rc == CKR_ATTRIBUTE_VALUE_INVALID ||
rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, der_ec_supported[i].name);
continue;
}
testcase_fail("C_GenerateKeyPair with valid input failed at i=%lu "
"(%s), rc=%s", i, der_ec_supported[i].name,
p11_get_ckr(rc));
goto testcase_cleanup;
}
// Extract public key A
rc = funcs->C_GetAttributeValue(session, publ_keyA,
extr1_tmpl, extr1_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #1: rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
// Now generate the EC key pair for party B
mech.mechanism = CKM_EC_KEY_PAIR_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
rc = funcs->C_GenerateKeyPair(session, &mech,
pub_attr_gen, pub_attr_gen_len,
prv_attr_gen, prv_attr_gen_len,
&publ_keyB, &priv_keyB);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
goto testcase_cleanup;
}
testcase_fail("C_GenerateKeyPair with valid input failed at i=%lu "
"(%s), rc=%s", i, der_ec_supported[i].name,
p11_get_ckr(rc));
goto testcase_cleanup;
}
// Extract public key B
rc = funcs->C_GetAttributeValue(session, publ_keyB,
extr2_tmpl, extr2_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #1: rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
// Check if the key lengths are equal
if (extr1_tmpl->ulValueLen != extr2_tmpl->ulValueLen) {
testcase_error("Length of public key A not equal to length of "
"public key B");
goto testcase_cleanup;
}
// Testcase #2 - Now derive the secrets...
for (j=0; j < NUM_KDFS; j++) {
switch (kdfs[j]) {
case CKD_SHA1_KDF:
case CKD_SHA1_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA_1)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA224_KDF:
case CKD_SHA224_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA224)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA256_KDF:
case CKD_SHA256_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA256)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA384_KDF:
case CKD_SHA384_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA384)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA512_KDF:
case CKD_SHA512_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA512)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA3_224_KDF:
case CKD_SHA3_224_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_224)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));;
continue;
}
break;
case CKD_SHA3_256_KDF:
case CKD_SHA3_256_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_256)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA3_384_KDF:
case CKD_SHA3_384_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_384)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
case CKD_SHA3_512_KDF:
case CKD_SHA3_512_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_512)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
break;
default:
break;
}
if (is_icsf_token(SLOT_ID)) {
switch (kdfs[j]) {
case CKD_SHA1_KDF:
case CKD_SHA224_KDF:
case CKD_SHA256_KDF:
case CKD_SHA384_KDF:
break;
default:
testcase_skip("The ICSF token in slot %u doesn't support "
"%s\n",
(unsigned int) SLOT_ID, p11_get_ckd(kdfs[j]));
continue;
}
}
for (k=0; k<NUM_SECRET_KEY_LENGTHS; k++) {
if (too_many_key_bytes_requested(i, j, secret_key_len[k])) {
/*
* Cannot provide requested key bytes with current curve
* without a kdf.
*/
continue;
}
if (is_ep11_token(SLOT_ID) && k > 9) {
testcase_skip("EP11 cannot provide %lu key bytes with "
"curve %s\n", secret_key_len[k],
der_ec_supported[i].name);
continue;
}
if (is_ep11_token(SLOT_ID) &&
secret_key_len[k] > 0 && secret_key_len[k] < 10) {
/*
* EP11 can not derive keys less than 80 bits (10 bytes).
* This was formerly dependent on control point
* XCP_CPB_KEYSZ_BELOW80BIT, but this control point
* is now always OFF.
* */
testcase_skip("EP11 cannot provide %lu key bytes (%lu bits < 80 bits)\n",
secret_key_len[k], secret_key_len[k] * 8);
continue;
}
if (secret_key_len[k] == 0 &&
der_ec_supported[i].type == CURVE_MONTGOMERY) {
/*
* Curve can not be used without the derived key size
* specified in CKA_VALUE_LEN.
*/
continue;
}
if (der_ec_supported[i].type == CURVE_BLS12_381) {
/*
* Skipping BLS 12 381 curve.
*/
continue;
}
if (is_icsf_token(SLOT_ID) && secret_key_len[k] == 0) {
testcase_skip("ICSF token can not derive keys without CKA_VALUE_LEN\n");
continue;
}
if (is_icsf_token(SLOT_ID) && secret_key_len[k] > 256) {
testcase_skip("ICSF token can not derive keys of that size\n");
continue;
}
if (is_cca_token(SLOT_ID)) {
if (secret_key_len[k] == derive_value_len) {
key_type = derive_key_type; /* CCA can only derive AES-256 keys */
} else if (secret_key_len[k] == 0 &&
der_ec_supported[i].bit_len == derive_value_len * 8) {
key_type = derive_key_type; /* CCA can only derive AES-256 keys */
} else {
testcase_skip("CCA token can not derive keys of size %lu\n",
secret_key_len[k]);
continue;
}
}
CK_ATTRIBUTE secretA_tmpl[] = {
{CKA_VALUE, secretA_value, sizeof(secretA_value)},
};
CK_ULONG secretA_tmpl_len =
sizeof(secretA_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE secretB_tmpl[] = {
{CKA_VALUE, deriveB_value, sizeof(deriveB_value)},
};
CK_ULONG secretB_tmpl_len =
sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE derive_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_SENSITIVE, &false, sizeof(false)},
{CKA_VALUE_LEN, &(secret_key_len[k]), sizeof(CK_ULONG)},
};
CK_ULONG secret_tmpl_len =
sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE);
CK_BYTE mac1[SHA1_HASH_SIZE] = { 0 };
CK_ULONG mac1_len = sizeof(mac1);
CK_BYTE mac2[SHA1_HASH_SIZE] = { 0 };
CK_ULONG mac2_len = sizeof(mac2);
CK_BYTE enc1[AES_BLOCK_SIZE] = { 0 };
CK_ULONG enc1_len = sizeof(enc1);
CK_BYTE enc2[AES_BLOCK_SIZE] = { 0 };
CK_ULONG enc2_len = sizeof(enc2);
if (secret_key_len[k] == 0)
secret_tmpl_len--;
for (m=0; m < (kdfs[j] == CKD_NULL ? 1 : NUM_SHARED_DATA); m++) {
if (is_cca_token(SLOT_ID)) {
switch (kdfs[j]) {
case CKD_SHA224_KDF:
case CKD_SHA256_KDF:
case CKD_SHA384_KDF:
case CKD_SHA512_KDF:
break;
default:
continue;
}
}
testcase_begin("Starting with curve=%s, kdf=%s, keylen=%lu, "
"shared_data=%u, mech=%s, pkey=%X",
der_ec_supported[i].name,
p11_get_ckd(kdfs[j]), secret_key_len[k],
shared_data[m].length,
p11_get_ckm(&mechtable_funcs, derive_mech_type),
pkey);
// Now, derive a generic secret key using party A's private
// key and B's public key
ecdh_parmA.kdf = kdfs[j];
ecdh_parmA.pPublicData = extr2_tmpl->pValue;
ecdh_parmA.ulPublicDataLen = extr2_tmpl->ulValueLen;
ecdh_parmA.pSharedData =
shared_data[m].length == 0 ?
NULL : (CK_BYTE_PTR) &shared_data[m].data;
ecdh_parmA.ulSharedDataLen = shared_data[m].length;
if (kdfs[j] == CKD_NULL) {
ecdh_parmA.pSharedData = NULL;
ecdh_parmA.ulSharedDataLen = 0;
}
mech.mechanism = derive_mech_type;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parmA;
rc = funcs->C_DeriveKey(session, &mech,
priv_keyA, derive_tmpl,
secret_tmpl_len, &secret_keyA);
if (rc != CKR_OK) {
if (is_ep11_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
(kdfs[j] != CKD_NULL ||
shared_data[m].length > 0)) {
testcase_skip("EP11 does not support KDF %s and/or "
"shared data with older firmware "
"versions\n",
p11_get_ckd(kdfs[j]));
continue;
}
if (is_icsf_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
kdfs[j] != CKD_NULL &&
kdfs[j] != CKD_SHA224_KDF &&
kdfs[j] != CKD_SHA256_KDF &&
kdfs[j] != CKD_SHA384_KDF &&
kdfs[j] != CKD_SHA512_KDF) {
testcase_skip("ICSF does not support KDF %s\n",
p11_get_ckd(kdfs[j]));
continue;
}
if (is_rejected_by_policy(rc, session)) {
testcase_skip("key derivation is not allowed by policy");
continue;
}
if (rc == CKR_FUNCTION_CANCELED) {
testcase_skip("key derivation is not allowed by "
"adapter control point");
continue;
}
if (rc == CKR_KEY_SIZE_RANGE) {
testcase_skip("key derivation is not allowed "
"because key to be generated is "
"stronger than the input material.");
continue;
}
testcase_fail("C_DeriveKey #1: rc = %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
switch (key_type) {
case CKK_GENERIC_SECRET:
mac1_len = sizeof(mac1);
rc = run_HMACSign(session, secret_keyA,
secret_key_len[k] > 0 ?
secret_key_len[k] : curve_len(i),
CKM_SHA_1_HMAC, mac1, &mac1_len);
if (rc != CKR_OK) {
testcase_fail("Derived key #1 is not usable: %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
break;
case CKK_AES:
enc1_len = sizeof(enc1);
rc = run_AESEncrypt(session, secret_keyA,
enc1, &enc1_len);
if (rc != CKR_OK) {
testcase_fail("Derived key #1 is not usable: %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
break;
}
// Now, derive a generic secret key using B's private key
// and A's public key
ecdh_parmB.kdf = kdfs[j];
ecdh_parmB.pPublicData = extr1_tmpl->pValue;
ecdh_parmB.ulPublicDataLen = extr1_tmpl->ulValueLen;
ecdh_parmB.pSharedData =
shared_data[m].length == 0 ?
NULL : (CK_BYTE_PTR)&shared_data[m].data;
ecdh_parmB.ulSharedDataLen = shared_data[m].length;
if (kdfs[j] == CKD_NULL) {
ecdh_parmB.pSharedData = NULL;
ecdh_parmB.ulSharedDataLen = 0;
}
mech.mechanism = derive_mech_type;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parmB;
rc = funcs->C_DeriveKey(session, &mech,
priv_keyB, derive_tmpl,
secret_tmpl_len, &secret_keyB);
if (rc != CKR_OK) {
if (is_ep11_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
(kdfs[j] != CKD_NULL ||
shared_data[m].length > 0)) {
testcase_skip("EP11 does not support KDF %s and/or "
"shared data with older firmware "
"versions\n",
p11_get_ckd(kdfs[j]));
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
continue;
}
if (is_icsf_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
kdfs[j] != CKD_NULL &&
kdfs[j] != CKD_SHA224_KDF &&
kdfs[j] != CKD_SHA256_KDF &&
kdfs[j] != CKD_SHA384_KDF &&
kdfs[j] != CKD_SHA512_KDF) {
testcase_skip("ICSF does not support KDF %s\n",
p11_get_ckd(kdfs[j]));
continue;
}
if (is_rejected_by_policy(rc, session)) {
testcase_skip("key derivation is not allowed by policy");
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
continue;
}
if (rc == CKR_FUNCTION_CANCELED) {
testcase_skip("key derivation is not allowed by "
"adapter control point");
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
continue;
}
if (rc == CKR_KEY_SIZE_RANGE) {
testcase_skip("key derivation is not allowed "
"because key to be generated is "
"stronger than the input material.");
continue;
}
testcase_fail("C_DeriveKey #2: rc = %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
switch (key_type) {
case CKK_GENERIC_SECRET:
mac2_len = sizeof(mac2);
rc = run_HMACSign(session, secret_keyB,
secret_key_len[k] > 0 ?
secret_key_len[k] : curve_len(i),
CKM_SHA_1_HMAC, mac2, &mac2_len);
if (rc != CKR_OK) {
testcase_fail("Derived key #2 is not usable: %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
if (mac1_len != mac2_len ||
memcmp(mac1, mac2, mac1_len) != 0) {
testcase_fail("ERROR: derived keys do not produce the "
"same HMAC");
goto testcase_cleanup;
}
break;
case CKK_AES:
enc2_len = sizeof(enc2);
rc = run_AESEncrypt(session, secret_keyA,
enc2, &enc2_len);
if (rc != CKR_OK) {
testcase_fail("Derived key #1 is not usable: %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
if (enc1_len != enc2_len ||
memcmp(enc1, enc2, enc1_len) != 0) {
testcase_fail("ERROR: derived keys do not produce the "
"same encrypted cipher text");
goto testcase_cleanup;
}
break;
}
/* A secure key token won't reveal the key value in clear */
if (!is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
// Extract the derived secret A
rc = funcs->C_GetAttributeValue(session, secret_keyA,
secretA_tmpl,
secretA_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #3:rc = %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
// Extract the derived secret B
rc = funcs->C_GetAttributeValue(session, secret_keyB,
secretB_tmpl,
secretB_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #4:rc = %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
// Compare lengths of derived secrets from key object
if (secretA_tmpl[0].ulValueLen !=
secretB_tmpl[0].ulValueLen) {
testcase_fail("ERROR: derived key #1 length = %lu, "
"derived key #2 length = %lu",
secretA_tmpl[0].ulValueLen,
secretB_tmpl[0].ulValueLen);
goto testcase_cleanup;
}
// Compare derive secrets A and B
if (memcmp(secretA_tmpl[0].pValue,
secretB_tmpl[0].pValue,
secretA_tmpl[0].ulValueLen) != 0) {
testcase_fail("ERROR: derived key mismatch, curve=%s, "
"kdf=%s, keylen=%lu, shared_data=%u",
der_ec_supported[i].name,
p11_get_ckd(kdfs[j]), secret_key_len[k],
shared_data[m].length);
goto testcase_cleanup;
}
}
testcase_pass("*Derive shared secret curve=%s, kdf=%s, "
"keylen=%lu, shared_data=%u, mech=%s passed.",
der_ec_supported[i].name,
p11_get_ckd(kdfs[j]), secret_key_len[k],
shared_data[m].length,
p11_get_ckm(&mechtable_funcs, derive_mech_type));
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
}
}
}
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
}
testcase_cleanup:
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
testcase_user_logout();
testcase_close_session();
return rc;
} /* end run_DeriveECDHKey() */
/*
* Run some ECDH known answer tests.
*/
CK_RV run_DeriveECDHKeyKAT(void)
{
CK_SESSION_HANDLE session;
CK_MECHANISM mech;
CK_FLAGS flags;
CK_OBJECT_HANDLE publ_keyA = CK_INVALID_HANDLE,
priv_keyA = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE publ_keyB = CK_INVALID_HANDLE,
priv_keyB = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE secret_keyA = CK_INVALID_HANDLE,
secret_keyB = CK_INVALID_HANDLE;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_KEY_TYPE secret_key_type = CKK_GENERIC_SECRET;
CK_OBJECT_CLASS class = CKO_SECRET_KEY;
CK_ECDH1_DERIVE_PARAMS ecdh_parmA, ecdh_parmB;
CK_BBOOL false = CK_FALSE;
CK_ULONG user_pin_len;
CK_RV rc = CKR_OK;
CK_BYTE secretA_value[1000] = { 0 }; // enough space for key lengths in ecdh_tv[]
CK_BYTE secretB_value[1000] = { 0 };
CK_BYTE mac1[SHA1_HASH_SIZE] = { 0 };
CK_ULONG mac1_len = sizeof(mac1);
CK_BYTE mac2[SHA1_HASH_SIZE] = { 0 };
CK_ULONG mac2_len = sizeof(mac2);
CK_BYTE macexpected[SHA1_HASH_SIZE] = { 0 };
CK_ULONG macexpected_len = sizeof(macexpected);
CK_ULONG i;
testcase_begin("starting run_DeriveECDHKeyKAT with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_ECDH1_DERIVE)) {
testcase_skip("Slot %u doesn't support CKM_ECDH1_DERIVE\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) &&
!mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) {
testcase_skip("Slot %u doesn't support CKM_SHA_1_HMAC, correctness "
"of derived keys can not be verified\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (is_cca_token(SLOT_ID)) {
testcase_skip("The CCA token in slot %u doesn't support ECDH with EC "
"keys imported from clear, only with randomly generated "
"keys. KATs not possible because of that\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
for (i=0; i<ECDH_TV_NUM; i++) {
testcase_begin("Starting with shared secret i=%lu, pkey=%X", i, pkey);
switch (ecdh_tv[i].kdf) {
case CKD_SHA1_KDF:
case CKD_SHA1_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA_1)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA224_KDF:
case CKD_SHA224_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA224)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA256_KDF:
case CKD_SHA256_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA256)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA384_KDF:
case CKD_SHA384_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA384)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA512_KDF:
case CKD_SHA512_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA512)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA3_224_KDF:
case CKD_SHA3_224_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_224)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA3_256_KDF:
case CKD_SHA3_256_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_256)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA3_384_KDF:
case CKD_SHA3_384_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_384)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
case CKD_SHA3_512_KDF:
case CKD_SHA3_512_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_512)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
break;
default:
break;
}
if (is_icsf_token(SLOT_ID)) {
switch (ecdh_tv[i].kdf) {
case CKD_SHA1_KDF:
case CKD_SHA224_KDF:
case CKD_SHA256_KDF:
case CKD_SHA384_KDF:
break;
default:
testcase_skip("The ICSF token in slot %u doesn't support "
"%s\n",
(unsigned int) SLOT_ID, p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
}
if (is_ep11_token(SLOT_ID) && ecdh_tv[i].derived_key_len > 256) {
testcase_skip("EP11 cannot provide %lu key bytes with "
"curve %s\n", ecdh_tv[i].derived_key_len,
ecdh_tv[i].name);
continue;
}
if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) &&
!check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC,
ecdh_tv[i].derived_key_len * 8)) {
testcase_skip("Mechanism CKM_SHA_1_HMAC can not be used with "
"keys of size %lu. Correctness of derived key "
"can not be verified.",
ecdh_tv[i].derived_key_len);
continue;
}
if (is_icsf_token(SLOT_ID)) {
if (der_ec_supported[i].twisted) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, der_ec_supported[i].name);
continue;
}
if (der_ec_supported[i].type != CURVE_BRAINPOOL &&
der_ec_supported[i].type != CURVE_PRIME &&
der_ec_supported[i].type != CURVE_KOBLITZ) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,der_ec_supported[i].name);
continue;
}
}
// First, import the EC key pair for party A
rc = create_ECPrivateKey(session, CKK_EC,
ecdh_tv[i].params, ecdh_tv[i].params_len,
ecdh_tv[i].privkeyA, ecdh_tv[i].privkey_len,
&priv_keyA, !pkey, CK_TRUE);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
rc = create_ECPublicKey(session, CKK_EC,
ecdh_tv[i].params, ecdh_tv[i].params_len,
ecdh_tv[i].pubkeyA, ecdh_tv[i].pubkey_len,
&publ_keyA, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
funcs->C_DestroyObject(session, priv_keyA);
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
// Now import the EC key pair for party B
rc = create_ECPrivateKey(session, CKK_EC,
ecdh_tv[i].params, ecdh_tv[i].params_len,
ecdh_tv[i].privkeyB, ecdh_tv[i].privkey_len,
&priv_keyB, !pkey, CK_TRUE);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
rc = create_ECPublicKey(session, CKK_EC,
ecdh_tv[i].params, ecdh_tv[i].params_len,
ecdh_tv[i].pubkeyB, ecdh_tv[i].pubkey_len,
&publ_keyB, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
// Now derive the secrets...
CK_ATTRIBUTE secretA_tmpl[] = {
{CKA_VALUE, secretA_value, sizeof(secretA_value)}
};
CK_ULONG secretA_tmpl_len = sizeof(secretA_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE secretB_tmpl[] = {
{CKA_VALUE, secretB_value, sizeof(secretB_value)}
};
CK_ULONG secretB_tmpl_len = sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE);
CK_BBOOL extractable = !pkey;
CK_ATTRIBUTE derive_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)},
{CKA_VALUE_LEN, &(ecdh_tv[i].derived_key_len), sizeof(CK_ULONG)},
{CKA_SENSITIVE, &false, sizeof(false)},
{CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)},
};
CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE);
// Now, derive a generic secret key using party A's private key
// and B's public key
ecdh_parmA.kdf = ecdh_tv[i].kdf;
ecdh_parmA.pPublicData = ecdh_tv[i].pubkeyB;
ecdh_parmA.ulPublicDataLen = ecdh_tv[i].pubkey_len;
ecdh_parmA.pSharedData =
ecdh_tv[i].shared_data_len == 0 ?
NULL : (CK_BYTE_PTR)&ecdh_tv[i].shared_data;
ecdh_parmA.ulSharedDataLen = ecdh_tv[i].shared_data_len;
if (ecdh_tv[i].kdf == CKD_NULL) {
ecdh_parmA.pSharedData = NULL;
ecdh_parmA.ulSharedDataLen = 0;
}
mech.mechanism = CKM_ECDH1_DERIVE;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parmA;
rc = funcs->C_DeriveKey(session, &mech,
priv_keyA, derive_tmpl,
derive_tmpl_len, &secret_keyA);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ecdh_tv[i].name);
goto testcase_next;
} else if (is_ep11_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
(ecdh_tv[i].kdf != CKD_NULL ||
ecdh_tv[i].shared_data_len > 0)) {
testcase_skip("EP11 does not support KDF %s and/or shared data "
"with older firmware versions\n",
p11_get_ckd(ecdh_tv[i].kdf));
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
continue;
} else if (is_icsf_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
ecdh_tv[i].kdf != CKD_NULL &&
ecdh_tv[i].kdf != CKD_SHA224_KDF &&
ecdh_tv[i].kdf != CKD_SHA256_KDF &&
ecdh_tv[i].kdf != CKD_SHA384_KDF &&
ecdh_tv[i].kdf != CKD_SHA512_KDF) {
testcase_skip("ICSF does not support KDF %s\n",
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
// Now, derive a generic secret key using B's private key and
// A's public key
ecdh_parmB.kdf = ecdh_tv[i].kdf;
ecdh_parmB.pPublicData = ecdh_tv[i].pubkeyA;
ecdh_parmB.ulPublicDataLen = ecdh_tv[i].pubkey_len;
ecdh_parmB.pSharedData =
ecdh_tv[i].shared_data_len == 0 ?
NULL : (CK_BYTE_PTR)&ecdh_tv[i].shared_data;
ecdh_parmB.ulSharedDataLen = ecdh_tv[i].shared_data_len;
if (ecdh_tv[i].kdf == CKD_NULL) {
ecdh_parmB.pSharedData = NULL;
ecdh_parmB.ulSharedDataLen = 0;
}
mech.mechanism = CKM_ECDH1_DERIVE;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parmB;
rc = funcs->C_DeriveKey(session, &mech,
priv_keyB, derive_tmpl,
derive_tmpl_len, &secret_keyB);
if (rc != CKR_OK) {
if (is_ep11_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
(ecdh_tv[i].kdf != CKD_NULL ||
ecdh_tv[i].shared_data_len > 0)) {
testcase_skip("EP11 does not support KDF %s and/or shared data "
"with older firmware versions\n",
p11_get_ckd(ecdh_tv[i].kdf));
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
continue;
} else if (is_icsf_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
ecdh_tv[i].kdf != CKD_NULL &&
ecdh_tv[i].kdf != CKD_SHA224_KDF &&
ecdh_tv[i].kdf != CKD_SHA256_KDF &&
ecdh_tv[i].kdf != CKD_SHA384_KDF &&
ecdh_tv[i].kdf != CKD_SHA512_KDF) {
testcase_skip("ICSF does not support KDF %s\n",
p11_get_ckd(ecdh_tv[i].kdf));
continue;
}
testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
testcase_new_assertion();
/* A secure key token won't reveal the key value in clear */
if (!is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
// Extract the derived secret A
rc = funcs->C_GetAttributeValue(session, secret_keyA,
secretA_tmpl, secretA_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #3:rc = %s",
p11_get_ckr(rc));
goto testcase_next;
}
// Compare lengths of derived secret from key object
if (ecdh_tv[i].derived_key_len != secretA_tmpl[0].ulValueLen) {
testcase_fail("ERROR:derived key #1 length = %lu, "
"derived key #2 length = %lu",
ecdh_tv[i].derived_key_len,
secretA_tmpl[0].ulValueLen);
goto testcase_next;
}
// Compare with known value
if (memcmp(secretA_tmpl[0].pValue,
ecdh_tv[i].derived_key,
ecdh_tv[i].derived_key_len) != 0) {
testcase_fail("ERROR:derived key mismatch, i=%lu",i);
goto testcase_next;
}
// Extract the derived secret B
rc = funcs->C_GetAttributeValue(session, secret_keyB,
secretB_tmpl, secretB_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #4:rc = %s",
p11_get_ckr(rc));
goto testcase_next;
}
// Compare lengths of derived secret from key object
if (ecdh_tv[i].derived_key_len != secretB_tmpl[0].ulValueLen) {
testcase_fail("ERROR:derived key #1 length = %lu, derived key "
"#2 length = %lu", ecdh_tv[i].derived_key_len,
secretB_tmpl[0].ulValueLen);
goto testcase_next;
}
// Compare with known value
if (memcmp(secretB_tmpl[0].pValue,
ecdh_tv[i].derived_key,
ecdh_tv[i].derived_key_len) != 0) {
testcase_fail("ERROR:derived key mismatch, i=%lu",i);
goto testcase_next;
}
} else {
/* Secure key:
* Calculate HMAC with derived keys and expected key and compare
* the MAC.
*/
rc = run_HMACSign_OpenSSL(ecdh_tv[i].derived_key,
ecdh_tv[i].derived_key_len,
CKM_SHA_1_HMAC,
macexpected, &macexpected_len);
if (rc != CKR_OK) {
testcase_fail("HMAC for expected key failed: %s",
p11_get_ckr(rc));
goto testcase_next;
}
rc = run_HMACSign(session, secret_keyA, ecdh_tv[i].derived_key_len,
CKM_SHA_1_HMAC, mac1, &mac1_len);
if (rc != CKR_OK) {
testcase_fail("HMAC for derived key #1 failed: %s",
p11_get_ckr(rc));
goto testcase_next;
}
if (mac1_len != 0 && /* skip check if mac can't be calcualted */
(mac1_len != macexpected_len ||
memcmp(mac1, macexpected, mac1_len) != 0)) {
testcase_fail("ERROR: derived key #1 does not produce the "
"expected HMAC");
goto testcase_next;
}
rc = run_HMACSign(session, secret_keyB, ecdh_tv[i].derived_key_len,
CKM_SHA_1_HMAC, mac2, &mac2_len);
if (rc != CKR_OK) {
testcase_fail("HMAC for derived key #2 failed: %s",
p11_get_ckr(rc));
goto testcase_next;
}
if (mac2_len != 0 && /* skip check if mac can't be calcualted */
(mac2_len != macexpected_len ||
memcmp(mac2, macexpected, mac2_len) != 0)) {
testcase_fail("ERROR: derived key #2 does not produce the "
"expected HMAC");
goto testcase_next;
}
}
testcase_pass("*Derive shared secret i=%lu passed.", i);
testcase_next:
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
}
testcase_cleanup:
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
testcase_user_logout();
testcase_close_session();
return rc;
} /* end run_DeriveECDHKeyKAT() */
CK_RV run_GenerateSignVerifyECC(CK_SESSION_HANDLE session,
CK_MECHANISM *mech,
CK_ULONG inputlen,
CK_ULONG parts,
CK_OBJECT_HANDLE priv_key,
CK_OBJECT_HANDLE publ_key,
enum curve_type curve_type,
CK_BYTE *params, CK_ULONG params_len)
{
CK_BYTE_PTR data = NULL, signature = NULL;
CK_ULONG i, signaturelen;
CK_MECHANISM_INFO mech_info;
CK_RV rc;
if ((mech->mechanism == CKM_IBM_ED25519_SHA512 ||
mech->mechanism == CKM_IBM_ED448_SHA3)) {
if (curve_type != CURVE_EDWARDS) {
/* Mechanism does not match to curve type, skip */
rc = CKR_OK;
goto testcase_cleanup;
}
if (mech->mechanism == CKM_IBM_ED25519_SHA512 &&
memcmp(params, ed25519, MIN(params_len, sizeof(ed25519))) != 0) {
/* Mechanism does not match to curve, skip */
rc = CKR_OK;
goto testcase_cleanup;
}
if (mech->mechanism == CKM_IBM_ED448_SHA3 &&
memcmp(params, ed448, MIN(params_len, sizeof(ed448))) != 0) {
/* Mechanism does not match to curve, skip */
rc = CKR_OK;
goto testcase_cleanup;
}
} else if (mech->mechanism == CKM_IBM_ECDSA_OTHER &&
memcmp(params, secp256k1, MIN(params_len, sizeof(secp256k1))) != 0 &&
memcmp(params, prime256v1, MIN(params_len, sizeof(prime256v1))) != 0 &&
memcmp(params, brainpoolP256r1, MIN(params_len, sizeof(brainpoolP256r1))) != 0 &&
memcmp(params, brainpoolP256t1, MIN(params_len, sizeof(brainpoolP256t1))) != 0 &&
memcmp(params, bls12_381, MIN(params_len, sizeof(bls12_381))) != 0) {
/* CKM_IBM_ECDSA_OTHER can only be used with 256-bit or BLS EC curves, skip */
rc = CKR_OK;
goto testcase_cleanup;
} else if (mech->mechanism == CKM_IBM_ECDSA_OTHER &&
memcmp(params, bls12_381, MIN(params_len, sizeof(bls12_381))) == 0 &&
mech->pParameter != NULL &&
mech->ulParameterLen == sizeof(CK_IBM_ECDSA_OTHER_PARAMS) &&
((CK_IBM_ECDSA_OTHER_PARAMS *)mech->pParameter)->submechanism != CKM_IBM_BLS) {
/* ECDSA_OTHER: BLS curve can only be used with CKM_IBM_BLS sub mech, skip */
rc = CKR_OK;
goto testcase_cleanup;
} else if (mech->mechanism == CKM_IBM_ECDSA_OTHER &&
memcmp(params, bls12_381, MIN(params_len, sizeof(bls12_381))) != 0 &&
mech->pParameter != NULL &&
mech->ulParameterLen == sizeof(CK_IBM_ECDSA_OTHER_PARAMS) &&
((CK_IBM_ECDSA_OTHER_PARAMS *)mech->pParameter)->submechanism == CKM_IBM_BLS) {
/* ECDSA_OTHER: Non-BLS curve can not be used with CKM_IBM_BLS sub mech, skip */
rc = CKR_OK;
goto testcase_cleanup;
} else if (mech->mechanism == CKM_EDDSA) {
if (curve_type != CURVE_EDWARDS) {
/* Mechanism does not match to curve type, skip */
rc = CKR_OK;
goto testcase_cleanup;
}
if (memcmp(params, ed448, MIN(params_len, sizeof(ed448))) == 0 &&
mech->pParameter == NULL) {
/* Ed448 requires a mechanism parameter, skip */
rc = CKR_OK;
goto testcase_cleanup;
}
} else if (mech->mechanism != CKM_IBM_ED25519_SHA512 &&
mech->mechanism != CKM_IBM_ED448_SHA3 &&
mech->mechanism != CKM_IBM_ECDSA_OTHER &&
mech->mechanism != CKM_EDDSA) {
if (curve_type == CURVE_EDWARDS || curve_type == CURVE_MONTGOMERY ||
curve_type == CURVE_BLS12_381) {
/* Mechanism does not match to curve type, skip */
rc = CKR_OK;
goto testcase_cleanup;
}
}
testcase_begin("Starting with mechtype='%s', inputlen=%lu parts=%lu, pkey=%X",
p11_get_ckm(&mechtable_funcs, mech->mechanism), inputlen, parts, pkey);
/* query the slot, check if this mech if supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech->mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support %s",
(unsigned int) SLOT_ID,
p11_get_ckm(&mechtable_funcs, mech->mechanism));
rc = CKR_OK;
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
if (inputlen > 0) {
data = calloc(inputlen, sizeof(CK_BYTE));
if (data == NULL) {
testcase_error("Can't allocate memory for %lu bytes",
sizeof(CK_BYTE) * inputlen);
rc = -1;
goto testcase_cleanup;
}
for (i = 0; i < inputlen; i++) {
data[i] = (i + 1) % 255;
}
}
rc = funcs->C_SignInit(session, mech, priv_key);
if (rc != CKR_OK) {
if (mech->mechanism == CKM_EDDSA && rc == CKR_MECHANISM_PARAM_INVALID) {
testcase_skip("EdDSA mechanism parameter combination is not "
"supported");
rc = CKR_OK;
goto testcase_cleanup;
}
testcase_error("C_SignInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (parts > 0) {
if (inputlen > 0) {
for (i = 0; i < parts && inputlen > 0; i++) {
rc = funcs->C_SignUpdate(session, data, inputlen);
if (rc != CKR_OK) {
testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
} else {
rc = funcs->C_SignUpdate(session, NULL, 0);
if (rc != CKR_OK) {
testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
/* get signature length */
rc = funcs->C_SignFinal(session, signature, &signaturelen);
if (rc != CKR_OK) {
testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
} else {
rc = funcs->C_Sign(session, data != NULL ? data : (CK_BYTE *)"",
inputlen, NULL, &signaturelen);
if (rc != CKR_OK) {
if (mech->mechanism == CKM_EDDSA &&
rc == CKR_MECHANISM_PARAM_INVALID) {
testcase_skip("EdDSA mechanism parameter combination is not "
"supported");
rc = CKR_OK;
goto testcase_cleanup;
}
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
signature = calloc(signaturelen, sizeof(CK_BYTE));
if (signature == NULL) {
testcase_error("Can't allocate memory for %lu bytes",
sizeof(CK_BYTE) * signaturelen);
rc = -1;
goto testcase_cleanup;
}
if (parts > 0) {
rc = funcs->C_SignFinal(session, signature, &signaturelen);
if (rc != CKR_OK) {
testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
} else {
rc = funcs->C_Sign(session, data != NULL ? data : (CK_BYTE *)"",
inputlen, signature, &signaturelen);
if (rc != CKR_OK) {
if (mech->mechanism == CKM_EDDSA &&
rc == CKR_MECHANISM_PARAM_INVALID) {
testcase_skip("EdDSA mechanism parameter combination is not "
"supported");
rc = CKR_OK;
goto testcase_cleanup;
}
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
/****** Verify *******/
rc = funcs->C_VerifyInit(session, mech, publ_key);
if (rc != CKR_OK) {
testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (parts > 0) {
if (inputlen > 0) {
for (i = 0; i < parts && inputlen > 0; i++) {
rc = funcs->C_VerifyUpdate(session, data, inputlen);
if (rc != CKR_OK) {
testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
} else {
rc = funcs->C_VerifyUpdate(session, NULL, 0);
if (rc != CKR_OK) {
testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
rc = funcs->C_VerifyFinal(session, signature, signaturelen);
if (rc != CKR_OK) {
testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
} else {
rc = funcs->C_Verify(session, data != NULL ? data : (CK_BYTE *)"",
inputlen, signature, signaturelen);
if (rc != CKR_OK) {
testcase_error("C_Verify rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
// corrupt the signature and re-verify
memcpy(signature, "ABCDEFGHIJKLMNOPQRSTUV",
strlen("ABCDEFGHIJKLMNOPQRSTUV"));
rc = funcs->C_VerifyInit(session, mech, publ_key);
if (rc != CKR_OK) {
testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (parts > 0) {
if (inputlen > 0) {
for (i = 0; i < parts && inputlen > 0; i++) {
rc = funcs->C_VerifyUpdate(session, data, inputlen);
if (rc != CKR_OK) {
testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
} else {
rc = funcs->C_VerifyUpdate(session, NULL, 0);
if (rc != CKR_OK) {
testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
rc = funcs->C_VerifyFinal(session, signature, signaturelen);
if (rc != CKR_SIGNATURE_INVALID) {
if (rc == CKR_FUNCTION_FAILED && is_ica_token(SLOT_ID)) {
testcase_notice("C_VerifyFinal rc=%s temporarily accepted for ICA token",
p11_get_ckr(rc));
} else {
testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc));
PRINT_ERR(" Expected CKR_SIGNATURE_INVALID\n");
goto testcase_cleanup;
}
}
} else {
rc = funcs->C_Verify(session, data != NULL ? data : (CK_BYTE *)"",
inputlen, signature, signaturelen);
if (rc != CKR_SIGNATURE_INVALID) {
if (rc == CKR_FUNCTION_FAILED && is_ica_token(SLOT_ID)) {
testcase_notice("C_Verify rc=%s temporarily accepted for ICA token",
p11_get_ckr(rc));
} else {
testcase_error("C_Verify rc=%s", p11_get_ckr(rc));
PRINT_ERR(" Expected CKR_SIGNATURE_INVALID\n");
goto testcase_cleanup;
}
}
}
rc = CKR_OK;
testcase_cleanup:
if (data)
free(data);
if (signature)
free(signature);
return rc;
}
CK_RV run_GenerateECCKeyPairSignVerify(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, i, j;
CK_FLAGS flags;
CK_MECHANISM_INFO mech_info;
CK_RV rc;
testcase_begin("Starting ECC generate key pair with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
mech.mechanism = CKM_EC_KEY_PAIR_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
/* query the slot, check if this mech is supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN",
(unsigned int) SLOT_ID);
rc = CKR_OK;
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
for (i = 0; i < NUMEC; i++) {
if (der_ec_supported[i].type == CURVE_MONTGOMERY) {
/* Montgomery curves can not be used for sign/verify. */
continue;
}
if (is_cca_token(SLOT_ID)) {
if (der_ec_supported[i].twisted) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, der_ec_supported[i].name);
continue;
}
if (der_ec_supported[i].type != CURVE_BRAINPOOL &&
der_ec_supported[i].type != CURVE_PRIME &&
der_ec_supported[i].type != CURVE_KOBLITZ) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,der_ec_supported[i].name);
continue;
}
}
if (is_icsf_token(SLOT_ID)) {
if (der_ec_supported[i].twisted ||
der_ec_supported[i].type == CURVE_EDWARDS ||
der_ec_supported[i].type == CURVE_BLS12_381) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, der_ec_supported[i].name);
continue;
}
}
rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN,
(CK_BYTE *)der_ec_supported[i].curve,
der_ec_supported[i].size,
&publ_key, &priv_key, !pkey);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
continue;
}
if (rc == CKR_MECHANISM_PARAM_INVALID ||
rc == CKR_ATTRIBUTE_VALUE_INVALID ||
rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, der_ec_supported[i].name);
continue;
}
testcase_fail
("generate_EC_KeyPair with valid input failed at i=%lu (%s), "
"rc=%s", i, der_ec_supported[i].name, p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Generate supported key pair index=%lu (%s) passed.", i,
der_ec_supported[i].name);
for (j = 0;
j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) {
testcase_new_assertion();
rc = run_GenerateSignVerifyECC(session,
&signVerifyInput[j].mech,
signVerifyInput[j].inputlen,
signVerifyInput[j].parts,
priv_key, publ_key,
der_ec_supported[i].type,
(CK_BYTE *)der_ec_supported[i].curve,
der_ec_supported[i].size);
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed index=%lu. i=%lu.", j, i);
goto testcase_cleanup;
}
testcase_pass("*Sign & verify i=%lu (%s), j=%lu passed.", i,
der_ec_supported[i].name, j);
}
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
publ_key = CK_INVALID_HANDLE;
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
priv_key = CK_INVALID_HANDLE;
}
for (i = 0; i < NUMECINVAL; i++) {
rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN,
(CK_BYTE *)der_ec_notsupported[i].curve,
der_ec_notsupported[i].size,
&publ_key, &priv_key, !pkey);
testcase_new_assertion();
if (rc == CKR_OK) {
testcase_fail
("generate_EC_KeyPair with invalid input failed at i=%lu (%s)",
i, der_ec_notsupported[i].name);
goto testcase_cleanup;
}
testcase_pass("*Generate unsupported key pair curve=%s passed.",
der_ec_notsupported[i].name);
}
rc = CKR_OK;
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
testcase_user_logout();
testcase_close_session();
return rc;
}
CK_RV run_ImportECCKeyPairSignVerify(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, i, j;
CK_FLAGS flags;
CK_MECHANISM_INFO mech_info;
CK_RV rc;
testcase_begin("Starting ECC import key pair with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
mech.mechanism = CKM_ECDSA;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
/* query the slot, check if this mech is supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support CKM_ECDSA",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
for (i = 0; i < EC_TV_NUM; i++) {
if ((is_ica_token(SLOT_ID) || is_cca_token(SLOT_ID) ||
is_icsf_token(SLOT_ID))) {
if (!curve_supported((char *)ec_tv[i].name)) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int)SLOT_ID,ec_tv[i].name);
continue;
}
}
if (ec_tv[i].curve_type == CURVE_MONTGOMERY) {
/* Sign/verify not supported for the curve. */
continue;
}
if (ec_tv[i].curve_type == CURVE_EDWARDS) {
if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) {
if (!mech_supported(SLOT_ID, CKM_IBM_ED25519_SHA512)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ED25519_SHA512\n",
(unsigned int) SLOT_ID);
continue;
}
} else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) {
if (!mech_supported(SLOT_ID, CKM_IBM_ED448_SHA3)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ED448_SHA3\n",
(unsigned int) SLOT_ID);
continue;
}
}
} else {
if (!mech_supported(SLOT_ID, CKM_ECDSA)) {
testcase_skip("Slot %u doesn't support CKM_ECDSA\n",
(unsigned int) SLOT_ID);
continue;
}
}
rc = create_ECPrivateKey(session, CKK_EC,
ec_tv[i].params, ec_tv[i].params_len,
ec_tv[i].privkey, ec_tv[i].privkey_len,
&priv_key, !pkey, CK_FALSE);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ec_tv[i].name);
continue;
}
if (is_ep11_token(SLOT_ID) &&
rc == CKR_ENCRYPTED_DATA_INVALID &&
(ec_tv[i].curve_type == CURVE_EDWARDS ||
ec_tv[i].curve_type == CURVE_MONTGOMERY)) {
testcase_skip("Slot %u doesn't support this curve %s with "
"older firmware versions",
(unsigned int)SLOT_ID, ec_tv[i].name);
continue;
}
testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu "
"(%s), rc=%s", i, ec_tv[i].name, p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Import EC private key (%s) index=%lu passed.",
ec_tv[i].name, i);
rc = create_ECPublicKey(session, CKK_EC,
ec_tv[i].params, ec_tv[i].params_len,
ec_tv[i].pubkey, ec_tv[i].pubkey_len,
&publ_key, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
funcs->C_DestroyObject(session, priv_key);
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ec_tv[i].name);
funcs->C_DestroyObject(session, priv_key);
continue;
}
if (is_ep11_token(SLOT_ID) &&
rc == CKR_ENCRYPTED_DATA_INVALID &&
(ec_tv[i].curve_type == CURVE_EDWARDS ||
ec_tv[i].curve_type == CURVE_MONTGOMERY)) {
testcase_skip("Slot %u doesn't support this curve %s with "
"older firmware versions",
(unsigned int)SLOT_ID, ec_tv[i].name);
funcs->C_DestroyObject(session, priv_key);
continue;
}
testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu "
"(%s), rc=%s", i, ec_tv[i].name, p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Import EC public key (%s) index=%lu passed.",
ec_tv[i].name, i);
/* create signature with private key */
for (j = 0;
j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) {
testcase_new_assertion();
rc = run_GenerateSignVerifyECC(session,
&signVerifyInput[j].mech,
signVerifyInput[j].inputlen,
signVerifyInput[j].parts,
priv_key, publ_key,
ec_tv[i].curve_type,
ec_tv[i].params,
ec_tv[i].params_len);
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed index=%lu.", j);
goto testcase_cleanup;
}
testcase_pass("*Sign & verify i=%lu, j=%lu passed.", i, j);
}
// clean up
rc = funcs->C_DestroyObject(session, publ_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
rc = funcs->C_DestroyObject(session, priv_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
}
goto done;
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
done:
testcase_user_logout();
testcase_close_session();
return rc;
}
CK_RV run_TransferECCKeyPairSignVerify(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, i, j;
CK_FLAGS flags;
CK_MECHANISM_INFO mech_info;
CK_RV rc;
CK_MECHANISM aes_keygen_mech;
CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE;
CK_BYTE_PTR wrapped_key = NULL;
CK_ULONG wrapped_keylen;
CK_OBJECT_HANDLE unwrapped_key = CK_INVALID_HANDLE;
CK_MECHANISM wrap_mech;
testcase_begin("Starting ECC transfer key pair with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
mech.mechanism = CKM_ECDSA;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
/* query the slot, check if this mech is supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support CKM_ECDSA",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_KEY_GEN, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for AES key gen? skip */
testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_CBC_PAD, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for AES CBC wrap? skip */
testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
if ((mech_info.flags & CKF_WRAP) == 0 ||
(mech_info.flags & CKF_UNWRAP) == 0) {
/* no support for AES CBC wrap? skip */
testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD for wrapping "
"keys", (unsigned int) SLOT_ID);
goto testcase_cleanup;
}
for (i = 0; i < EC_TV_NUM; i++) {
if (is_cca_token(SLOT_ID) || is_icsf_token(SLOT_ID)) {
if (strstr((char *)ec_tv[i].name, "t1") != NULL) {
testcase_skip("Slot %u doesn't support curve %s",
(unsigned int)SLOT_ID, ec_tv[i].name);
continue;
}
if (ec_tv[i].curve_type == CURVE_EDWARDS ||
ec_tv[i].curve_type == CURVE_MONTGOMERY ||
ec_tv[i].curve_type == CURVE_BLS12_381) {
testcase_skip("Slot %u doesn't support curve %s",
(unsigned int)SLOT_ID, ec_tv[i].name);
continue;
}
}
if (ec_tv[i].curve_type == CURVE_MONTGOMERY) {
/* Sign/verify not supported for the curve. */
continue;
}
if (ec_tv[i].curve_type == CURVE_EDWARDS) {
if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) {
if (!mech_supported(SLOT_ID, CKM_IBM_ED25519_SHA512)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ED25519_SHA512\n",
(unsigned int) SLOT_ID);
continue;
}
} else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) {
if (!mech_supported(SLOT_ID, CKM_IBM_ED448_SHA3)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ED448_SHA3\n",
(unsigned int) SLOT_ID);
continue;
}
}
} else {
if (!mech_supported(SLOT_ID, CKM_ECDSA)) {
testcase_skip("Slot %u doesn't support CKM_ECDSA\n",
(unsigned int) SLOT_ID);
continue;
}
}
rc = create_ECPrivateKey(session, CKK_EC,
ec_tv[i].params, ec_tv[i].params_len,
ec_tv[i].privkey, ec_tv[i].privkey_len,
&priv_key, CK_TRUE, // key to be wrapped must be extractable
CK_FALSE);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ec_tv[i].name);
continue;
}
if (is_ep11_token(SLOT_ID) &&
rc == CKR_ENCRYPTED_DATA_INVALID &&
(ec_tv[i].curve_type == CURVE_EDWARDS ||
ec_tv[i].curve_type == CURVE_MONTGOMERY)) {
testcase_skip("Slot %u doesn't support this curve %s with "
"older firmware versions",
(unsigned int)SLOT_ID, ec_tv[i].name);
continue;
}
testcase_fail
("C_CreateObject (EC Private Key) failed at i=%lu, rc=%s", i,
p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Import EC private key (%s) index=%lu passed.",
ec_tv[i].name, i);
rc = create_ECPublicKey(session, CKK_EC,
ec_tv[i].params, ec_tv[i].params_len,
ec_tv[i].pubkey, ec_tv[i].pubkey_len,
&publ_key, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
funcs->C_DestroyObject(session, priv_key);
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ec_tv[i].name);
funcs->C_DestroyObject(session, priv_key);
continue;
}
if (is_ep11_token(SLOT_ID) &&
rc == CKR_ENCRYPTED_DATA_INVALID &&
(ec_tv[i].curve_type == CURVE_EDWARDS ||
ec_tv[i].curve_type == CURVE_MONTGOMERY)) {
testcase_skip("Slot %u doesn't support this curve %s with "
"older firmware versions",
(unsigned int)SLOT_ID, ec_tv[i].name);
funcs->C_DestroyObject(session, priv_key);
continue;
}
testcase_fail
("C_CreateObject (EC Public Key) failed at i=%lu, rc=%s", i,
p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Import EC public key (%s) index=%lu passed.",
ec_tv[i].name, i);
/* create wrapping key (secret key) */
aes_keygen_mech.mechanism = CKM_AES_KEY_GEN;
CK_OBJECT_CLASS wkclass = CKO_SECRET_KEY;
CK_ULONG keylen = 32;
CK_BBOOL true = TRUE;
CK_BBOOL false = FALSE;
CK_BBOOL sign = TRUE;
CK_BBOOL derive = TRUE;
CK_BYTE wrap_key_label[] = "Wrap_Key";
CK_OBJECT_CLASS wclass = CKO_PRIVATE_KEY;
CK_KEY_TYPE keyType = CKK_EC;
CK_ATTRIBUTE cka_wrap_tmpl[] = {
{CKA_PRIVATE, &true, sizeof(true)},
{CKA_CLASS, &wclass, sizeof(wclass)},
{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
};
CK_ATTRIBUTE cka_unwrap_tmpl[] = {
{CKA_DECRYPT, &true, sizeof(true)},
{CKA_SIGN, &sign, sizeof(sign)},
{CKA_DERIVE, &derive, sizeof(derive)},
{CKA_PRIVATE, &true, sizeof(true)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)},
{CKA_EXTRACTABLE, &false, sizeof(false)},
};
CK_ATTRIBUTE secret_tmpl[] = {
{CKA_CLASS, &wkclass, sizeof(wkclass)},
{CKA_VALUE_LEN, &keylen, sizeof(keylen)},
{CKA_LABEL, &wrap_key_label, sizeof(wrap_key_label)},
{CKA_TOKEN, &true, sizeof(true)},
{CKA_WRAP, &true, sizeof(true)},
{CKA_UNWRAP, &true, sizeof(true)},
{CKA_WRAP_TEMPLATE, &cka_wrap_tmpl, sizeof(cka_wrap_tmpl)},
{CKA_UNWRAP_TEMPLATE, &cka_unwrap_tmpl, sizeof(cka_unwrap_tmpl)},
};
CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE);
if (ec_tv[i].curve_type == CURVE_EDWARDS)
derive = FALSE;
if (ec_tv[i].curve_type == CURVE_MONTGOMERY)
sign = FALSE;
if (ec_tv[i].curve_type == CURVE_BLS12_381) {
sign = TRUE;
derive = TRUE;
}
if (is_icsf_token(SLOT_ID))
secret_tmpl_len -= 2; /* ICSF does not support array-attributes */
rc = funcs->C_GenerateKey(session, &aes_keygen_mech, secret_tmpl,
secret_tmpl_len, &secret_key);
if (rc != CKR_OK) {
testcase_error("C_GenerateKey, rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
/* wrap/unwrap private and public EC key with a transport key */
// length only
wrap_mech.mechanism = CKM_AES_CBC_PAD;
wrap_mech.pParameter = "0123456789abcdef";
wrap_mech.ulParameterLen = 16;
rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key,
NULL, &wrapped_keylen);
if (rc != CKR_OK) {
testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc));
goto testcase_cleanup;
}
// allocate memory for wrapped_key
wrapped_key = calloc(wrapped_keylen, sizeof(CK_BYTE));
if (wrapped_key == NULL) {
testcase_error("Can't allocate memory for %lu bytes.",
sizeof(CK_BYTE) * wrapped_keylen);
rc = CKR_HOST_MEMORY;
goto testcase_cleanup;
}
// wrap key
//
rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key,
wrapped_key, &wrapped_keylen);
if (rc != CKR_OK) {
testcase_fail("C_WrapKey, rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
// unwrap key
//
CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
CK_KEY_TYPE key_type = CKK_EC;
CK_BYTE unwrap_label[] = "unwrapped_private_EC_Key";
CK_BYTE id[] = { 123 };
CK_ATTRIBUTE unwrap_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_TOKEN, &true, sizeof(true)},
{CKA_LABEL, &unwrap_label, sizeof(unwrap_label)},
{CKA_ID, id, sizeof(id)},
{CKA_SENSITIVE, &true, sizeof(true)},
{CKA_DERIVE, &derive, sizeof(derive)},
{CKA_SIGN, &sign, sizeof(sign)},
{CKA_EXTRACTABLE, &false, sizeof(false)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)},
};
CK_ULONG unwrap_tmpl_len = sizeof(unwrap_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE unwrap_base_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_DERIVE, &derive, sizeof(derive)},
{CKA_SIGN, &sign, sizeof(sign)},
};
if (is_icsf_token(SLOT_ID))
unwrap_tmpl_len -= 1; /* ICSF does not supp. CKA_IBM_PROTKEY_... */
rc = funcs->C_UnwrapKey(session, &wrap_mech, secret_key,
wrapped_key, wrapped_keylen,
unwrap_tmpl, unwrap_tmpl_len,
&unwrapped_key);
if (rc != CKR_OK) {
testcase_fail("C_UnwrapKey, rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
// unwrap again with each CKA_SENSITIVE / CKA_EXTRACTABLE choice; the
// transport key's CKA_UNWRAP_TEMPLATE sets CKA_EXTRACTABLE = FALSE
// (except on ICSF, which gets no array attributes)
rc = check_unwrap_sensitive_extractable(session, &wrap_mech,
secret_key, wrapped_key, wrapped_keylen, unwrap_base_tmpl,
sizeof(unwrap_base_tmpl) / sizeof(CK_ATTRIBUTE),
CKA_VALUE, NULL,
is_icsf_token(SLOT_ID) ? NULL : &false);
if (rc != CKR_OK)
goto testcase_cleanup;
if (wrapped_key) {
free(wrapped_key);
wrapped_key = NULL;
}
/* create signature with unwrapped private key and verify with
* public key */
for (j = 0;
j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) {
testcase_new_assertion();
rc = run_GenerateSignVerifyECC(session,
&signVerifyInput[j].mech,
signVerifyInput[j].inputlen,
signVerifyInput[j].parts,
unwrapped_key, publ_key,
ec_tv[i].curve_type,
ec_tv[i].params,
ec_tv[i].params_len);
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed index=%lu.", j);
goto testcase_cleanup;
}
testcase_pass("*Sign & verify i=%lu, j=%lu passed.", i, j);
}
// clean up
rc = funcs->C_DestroyObject(session, publ_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
rc = funcs->C_DestroyObject(session, priv_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
rc = funcs->C_DestroyObject(session, secret_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
rc = funcs->C_DestroyObject(session, unwrapped_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
}
goto done;
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
if (secret_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_key);
if (unwrapped_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, unwrapped_key);
if (wrapped_key)
free(wrapped_key);
done:
testcase_user_logout();
testcase_close_session();
return rc;
}
/**
* Tests the EP11 token protected key option. PKEY_MODE ENABLE4NONEXTR must be
* set in ep11tok.conf in order to activate protected key support. With MSA9,
* ECDSA with curves p256, p384, p521, and EDDSA with curves ed25519, and
* ed448 are supported via CPACF. On older machines there is no CPACF support
* for EC/ED at all and therefore all tests are performed only via the ep11
* card. So the actual behavior of this testcase heavily depends on the
* machine and token config.
*/
CK_RV run_ImportSignVerify_Pkey(void)
{
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len;
CK_FLAGS flags;
CK_RV rc;
CK_OBJECT_CLASS class;
CK_KEY_TYPE keytype = CKK_EC;
CK_BBOOL true = TRUE;
CK_BBOOL extr_priv, pkey_extr_priv, pkey_extr_pub;
CK_MECHANISM ec_mech = {CKM_ECDSA, NULL, 0};
CK_MECHANISM ed25519_mech = {CKM_IBM_ED25519_SHA512, NULL, 0};
CK_MECHANISM ed448_mech = {CKM_IBM_ED448_SHA3, NULL, 0};
CK_BYTE data[] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
};
CK_BYTE *sig = NULL;
CK_ULONG sig_len;
unsigned int i, j;
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
for (i = 0; i < EC_TV_NUM; i++) {
CK_ATTRIBUTE priv_tmpl[] = {
{CKA_CLASS, &class, sizeof(CK_OBJECT_CLASS)},
{CKA_KEY_TYPE, &keytype, sizeof(CK_KEY_TYPE)},
{CKA_PRIVATE, &true, sizeof(CK_BBOOL)},
{CKA_SIGN, &true, sizeof(CK_BBOOL)},
{CKA_EC_PARAMS, ec_tv[i].params, ec_tv[i].params_len},
{CKA_EC_POINT, ec_tv[i].pubkey, ec_tv[i].pubkey_len},
{CKA_VALUE, ec_tv[i].privkey, ec_tv[i].privkey_len},
{CKA_EXTRACTABLE, &extr_priv, sizeof(CK_BBOOL)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_extr_priv, sizeof(CK_BBOOL)},
};
CK_ATTRIBUTE publ_tmpl[] = {
{CKA_CLASS, &class, sizeof(CK_OBJECT_CLASS)},
{CKA_KEY_TYPE, &keytype, sizeof(CK_KEY_TYPE)},
{CKA_VERIFY, &true, sizeof(CK_BBOOL)},
{CKA_EC_PARAMS, ec_tv[i].params, ec_tv[i].params_len},
{CKA_EC_POINT, ec_tv[i].pubkey, ec_tv[i].pubkey_len},
{CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_extr_pub, sizeof(CK_BBOOL)},
};
if (ec_tv[i].curve_type == CURVE_MONTGOMERY) {
/* Sign/verify not supported for the curve. */
continue;
}
if (ec_tv[i].curve_type == CURVE_EDWARDS) {
if (memcmp(ec_tv[i].name, "ed25519", 7) == 0) {
if (!mech_supported(SLOT_ID, CKM_IBM_ED25519_SHA512)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ED25519_SHA512\n",
(unsigned int) SLOT_ID);
continue;
}
} else if (memcmp(ec_tv[i].name, "ed448", 5) == 0) {
if (!mech_supported(SLOT_ID, CKM_IBM_ED448_SHA3)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ED448_SHA3\n",
(unsigned int) SLOT_ID);
continue;
}
}
} else {
if (!mech_supported(SLOT_ID, CKM_ECDSA)) {
testcase_skip("Slot %u doesn't support CKM_ECDSA\n",
(unsigned int) SLOT_ID);
continue;
}
}
for (j = 0; j < 2; j++) {
if (ec_tv[i].curve_type == CURVE_BLS12_381) {
/* BLS does not use protected keys, skip */
continue;
}
if (j == 0)
testcase_begin("Starting Import EC private key (%s) index=%u sign via CPACF / verify via card",
ec_tv[i].name, i);
else
testcase_begin("Starting Import EC private key (%s) index=%u sign via card / verify via CPACF",
ec_tv[i].name, i);
/* j toggles between sign via protected key / verify via card
* and vice versa. */
if (j == 0) {
extr_priv = FALSE;
pkey_extr_priv = TRUE;
pkey_extr_pub = FALSE;
} else {
extr_priv = TRUE;
pkey_extr_priv = FALSE;
pkey_extr_pub = TRUE;
}
class = CKO_PRIVATE_KEY;
rc = funcs->C_CreateObject(session, priv_tmpl,
sizeof(priv_tmpl) / sizeof(CK_ATTRIBUTE),
&priv_key);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ec_tv[i].name);
continue;
}
testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
class = CKO_PUBLIC_KEY;
rc = funcs->C_CreateObject(session, publ_tmpl,
sizeof(publ_tmpl) / sizeof(CK_ATTRIBUTE),
&publ_key);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
goto testcase_cleanup;
}
testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (ec_tv[i].curve_type != CURVE_EDWARDS &&
ec_tv[i].curve_type != CURVE_MONTGOMERY)
rc = funcs->C_SignInit(session, &ec_mech, priv_key);
else if (memcmp(ec_tv[i].name, "ed25519", 7) == 0)
rc = funcs->C_SignInit(session, &ed25519_mech, priv_key);
else if (memcmp(ec_tv[i].name, "ed448", 5) == 0)
rc = funcs->C_SignInit(session, &ed448_mech, priv_key);
else {
/* Sign/verify not supported for the curve. */
continue;
}
if (rc != CKR_OK) {
testcase_error("C_SignInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
rc = funcs->C_Sign(session, data, sizeof(data), NULL, &sig_len);
if (rc != CKR_OK) {
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
sig = calloc(sig_len, sizeof(CK_BYTE));
if (sig == NULL) {
testcase_error("Can't allocate memory for %lu bytes", sig_len);
rc = CKR_HOST_MEMORY;
goto testcase_cleanup;
}
rc = funcs->C_Sign(session, data, sizeof(data), sig, &sig_len);
if (rc != CKR_OK) {
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (ec_tv[i].curve_type != CURVE_EDWARDS &&
ec_tv[i].curve_type != CURVE_MONTGOMERY)
rc = funcs->C_VerifyInit(session, &ec_mech, publ_key);
else if (memcmp(ec_tv[i].name, "ed25519", 7) == 0)
rc = funcs->C_VerifyInit(session, &ed25519_mech, publ_key);
else
rc = funcs->C_VerifyInit(session, &ed448_mech, publ_key);
if (rc != CKR_OK) {
testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Verify(session, data, sizeof(data), sig, sig_len);
if (rc != CKR_OK) {
testcase_error("C_Verify rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (sig) {
free(sig);
sig = NULL;
}
if (j == 0)
testcase_pass("*Import EC private key (%s) index=%u sign via CPACF / verify via card passed.",
ec_tv[i].name, i);
else
testcase_pass("*Import EC private key (%s) index=%u sign via card / verify via CPACF passed.",
ec_tv[i].name, i);
}
}
rc = CKR_OK;
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
if (sig)
free(sig);
testcase_close_session();
return rc;
}
struct btc_test {
const _ec_struct ec;
CK_ULONG master_key_derive;
CK_ULONG priv_to_pub;
CK_ULONG priv_to_priv;
CK_ULONG pub_to_pub;
};
static const struct btc_test btc_tests[] = {
{ .ec = { &secp256k1, sizeof(secp256k1), CK_FALSE, CURVE_KOBLITZ,
CURVE256_LENGTH, "secp256k1" },
.master_key_derive = CK_IBM_BTC_BIP0032_MASTERK,
.priv_to_pub = CK_IBM_BTC_BIP0032_PRV2PUB,
.priv_to_priv = CK_IBM_BTC_BIP0032_PRV2PRV,
.pub_to_pub = CK_IBM_BTC_BIP0032_PUB2PUB,
},
{ .ec = { &secp256k1, sizeof(secp256k1), CK_FALSE, CURVE_KOBLITZ,
CURVE256_LENGTH, "secp256k1" },
.master_key_derive = CK_IBM_BTC_SLIP0010_MASTERK,
.priv_to_pub = CK_IBM_BTC_SLIP0010_PRV2PUB,
.priv_to_priv = CK_IBM_BTC_SLIP0010_PRV2PRV,
.pub_to_pub = CK_IBM_BTC_SLIP0010_PUB2PUB,
},
{ .ec = { &prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME,
CURVE256_LENGTH, "prime256v1" },
.master_key_derive = CK_IBM_BTC_SLIP0010_MASTERK,
.priv_to_pub = CK_IBM_BTC_SLIP0010_PRV2PUB,
.priv_to_priv = CK_IBM_BTC_SLIP0010_PRV2PRV,
.pub_to_pub = CK_IBM_BTC_SLIP0010_PUB2PUB,
},
{ .ec = { &ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS,
CURVE256_LENGTH, "ed25519" },
.master_key_derive = CK_IBM_BTC_SLIP0010_MASTERK,
.priv_to_pub = CK_IBM_BTC_SLIP0010_PRV2PUB,
.priv_to_priv = CK_IBM_BTC_SLIP0010_PRV2PRV,
.pub_to_pub = CK_IBM_BTC_SLIP0010_PUB2PUB,
},
};
#define NUM_BTC_TESTS 4
static const CK_ULONG btc_child_key_index[] = {
0,
0x12,
0x3456,
0x987654,
0x7fffffff,
0 + CK_IBM_BTC_BIP0032_HARDENED,
0x12 + CK_IBM_BTC_BIP0032_HARDENED,
0x3456 + CK_IBM_BTC_BIP0032_HARDENED,
0x987654 + CK_IBM_BTC_BIP0032_HARDENED,
0x7fffffff + CK_IBM_BTC_BIP0032_HARDENED,
};
#define NUM_BTC_CHILD_KEY_INDEXES 10
static const char *btc_type_to_str(CK_ULONG btc_type)
{
switch (btc_type) {
case CK_IBM_BTC_BIP0032_PRV2PRV:
return "CK_IBM_BTC_BIP0032_PRV2PRV";
case CK_IBM_BTC_BIP0032_PRV2PUB:
return "CK_IBM_BTC_BIP0032_PRV2PUB";
case CK_IBM_BTC_BIP0032_PUB2PUB:
return "CK_IBM_BTC_BIP0032_PUB2PUB";
case CK_IBM_BTC_BIP0032_MASTERK:
return "CK_IBM_BTC_BIP0032_MASTERK";
case CK_IBM_BTC_SLIP0010_PRV2PRV:
return "CK_IBM_BTC_SLIP0010_PRV2PRV";
case CK_IBM_BTC_SLIP0010_PRV2PUB:
return "CK_IBM_BTC_SLIP0010_PRV2PUB";
case CK_IBM_BTC_SLIP0010_PUB2PUB:
return "CK_IBM_BTC_SLIP0010_PUB2PUB";
case CK_IBM_BTC_SLIP0010_MASTERK:
return "CK_IBM_BTC_SLIP0010_MASTERK";
default:
return "UNKNOWN";
}
}
/*
* Run Bitcoin Key Derivation tests:
* Derive a BTC master key from a generic secret key. Then derive a number of
* child keys (public and private, hardened and non hardened) from the master
* key.
*/
CK_RV run_DeriveBTC(void)
{
CK_SESSION_HANDLE session;
CK_MECHANISM mech;
CK_FLAGS flags;
CK_OBJECT_HANDLE secret = CK_INVALID_HANDLE, master = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE child_priv = CK_INVALID_HANDLE, child_pub = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE child_pub2 = CK_INVALID_HANDLE;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len;
CK_RV rc = CKR_OK;
CK_BBOOL true = CK_TRUE;
CK_IBM_BTC_DERIVE_PARAMS btc_parms;
CK_BYTE master_chain_code[CK_IBM_BTC_CHAINCODE_LENGTH];
CK_BYTE child_chain_code[CK_IBM_BTC_CHAINCODE_LENGTH];
CK_OBJECT_CLASS priv_class = CKO_PRIVATE_KEY;
CK_OBJECT_CLASS pub_class = CKO_PUBLIC_KEY;
CK_KEY_TYPE key_type = CKK_EC;
CK_OBJECT_CLASS secret_class = CKO_SECRET_KEY;
CK_ULONG secret_keylen = 32;
CK_ULONG i, k;
testsuite_begin("starting run_DeriveBTC with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_GENERIC_SECRET_KEY_GEN)) {
testcase_skip("Slot %u doesn't support CKM_GENERIC_SECRET_KEY_GEN\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_IBM_BTC_DERIVE)) {
testcase_skip("Slot %u doesn't support CKM_IBM_BTC_DERIVE\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
for (i = 0; i < NUM_BTC_TESTS; i++) {
CK_ATTRIBUTE secret_tmpl[] = {
{CKA_CLASS, &secret_class, sizeof(secret_class)},
{CKA_VALUE_LEN, &secret_keylen, sizeof(secret_keylen)},
{CKA_IBM_USE_AS_DATA, &true, sizeof(true)},
};
CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE priv_derive_tmpl[] = {
{CKA_CLASS, &priv_class, sizeof(priv_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_DERIVE, &true, sizeof(true)},
{CKA_EC_PARAMS, (CK_VOID_PTR)btc_tests[i].ec.curve, btc_tests[i].ec.size},
{CKA_IBM_USE_AS_DATA, &true, sizeof(true)},
};
CK_ULONG priv_derive_tmpl_len = sizeof(priv_derive_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE pub_derive_tmpl[] = {
{CKA_CLASS, &pub_class, sizeof(pub_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_DERIVE, &true, sizeof(true)},
{CKA_EC_PARAMS, (CK_VOID_PTR)btc_tests[i].ec.curve, btc_tests[i].ec.size},
{CKA_IBM_USE_AS_DATA, &true, sizeof(true)},
};
CK_ULONG pub_derive_tmpl_len = sizeof(pub_derive_tmpl) / sizeof(CK_ATTRIBUTE);
/* Testcase #1: Derive the BTC master key from a secret key */
testcase_new_assertion();
testcase_begin("BTC master key derive with curve=%s and type=%s, pkey=%X",
btc_tests[i].ec.name,
btc_type_to_str(btc_tests[i].master_key_derive), pkey);
mech.mechanism = CKM_GENERIC_SECRET_KEY_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
rc = funcs->C_GenerateKey(session, &mech, secret_tmpl, secret_tmpl_len,
&secret);
if (rc != CKR_OK) {
testcase_fail("C_GenerateKey, rc=%s", p11_get_ckr(rc));
goto run_cleanup;
}
mech.mechanism = CKM_IBM_BTC_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS);
mech.pParameter = &btc_parms;
memset(master_chain_code, 0, sizeof(master_chain_code));
memset(&btc_parms, 0, sizeof(btc_parms));
btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1;
btc_parms.type = btc_tests[i].master_key_derive;
btc_parms.childKeyIndex = 0;
btc_parms.ulChainCodeLen = 0;
btc_parms.pChainCode = master_chain_code;
rc = funcs->C_DeriveKey(session, &mech,
secret, priv_derive_tmpl,
priv_derive_tmpl_len, &master);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey BTC master key: rc = %s",
p11_get_ckr(rc));
goto run_cleanup;
}
testcase_pass("BTC master key derive with curve=%s and type=%s, pkey=%X",
btc_tests[i].ec.name,
btc_type_to_str(btc_tests[i].master_key_derive), pkey);
/* Derive child keys from the master key */
for (k = 0; k < NUM_BTC_CHILD_KEY_INDEXES; k++) {
/* Testcase #2: Derive private child key from private master key */
/* For ed25519 only hardened child keys are supported (SLIP0010) */
if (btc_tests[i].master_key_derive == CK_IBM_BTC_SLIP0010_MASTERK &&
btc_tests[i].ec.type == CURVE_EDWARDS &&
(btc_child_key_index[k] & CK_IBM_BTC_BIP0032_HARDENED) == 0)
continue;
testcase_new_assertion();
testcase_begin("BTC priv-to-priv child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k],
btc_type_to_str(btc_tests[i].priv_to_priv), pkey);
mech.mechanism = CKM_IBM_BTC_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS);
mech.pParameter = &btc_parms;
memcpy(child_chain_code, master_chain_code, sizeof(master_chain_code));
memset(&btc_parms, 0, sizeof(btc_parms));
btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1;
btc_parms.type = btc_tests[i].priv_to_priv;
btc_parms.childKeyIndex = btc_child_key_index[k];
btc_parms.ulChainCodeLen = sizeof(child_chain_code);
btc_parms.pChainCode = child_chain_code;
rc = funcs->C_DeriveKey(session, &mech,
master, priv_derive_tmpl,
priv_derive_tmpl_len, &child_priv);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey BTC child key (priv): rc = %s",
p11_get_ckr(rc));
goto run_child_cleanup;
}
testcase_pass("BTC priv-to-priv child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k],
btc_type_to_str(btc_tests[i].priv_to_priv), pkey);
/* Testcase #3: Derive public child key from private master key */
testcase_new_assertion();
testcase_begin("BTC priv-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k],
btc_type_to_str(btc_tests[i].priv_to_pub), pkey);
mech.mechanism = CKM_IBM_BTC_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS);
mech.pParameter = &btc_parms;
memcpy(child_chain_code, master_chain_code, sizeof(master_chain_code));
memset(&btc_parms, 0, sizeof(btc_parms));
btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1;
btc_parms.type = btc_tests[i].priv_to_pub;
btc_parms.childKeyIndex = btc_child_key_index[k];
btc_parms.ulChainCodeLen = sizeof(child_chain_code);
btc_parms.pChainCode = child_chain_code;
rc = funcs->C_DeriveKey(session, &mech,
master, pub_derive_tmpl,
pub_derive_tmpl_len, &child_pub);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey BTC child key (pub): rc = %s",
p11_get_ckr(rc));
goto run_child_cleanup;
}
testcase_pass("BTC priv-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k],
btc_type_to_str(btc_tests[i].priv_to_pub), pkey);
/* Testcase #4: Test if derived keys are usable */
testcase_new_assertion();
if (btc_tests[i].ec.type == CURVE_EDWARDS)
mech.mechanism = CKM_IBM_ED25519_SHA512;
else
mech.mechanism = CKM_ECDSA;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
rc = run_GenerateSignVerifyECC(session, &mech, 20, 0,
child_priv, child_pub,
btc_tests[i].ec.type,
(CK_BYTE *)btc_tests[i].ec.curve,
btc_tests[i].ec.size);
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed.");
goto run_child_cleanup;
}
testcase_pass("BTC check derived keys with curve=%s child-key-index=0x%lx, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k], pkey);
/*
* Testcase #5: Derive public child key from public key
* (non-hardened keys only, thus not supported for ed25519)
*/
if ((btc_child_key_index[k] & CK_IBM_BTC_BIP0032_HARDENED) != 0)
goto run_child_cleanup;
testcase_new_assertion();
testcase_begin("BTC pub-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k],
btc_type_to_str(btc_tests[i].pub_to_pub), pkey);
mech.mechanism = CKM_IBM_BTC_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_BTC_DERIVE_PARAMS);
mech.pParameter = &btc_parms;
memset(&btc_parms, 0, sizeof(btc_parms));
btc_parms.version = CK_IBM_BTC_DERIVE_PARAMS_VERSION_1;
btc_parms.type = btc_tests[i].pub_to_pub;
btc_parms.childKeyIndex = btc_child_key_index[k];
btc_parms.ulChainCodeLen = sizeof(child_chain_code);
btc_parms.pChainCode = child_chain_code;
rc = funcs->C_DeriveKey(session, &mech,
child_pub, pub_derive_tmpl,
pub_derive_tmpl_len, &child_pub2);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey BTC child key (pub): rc = %s",
p11_get_ckr(rc));
goto run_child_cleanup;
}
testcase_pass("BTC pub-to-pub child key derive with curve=%s child-key-index=0x%lx and type=%s, pkey=%X",
btc_tests[i].ec.name, btc_child_key_index[k],
btc_type_to_str(btc_tests[i].pub_to_pub), pkey);
run_child_cleanup:
if (child_priv != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, child_priv);
child_priv = CK_INVALID_HANDLE;
if (child_pub != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, child_pub);
child_pub = CK_INVALID_HANDLE;
if (child_pub2 != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, child_pub2);
child_pub2 = CK_INVALID_HANDLE;
}
run_cleanup:
if (secret != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret);
secret = CK_INVALID_HANDLE;
if (master != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, master);
master = CK_INVALID_HANDLE;
}
testcase_cleanup:
if (secret != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret);
if (master != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, master);
testcase_user_logout();
testcase_close_session();
return rc;
} /* end run_DeriveBTC() */
_ec_struct bls_test = {&bls12_381, sizeof(bls12_381), CK_TRUE, CURVE_BLS12_381,
CURVE384_LENGTH, "bls12_381"};
_signVerifyParam bls_test_input = {{CKM_IBM_ECDSA_OTHER, &other_bls,
sizeof(other_bls)}, 20, 0, ""};
/*
* BLS test for Sign and derive
*/
CK_RV run_BLSAggregation(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE priv_key[CK_IBM_BLS_MAX_AGGREGATIONS] = { CK_INVALID_HANDLE },
pub_key[CK_IBM_BLS_MAX_AGGREGATIONS] = { CK_INVALID_HANDLE };
CK_IBM_ECDSA_OTHER_BLS_PARAMS blsparam1, blsparam2;
CK_OBJECT_HANDLE aggpubkey = CK_INVALID_HANDLE;
CK_ULONG signatlen = CK_IBM_BLS12_381_SIGN_LEN;
CK_BYTE aggsignature[1000];
CK_BYTE signature[CK_IBM_BLS_MAX_AGGREGATIONS][CK_IBM_BLS12_381_SIGN_LEN];
CK_ULONG aggsignaturelen = CK_IBM_BLS12_381_SIGN_LEN;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, k, numElements = 10;
CK_FLAGS flags;
CK_RV rc;
CK_BYTE message[32];
CK_BBOOL lotrue = CK_TRUE;
CK_IBM_ECDSA_OTHER_PARAMS *param;
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_EC_PARAMS, (CK_BYTE *)bls_test.curve, bls_test.size },
{ CKA_VERIFY, &lotrue, sizeof(lotrue) },
{ CKA_DERIVE, &lotrue, sizeof(lotrue) },
};
CK_ULONG pub_derive_tmpl_len = sizeof(publicKeyTemplate)
/ sizeof(CK_ATTRIBUTE);
testsuite_begin("Starting run_BLSAggregation");
testcase_rw_session();
testcase_user_login();
/* Skip tests if not EP11 token*/
if (!is_ep11_token(SLOT_ID)) {
testcase_skip("Slot %u doesn't support BLS aggregation",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, bls_test_input.mech.mechanism)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
mech_to_str(bls_test_input.mech.mechanism));
rc = CKR_OK;
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_IBM_EC_AGGREGATE)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
mech_to_str(CKM_IBM_EC_AGGREGATE));
rc = CKR_OK;
goto testcase_cleanup;
}
for (k = 0; k < numElements; k++) {
testcase_new_assertion();
testcase_begin("Generate key pair with for index %lu", k);
rc = generate_EC_KeyPair(session, CKM_EC_KEY_PAIR_GEN,
(CK_BYTE *)bls_test.curve, bls_test.size,
&pub_key[k], &priv_key[k], !pkey);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
goto testcase_cleanup;;
}
if (rc == CKR_MECHANISM_PARAM_INVALID ||
rc == CKR_ATTRIBUTE_VALUE_INVALID ||
rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, bls_test.name);
goto testcase_cleanup;;
}
testcase_fail("generate_EC_KeyPair with valid input failed (%s), "
"rc=%s", bls_test.name, p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_pass("*Generate supported key pair (%s) passed.",
bls_test.name);
blsparam1.pAggrElements[k] = (CK_OBJECT_HANDLE_PTR)&(pub_key[k]);
}
blsparam1.numElements = numElements;
blsparam1.elementSize = sizeof(CK_OBJECT_HANDLE_PTR);
blsparam2.numElements = numElements;
blsparam2.elementSize = CK_IBM_BLS12_381_SIGN_LEN;
for (k = 0; k < bls_test_input.inputlen; k++) {
message[k] = (k + 1) % 255;
}
for (k = 0; k < blsparam1.numElements; k++) {
testcase_new_assertion();
testcase_begin("Starting sign/verify with mechtype='%s', inputlen=%lu "
"parts=%lu, index=%lu",
p11_get_ckm(&mechtable_funcs,
bls_test_input.mech.mechanism),
bls_test_input.inputlen, bls_test_input.parts, k);
param = (CK_IBM_ECDSA_OTHER_PARAMS *)bls_test_input.mech.pParameter;
if (param->submechanism != CKM_IBM_BLS) {
goto testcase_cleanup;
}
/****** Sign *******/
rc = funcs->C_SignInit(session, &bls_test_input.mech, priv_key[k]);
if (rc != CKR_OK) {
testcase_error("C_SignInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Sign(session, message, bls_test_input.inputlen,
signature[k], &signatlen);
if (rc != 0) {
testcase_fail("C_Sign failed index=%lu.", k);
goto testcase_cleanup;
}
/****** Verify *******/
rc = funcs->C_VerifyInit(session, &bls_test_input.mech,
*(CK_OBJECT_HANDLE_PTR)
blsparam1.pAggrElements[k]);
if (rc != CKR_OK) {
testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Verify(session, message, bls_test_input.inputlen,
signature[k], signatlen);
if (rc != CKR_OK) {
testcase_error("C_Verify rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_pass("*Sign & verify k=%lu, passed.", k);
blsparam2.pAggrElements[k] = (CK_BYTE_PTR)&(signature[k][0]);
}
mech.mechanism = CKM_IBM_EC_AGGREGATE;
mech.pParameter = &blsparam2;
mech.ulParameterLen = sizeof(blsparam2);
testcase_new_assertion();
testcase_begin("Starting BLS signature aggregation ");
rc = funcs->C_SignInit(session, &mech, CK_INVALID_HANDLE);
if (rc != CKR_OK) {
testcase_error("C_SignInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Sign(session, NULL, 0, NULL, &aggsignaturelen);
if (rc != CKR_OK) {
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Sign(session, NULL,
0, aggsignature, &aggsignaturelen);
if (rc != CKR_OK) {
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_pass("*BLS signature aggregation passed.");
testcase_new_assertion();
testcase_begin("Starting BLS public key aggregation ");
mech.mechanism = CKM_IBM_EC_AGGREGATE;
mech.pParameter = &blsparam1;
mech.ulParameterLen = sizeof(blsparam1);
rc = funcs->C_DeriveKey(session, &mech, CK_INVALID_HANDLE,
publicKeyTemplate, pub_derive_tmpl_len,
&aggpubkey);
if (rc != CKR_OK) {
testcase_error("C_Derive rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_pass("*BLS Public key aggregation passed.");
testcase_new_assertion();
testcase_begin("Starting BLS aggregation verification");
rc = funcs->C_VerifyInit(session, &bls_test_input.mech, aggpubkey);
if (rc != CKR_OK) {
testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Verify(session, message, bls_test_input.inputlen,
&(aggsignature[0]), aggsignaturelen);
if (rc != CKR_OK) {
testcase_error("C_Verify rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_pass("*Verification aggregation passed.");
testcase_cleanup:
for (k = 0; k < numElements; k++) {
if (pub_key[k] != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, pub_key[k]);
if (priv_key[k] != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key[k]);
}
if (aggpubkey != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, aggpubkey);
testcase_user_logout();
testcase_close_session();
return rc;
}
static const struct {
CK_ULONG index;
CK_BYTE *key_info;
CK_ULONG key_info_len;
} eth_child_key_index[] = {
{ 0, NULL, 0 },
{ 0x12, (CK_BYTE *)"test", 4 },
{ 0x3456, (CK_BYTE *)"00112233445566778899", 20 },
{ 0x987654, NULL, 0 },
{ 0x7fffffff, NULL, 0 },
};
#define NUM_ETH_CHILD_KEY_INDEXES 5
/*
* Run Ethereum 2.0 Key Derivation tests:
* Derive a ETH master key from a generic secret key. Then derive child keys
* (public and private) from the master key.
*/
CK_RV run_DeriveETH(void)
{
CK_SESSION_HANDLE session;
CK_MECHANISM mech;
CK_FLAGS flags;
CK_OBJECT_HANDLE secret = CK_INVALID_HANDLE, master = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE child_priv = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE child_pub = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE child_pub2 = CK_INVALID_HANDLE;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len;
CK_RV rc = CKR_OK;
CK_BBOOL true = CK_TRUE;
CK_IBM_ETH_DERIVE_PARAMS eth_parms;
CK_OBJECT_CLASS priv_class = CKO_PRIVATE_KEY;
CK_OBJECT_CLASS pub_class = CKO_PUBLIC_KEY;
CK_KEY_TYPE key_type = CKK_EC;
CK_OBJECT_CLASS secret_class = CKO_SECRET_KEY;
CK_ULONG secret_keylen = 32;
CK_ULONG k;
CK_ATTRIBUTE secret_tmpl[] = {
{CKA_CLASS, &secret_class, sizeof(secret_class)},
{CKA_VALUE_LEN, &secret_keylen, sizeof(secret_keylen)},
{CKA_IBM_USE_AS_DATA, &true, sizeof(true)},
};
CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE priv_derive_tmpl[] = {
{CKA_CLASS, &priv_class, sizeof(priv_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_DERIVE, &true, sizeof(true)},
{CKA_EC_PARAMS, (CK_VOID_PTR)bls12_381, sizeof(bls12_381)},
{CKA_IBM_USE_AS_DATA, &true, sizeof(true)},
};
CK_ULONG priv_derive_tmpl_len =
sizeof(priv_derive_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE pub_derive_tmpl[] = {
{CKA_CLASS, &pub_class, sizeof(pub_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_DERIVE, &true, sizeof(true)},
{CKA_EC_PARAMS, (CK_VOID_PTR)bls12_381, sizeof(bls12_381)},
{CKA_IBM_USE_AS_DATA, &true, sizeof(true)},
};
CK_ULONG pub_derive_tmpl_len =
sizeof(pub_derive_tmpl) / sizeof(CK_ATTRIBUTE);
testsuite_begin("starting run_DeriveETH with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support "
"protected keys", (unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_GENERIC_SECRET_KEY_GEN)) {
testcase_skip("Slot %u doesn't support CKM_GENERIC_SECRET_KEY_GEN\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_IBM_ETH_DERIVE)) {
testcase_skip("Slot %u doesn't support CKM_IBM_ETH_DERIVE\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
/* Testcase #1: Derive the ETH master key from a secret key */
testcase_new_assertion();
testcase_begin("ETH master key derive with pkey=%X", pkey);
mech.mechanism = CKM_GENERIC_SECRET_KEY_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
rc = funcs->C_GenerateKey(session, &mech, secret_tmpl, secret_tmpl_len,
&secret);
if (rc != CKR_OK) {
testcase_fail("C_GenerateKey, rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
mech.mechanism = CKM_IBM_ETH_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_ETH_DERIVE_PARAMS);
mech.pParameter = &eth_parms;
memset(&eth_parms, 0, sizeof(eth_parms));
eth_parms.version = CK_IBM_ETH_DERIVE_PARAMS_VERSION_1;
eth_parms.sigVersion = CK_IBM_ETH_SIG_VERSION_4;
eth_parms.type = CK_IBM_ETH_EIP2333_MASTERK;
eth_parms.childKeyIndex = 0;
eth_parms.pKeyInfo = NULL;
eth_parms.ulKeyInfoLen = 0;
rc = funcs->C_DeriveKey(session, &mech,
secret, priv_derive_tmpl,
priv_derive_tmpl_len, &master);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey ETH master key: rc = %s",
p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_pass("ETH master key derive with pkey=%X", pkey);
/* Derive child keys from the master key */
for (k = 0; k < NUM_ETH_CHILD_KEY_INDEXES; k++) {
/* Testcase #2: Derive private child key from private master key */
testcase_new_assertion();
testcase_begin("ETH priv-to-priv child key derive with "
"child-key-index=0x%lx, KeyInfoLen=%lu, pkey=%X",
eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
mech.mechanism = CKM_IBM_ETH_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_ETH_DERIVE_PARAMS);
mech.pParameter = &eth_parms;
eth_parms.version = CK_IBM_ETH_DERIVE_PARAMS_VERSION_1;
eth_parms.sigVersion = CK_IBM_ETH_SIG_VERSION_4;
eth_parms.type = CK_IBM_ETH_EIP2333_PRV2PRV;
eth_parms.childKeyIndex = eth_child_key_index[k].index;
eth_parms.pKeyInfo = eth_child_key_index[k].key_info;
eth_parms.ulKeyInfoLen = eth_child_key_index[k].key_info_len;
rc = funcs->C_DeriveKey(session, &mech,
master, priv_derive_tmpl,
priv_derive_tmpl_len, &child_priv);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey ETH child key (priv): rc = %s",
p11_get_ckr(rc));
goto run_child_cleanup;
}
testcase_pass("ETH priv-to-priv child key derive with "
"child-key-index=0x%lx, KeyInfoLen=%lu, pkey=%X",
eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
/* Testcase #3: Derive public child key from private master key */
testcase_new_assertion();
testcase_begin("ETH priv-to-pub child key derive with "
"child-key-index=0x%lx, KeyInfoLen=%lu, pkey=%X",
eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
eth_parms.version = CK_IBM_ETH_DERIVE_PARAMS_VERSION_1;
eth_parms.sigVersion = CK_IBM_ETH_SIG_VERSION_4;
eth_parms.type = CK_IBM_ETH_EIP2333_PRV2PUB;
eth_parms.childKeyIndex = eth_child_key_index[k].index;
eth_parms.pKeyInfo = eth_child_key_index[k].key_info;
eth_parms.ulKeyInfoLen = eth_child_key_index[k].key_info_len;
mech.mechanism = CKM_IBM_ETH_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_ETH_DERIVE_PARAMS);
mech.pParameter = &eth_parms;
rc = funcs->C_DeriveKey(session, &mech,
master, pub_derive_tmpl,
pub_derive_tmpl_len, &child_pub);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey ETH child key (pub): rc = %s",
p11_get_ckr(rc));
goto run_child_cleanup;
}
testcase_pass("ETH priv-to-pub child key derive with "
"child-key-index=0x%lx, KeyInfoLen=%lu, pkey=%X",
eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
/* Testcase #4: Test if derived keys are usable */
testcase_new_assertion();
mech.mechanism = CKM_ECDSA;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
rc = run_GenerateSignVerifyECC(session, &mech, 20, 0,
child_priv, child_pub,
CURVE_BLS12_381,
(CK_BYTE *)bls12_381,
sizeof(bls12_381));
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed.");
goto run_child_cleanup;
}
testcase_pass("ETH check derived keys with child-key-index=0x%lx, "
"KeyInfoLen=%lu, pkey=%X", eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
/*
* Testcase #5: Derive public child key from private key
*/
testcase_new_assertion();
testcase_begin("ETH priv-to-pub child key derive with "
"child-key-index=0x%lx, KeyInfoLen=%lu, pkey=%X",
eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
mech.mechanism = CKM_IBM_ETH_DERIVE;
mech.ulParameterLen = sizeof(CK_IBM_ETH_DERIVE_PARAMS);
mech.pParameter = &eth_parms;
eth_parms.version = CK_IBM_ETH_DERIVE_PARAMS_VERSION_1;
eth_parms.sigVersion = CK_IBM_ETH_SIG_VERSION_4;
eth_parms.type = CK_IBM_ETH_EIP2333_PRV2PUB;
eth_parms.childKeyIndex = eth_child_key_index[k].index;
eth_parms.pKeyInfo = eth_child_key_index[k].key_info;
eth_parms.ulKeyInfoLen = eth_child_key_index[k].key_info_len;
rc = funcs->C_DeriveKey(session, &mech,
child_priv, pub_derive_tmpl,
pub_derive_tmpl_len, &child_pub2);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey ETH child key (pub): rc = %s",
p11_get_ckr(rc));
goto run_child_cleanup;
}
testcase_pass("ETH priv-to-pub child key derive with "
"child-key-index=0x%lx, KeyInfoLen=%lu, pkey=%X",
eth_child_key_index[k].index,
eth_child_key_index[k].key_info_len, pkey);
run_child_cleanup:
if (child_priv != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, child_priv);
child_priv = CK_INVALID_HANDLE;
if (child_pub != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, child_pub);
child_pub = CK_INVALID_HANDLE;
if (child_pub2 != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, child_pub2);
child_pub2 = CK_INVALID_HANDLE;
}
testcase_cleanup:
if (secret != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret);
if (master != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, master);
testcase_user_logout();
testcase_close_session();
return rc;
}
#define NUMED 4
const _ec_struct der_ec_edwards_supported[NUMED] = {
{&curve25519, sizeof(curve25519), CK_FALSE, CURVE_MONTGOMERY,
CURVE256_LENGTH, "curve25519"},
{&curve448, sizeof(curve448), CK_FALSE, CURVE_MONTGOMERY,
CURVE448_LENGTH, "curve448"},
{&ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS,
CURVE256_LENGTH, "ed25519"},
{&ed448, sizeof(ed448), CK_FALSE, CURVE_EDWARDS,
CURVE456_LENGTH, "ed448"},
};
CK_BYTE eddsa_ctx_data[] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
CK_EDDSA_PARAMS eddsa_none = { FALSE, 0, NULL };
CK_EDDSA_PARAMS eddsa_ph = { TRUE, 0, NULL };
CK_EDDSA_PARAMS eddsa_ctx = { FALSE, sizeof(eddsa_ctx_data), eddsa_ctx_data };
CK_EDDSA_PARAMS eddsa_ph_ctx = { TRUE, sizeof(eddsa_ctx_data), eddsa_ctx_data };
_signVerifyParam edwardsSignVerifyInput[] = {
{{CKM_EDDSA, NULL, 0}, 20, 0, ""},
{{CKM_EDDSA, NULL, 0}, 32, 0, ""},
{{CKM_EDDSA, NULL, 0}, 48, 0, ""},
{{CKM_EDDSA, NULL, 0}, 64, 0, ""},
{{CKM_EDDSA, &eddsa_none, sizeof(eddsa_none)}, 64, 0,
"Neither Pre-Hash nor Context"},
{{CKM_EDDSA, &eddsa_ph, sizeof(eddsa_ph)}, 64, 0, "Pre-Hash"},
{{CKM_EDDSA, &eddsa_ctx, sizeof(eddsa_ctx)}, 64, 0, "Context"},
{{CKM_EDDSA, &eddsa_ph_ctx, sizeof(eddsa_ph_ctx)}, 64, 0,
"Pre-Hash & Context"},
};
CK_RV run_GenerateEdwardsKeyPairSignVerify(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, i = 0, j;
CK_FLAGS flags;
CK_MECHANISM_INFO mech_info;
CK_RV rc;
testcase_begin("Starting Edwards generate key pair with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support "
"protected keys", (unsigned int) SLOT_ID);
goto done;
}
mech.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
/* query the slot, check if this mech is supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support CKM_EC_EDWARDS_KEY_PAIR_GEN",
(unsigned int) SLOT_ID);
rc = CKR_OK;
goto done;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto done;
}
}
for (i = 0; i < NUMED; i++) {
if (der_ec_edwards_supported[i].type != CURVE_EDWARDS)
continue;
rc = generate_EC_KeyPair(session, CKM_EC_EDWARDS_KEY_PAIR_GEN,
(CK_BYTE *)der_ec_edwards_supported[i].curve,
der_ec_edwards_supported[i].size,
&publ_key, &priv_key, !pkey);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
continue;
}
if (rc == CKR_MECHANISM_PARAM_INVALID ||
rc == CKR_ATTRIBUTE_VALUE_INVALID ||
rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
der_ec_edwards_supported[i].name);
continue;
}
testcase_fail
("generate_EC_KeyPair with valid input failed at i=%lu (%s), "
"rc=%s", i, der_ec_edwards_supported[i].name, p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Generate supported key pair index=%lu (%s) passed.", i,
der_ec_edwards_supported[i].name);
for (j = 0;
j < (sizeof(edwardsSignVerifyInput) / sizeof(_signVerifyParam));
j++) {
if (memcmp(der_ec_edwards_supported[i].curve, ed448,
MIN(der_ec_edwards_supported[i].size,
sizeof(ed448))) == 0 &&
edwardsSignVerifyInput[j].mech.pParameter == NULL) {
/* Ed448 requires a mechanism parameter, skip */
continue;
}
testcase_new_assertion();
rc = run_GenerateSignVerifyECC(session,
&edwardsSignVerifyInput[j].mech,
edwardsSignVerifyInput[j].inputlen,
edwardsSignVerifyInput[j].parts,
priv_key, publ_key,
der_ec_edwards_supported[i].type,
(CK_BYTE *)der_ec_edwards_supported[i].curve,
der_ec_edwards_supported[i].size);
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed index=%lu (%s).",
j, edwardsSignVerifyInput[j].name);
goto testcase_cleanup;
}
testcase_pass("*Sign & verify %s i=%lu (%s), j=%lu passed.",
edwardsSignVerifyInput[j].name, i,
der_ec_edwards_supported[i].name, j);
}
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
publ_key = CK_INVALID_HANDLE;
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
priv_key = CK_INVALID_HANDLE;
}
rc = CKR_OK;
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
done:
testcase_user_logout();
testcase_close_session();
return rc;
}
CK_RV run_ImportEdwardsKeyPairSignVerifyKAT(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, i = 0, signaturelen;
CK_FLAGS flags;
CK_MECHANISM_INFO mech_info;
CK_EDDSA_PARAMS eddsa_param;
CK_BYTE signature[128];
CK_RV rc;
testcase_begin("Starting Edwards import key pair with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support "
"protected keys", (unsigned int) SLOT_ID);
goto done;
}
mech.mechanism = CKM_EDDSA;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
/* query the slot, check if this mech is supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support CKM_EDDSA",
(unsigned int) SLOT_ID);
goto done;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto done;
}
}
for (i = 0; i < ED_TV_NUM; i++) {
rc = create_ECPrivateKey(session, CKK_EC_EDWARDS,
ed_tv[i].params, ed_tv[i].params_len,
ed_tv[i].privkey, ed_tv[i].privkey_len,
&priv_key, !pkey, CK_FALSE);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC-Edwards key import is not allowed by policy");
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ed_tv[i].name);
continue;
}
testcase_fail("C_CreateObject (EC-Edwards Private Key) failed at "
"i=%lu (%s), rc=%s", i, ed_tv[i].name,
p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Import EC-Edwards private key (%s) index=%lu passed.",
ed_tv[i].name, i);
rc = create_ECPublicKey(session, CKK_EC_EDWARDS,
ed_tv[i].params, ed_tv[i].params_len,
ed_tv[i].pubkey, ed_tv[i].pubkey_len,
&publ_key, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC-Edwards key import is not allowed by policy");
funcs->C_DestroyObject(session, priv_key);
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID, ed_tv[i].name);
funcs->C_DestroyObject(session, priv_key);
continue;
}
testcase_fail("C_CreateObject (EC-Edwards Public Key) failed at "
"i=%lu (%s), rc=%s", i, ed_tv[i].name,
p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Import EC-Edwards public key (%s) index=%lu passed.",
ed_tv[i].name, i);
if (ed_tv[i].mech_param) {
eddsa_param.phFlag = ed_tv[i].prehash;
eddsa_param.pContextData = ed_tv[i].ctx;
eddsa_param.ulContextDataLen = ed_tv[i].ctx_len;
mech.pParameter = &eddsa_param;
mech.ulParameterLen = sizeof(eddsa_param);
} else {
mech.pParameter = NULL;
mech.ulParameterLen = 0;
}
/* create signature with private key */
rc = funcs->C_SignInit(session, &mech, priv_key);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_PARAM_INVALID) {
testcase_skip("EdDSA mechanism parameter combination is not "
"supported (%s)", ed_tv[i].name);
rc = CKR_OK;
goto testcase_cleanup;
}
testcase_error("C_SignInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
memset(signature, 0, sizeof(signature));
signaturelen = sizeof(signature);
rc = funcs->C_Sign(session, ed_tv[i].msg, ed_tv[i].msg_len,
signature, &signaturelen);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_PARAM_INVALID) {
testcase_skip("EdDSA mechanism parameter combination is not "
"supported (%s)", ed_tv[i].name);
rc = CKR_OK;
goto testcase_cleanup;
}
testcase_error("C_Sign rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
/* Verify signature with public key */
rc = funcs->C_VerifyInit(session, &mech, publ_key);
if (rc != CKR_OK) {
testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_Verify(session, ed_tv[i].msg, ed_tv[i].msg_len,
signature, signaturelen);
if (rc != CKR_OK) {
testcase_error("C_Verify rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
if (signaturelen != ed_tv[i].signature_len ||
memcmp(signature, ed_tv[i].signature, signaturelen) != 0) {
testcase_fail("Signature is not the expected one at "
"i=%lu (%s)", i, ed_tv[i].name);
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Sign & Verify with expected result (%s) index=%lu passed.",
ed_tv[i].name, i);
// clean up
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
publ_key = CK_INVALID_HANDLE;
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
priv_key = CK_INVALID_HANDLE;
}
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
done:
testcase_user_logout();
testcase_close_session();
return rc;
}
CK_RV run_TransferEdwardsMontgomeryKeyPair(void)
{
CK_MECHANISM mech;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE;
CK_SESSION_HANDLE session;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len, i = 0;
CK_FLAGS flags;
CK_MECHANISM_INFO mech_info;
CK_RV rc;
CK_MECHANISM aes_keygen_mech;
CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE;
CK_BYTE_PTR wrapped_key = NULL;
CK_ULONG wrapped_keylen;
CK_OBJECT_HANDLE unwrapped_key = CK_INVALID_HANDLE;
CK_MECHANISM wrap_mech;
testcase_begin("Starting Edwards/Montgomery transfer key pair with "
"pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support "
"protected keys", (unsigned int) SLOT_ID);
goto done;
}
rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_KEY_GEN, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for AES key gen? skip */
testcase_skip("Slot %u doesn't support CKM_AES_KEY_GEN",
(unsigned int) SLOT_ID);
goto done;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto done;
}
}
rc = funcs->C_GetMechanismInfo(SLOT_ID, CKM_AES_CBC_PAD, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for AES CBC wrap? skip */
testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD",
(unsigned int) SLOT_ID);
goto done;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto done;
}
}
if ((mech_info.flags & CKF_WRAP) == 0 ||
(mech_info.flags & CKF_UNWRAP) == 0) {
/* no support for AES CBC wrap? skip */
testcase_skip("Slot %u doesn't support CKM_AES_CBC_PAD for wrapping "
"keys", (unsigned int) SLOT_ID);
goto done;
}
for (i = 0; i < NUMED; i++) {
if (der_ec_edwards_supported[i].type == CURVE_EDWARDS)
mech.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN;
else if (der_ec_edwards_supported[i].type == CURVE_MONTGOMERY)
mech.mechanism = CKM_EC_MONTGOMERY_KEY_PAIR_GEN;
else
continue;
/* query the slot, check if this mech is supported */
rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info);
if (rc != CKR_OK) {
if (rc == CKR_MECHANISM_INVALID) {
/* no support for EC key gen? skip */
testcase_skip("Slot %u doesn't support %s",
(unsigned int) SLOT_ID,
p11_get_ckm(&mechtable_funcs, mech.mechanism));
goto testcase_cleanup;
} else {
testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
}
rc = generate_EC_KeyPair(session, mech.mechanism,
(CK_BYTE *)der_ec_edwards_supported[i].curve,
der_ec_edwards_supported[i].size,
&publ_key, &priv_key, !pkey);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
continue;
}
if (rc == CKR_MECHANISM_PARAM_INVALID ||
rc == CKR_ATTRIBUTE_VALUE_INVALID ||
rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
der_ec_edwards_supported[i].name);
continue;
}
testcase_fail
("generate_EC_KeyPair with valid input failed at i=%lu (%s), "
"rc=%s", i, der_ec_edwards_supported[i].name, p11_get_ckr(rc));
goto testcase_cleanup;
}
testcase_new_assertion();
testcase_pass("*Generate supported key pair index=%lu (%s) passed.", i,
der_ec_edwards_supported[i].name);
/* create wrapping key (secret key) */
aes_keygen_mech.mechanism = CKM_AES_KEY_GEN;
CK_OBJECT_CLASS wkclass = CKO_SECRET_KEY;
CK_ULONG keylen = 32;
CK_BBOOL true = TRUE;
CK_BBOOL false = FALSE;
CK_BBOOL sign = TRUE;
CK_BBOOL derive = TRUE;
CK_BYTE wrap_key_label[] = "Wrap_Key";
CK_OBJECT_CLASS wclass = CKO_PRIVATE_KEY;
CK_KEY_TYPE keyType = (mech.mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN ?
CKK_EC_EDWARDS : CKK_EC_MONTGOMERY);
CK_ATTRIBUTE cka_wrap_tmpl[] = {
{CKA_PRIVATE, &true, sizeof(true)},
{CKA_CLASS, &wclass, sizeof(wclass)},
{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
};
CK_ATTRIBUTE cka_unwrap_tmpl[] = {
{CKA_DECRYPT, &true, sizeof(true)},
{CKA_SIGN, &sign, sizeof(sign)},
{CKA_DERIVE, &derive, sizeof(derive)},
{CKA_PRIVATE, &true, sizeof(true)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)},
{CKA_EXTRACTABLE, &false, sizeof(false)},
};
CK_ATTRIBUTE secret_tmpl[] = {
{CKA_CLASS, &wkclass, sizeof(wkclass)},
{CKA_VALUE_LEN, &keylen, sizeof(keylen)},
{CKA_LABEL, &wrap_key_label, sizeof(wrap_key_label)},
{CKA_TOKEN, &true, sizeof(true)},
{CKA_WRAP, &true, sizeof(true)},
{CKA_UNWRAP, &true, sizeof(true)},
{CKA_WRAP_TEMPLATE, &cka_wrap_tmpl, sizeof(cka_wrap_tmpl)},
{CKA_UNWRAP_TEMPLATE, &cka_unwrap_tmpl, sizeof(cka_unwrap_tmpl)},
};
CK_ULONG secret_tmpl_len = sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE);
if (der_ec_edwards_supported[i].type == CURVE_EDWARDS)
derive = FALSE;
if (der_ec_edwards_supported[i].type == CURVE_MONTGOMERY)
sign = FALSE;
if (is_icsf_token(SLOT_ID))
secret_tmpl_len -= 2; /* ICSF does not support array-attributes */
rc = funcs->C_GenerateKey(session, &aes_keygen_mech, secret_tmpl,
secret_tmpl_len, &secret_key);
if (rc != CKR_OK) {
testcase_error("C_GenerateKey, rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
/* wrap/unwrap private and public Edwards key with a transport key */
wrap_mech.mechanism = CKM_AES_CBC_PAD;
wrap_mech.pParameter = "0123456789abcdef";
wrap_mech.ulParameterLen = 16;
rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key,
NULL, &wrapped_keylen);
if (rc != CKR_OK) {
if (rc == CKR_KEY_NOT_WRAPPABLE) {
testcase_skip("Slot %u doesn't support this to wrap keys of "
"type 0x%lx", (unsigned int) SLOT_ID, keyType);
} else {
testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc));
}
goto testcase_cleanup;
}
wrapped_key = calloc(wrapped_keylen, sizeof(CK_BYTE));
if (wrapped_key == NULL) {
testcase_error("Can't allocate memory for %lu bytes.",
sizeof(CK_BYTE) * wrapped_keylen);
rc = CKR_HOST_MEMORY;
goto testcase_cleanup;
}
rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key,
wrapped_key, &wrapped_keylen);
if (rc != CKR_OK) {
if (rc == CKR_KEY_NOT_WRAPPABLE) {
testcase_skip("Slot %u doesn't support this to wrap keys of "
"type 0x%lx", (unsigned int) SLOT_ID, keyType);
} else {
testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc));
}
goto testcase_cleanup;
}
CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
CK_KEY_TYPE key_type = (mech.mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN ?
CKK_EC_EDWARDS : CKK_EC_MONTGOMERY);
CK_BYTE unwrap_label[] = "unwrapped_private_EC_Key";
CK_BYTE id[] = { 123 };
CK_ATTRIBUTE unwrap_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_TOKEN, &true, sizeof(true)},
{CKA_LABEL, &unwrap_label, sizeof(unwrap_label)},
{CKA_ID, id, sizeof(id)},
{CKA_SENSITIVE, &true, sizeof(true)},
{CKA_DERIVE, &derive, sizeof(derive)},
{CKA_SIGN, &sign, sizeof(sign)},
{CKA_EXTRACTABLE, &false, sizeof(false)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &true, sizeof(true)},
};
CK_ULONG unwrap_tmpl_len = sizeof(unwrap_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE unwrap_base_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_DERIVE, &derive, sizeof(derive)},
{CKA_SIGN, &sign, sizeof(sign)},
};
if (is_icsf_token(SLOT_ID))
unwrap_tmpl_len -= 1; /* ICSF does not supp. CKA_IBM_PROTKEY_... */
rc = funcs->C_UnwrapKey(session, &wrap_mech, secret_key,
wrapped_key, wrapped_keylen,
unwrap_tmpl, unwrap_tmpl_len,
&unwrapped_key);
if (rc != CKR_OK) {
testcase_fail("C_UnwrapKey, rc=%s", p11_get_ckr(rc));
goto testcase_cleanup;
}
// unwrap again with each CKA_SENSITIVE / CKA_EXTRACTABLE choice; the
// transport key's CKA_UNWRAP_TEMPLATE sets CKA_EXTRACTABLE = FALSE
// (except on ICSF, which gets no array attributes)
rc = check_unwrap_sensitive_extractable(session, &wrap_mech,
secret_key, wrapped_key, wrapped_keylen, unwrap_base_tmpl,
sizeof(unwrap_base_tmpl) / sizeof(CK_ATTRIBUTE),
CKA_VALUE, NULL,
is_icsf_token(SLOT_ID) ? NULL : &false);
if (rc != CKR_OK)
goto testcase_cleanup;
if (wrapped_key) {
free(wrapped_key);
wrapped_key = NULL;
}
if (mech.mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN) {
/*
* create signature with unwrapped private key and verify with
* public key
*/
testcase_new_assertion();
rc = run_GenerateSignVerifyECC(session,
&edwardsSignVerifyInput[0].mech,
edwardsSignVerifyInput[0].inputlen,
edwardsSignVerifyInput[0].parts,
unwrapped_key, publ_key,
der_ec_edwards_supported[i].type,
(CK_BYTE *)der_ec_edwards_supported[i].curve,
der_ec_edwards_supported[i].size);
if (rc != 0) {
testcase_fail("run_GenerateSignVerifyECC failed index=0 (%s).",
edwardsSignVerifyInput[0].name);
goto testcase_cleanup;
}
testcase_pass("*Sign & verify %s i=%lu (%s), passed.",
edwardsSignVerifyInput[0].name, i,
der_ec_edwards_supported[i].name);
} else {
CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE;
CK_ECDH1_DERIVE_PARAMS ecdh_parm;
CK_BYTE ec_point[64];
CK_ATTRIBUTE ec_point_attr =
{ CKA_EC_POINT, ec_point, sizeof(ec_point) };
CK_BBOOL extractable = !pkey;
CK_KEY_TYPE secret_key_type = CKK_GENERIC_SECRET;
CK_ULONG secret_key_len =
(der_ec_edwards_supported[i].bit_len + 7) / 8;
CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY;
CK_ATTRIBUTE derive_tmpl[] = {
{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)},
{CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)},
{CKA_VALUE_LEN, &secret_key_len, sizeof(secret_key_len)},
{CKA_SENSITIVE, &false, sizeof(false)},
{CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)},
};
CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE);
testcase_new_assertion();
/* Perform ECDH with unwrapped private key and public key */
rc = funcs->C_GetAttributeValue(session, publ_key,
&ec_point_attr, 1);
if (rc != CKR_OK) {
testcase_fail("C_GetAttributeValue: rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
ecdh_parm.kdf = CKD_NULL;
ecdh_parm.pPublicData = ec_point_attr.pValue;
ecdh_parm.ulPublicDataLen = ec_point_attr.ulValueLen;
ecdh_parm.pSharedData = NULL;
ecdh_parm.ulSharedDataLen = 0;
mech.mechanism = CKM_ECDH1_DERIVE;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parm;
rc = funcs->C_DeriveKey(session, &mech,
unwrapped_key, derive_tmpl,
derive_tmpl_len, &secret_key);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
der_ec_edwards_supported[i].name);
goto testcase_cleanup;
}
testcase_fail("C_DeriveKey: rc = %s", p11_get_ckr(rc));
goto testcase_cleanup;
}
rc = funcs->C_DestroyObject(session, secret_key);
if (rc != CKR_OK) {
testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc));
}
testcase_pass("*ECDH i=%lu (%s), passed.", i,
der_ec_edwards_supported[i].name);
}
testcase_cleanup:
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
publ_key = CK_INVALID_HANDLE;
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
priv_key = CK_INVALID_HANDLE;
if (secret_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_key);
secret_key = CK_INVALID_HANDLE;
if (unwrapped_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, unwrapped_key);
unwrapped_key = CK_INVALID_HANDLE;
}
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
if (secret_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_key);
if (unwrapped_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, unwrapped_key);
if (wrapped_key)
free(wrapped_key);
done:
testcase_user_logout();
testcase_close_session();
return rc;
}
CK_RV run_MontgomeryECDHKeyKAT(void)
{
CK_SESSION_HANDLE session;
CK_MECHANISM mech;
CK_FLAGS flags;
CK_OBJECT_HANDLE publ_keyA = CK_INVALID_HANDLE,
priv_keyA = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE publ_keyB = CK_INVALID_HANDLE,
priv_keyB = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE secret_keyA = CK_INVALID_HANDLE,
secret_keyB = CK_INVALID_HANDLE;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_KEY_TYPE secret_key_type = CKK_GENERIC_SECRET;
CK_OBJECT_CLASS class = CKO_SECRET_KEY;
CK_ECDH1_DERIVE_PARAMS ecdh_parmA, ecdh_parmB;
CK_BBOOL false = CK_FALSE;
CK_ULONG user_pin_len;
CK_RV rc = CKR_OK;
CK_BYTE secretA_value[1000] = { 0 }; // enough space for key lengths in ecdh_tv[]
CK_BYTE secretB_value[1000] = { 0 };
CK_BYTE mac1[SHA1_HASH_SIZE] = { 0 };
CK_ULONG mac1_len = sizeof(mac1);
CK_BYTE mac2[SHA1_HASH_SIZE] = { 0 };
CK_ULONG mac2_len = sizeof(mac2);
CK_BYTE macexpected[SHA1_HASH_SIZE] = { 0 };
CK_ULONG macexpected_len = sizeof(macexpected);
CK_ULONG i;
testcase_begin("starting run_MontgomeryECDHKeyKAT with pkey=%X ...", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support "
"protected keys",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_EC_MONTGOMERY_KEY_PAIR_GEN)) {
testcase_skip("Slot %u doesn't support CKM_EC_MONTGOMERY_KEY_PAIR_GEN\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (!mech_supported(SLOT_ID, CKM_ECDH1_DERIVE)) {
testcase_skip("Slot %u doesn't support CKM_ECDH1_DERIVE\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) &&
!mech_supported(SLOT_ID, CKM_SHA_1_HMAC)) {
testcase_skip("Slot %u doesn't support CKM_SHA_1_HMAC, correctness "
"of derived keys can not be verified\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
if (is_cca_token(SLOT_ID)) {
testcase_skip("The CCA token in slot %u doesn't support ECDH with EC "
"keys imported from clear, only with randomly generated "
"keys. KATs not possible because of that\n",
(unsigned int) SLOT_ID);
goto testcase_cleanup;
}
for (i=0; i< MONTGOMERY_ECDH_TV_NUM; i++) {
testcase_begin("Starting with shared secret i=%lu (%s), pkey=%X",
i, montgomery_ecdh_tv[i].name, pkey);
if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) &&
!check_supp_keysize(SLOT_ID, CKM_SHA_1_HMAC,
montgomery_ecdh_tv[i].derived_key_len * 8)) {
testcase_skip("Mechanism CKM_SHA_1_HMAC can not be used with "
"keys of size %lu. Correctness of derived key "
"can not be verified.",
montgomery_ecdh_tv[i].derived_key_len);
continue;
}
// First, import the EC-Montgomery key pair for party A
rc = create_ECPrivateKey(session, CKK_EC_MONTGOMERY,
montgomery_ecdh_tv[i].params,
montgomery_ecdh_tv[i].params_len,
montgomery_ecdh_tv[i].privkeyA,
montgomery_ecdh_tv[i].privkey_len,
&priv_keyA, !pkey, CK_TRUE);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
montgomery_ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
rc = create_ECPublicKey(session, CKK_EC_MONTGOMERY,
montgomery_ecdh_tv[i].params,
montgomery_ecdh_tv[i].params_len,
montgomery_ecdh_tv[i].pubkeyA,
montgomery_ecdh_tv[i].pubkey_len,
&publ_keyA, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_POLICY_VIOLATION) {
testcase_skip("EC key import is not allowed by policy");
funcs->C_DestroyObject(session, priv_keyA);
continue;
}
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
montgomery_ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
// Now import the EC key pair for party B
rc = create_ECPrivateKey(session, CKK_EC_MONTGOMERY,
montgomery_ecdh_tv[i].params,
montgomery_ecdh_tv[i].params_len,
montgomery_ecdh_tv[i].privkeyB,
montgomery_ecdh_tv[i].privkey_len,
&priv_keyB, !pkey, CK_TRUE);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
montgomery_ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
rc = create_ECPublicKey(session, CKK_EC_MONTGOMERY,
montgomery_ecdh_tv[i].params,
montgomery_ecdh_tv[i].params_len,
montgomery_ecdh_tv[i].pubkeyB,
montgomery_ecdh_tv[i].pubkey_len,
&publ_keyB, !pkey);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
montgomery_ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu, "
"rc=%s", i, p11_get_ckr(rc));
goto testcase_next;
}
// Now derive the secrets...
CK_ATTRIBUTE secretA_tmpl[] = {
{CKA_VALUE, secretA_value, sizeof(secretA_value)}
};
CK_ULONG secretA_tmpl_len = sizeof(secretA_tmpl) / sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE secretB_tmpl[] = {
{CKA_VALUE, secretB_value, sizeof(secretB_value)}
};
CK_ULONG secretB_tmpl_len = sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE);
CK_BBOOL extractable = !pkey;
CK_ATTRIBUTE derive_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)},
{CKA_VALUE_LEN, &(montgomery_ecdh_tv[i].derived_key_len), sizeof(CK_ULONG)},
{CKA_SENSITIVE, &false, sizeof(false)},
{CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)},
{CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)},
};
CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE);
// Now, derive a generic secret key using party A's private key
// and B's public key
ecdh_parmA.kdf = montgomery_ecdh_tv[i].kdf;
ecdh_parmA.pPublicData = montgomery_ecdh_tv[i].pubkeyB;
ecdh_parmA.ulPublicDataLen = montgomery_ecdh_tv[i].pubkey_len;
ecdh_parmA.pSharedData = NULL;
ecdh_parmA.ulSharedDataLen = 0;
mech.mechanism = CKM_ECDH1_DERIVE;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parmA;
rc = funcs->C_DeriveKey(session, &mech,
priv_keyA, derive_tmpl,
derive_tmpl_len, &secret_keyA);
if (rc != CKR_OK) {
if (rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
montgomery_ecdh_tv[i].name);
goto testcase_next;
}
testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
// Now, derive a generic secret key using B's private key and
// A's public key
ecdh_parmB.kdf = montgomery_ecdh_tv[i].kdf;
ecdh_parmB.pPublicData = montgomery_ecdh_tv[i].pubkeyA;
ecdh_parmB.ulPublicDataLen = montgomery_ecdh_tv[i].pubkey_len;
ecdh_parmB.pSharedData = NULL;
ecdh_parmB.ulSharedDataLen = 0;
mech.mechanism = CKM_ECDH1_DERIVE;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parmB;
rc = funcs->C_DeriveKey(session, &mech,
priv_keyB, derive_tmpl,
derive_tmpl_len, &secret_keyB);
if (rc != CKR_OK) {
testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
testcase_new_assertion();
/* A secure key token won't reveal the key value in clear */
if (!is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
// Extract the derived secret A
rc = funcs->C_GetAttributeValue(session, secret_keyA,
secretA_tmpl, secretA_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #3:rc = %s",
p11_get_ckr(rc));
goto testcase_next;
}
// Compare lengths of derived secret from key object
if (montgomery_ecdh_tv[i].derived_key_len !=
secretA_tmpl[0].ulValueLen) {
testcase_fail("ERROR: derived key #1 length = %lu, "
"derived key #2 length = %lu",
montgomery_ecdh_tv[i].derived_key_len,
secretA_tmpl[0].ulValueLen);
goto testcase_next;
}
// Compare with known value
if (memcmp(secretA_tmpl[0].pValue,
montgomery_ecdh_tv[i].derived_key,
montgomery_ecdh_tv[i].derived_key_len) != 0) {
testcase_fail("ERROR: derived key mismatch, i=%lu",i);
goto testcase_next;
}
// Extract the derived secret B
rc = funcs->C_GetAttributeValue(session, secret_keyB,
secretB_tmpl, secretB_tmpl_len);
if (rc != CKR_OK) {
testcase_error("C_GetAttributeValue #4:rc = %s",
p11_get_ckr(rc));
goto testcase_next;
}
// Compare lengths of derived secret from key object
if (montgomery_ecdh_tv[i].derived_key_len !=
secretB_tmpl[0].ulValueLen) {
testcase_fail("ERROR: derived key #1 length = %lu, "
"derived key #2 length = %lu",
montgomery_ecdh_tv[i].derived_key_len,
secretB_tmpl[0].ulValueLen);
goto testcase_next;
}
// Compare with known value
if (memcmp(secretB_tmpl[0].pValue,
montgomery_ecdh_tv[i].derived_key,
montgomery_ecdh_tv[i].derived_key_len) != 0) {
testcase_fail("ERROR: derived key mismatch, i=%lu",i);
goto testcase_next;
}
} else {
/* Secure key:
* Calculate HMAC with derived keys and expected key and compare
* the MAC.
*/
rc = run_HMACSign_OpenSSL(montgomery_ecdh_tv[i].derived_key,
montgomery_ecdh_tv[i].derived_key_len,
CKM_SHA_1_HMAC,
macexpected, &macexpected_len);
if (rc != CKR_OK) {
testcase_fail("HMAC for expected key failed: %s",
p11_get_ckr(rc));
goto testcase_next;
}
rc = run_HMACSign(session, secret_keyA,
montgomery_ecdh_tv[i].derived_key_len,
CKM_SHA_1_HMAC, mac1, &mac1_len);
if (rc != CKR_OK) {
testcase_fail("HMAC for derived key #1 failed: %s",
p11_get_ckr(rc));
goto testcase_next;
}
if (mac1_len != 0 && /* skip check if mac can't be calculated */
(mac1_len != macexpected_len ||
memcmp(mac1, macexpected, mac1_len) != 0)) {
testcase_fail("ERROR: derived key #1 does not produce the "
"expected HMAC");
goto testcase_next;
}
rc = run_HMACSign(session, secret_keyB,
montgomery_ecdh_tv[i].derived_key_len,
CKM_SHA_1_HMAC, mac2, &mac2_len);
if (rc != CKR_OK) {
testcase_fail("HMAC for derived key #2 failed: %s",
p11_get_ckr(rc));
goto testcase_next;
}
if (mac2_len != 0 && /* skip check if mac can't be calculated */
(mac2_len != macexpected_len ||
memcmp(mac2, macexpected, mac2_len) != 0)) {
testcase_fail("ERROR: derived key #2 does not produce the "
"expected HMAC");
goto testcase_next;
}
}
testcase_pass("*Derive shared secret i=%lu (%s) passed.", i,
montgomery_ecdh_tv[i].name);
testcase_next:
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
priv_keyA = CK_INVALID_HANDLE;
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
publ_keyA = CK_INVALID_HANDLE;
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
priv_keyB = CK_INVALID_HANDLE;
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
publ_keyB = CK_INVALID_HANDLE;
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
secret_keyA = CK_INVALID_HANDLE;
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
secret_keyB = CK_INVALID_HANDLE;
}
testcase_cleanup:
if (priv_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyA);
if (publ_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyA);
if (priv_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_keyB);
if (publ_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_keyB);
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
testcase_user_logout();
testcase_close_session();
return rc;
}
typedef struct ecdh_encaps_decaps_params {
_ec_struct curve;
CK_KEY_TYPE sym_key_type;
CK_ULONG sym_key_size;
CK_EC_KDF_TYPE kdf;
CK_BYTE *shared_data;
CK_ULONG shared_data_len;
} ecdh_encaps_decaps_params;
const ecdh_encaps_decaps_params ecdh_encaps_decaps_tests[] = {
{ .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE,
CURVE_PRIME, CURVE256_LENGTH, "prime256v1" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_NULL,
.shared_data = NULL,
.shared_data_len = 0,
},
{ .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE,
CURVE_PRIME, CURVE256_LENGTH, "prime256v1" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &secp521r1, sizeof(secp521r1), CK_FALSE,
CURVE_PRIME, CURVE521_LENGTH + 8, "secp521r1" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &brainpoolP256r1, sizeof(brainpoolP256r1), CK_FALSE,
CURVE_BRAINPOOL, CURVE256_LENGTH, "brainpoolP256r1" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &brainpoolP512r1, sizeof(brainpoolP512r1), CK_FALSE,
CURVE_BRAINPOOL, CURVE512_LENGTH, "brainpoolP512r1" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &curve25519, sizeof(curve25519), CK_FALSE,
CURVE_MONTGOMERY, CURVE256_LENGTH, "curve25519" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &curve448, sizeof(curve448), CK_FALSE,
CURVE_MONTGOMERY, CURVE448_LENGTH, "curve448" },
.sym_key_type = CKK_AES,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE,
CURVE_PRIME, CURVE256_LENGTH, "prime256v1" },
.sym_key_type = CKK_AES,
.sym_key_size = 16,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE,
CURVE_PRIME, CURVE256_LENGTH, "prime256v1" },
.sym_key_type = CKK_AES_XTS,
.sym_key_size = 64,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE,
CURVE_PRIME, CURVE256_LENGTH, "prime256v1" },
.sym_key_type = CKK_GENERIC_SECRET,
.sym_key_size = 32,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
{ .curve = { &prime256v1, sizeof(prime256v1), CK_FALSE,
CURVE_PRIME, CURVE256_LENGTH, "prime256v1" },
.sym_key_type = CKK_GENERIC_SECRET,
.sym_key_size = 64,
.kdf = CKD_SHA256_KDF,
.shared_data = (CK_BYTE *)"abcdefg",
.shared_data_len = 6,
},
};
#define NUMENCAPSDECAPS sizeof(ecdh_encaps_decaps_tests) / \
sizeof(ecdh_encaps_decaps_params)
CK_RV run_EncapsDecapsECDH(CK_BBOOL cofactor_mode)
{
CK_SESSION_HANDLE session;
CK_MECHANISM mech;
CK_FLAGS flags;
CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE,
priv_key = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE secret_keyA = CK_INVALID_HANDLE,
secret_keyB = CK_INVALID_HANDLE;
CK_BYTE user_pin[PKCS11_MAX_PIN_LEN];
CK_ULONG user_pin_len;
CK_RV rc = CKR_OK;
CK_OBJECT_CLASS class = CKO_SECRET_KEY;
CK_ECDH1_DERIVE_PARAMS ecdh_parm;
CK_ULONG i;
CK_BBOOL ck_true = CK_TRUE;
CK_BBOOL ck_false = CK_FALSE;
CK_BYTE *cipher = NULL;
CK_ULONG cipher_len;
CK_BYTE mac1[SHA256_HASH_SIZE] = { 0 };
CK_ULONG mac1_len = sizeof(mac1);
CK_BYTE mac2[SHA256_HASH_SIZE] = { 0 };
CK_ULONG mac2_len = sizeof(mac2);
CK_BYTE enc1[AES_BLOCK_SIZE] = { 0 };
CK_ULONG enc1_len = sizeof(enc1);
CK_BYTE enc2[AES_BLOCK_SIZE] = { 0 };
CK_ULONG enc2_len = sizeof(enc2);
testcase_begin("starting run_EncapsDecapsECDH %s with pkey=%X ...",
cofactor_mode ? "in cofactor mode" : "", pkey);
testcase_rw_session();
testcase_user_login();
/* Skip tests if pkey = true, but the slot doesn't support protected keys*/
if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) {
testcase_skip("pkey test option is true, but slot %u doesn't support "
"protected keys", (unsigned int)SLOT_ID);
goto testcase_cleanup;
}
mech.mechanism = cofactor_mode ?
CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE;
if (!mech_supported(SLOT_ID, mech.mechanism)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int)SLOT_ID,
p11_get_ckm(&mechtable_funcs, mech.mechanism));
goto testcase_cleanup;
}
if (!encapsulate_supported(SLOT_ID, mech) ||
!decapsulate_supported(SLOT_ID, mech)) {
testcase_skip("Slot %u doesn't support key encapsulation with %s",
(unsigned int)SLOT_ID,
p11_get_ckm(&mechtable_funcs, mech.mechanism));
goto testcase_cleanup;
}
for (i = 0; i < NUMENCAPSDECAPS; i++) {
CK_ATTRIBUTE decaps_tmp[] = {
{CKA_KEY_TYPE,
(CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_type,
sizeof(ecdh_encaps_decaps_tests[i].sym_key_type)},
{CKA_VALUE_LEN,
(CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_size,
sizeof(ecdh_encaps_decaps_tests[i].sym_key_size)},
};
CK_ATTRIBUTE prv_attr[] = {
{CKA_SIGN, &ck_true, sizeof(ck_true)},
{CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)},
{CKA_SENSITIVE, &ck_true, sizeof(ck_true)},
{CKA_DERIVE, &ck_false, sizeof(ck_false)},
{CKA_DECAPSULATE, &ck_true, sizeof(ck_true)},
{CKA_DECAPSULATE_TEMPLATE, &decaps_tmp, sizeof(decaps_tmp)},
};
CK_ULONG prv_attr_len = sizeof(prv_attr)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE pub_attr[] = {
{CKA_EC_PARAMS,
(CK_VOID_PTR)ecdh_encaps_decaps_tests[i].curve.curve,
ecdh_encaps_decaps_tests[i].curve.size},
{CKA_VERIFY, &ck_true, sizeof(ck_true)},
{CKA_DERIVE, &ck_false, sizeof(ck_false)},
{CKA_ENCAPSULATE, &ck_true, sizeof(ck_true)},
};
CK_ULONG pub_attr_len = sizeof(pub_attr)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE encaps_decaps_tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE,
(CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_type,
sizeof(ecdh_encaps_decaps_tests[i].sym_key_type)},
{CKA_EXTRACTABLE, &ck_false, sizeof(ck_false)},
{CKA_SENSITIVE, &ck_true, sizeof(ck_true)},
{CKA_VALUE_LEN,
(CK_VOID_PTR)&ecdh_encaps_decaps_tests[i].sym_key_size,
sizeof(ecdh_encaps_decaps_tests[i].sym_key_size)},
};
CK_ULONG encaps_decaps_tmpl_len =
sizeof(encaps_decaps_tmpl) / sizeof(CK_ATTRIBUTE);
mech.mechanism = cofactor_mode ?
CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE;
testcase_begin("Starting with mech=%s, index=%lu, curve=%s, kdf=%s, "
"keytype=0x%lx, keylen=%lu, shared_data=%lu, pkey=%X",
p11_get_ckm(&mechtable_funcs, mech.mechanism), i,
ecdh_encaps_decaps_tests[i].curve.name,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf),
ecdh_encaps_decaps_tests[i].sym_key_type,
ecdh_encaps_decaps_tests[i].sym_key_size,
ecdh_encaps_decaps_tests[i].shared_data_len,
pkey);
/* Check the curve */
if (ecdh_encaps_decaps_tests[i].curve.type == CURVE_EDWARDS||
ecdh_encaps_decaps_tests[i].curve.type == CURVE_BLS12_381) {
/* Edwards/BLS curves can not be used for ECDH encaps/decaps */
continue;
}
if (is_cca_token(SLOT_ID)) {
if (ecdh_encaps_decaps_tests[i].curve.twisted) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
ecdh_encaps_decaps_tests[i].curve.name);
continue;
}
}
/* Check the KDF */
switch (ecdh_encaps_decaps_tests[i].kdf) {
case CKD_SHA1_KDF:
case CKD_SHA1_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA_1)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA224_KDF:
case CKD_SHA224_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA224)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA256_KDF:
case CKD_SHA256_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA256)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA384_KDF:
case CKD_SHA384_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA384)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA512_KDF:
case CKD_SHA512_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA512)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA3_224_KDF:
case CKD_SHA3_224_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_224)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));;
continue;
}
break;
case CKD_SHA3_256_KDF:
case CKD_SHA3_256_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_256)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA3_384_KDF:
case CKD_SHA3_384_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_384)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
case CKD_SHA3_512_KDF:
case CKD_SHA3_512_KDF_SP800:
if (!mech_supported(SLOT_ID, CKM_SHA3_512)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int) SLOT_ID,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
break;
default:
break;
}
if (is_cca_token(SLOT_ID)) {
switch (ecdh_encaps_decaps_tests[i].kdf) {
case CKD_SHA224_KDF:
case CKD_SHA256_KDF:
case CKD_SHA384_KDF:
case CKD_SHA512_KDF:
break;
default:
testcase_skip("CCA token can not en/decapsulate keys with "
"this KDF %s",
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf));
continue;
}
}
/* Check the to be en/decapsulated key type and size */
if (is_cca_token(SLOT_ID)) {
if (ecdh_encaps_decaps_tests[i].sym_key_type != CKK_AES) {
testcase_skip("CCA token can not en/decapsulate keys other "
"than AES\n");
continue;
}
}
/* Generate the EC key pair for party A */
mech.mechanism =
ecdh_encaps_decaps_tests[i].curve.type == CURVE_MONTGOMERY ?
CKM_EC_MONTGOMERY_KEY_PAIR_GEN : CKM_EC_KEY_PAIR_GEN;
mech.ulParameterLen = 0;
mech.pParameter = NULL;
if (!mech_supported(SLOT_ID, mech.mechanism)) {
testcase_skip("Slot %u doesn't support %s\n",
(unsigned int)SLOT_ID,
p11_get_ckm(&mechtable_funcs, mech.mechanism));
continue;
}
rc = funcs->C_GenerateKeyPair(session, &mech,
pub_attr, pub_attr_len,
prv_attr, prv_attr_len,
&publ_key, &priv_key);
if (rc != CKR_OK) {
if (is_rejected_by_policy(rc, session)) {
testcase_skip("EC key generation is not allowed by policy");
goto testcase_next;
}
if (rc == CKR_MECHANISM_PARAM_INVALID ||
rc == CKR_ATTRIBUTE_VALUE_INVALID ||
rc == CKR_CURVE_NOT_SUPPORTED) {
testcase_skip("Slot %u doesn't support this curve: %s",
(unsigned int) SLOT_ID,
ecdh_encaps_decaps_tests[i].curve.name);
goto testcase_next;
}
testcase_new_assertion();
testcase_fail("C_GenerateKeyPair with valid input failed at i=%lu "
"(%s), rc=%s", i,
ecdh_encaps_decaps_tests[i].curve.name,
p11_get_ckr(rc));
goto testcase_next;
}
/* Encapsulate on party B */
mech.mechanism = cofactor_mode ?
CKM_ECDH1_COFACTOR_DERIVE : CKM_ECDH1_DERIVE;
mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
mech.pParameter = &ecdh_parm;
ecdh_parm.kdf = ecdh_encaps_decaps_tests[i].kdf;
ecdh_parm.pSharedData = ecdh_encaps_decaps_tests[i].shared_data;
ecdh_parm.ulSharedDataLen = ecdh_encaps_decaps_tests[i].shared_data_len;
ecdh_parm.pPublicData = NULL;
ecdh_parm.ulPublicDataLen = 0;
rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key,
encaps_decaps_tmpl,
encaps_decaps_tmpl_len,
NULL, &cipher_len, NULL);
if (rc != CKR_OK) {
if (is_ep11_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
(ecdh_parm.kdf != CKD_NULL ||
ecdh_parm.ulSharedDataLen > 0)) {
testcase_skip("EP11 does not support KDF %s and/or "
"shared data with older firmware "
"versions\n",
p11_get_ckd(ecdh_parm.kdf));
goto testcase_next;
}
if (rc == CKR_KEY_TYPE_INCONSISTENT) {
testcase_skip("Slot %u doesn't support to en/decaps key "
"type 0x%lx", (unsigned int) SLOT_ID,
ecdh_encaps_decaps_tests[i].sym_key_type);
goto testcase_next;
}
if (is_rejected_by_policy(rc, session)) {
testcase_skip("key derivation is not allowed by policy");
continue;
}
if (rc == CKR_FUNCTION_CANCELED) {
testcase_skip("key derivation is not allowed by "
"adapter control point");
goto testcase_next;
}
if (rc == CKR_KEY_SIZE_RANGE) {
testcase_skip("key derivation is not allowed because key to be "
"generated is stronger than the input material.");
goto testcase_next;
}
testcase_new_assertion();
testcase_fail("C_EncapsulateKey #1: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
cipher = calloc(cipher_len, sizeof(CK_BYTE));
if (cipher == NULL) {
testcase_error("Can't allocate memory for %lu bytes.", cipher_len);
rc = CKR_HOST_MEMORY;
goto testcase_cleanup;
}
rc = funcs3_2->C_EncapsulateKey(session, &mech, publ_key,
encaps_decaps_tmpl,
encaps_decaps_tmpl_len,
cipher, &cipher_len, &secret_keyB);
if (rc != CKR_OK) {
if (is_ep11_token(SLOT_ID) &&
rc == CKR_MECHANISM_PARAM_INVALID &&
(ecdh_parm.kdf != CKD_NULL ||
ecdh_parm.ulSharedDataLen > 0)) {
testcase_skip("EP11 does not support KDF %s and/or "
"shared data with older firmware "
"versions\n",
p11_get_ckd(ecdh_parm.kdf));
goto testcase_next;
}
if (rc == CKR_KEY_TYPE_INCONSISTENT) {
testcase_skip("Slot %u doesn't support to en/decaps key "
"type 0x%lx", (unsigned int) SLOT_ID,
ecdh_encaps_decaps_tests[i].sym_key_type);
goto testcase_next;
}
if (is_rejected_by_policy(rc, session)) {
testcase_skip("key derivation is not allowed by policy");
continue;
}
if (rc == CKR_FUNCTION_CANCELED) {
testcase_skip("key derivation is not allowed by "
"adapter control point");
goto testcase_next;
}
if (rc == CKR_KEY_SIZE_RANGE) {
testcase_skip("key derivation is not allowed because key to be "
"generated is stronger than the input material.");
goto testcase_next;
}
testcase_new_assertion();
testcase_fail("C_EncapsulateKey #2: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
/* Decapsulate on party A */
rc = funcs3_2->C_DecapsulateKey(session, &mech, priv_key,
encaps_decaps_tmpl,
encaps_decaps_tmpl_len,
cipher, cipher_len, &secret_keyA);
if (rc != CKR_OK) {
testcase_new_assertion();
testcase_fail("C_DecapsulateKey: rc = %s", p11_get_ckr(rc));
goto testcase_next;
}
/* Check if encapsulated key is the same as the decapsukated key */
testcase_new_assertion();
switch (ecdh_encaps_decaps_tests[i].sym_key_type) {
case CKK_GENERIC_SECRET:
mac1_len = sizeof(mac1);
rc = run_HMACSign(session, secret_keyB,
ecdh_encaps_decaps_tests[i].sym_key_size,
CKM_SHA256_HMAC, mac1, &mac1_len);
if (rc != CKR_OK) {
testcase_fail("Encapsulated key #1 is not usable: %s",
p11_get_ckr(rc));
goto testcase_next;
}
mac2_len = sizeof(mac2);
rc = run_HMACSign(session, secret_keyA,
ecdh_encaps_decaps_tests[i].sym_key_size,
CKM_SHA256_HMAC, mac2, &mac2_len);
if (rc != CKR_OK) {
testcase_fail("Decapsulated key #2 is not usable: %s",
p11_get_ckr(rc));
goto testcase_next;
}
if (mac1_len != mac2_len ||
memcmp(mac1, mac2, mac1_len) != 0) {
testcase_fail("ERROR: en/Decapsulated keys do not produce the "
"same HMAC");
goto testcase_next;
}
break;
case CKK_AES:
enc1_len = sizeof(enc1);
rc = run_AESEncrypt(session, secret_keyB, enc1, &enc1_len);
if (rc != CKR_OK) {
testcase_fail("Encapsulated key #1 is not usable: %s",
p11_get_ckr(rc));
goto testcase_next;
}
enc2_len = sizeof(enc2);
rc = run_AESEncrypt(session, secret_keyA, enc2, &enc2_len);
if (rc != CKR_OK) {
testcase_fail("Decapsulated key #2 is not usable: %s",
p11_get_ckr(rc));
goto testcase_next;
}
if (enc1_len != enc2_len ||
memcmp(enc1, enc2, enc1_len) != 0) {
testcase_fail("ERROR: en/decapsulated keys do not produce the "
"same encrypted cipher text");
goto testcase_next;
}
break;
}
testcase_pass("EnDecapsulate shared secret mech=%s, index=%lu, "
"curve=%s, kdf=%s, keytype=ox%lx, keylen=%lu, "
"shared_data=%lu passed.",
p11_get_ckm(&mechtable_funcs, mech.mechanism), i,
ecdh_encaps_decaps_tests[i].curve.name,
p11_get_ckd(ecdh_encaps_decaps_tests[i].kdf),
ecdh_encaps_decaps_tests[i].sym_key_type,
ecdh_encaps_decaps_tests[i].sym_key_size,
ecdh_encaps_decaps_tests[i].shared_data_len);
testcase_next:
if (cipher)
free(cipher);
cipher = NULL;
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
secret_keyA = CK_INVALID_HANDLE;
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
secret_keyB = CK_INVALID_HANDLE;
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
publ_key = CK_INVALID_HANDLE;
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
priv_key = CK_INVALID_HANDLE;
}
testcase_cleanup:
if (cipher)
free(cipher);
if (secret_keyA != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyA);
secret_keyA = CK_INVALID_HANDLE;
if (secret_keyB != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, secret_keyB);
secret_keyB = CK_INVALID_HANDLE;
if (publ_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, publ_key);
publ_key = CK_INVALID_HANDLE;
if (priv_key != CK_INVALID_HANDLE)
funcs->C_DestroyObject(session, priv_key);
priv_key = CK_INVALID_HANDLE;
testcase_user_logout();
testcase_close_session();
return rc;
}
int main(int argc, char **argv)
{
CK_C_INITIALIZE_ARGS cinit_args;
int rc;
CK_RV rv;
rc = do_ParseArgs(argc, argv);
if (rc != 1)
return rc;
printf("Using slot #%lu...\n\n", SLOT_ID);
printf("With options: combined_extract: %d, nostop: %d\n",
combined_extract, no_stop);
if (combined_extract)
printf("\n--------------------------------------------------------\n"
"Caution: combined_extract does only work on systems with\n"
"control point 75 (XCP_CPB_ALLOW_COMBINED_EXTRACT)='on'.\n"
"--------------------------------------------------------\n\n");
rc = do_GetFunctionList();
if (!rc) {
PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc);
return rc;
}
memset(&cinit_args, 0x0, sizeof(cinit_args));
cinit_args.flags = CKF_OS_LOCKING_OK;
// SAB Add calls to ALL functions before the C_Initialize gets hit
funcs->C_Initialize(&cinit_args);
{
CK_SESSION_HANDLE hsess = 0;
rc = funcs->C_GetFunctionStatus(hsess);
if (rc != CKR_FUNCTION_NOT_PARALLEL)
return rc;
rc = funcs->C_CancelFunction(hsess);
if (rc != CKR_FUNCTION_NOT_PARALLEL)
return rc;
}
testcase_setup();
pkey = CK_FALSE;
rv = run_GenerateECCKeyPairSignVerify();
rv += run_ImportECCKeyPairSignVerify();
rv += run_TransferECCKeyPairSignVerify();
rv += run_DeriveECDHKey(FALSE);
rv += run_DeriveECDHKey(TRUE);
rv += run_DeriveECDHKeyKAT();
rv += run_DeriveBTC();
rv += run_BLSAggregation();
rv += run_DeriveETH();
rv += run_GenerateEdwardsKeyPairSignVerify();
rv += run_ImportEdwardsKeyPairSignVerifyKAT();
rv += run_TransferEdwardsMontgomeryKeyPair();
rv += run_MontgomeryECDHKeyKAT();
rv += run_EncapsDecapsECDH(FALSE);
rv += run_EncapsDecapsECDH(TRUE);
#ifndef NO_PKEY
if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) {
pkey = CK_TRUE;
rv += run_GenerateECCKeyPairSignVerify();
rv += run_ImportECCKeyPairSignVerify();
rv += run_TransferECCKeyPairSignVerify();
rv += run_DeriveECDHKey(FALSE);
rv += run_DeriveECDHKeyKAT();
rv += run_ImportSignVerify_Pkey();
rv += run_GenerateEdwardsKeyPairSignVerify();
rv += run_ImportEdwardsKeyPairSignVerifyKAT();
rv += run_TransferEdwardsMontgomeryKeyPair();
rv += run_MontgomeryECDHKeyKAT();
rv += run_EncapsDecapsECDH(FALSE);
}
#endif
testcase_print_result();
funcs->C_Finalize(NULL);
return testcase_return(rv);
}