From d2cefc66b7212bdd899f5c501a977bcbb691e632 Mon Sep 17 00:00:00 2001 From: Alessio Di Mauro Date: Fri, 28 Aug 2015 17:15:11 +0200 Subject: [PATCH] Initial stab at private key import. --- ykcs11/objects.c | 167 ++++++++++++++++++++++++++++++++++++++++- ykcs11/objects.h | 10 +++ ykcs11/token_vendors.c | 11 +++ ykcs11/token_vendors.h | 6 +- ykcs11/ykcs11.c | 60 +++++++++++++-- 5 files changed, 245 insertions(+), 9 deletions(-) diff --git a/ykcs11/objects.c b/ykcs11/objects.c index 92e8b70..3594064 100644 --- a/ykcs11/objects.c +++ b/ykcs11/objects.c @@ -942,11 +942,12 @@ CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, has_value = CK_TRUE; *value = (CK_BYTE_PTR)templ[i].pValue; - *cert_len = 0; - *cert_len += get_length(value + 1, cert_len) + 1; + /**cert_len = 0; + *cert_len += get_length(value + 1, cert_len) + 1;*/ + *cert_len = templ[i].ulValueLen; break; - default: + default: // TODO: don't error on valid parameters // Ignore other attributes for now DBG(("Invalid %lx", templ[i].type)); return CKR_ATTRIBUTE_TYPE_INVALID; @@ -959,3 +960,163 @@ CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, return CKR_OK; } + +CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, + CK_BYTE_PTR *value, CK_ULONG_PTR cert_len, + CK_BYTE_PTR *ec_params, CK_ULONG_PTR ec_params_len) { + + CK_ULONG i; + CK_BBOOL has_id = CK_FALSE; + CK_BBOOL has_value = CK_FALSE; + CK_BBOOL has_params = CK_FALSE; + + for (i = 0; i < n; i++) { + switch (templ[i].type) { + case CKA_CLASS: + if (*((CK_ULONG_PTR)templ[i].pValue) != CKO_PRIVATE_KEY) + return CKR_ATTRIBUTE_VALUE_INVALID; + + break; + + case CKA_KEY_TYPE: + if (*((CK_ULONG_PTR)templ[i].pValue) != CKK_ECDSA) + return CKR_ATTRIBUTE_VALUE_INVALID; + + break; + + case CKA_ID: + has_id = CK_TRUE; + if (is_valid_key_id(*((CK_BYTE_PTR)templ[i].pValue)) == CK_FALSE) + return CKR_ATTRIBUTE_VALUE_INVALID; + + *id = *((CK_BYTE_PTR)templ[i].pValue); + break; + + case CKA_VALUE: + has_value = CK_TRUE; + *value = (CK_BYTE_PTR)templ[i].pValue; + *cert_len = templ[i].ulValueLen; + + break; + + case CKA_EC_PARAMS: + has_params = CK_TRUE; + *ec_params = (CK_BYTE_PTR)templ[i].pValue; + *ec_params_len = templ[i].ulValueLen; + + break; + + default: // TODO: don't error on valid parameters + // Ignore other attributes for now + DBG(("Invalid %lx", templ[i].type)); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + } + + if (has_id == CK_FALSE || + has_value == CK_FALSE || + has_params == CK_FALSE) + return CKR_TEMPLATE_INCOMPLETE; + + return CKR_OK; +} + +CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, + CK_BYTE_PTR *e, CK_ULONG_PTR e_len, + CK_BYTE_PTR *p, CK_ULONG_PTR p_len, + CK_BYTE_PTR *q, CK_ULONG_PTR q_len, + CK_BYTE_PTR *dp, CK_ULONG_PTR dp_len, + CK_BYTE_PTR *dq, CK_ULONG_PTR dq_len, + CK_BYTE_PTR *qinv, CK_ULONG_PTR qinv_len) { + + CK_ULONG i; + CK_BBOOL has_id = CK_FALSE; + CK_BBOOL has_e = CK_FALSE; + CK_BBOOL has_p = CK_FALSE; + CK_BBOOL has_q = CK_FALSE; + CK_BBOOL has_dp = CK_FALSE; + CK_BBOOL has_dq = CK_FALSE; + CK_BBOOL has_qinv = CK_FALSE; + + for (i = 0; i < n; i++) { + switch (templ[i].type) { + case CKA_CLASS: + if (*((CK_ULONG_PTR)templ[i].pValue) != CKO_PRIVATE_KEY) + return CKR_ATTRIBUTE_VALUE_INVALID; + + break; + + case CKA_ID: + has_id = CK_TRUE; + if (is_valid_key_id(*((CK_BYTE_PTR)templ[i].pValue)) == CK_FALSE) + return CKR_ATTRIBUTE_VALUE_INVALID; + + *id = *((CK_BYTE_PTR)templ[i].pValue); + break; + + case CKA_KEY_TYPE: + if (*((CK_ULONG_PTR)templ[i].pValue) != CKK_RSA) + return CKR_ATTRIBUTE_VALUE_INVALID; + + break; + + case CKA_PUBLIC_EXPONENT: // TODO: check that it is F4 + has_e = CK_TRUE; + *e = (CK_BYTE_PTR)templ[i].pValue; + *e_len = templ[i].ulValueLen; + + break; + + case CKA_PRIME_1: + has_p = CK_TRUE; + *p = (CK_BYTE_PTR)templ[i].pValue; + *p_len = templ[i].ulValueLen; + + break; + + case CKA_PRIME_2: + has_q = CK_TRUE; + *q = (CK_BYTE_PTR)templ[i].pValue; + *q_len = templ[i].ulValueLen; + + break; + + case CKA_EXPONENT_1: + has_dp = CK_TRUE; + *dp = (CK_BYTE_PTR)templ[i].pValue; + *dp_len = templ[i].ulValueLen; + + break; + + case CKA_EXPONENT_2: + has_dq = CK_TRUE; + *dq = (CK_BYTE_PTR)templ[i].pValue; + *dq_len = templ[i].ulValueLen; + + break; + + case CKA_COEFFICIENT: + has_qinv = CK_TRUE; + *qinv = (CK_BYTE_PTR)templ[i].pValue; + *qinv_len = templ[i].ulValueLen; + + break; + + default: // TODO: don't error on valid parameters + // Ignore other attributes for now + DBG(("Invalid %lx", templ[i].type)); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + } + + if (has_id == CK_FALSE || + has_e == CK_FALSE || + has_p == CK_FALSE || + has_q == CK_FALSE || + has_dp == CK_FALSE || + has_dq == CK_FALSE || + has_qinv == CK_FALSE) + return CKR_TEMPLATE_INCOMPLETE; + + return CKR_OK; +} diff --git a/ykcs11/objects.h b/ykcs11/objects.h index 84dded1..b48cc57 100644 --- a/ykcs11/objects.h +++ b/ykcs11/objects.h @@ -14,5 +14,15 @@ CK_RV store_cert(piv_obj_id_t cert_id, CK_BYTE_PTR data, CK_ULONG len); CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, CK_BYTE_PTR *value, CK_ULONG_PTR cert_len); +CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, + CK_BYTE_PTR *value, CK_ULONG_PTR cert_len, + CK_BYTE_PTR *ec_params, CK_ULONG_PTR ec_params_len); +CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, + CK_BYTE_PTR *e, CK_ULONG_PTR e_len, + CK_BYTE_PTR *p, CK_ULONG_PTR p_len, + CK_BYTE_PTR *q, CK_ULONG_PTR q_len, + CK_BYTE_PTR *dp, CK_ULONG_PTR dp_len, + CK_BYTE_PTR *dq, CK_ULONG_PTR dq_len, + CK_BYTE_PTR *qinv, CK_ULONG_PTR qinv_len); #endif diff --git a/ykcs11/token_vendors.c b/ykcs11/token_vendors.c index 4bc9348..bdb5218 100644 --- a/ykcs11/token_vendors.c +++ b/ykcs11/token_vendors.c @@ -122,6 +122,15 @@ static CK_RV COMMON_token_import_cert(ykpiv_state *state, CK_ULONG cert_id, CK_B return CKR_OK; } +CK_RV COMMON_token_import_private_key(ykpiv_state *state , CK_BYTE_PTR key_id, CK_BYTE_PTR p, CK_ULONG p_len, + CK_BYTE_PTR q, CK_ULONG q_len, CK_BYTE_PTR dp, CK_ULONG dp_len, + CK_BYTE_PTR dq, CK_ULONG dq_len, CK_BYTE_PTR qinv, CK_ULONG qinv_len, + CK_BYTE_PTR ec_data, CK_ULONG ec_data_len) { + + return CKR_OK; + +} + token_vendor_t get_token_vendor(vendor_id_t vid) { token_vendor_t v; @@ -141,6 +150,7 @@ token_vendor_t get_token_vendor(vendor_id_t vid) { v.get_token_raw_certificate = YUBICO_get_token_raw_certificate; v.token_generate_key = COMMON_token_generate_key; v.token_import_cert = COMMON_token_import_cert; + v.token_import_private_key = COMMON_token_import_private_key; break; case UNKNOWN: @@ -159,6 +169,7 @@ token_vendor_t get_token_vendor(vendor_id_t vid) { v.get_token_raw_certificate = NULL; v.token_generate_key = NULL; v.token_import_cert = NULL; + v.token_import_private_key = NULL; } return v; diff --git a/ykcs11/token_vendors.h b/ykcs11/token_vendors.h index e07f96e..5a86be4 100644 --- a/ykcs11/token_vendors.h +++ b/ykcs11/token_vendors.h @@ -22,8 +22,11 @@ typedef CK_RV (*get_t_raw_certificate_f)(ykpiv_state *, piv_obj_id_t, CK_BYTE_PT // Common token functions below typedef CK_RV (*t_generate_key_f)(ykpiv_state *, CK_BBOOL, CK_BYTE, CK_ULONG); typedef CK_RV (*t_import_cert_f)(ykpiv_state *, CK_ULONG, CK_BYTE_PTR); +typedef CK_RV (*t_import_private_key_f)(ykpiv_state *, CK_BYTE_PTR ,CK_BYTE_PTR, CK_ULONG, + CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG, + CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG); -// TODO: replace all the common call with functions defined in .c that use libykpiv +// TODO: replace all the common calls with functions defined in .c that use libykpiv typedef struct { get_t_label_f get_token_label; @@ -40,6 +43,7 @@ typedef struct { get_t_raw_certificate_f get_token_raw_certificate; t_generate_key_f token_generate_key; t_import_cert_f token_import_cert; + t_import_private_key_f token_import_private_key; } token_vendor_t; token_vendor_t get_token_vendor(vendor_id_t vid); diff --git a/ykcs11/ykcs11.c b/ykcs11/ykcs11.c index 6297040..b0a326c 100644 --- a/ykcs11/ykcs11.c +++ b/ykcs11/ykcs11.c @@ -827,15 +827,31 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( CK_OBJECT_CLASS class; CK_BYTE id; CK_BYTE_PTR value; - CK_ULONG len; + CK_ULONG value_len; + CK_BYTE_PTR ec_params; + CK_ULONG ec_params_len; + CK_BYTE_PTR e; + CK_ULONG e_len; + CK_BYTE_PTR p; + CK_ULONG p_len; + CK_BYTE_PTR q; + CK_ULONG q_len; + CK_BYTE_PTR dp; + CK_ULONG dp_len; + CK_BYTE_PTR dq; + CK_ULONG dq_len; + CK_BYTE_PTR qinv; + CK_ULONG qinv_len; token_vendor_t token; CK_BBOOL is_new; + CK_BBOOL is_rsa; CK_OBJECT_HANDLE object; CK_ULONG cert_id; CK_ULONG pvtk_id; CK_ULONG pubk_id; piv_obj_id_t *obj_ptr; + if (piv_state == NULL) { DBG(("libykpiv is not initialized or already finalized")); return CKR_CRYPTOKI_NOT_INITIALIZED; @@ -869,7 +885,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( // Can only import certificates and private keys if (*((CK_ULONG_PTR)pTemplate[i].pValue) != CKO_CERTIFICATE && - *((CK_ULONG_PTR)pTemplate[i].pValue) != CKO_PUBLIC_KEY) { + *((CK_ULONG_PTR)pTemplate[i].pValue) != CKO_PRIVATE_KEY) { DBG(("Unsupported class %lu", class)); return CKR_ATTRIBUTE_VALUE_INVALID; } @@ -887,7 +903,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( case CKO_CERTIFICATE: DBG(("Importing certificate")); - rv = check_create_cert(pTemplate, ulCount, &id, &value, &len); + rv = check_create_cert(pTemplate, ulCount, &id, &value, &value_len); if (rv != CKR_OK) { DBG(("Certificate template not valid")); return rv; @@ -933,7 +949,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( *obj_ptr++ = pubk_id; } - rv = store_cert(cert_id, value, len); + rv = store_cert(cert_id, value, value_len); if (rv != CKR_OK) { DBG(("Unable to store certificate data")); return CKR_FUNCTION_FAILED; @@ -942,7 +958,41 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( break; case CKO_PRIVATE_KEY: - //rv = create_pvt_key(); + DBG(("Importing private key")); + + // Try to parse the key as EC + is_rsa = CK_FALSE; + rv = check_create_ec_key(pTemplate, ulCount, &id, &value, &value_len, &ec_params, &ec_params_len); + if (rv != CKR_OK) { + // Try to parse the key as RSA + is_rsa = CK_TRUE; + rv = check_create_rsa_key(pTemplate, ulCount, &id, &e, &e_len, &p, &p_len, + &q, &q_len, &dp, &dp_len, &dq, &dq_len, &qinv, &qinv_len); + if (rv != CKR_OK) { + DBG(("Private key template not valid")); + return rv; + } + } + + DBG(("Key id is %u", id)); + + if (is_rsa == CK_TRUE) { + DBG(("Key is RSA")); + rv = token.token_import_private_key(piv_state, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0); + if (rv != CKR_OK) { + DBG(("Unable to import RSA private key")); + return rv; + } + } + else { + DBG(("Key is ECDSA")); + rv = token.token_import_private_key(piv_state, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0); + if (rv != CKR_OK) { + DBG(("Unable to import ECDSA private key")); + return rv; + } + } + return CKR_FUNCTION_FAILED; break;