Pkcs11-tool.c changes to accommodate ECDH operations using SoftHSM. (#901)

PKCS#11 v2.20 in not clear on the format of the public key of the other party
pased during ECDH key derivation. Some implementations (OpenSC) pass just the value
of the public key (RAW), while others (SoftHSM) pass an ASN.1 DER encoded OCTET_STRING.

PKCS$11 v2.40 points out this problem and says implementations must support the
RAW format and may also support the DER format.

To allow pkcs11-tool.c to work with ECDH derivation and using the current libSoftHSM2.so
a new parameter was added to pkcs11-tool, --derive-pass-der.

Also added to teh template fot the new key were:

CKA_SENSITIVE = false
CKA_EXTRACTABLE = true
CKA_VALUE_LEN = size of key to be derived.

OpenSC currently only support derivation of ECDH session keys, (CKA_TOKEN = false)
The derived key must be CK_KEY_TYPE = CKK_GENERIC_SECRET
Additional changes could be made to support AES or DES3 keys.

It is not clear if there is a need to support CKA_TOKEN =  true which says the
derived key must be on the hardware token. For ECDH, these keys are short lived.

 On branch pkcs11-tool-simple-ecdh
 Changes to be committed:
	modified:   src/tools/pkcs11-tool.c
This commit is contained in:
Doug Engert 2016-11-20 09:28:42 -08:00 committed by viktorTarasov
parent a25a2484f1
commit 3ff7309520
1 changed files with 58 additions and 9 deletions

View File

@ -140,6 +140,7 @@ enum {
OPT_LOGIN_TYPE,
OPT_TEST_EC,
OPT_DERIVE,
OPT_DERIVE_PASS_DER,
OPT_DECRYPT,
OPT_TEST_FORK,
OPT_GENERATE_KEY,
@ -157,6 +158,7 @@ static const struct option options[] = {
{ "decrypt", 0, NULL, OPT_DECRYPT },
{ "hash", 0, NULL, 'h' },
{ "derive", 0, NULL, OPT_DERIVE },
{ "derive-pass-der", 0, NULL, OPT_DERIVE_PASS_DER },
{ "mechanism", 1, NULL, 'm' },
{ "login", 0, NULL, 'l' },
@ -220,6 +222,7 @@ static const char *option_help[] = {
"Decrypt some data",
"Hash some data",
"Derive a secret key using another key and some data",
"Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations"
"Specify mechanism (use -M for a list of supported mechanisms)",
"Log into the token first",
@ -308,6 +311,7 @@ static int opt_key_usage_sign = 0;
static int opt_key_usage_decrypt = 0;
static int opt_key_usage_derive = 0;
static int opt_key_usage_default = 1; /* uses defaults if no opt_key_usage options */
static int opt_derive_pass_der = 0;
static void *module = NULL;
static CK_FUNCTION_LIST_PTR p11 = NULL;
@ -728,6 +732,9 @@ int main(int argc, char * argv[])
do_test_ec = 1;
action_count++;
break;
case OPT_DERIVE_PASS_DER:
opt_derive_pass_der = 1;
/* fall through */
case OPT_DERIVE:
need_session |= NEED_SESSION_RW;
do_derive = 1;
@ -2931,22 +2938,31 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
CK_BBOOL true = TRUE;
CK_BBOOL false = FALSE;
CK_OBJECT_HANDLE newkey = 0;
CK_ATTRIBUTE newkey_template[] = {
CK_ATTRIBUTE newkey_template[20] = {
{CKA_TOKEN, &false, sizeof(false)}, /* session only object */
{CKA_CLASS, &newkey_class, sizeof(newkey_class)},
{CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)},
{CKA_SENSITIVE, &false, sizeof(false)},
{CKA_EXTRACTABLE, &true, sizeof(true)},
{CKA_ENCRYPT, &true, sizeof(true)},
{CKA_DECRYPT, &true, sizeof(true)}
{CKA_DECRYPT, &true, sizeof(true)},
{CKA_WRAP, &true, sizeof(true)},
{CKA_UNWRAP, &true, sizeof(true)}
};
int n_attrs = 9;
CK_ECDH1_DERIVE_PARAMS ecdh_parms;
CK_RV rv;
BIO *bio_in = NULL;
EC_KEY *eckey = NULL;
const EC_GROUP *ecgroup = NULL;
const EC_POINT *ecpoint = NULL;
unsigned char buf[512];
unsigned char *buf = NULL;
size_t buf_size = 0;
int len;
CK_ULONG key_len = 0;
ASN1_OCTET_STRING *octet = NULL;
unsigned char * der = NULL;
unsigned char * derp = NULL;
size_t der_size = 0;
printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(mech_mech));
memset(&mech, 0, sizeof(mech));
@ -2963,11 +2979,32 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
ecpoint = EC_KEY_get0_public_key(eckey);
ecgroup = EC_KEY_get0_group(eckey);
if (!ecpoint || !ecgroup)
util_fatal("Failed to parse other EC key from %s", opt_input);
buf_size = sizeof(buf);
len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL);
/* both eckeys must be same curve */
key_len = (EC_GROUP_get_degree(ecgroup) + 7) / 8;
FILL_ATTR(newkey_template[n_attrs], CKA_VALUE_LEN, &key_len, sizeof(key_len));
n_attrs++;
buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
buf = (unsigned char *)malloc(buf_size);
if (buf == NULL)
util_fatal("malloc() failure\n");
buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL);
if (opt_derive_pass_der) {
octet = ASN1_OCTET_STRING_new();
if (octet == NULL)
util_fatal("ASN1_OCTET_STRING_new failure\n");
ASN1_OCTET_STRING_set(octet, buf, buf_size);
der_size = i2d_ASN1_OCTET_STRING(octet, NULL);
derp = der = (unsigned char *) malloc(der_size);
if (der == NULL)
util_fatal("malloc() failure\n");
der_size = i2d_ASN1_OCTET_STRING(octet, &derp);
}
BIO_free(bio_in);
EC_KEY_free(eckey);
@ -2976,15 +3013,27 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
ecdh_parms.kdf = CKD_NULL;
ecdh_parms.ulSharedDataLen = 0;
ecdh_parms.pSharedData = NULL;
ecdh_parms.ulPublicDataLen = len;
ecdh_parms.pPublicData = buf;
if (opt_derive_pass_der) {
ecdh_parms.ulPublicDataLen = der_size;
ecdh_parms.pPublicData = der;
} else {
ecdh_parms.ulPublicDataLen = buf_size;
ecdh_parms.pPublicData = buf;
}
mech.pParameter = &ecdh_parms;
mech.ulParameterLen = sizeof(ecdh_parms);
rv = p11->C_DeriveKey(session, &mech, key, newkey_template, 5, &newkey);
rv = p11->C_DeriveKey(session, &mech, key, newkey_template, n_attrs, &newkey);
if (rv != CKR_OK)
p11_fatal("C_DeriveKey", rv);
if (der)
OPENSSL_free(der);
if (buf)
free(buf);
if (octet)
ASN1_OCTET_STRING_free(octet);
return newkey;
#else
util_fatal("Derive EC key not supported");