diff --git a/ykcs11/objects.c b/ykcs11/objects.c index 3594064..9ca92c9 100644 --- a/ykcs11/objects.c +++ b/ykcs11/objects.c @@ -9,6 +9,9 @@ #define IS_CERT(x) (((x) >= PIV_CERT_OBJ_X509_PIV_AUTH && (x) < PIV_CERT_OBJ_LAST) ? CK_TRUE : CK_FALSE) +#define F4 "\x01\x00\x01" // TODO: already define in mechanisms.c. Move +#define PRIME256V1 "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" // TODO: already define in mechanisms.c. Move + CK_RV get_doa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template); // TODO: static? CK_RV get_coa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template); CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template); @@ -942,13 +945,16 @@ 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 = templ[i].ulValueLen; break; - default: // TODO: don't error on valid parameters - // Ignore other attributes for now + case CKA_TOKEN: + case CKA_LABEL: + case CKA_SUBJECT: + // Ignore other attributes + break; + + default: DBG(("Invalid %lx", templ[i].type)); return CKR_ATTRIBUTE_TYPE_INVALID; } @@ -957,19 +963,21 @@ CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, if (has_id == CK_FALSE || has_value == CK_FALSE) return CKR_TEMPLATE_INCOMPLETE; - + 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_BYTE_PTR *value, CK_ULONG_PTR value_len) { CK_ULONG i; CK_BBOOL has_id = CK_FALSE; CK_BBOOL has_value = CK_FALSE; CK_BBOOL has_params = CK_FALSE; + CK_BYTE_PTR ec_params; + CK_ULONG ec_params_len; + for (i = 0; i < n; i++) { switch (templ[i].type) { case CKA_CLASS: @@ -995,19 +1003,25 @@ CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, case CKA_VALUE: has_value = CK_TRUE; *value = (CK_BYTE_PTR)templ[i].pValue; - *cert_len = templ[i].ulValueLen; - + *value_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; + 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 + case CKA_TOKEN: + case CKA_LABEL: + case CKA_SUBJECT: + case CKA_SENSITIVE: + case CKA_DERIVE: + // Ignore other attributes + break; + + default: DBG(("Invalid %lx", templ[i].type)); return CKR_ATTRIBUTE_TYPE_INVALID; } @@ -1017,17 +1031,19 @@ CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, has_value == CK_FALSE || has_params == CK_FALSE) return CKR_TEMPLATE_INCOMPLETE; - + + if (*value_len != 32) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (*value_len == 32 && (ec_params_len != 10 || memcmp(ec_params, PRIME256V1, ec_params_len)) != 0) + return CKR_TEMPLATE_INCONSISTENT; + 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_BYTE_PTR *p, CK_BYTE_PTR *q, CK_BYTE_PTR *dp, + CK_BYTE_PTR *dq, CK_BYTE_PTR *qinv, CK_ULONG_PTR value_len) { CK_ULONG i; CK_BBOOL has_id = CK_FALSE; @@ -1037,6 +1053,11 @@ CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, CK_BBOOL has_dp = CK_FALSE; CK_BBOOL has_dq = CK_FALSE; CK_BBOOL has_qinv = CK_FALSE; + CK_ULONG p_len; + CK_ULONG q_len; + CK_ULONG dp_len; + CK_ULONG dq_len; + CK_ULONG qinv_len; for (i = 0; i < n; i++) { switch (templ[i].type) { @@ -1060,50 +1081,57 @@ CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, break; - case CKA_PUBLIC_EXPONENT: // TODO: check that it is F4 + case CKA_PUBLIC_EXPONENT: has_e = CK_TRUE; - *e = (CK_BYTE_PTR)templ[i].pValue; - *e_len = templ[i].ulValueLen; - + + if (templ[i].ulValueLen != 3 || memcmp((CK_BYTE_PTR)templ[i].pValue, F4, 3) != 0) + return CKR_ATTRIBUTE_VALUE_INVALID; break; case CKA_PRIME_1: has_p = CK_TRUE; *p = (CK_BYTE_PTR)templ[i].pValue; - *p_len = templ[i].ulValueLen; - + 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; - + 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; - + 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; - + 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; + qinv_len = templ[i].ulValueLen; break; - default: // TODO: don't error on valid parameters - // Ignore other attributes for now + case CKA_TOKEN: + case CKA_LABEL: + case CKA_SUBJECT: + case CKA_SENSITIVE: + case CKA_DERIVE: + // Ignore other attributes + break; + + default: DBG(("Invalid %lx", templ[i].type)); return CKR_ATTRIBUTE_TYPE_INVALID; } @@ -1117,6 +1145,15 @@ CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, has_dq == CK_FALSE || has_qinv == CK_FALSE) return CKR_TEMPLATE_INCOMPLETE; - + + if (p_len != 64 || p_len != 128) + return CKR_ATTRIBUTE_VALUE_INVALID; + + *value_len = p_len; + + if (q_len != p_len || dp_len != p_len || + dq_len != p_len || qinv_len != p_len) + return CKR_ATTRIBUTE_VALUE_INVALID; + return CKR_OK; } diff --git a/ykcs11/objects.h b/ykcs11/objects.h index b48cc57..892cb54 100644 --- a/ykcs11/objects.h +++ b/ykcs11/objects.h @@ -15,14 +15,10 @@ 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_BYTE_PTR *value, CK_ULONG_PTR value_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); + CK_BYTE_PTR *p, CK_BYTE_PTR *q, CK_BYTE_PTR *dp, + CK_BYTE_PTR *dq, CK_BYTE_PTR *qinv, CK_ULONG_PTR value_len); + #endif diff --git a/ykcs11/openssl_utils.c b/ykcs11/openssl_utils.c index 08cf954..1756735 100644 --- a/ykcs11/openssl_utils.c +++ b/ykcs11/openssl_utils.c @@ -42,7 +42,7 @@ CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) { } CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa, CK_ULONG key_len, - CK_BYTE_PTR out, CK_ULONG_PTR out_len) { + CK_BYTE_PTR out, CK_ULONG_PTR out_len) { X509 *cert = NULL; EVP_PKEY *key = NULL; @@ -455,7 +455,7 @@ CK_RV do_pkcs_1_digest_info(CK_BYTE_PTR in, CK_ULONG in_len, int nid, CK_BYTE_PT } CK_RV do_pkcs_pss(RSA *key, CK_BYTE_PTR in, CK_ULONG in_len, int nid, - CK_BYTE_PTR out, CK_ULONG_PTR out_len) { + CK_BYTE_PTR out, CK_ULONG_PTR out_len) { unsigned char em[512]; // Max for this is ceil((|key_len_bits| - 1) / 8) OpenSSL_add_all_digests(); diff --git a/ykcs11/token_vendors.c b/ykcs11/token_vendors.c index bdb5218..30b9883 100644 --- a/ykcs11/token_vendors.c +++ b/ykcs11/token_vendors.c @@ -122,13 +122,65 @@ 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) { +CK_RV COMMON_token_import_private_key(ykpiv_state *state, CK_BYTE key_id, CK_BYTE_PTR p, CK_BYTE_PTR q, + CK_BYTE_PTR dp, CK_BYTE_PTR dq, CK_BYTE_PTR qinv, + CK_BYTE_PTR ec_data, CK_ULONG elem_len) { + + unsigned char key_data[1024]; + unsigned char *in_ptr = key_data; + unsigned char templ[] = {0, YKPIV_INS_IMPORT_KEY, 0, key_id}; + unsigned char data[0xff]; + unsigned long recv_len = sizeof(data); + int sw; + + if (elem_len == 128) + templ[2] = YKPIV_ALGO_RSA2048; + else if (elem_len == 64) + templ[2] = YKPIV_ALGO_RSA1024; + else if(elem_len == 32) + templ[2] = YKPIV_ALGO_ECCP256; + + if (templ[2] == YKPIV_ALGO_RSA1024 ||templ[2] == YKPIV_ALGO_RSA2048) { + *in_ptr++ = 0x01; + in_ptr += set_length(in_ptr, elem_len); + memcpy(in_ptr, p, (size_t)(elem_len)); + in_ptr += elem_len; + + *in_ptr++ = 0x02; + in_ptr += set_length(in_ptr, elem_len); + memcpy(in_ptr, q, (size_t)(elem_len)); + in_ptr += elem_len; + + *in_ptr++ = 0x03; + in_ptr += set_length(in_ptr, elem_len); + memcpy(in_ptr, dp, (size_t)(elem_len)); + in_ptr += elem_len; + + *in_ptr++ = 0x04; + in_ptr += set_length(in_ptr, elem_len); + memcpy(in_ptr, dq, (size_t)(elem_len)); + in_ptr += elem_len; + + *in_ptr++ = 0x05; + in_ptr += set_length(in_ptr, elem_len); + memcpy(in_ptr, qinv, (size_t)(elem_len)); + in_ptr += elem_len; + } + else if(templ[2] == YKPIV_ALGO_ECCP256) { + *in_ptr++ = 0x06; + in_ptr += set_length(in_ptr, elem_len); + memcpy(in_ptr, ec_data, (size_t)(elem_len)); + in_ptr += elem_len; + } + + if(ykpiv_transfer_data(state, templ, key_data, in_ptr - key_data, data, &recv_len, &sw) != YKPIV_OK) + return CKR_FUNCTION_FAILED; + + if(sw != 0x9000) + return CKR_DEVICE_ERROR; return CKR_OK; - + } token_vendor_t get_token_vendor(vendor_id_t vid) { diff --git a/ykcs11/token_vendors.h b/ykcs11/token_vendors.h index 5a86be4..a5b6175 100644 --- a/ykcs11/token_vendors.h +++ b/ykcs11/token_vendors.h @@ -22,9 +22,8 @@ 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); +typedef CK_RV (*t_import_private_key_f)(ykpiv_state *, CK_BYTE, CK_BYTE_PTR, CK_BYTE_PTR, CK_BYTE_PTR, + CK_BYTE_PTR, CK_BYTE_PTR, CK_BYTE_PTR, CK_ULONG); // TODO: replace all the common calls with functions defined in .c that use libykpiv diff --git a/ykcs11/ykcs11.c b/ykcs11/ykcs11.c index b0a326c..f5bacab 100644 --- a/ykcs11/ykcs11.c +++ b/ykcs11/ykcs11.c @@ -830,18 +830,11 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( 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; @@ -910,7 +903,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( } DBG(("Certificate id is %u", id)); - object = PIV_CERT_OBJ_X509_PIV_AUTH + id ; + object = PIV_CERT_OBJ_X509_PIV_AUTH + id; rv = token.token_import_cert(piv_state, piv_2_ykpiv(object), value); // TODO: make function to get cert id if (rv != CKR_OK) { @@ -962,12 +955,11 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( // 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); + rv = check_create_ec_key(pTemplate, ulCount, &id, &value, &value_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); + rv = check_create_rsa_key(pTemplate, ulCount, &id, &p, &q, &dp, &dq, &qinv, &value_len); if (rv != CKR_OK) { DBG(("Private key template not valid")); return rv; @@ -975,25 +967,29 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( } DBG(("Key id is %u", id)); + DBG(("ITEM LENGTH IS %lu", value_len)); + object = PIV_PVTK_OBJ_PIV_AUTH + 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); + rv = token.token_import_private_key(piv_state, piv_2_ykpiv(object), p, q, dp, dq, qinv, + NULL, + value_len); 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; + else { + DBG(("Key is ECDSA")); + rv = token.token_import_private_key(piv_state, piv_2_ykpiv(object), NULL, NULL, NULL, NULL, NULL, + value, + value_len); + if (rv != CKR_OK) { + DBG(("Unable to import ECDSA private key")); + return rv; } } - - return CKR_FUNCTION_FAILED; break; default: