diff --git a/ykcs11/Makefile.am b/ykcs11/Makefile.am index d93c75c..f94ef82 100644 --- a/ykcs11/Makefile.am +++ b/ykcs11/Makefile.am @@ -39,8 +39,9 @@ libykcs11_la_SOURCES += slot_vendors.c slot_vendor.h libykcs11_la_SOURCES += token_vendors.c token_vendor.h libykcs11_la_SOURCES += mechanisms.c mechanisms.h libykcs11_la_SOURCES += yubico_slot.c yubico_slot.h yubico_token.c yubico_token.h -libykcs11_la_SOURCES += utils.h utils.c -libykcs11_la_SOURCES += obj_types.h objects.h objects.c +libykcs11_la_SOURCES += utils.c utils.h +libykcs11_la_SOURCES += openssl_utils.c openssl_utils.h +libykcs11_la_SOURCES += objects.c objects.h obj_types.h #internal.h #libykcs11_la_SOURCES += error.c @@ -54,6 +55,7 @@ EXTRA_libykcs11_la_DEPENDENCIES = ykcs11.map #libykcs11_la_LIBADD = $(OPENSSL_LIBS) $(PCSC_LIBS) #libykcs11_la_LIBADD += $(PCSC_WIN_LIBS) $(PCSC_MACOSX_LIBS) libykcs11_la_LIBADD = $(LIBNSPR) ../lib/libykpiv.la +libykcs11_la_LIBADD += ../tool/libpiv_util.la libykcs11_la_LDFLAGS = -no-undefined libykcs11_la_LDFLAGS += -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/ykcs11/mechanisms.c b/ykcs11/mechanisms.c index b63ea59..7eb0c69 100644 --- a/ykcs11/mechanisms.c +++ b/ykcs11/mechanisms.c @@ -40,7 +40,7 @@ CK_RV check_sign_mechanism(const ykcs11_session_t *s, const CK_MECHANISM_PTR m) if (token.get_token_mechanism_info(m->mechanism, &info) != CKR_OK) return CKR_MECHANISM_INVALID; - // TODO: also check that parametes make sens if any? + // TODO: also check that parametes make sense if any? CKR_OK; @@ -84,3 +84,20 @@ CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m) { // Not reached return CK_FALSE; } + +CK_RV do_sign_padding(CK_MECHANISM_PTR m, CK_BYTE_PTR in, CK_ULONG in_len, + CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len) { + switch (m->mechanism) { + case CKM_RSA_PKCS: + return do_pkcs_t1(in, in_len, out, out_len, key_len); + + case CKM_RSA_PKCS_PSS: + case CKM_RSA_X_509: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + return CKR_FUNCTION_FAILED; + } + +} diff --git a/ykcs11/mechanisms.h b/ykcs11/mechanisms.h index f95565e..8a38121 100644 --- a/ykcs11/mechanisms.h +++ b/ykcs11/mechanisms.h @@ -7,4 +7,7 @@ CK_RV check_sign_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m); CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m); +CK_RV do_sign_padding(CK_MECHANISM_PTR m, CK_BYTE_PTR in, CK_ULONG in_len, + CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len); + #endif diff --git a/ykcs11/obj_types.h b/ykcs11/obj_types.h index a0f3c3c..1f0913f 100644 --- a/ykcs11/obj_types.h +++ b/ykcs11/obj_types.h @@ -103,12 +103,12 @@ typedef struct { X509 *data; } piv_cert_obj_t; -typedef struct { +typedef struct { // TODO: enough to use the public key for the parameters? CK_BBOOL todo; } piv_pvtk_obj_t; typedef struct { - CK_BBOOL todo; + EVP_PKEY *data; } piv_pubk_obj_t; typedef struct { diff --git a/ykcs11/objects.c b/ykcs11/objects.c index 19a749e..270e94d 100644 --- a/ykcs11/objects.c +++ b/ykcs11/objects.c @@ -3,6 +3,9 @@ #include #include #include +#include "openssl_utils.h" + +#define IS_CERT(x) (((x) >= PIV_CERT_OBJ_X509_PIV_AUTH && (x) < PIV_CERT_OBJ_LAST) ? CK_TRUE : CK_FALSE) 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); @@ -843,6 +846,38 @@ CK_RV get_puoa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { } +CK_ULONG piv_2_ykpiv(piv_obj_id_t id) { + // TODO: add retired keys + switch(id) { + case PIV_CERT_OBJ_X509_PIV_AUTH: + return YKPIV_OBJ_AUTHENTICATION; + + case PIV_CERT_OBJ_X509_CARD_AUTH: + return YKPIV_OBJ_CARD_AUTH; + + case PIV_CERT_OBJ_X509_DS: + return YKPIV_OBJ_SIGNATURE; + + case PIV_CERT_OBJ_X509_KM: + return YKPIV_OBJ_KEY_MANAGEMENT; + + case PIV_PVTK_OBJ_PIV_AUTH: + return YKPIV_KEY_AUTHENTICATION; + + case PIV_PVTK_OBJ_CARD_AUTH: + return YKPIV_KEY_CARDAUTH; + + case PIV_PVTK_OBJ_DS: + return YKPIV_KEY_SIGNATURE; + + case PIV_PVTK_OBJ_KM: + return YKPIV_KEY_KEYMGM; + + default: + return 0ul; + } +} + CK_RV get_attribute(ykcs11_session_t *s, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { CK_ULONG i; @@ -851,6 +886,34 @@ CK_RV get_attribute(ykcs11_session_t *s, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR return piv_objects[obj].get_attribute(obj, template); } - return CKR_OBJECT_HANDLE_INVALID; } + +CK_RV get_available_certificate_ids(ykcs11_session_t *s, piv_obj_id_t *cert_ids, CK_ULONG n_certs) { + CK_ULONG i, j; + + j = 0; + for (i = 0; i < s->slot->token->n_objects; i++) + if (IS_CERT(s->slot->token->objects[i]) == CK_TRUE) + cert_ids[j++] = s->slot->token->objects[i]; + + fprintf(stderr, "Just to check: %lu %lu\n", j, n_certs); + + return CKR_OK; +} + +CK_RV store_cert(piv_obj_id_t cert_id, CK_BYTE_PTR data, CK_ULONG len) { + + CK_RV rv; + + // Store the certificate as an object + rv = do_store_cert(data, len, &cert_objects[piv_objects[cert_id].sub_id].data); + if (rv != CKR_OK) + return rv; + + // Extract and store the public key as an object + rv = do_store_pubk(cert_objects[piv_objects[cert_id].sub_id].data, &pubkey_objects[piv_objects[cert_id].sub_id].data); + + return CKR_OK; +} + diff --git a/ykcs11/objects.h b/ykcs11/objects.h index 439361e..df0a60f 100644 --- a/ykcs11/objects.h +++ b/ykcs11/objects.h @@ -5,6 +5,10 @@ #include // TODO: delete +CK_ULONG piv_2_ykpiv(piv_obj_id_t id); + CK_RV get_attribute(ykcs11_session_t *s, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template); +CK_RV get_available_certificate_ids(ykcs11_session_t *s, piv_obj_id_t *cert_ids, CK_ULONG n_certs); +CK_RV store_cert(piv_obj_id_t cert_id, CK_BYTE_PTR data, CK_ULONG len); #endif diff --git a/ykcs11/openssl_utils.c b/ykcs11/openssl_utils.c new file mode 100644 index 0000000..d139a99 --- /dev/null +++ b/ykcs11/openssl_utils.c @@ -0,0 +1,78 @@ +#include "openssl_utils.h" +#include +#include "../tool/util.h" // TODO: share this better? + + +CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) { + + const unsigned char *p = data; // Mandatory temp variable required by OpenSSL + int cert_len; + + /**cert = X509_new(); + if (*cert == NULL) + return CKR_HOST_MEMORY;*/ + //dump_hex(data, len, stderr, CK_TRUE); + + if (*p++ != 0x70) + return CKR_FUNCTION_FAILED; + + p += get_length(p, &cert_len); + + *cert = d2i_X509(NULL, &p, cert_len); + if (*cert == NULL) + return CKR_FUNCTION_FAILED; + + /* + BIO *STDout = BIO_new_fp(stderr, BIO_NOCLOSE); + + X509_print_ex(STDout, *cert, 0, 0); + + BIO_free(STDout); + */ + + return CKR_OK; + +} + +CK_RV free_cert(X509 *cert) { + + X509_free((X509 *) cert); + + return CKR_OK; +} + + +CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key) { + + *key = X509_get_pubkey(cert); + + if (*key == NULL) + return CKR_FUNCTION_FAILED; + + return CKR_OK; + +} + +CK_RV free_key(EVP_PKEY *key) { + + EVP_PKEY_free(key); + + return CKR_OK; + +} +/* #include */ +/* #include */ +/* ERR_load_crypto_strings(); */ +/* //SSL_load_error_strings(); */ +CK_RV do_pkcs_t1(CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len) { + fprintf(stderr, "Apply padding to %lu bytes and get %lu\n", in_len, key_len); + + + if (out_len < key_len) + CKR_BUFFER_TOO_SMALL; + + if (RSA_padding_add_PKCS1_type_1(out, key_len, in, in_len) == 0) + return CKR_FUNCTION_FAILED; + + return CKR_OK; +} diff --git a/ykcs11/openssl_utils.h b/ykcs11/openssl_utils.h new file mode 100644 index 0000000..f9382d5 --- /dev/null +++ b/ykcs11/openssl_utils.h @@ -0,0 +1,17 @@ +#ifndef OPENSSL_UTIL_H +#define OPENSSL_UTIL_H + +#include +#include +#include +#include "pkcs11t.h" + +CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert); +CK_RV free_cert(X509 *cert); + +CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key); +CK_RV free_key(EVP_PKEY *key); + +CK_RV do_pkcs_t1(CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG out_len, CK_ULONG key_len); + +#endif diff --git a/ykcs11/token_vendors.c b/ykcs11/token_vendors.c index a19c18e..7fd1bfc 100644 --- a/ykcs11/token_vendors.c +++ b/ykcs11/token_vendors.c @@ -6,32 +6,34 @@ token_vendor_t get_token_vendor(vendor_id_t vid) { switch (vid) { case YUBICO: - v.get_token_label = YUBICO_get_token_label; - v.get_token_manufacturer = YUBICO_get_token_manufacturer; - v.get_token_model = YUBICO_get_token_model; - v.get_token_flags = YUBICO_get_token_flags; - v.get_token_version = YUBICO_get_token_version; - v.get_token_serial = YUBICO_get_token_serial; - v.get_token_mechanisms_num = YUBICO_get_token_mechanisms_num; - v.get_token_mechanism_list = YUBICO_get_token_mechanism_list; - v.get_token_mechanism_info = YUBICO_get_token_mechanism_info; - v.get_token_objects_num = YUBICO_get_token_objects_num; - v.get_token_object_list = YUBICO_get_token_object_list; + v.get_token_label = YUBICO_get_token_label; + v.get_token_manufacturer = YUBICO_get_token_manufacturer; + v.get_token_model = YUBICO_get_token_model; + v.get_token_flags = YUBICO_get_token_flags; + v.get_token_version = YUBICO_get_token_version; + v.get_token_serial = YUBICO_get_token_serial; + v.get_token_mechanisms_num = YUBICO_get_token_mechanisms_num; + v.get_token_mechanism_list = YUBICO_get_token_mechanism_list; + v.get_token_mechanism_info = YUBICO_get_token_mechanism_info; + v.get_token_objects_num = YUBICO_get_token_objects_num; + v.get_token_object_list = YUBICO_get_token_object_list; + v.get_token_raw_certificate = YUBICO_get_token_raw_certificate; break; case UNKNOWN: default: - v.get_token_label = NULL; - v.get_token_manufacturer = NULL; - v.get_token_model = NULL; - v.get_token_flags = NULL; - v.get_token_version = NULL; - v.get_token_serial = NULL; - v.get_token_mechanisms_num = NULL; - v.get_token_mechanism_list = NULL; - v.get_token_mechanism_info = NULL; - v.get_token_objects_num = NULL; - v.get_token_object_list = NULL; + v.get_token_label = NULL; + v.get_token_manufacturer = NULL; + v.get_token_model = NULL; + v.get_token_flags = NULL; + v.get_token_version = NULL; + v.get_token_serial = NULL; + v.get_token_mechanisms_num = NULL; + v.get_token_mechanism_list = NULL; + v.get_token_mechanism_info = NULL; + v.get_token_objects_num = NULL; + v.get_token_object_list = NULL; + v.get_token_raw_certificate = NULL; } return v; diff --git a/ykcs11/token_vendors.h b/ykcs11/token_vendors.h index a57a6cd..4df53e0 100644 --- a/ykcs11/token_vendors.h +++ b/ykcs11/token_vendors.h @@ -15,21 +15,23 @@ typedef CK_RV (*get_t_serial_f)(CK_CHAR_PTR, CK_ULONG); typedef CK_RV (*get_t_mechanisms_num_f)(CK_ULONG_PTR); typedef CK_RV (*get_t_mechanism_list_f)(CK_MECHANISM_TYPE_PTR, CK_ULONG); typedef CK_RV (*get_t_mechanism_info_f)(CK_MECHANISM_TYPE, CK_MECHANISM_INFO_PTR); -typedef CK_RV (*get_t_objects_num_f)(ykpiv_state *, CK_ULONG_PTR); +typedef CK_RV (*get_t_objects_num_f)(ykpiv_state *, CK_ULONG_PTR, CK_ULONG_PTR); typedef CK_RV (*get_t_object_list_f)(ykpiv_state *, piv_obj_id_t *, CK_ULONG); - +typedef CK_RV (*get_t_raw_certificate_f)(ykpiv_state *, piv_obj_id_t, CK_BYTE_PTR, CK_ULONG); +// TODO: replace all the common call with functions defined in .c that use libykpiv typedef struct { - get_t_label_f get_token_label; - get_t_manufacturer_f get_token_manufacturer; - get_t_model_f get_token_model; - get_t_flags_f get_token_flags; - get_t_version_f get_token_version; - get_t_serial_f get_token_serial; - get_t_mechanisms_num_f get_token_mechanisms_num; - get_t_mechanism_list_f get_token_mechanism_list; - get_t_mechanism_info_f get_token_mechanism_info; - get_t_objects_num_f get_token_objects_num; - get_t_object_list_f get_token_object_list; + get_t_label_f get_token_label; + get_t_manufacturer_f get_token_manufacturer; + get_t_model_f get_token_model; + get_t_flags_f get_token_flags; + get_t_version_f get_token_version; + get_t_serial_f get_token_serial; + get_t_mechanisms_num_f get_token_mechanisms_num; + get_t_mechanism_list_f get_token_mechanism_list; + get_t_mechanism_info_f get_token_mechanism_info; + get_t_objects_num_f get_token_objects_num; + get_t_object_list_f get_token_object_list; + get_t_raw_certificate_f get_token_raw_certificate; } token_vendor_t; token_vendor_t get_token_vendor(vendor_id_t vid); diff --git a/ykcs11/utils.c b/ykcs11/utils.c index 09fdc55..add1aef 100644 --- a/ykcs11/utils.c +++ b/ykcs11/utils.c @@ -156,6 +156,8 @@ CK_RV create_token(CK_BYTE_PTR p, ykcs11_slot_t *slot) { memset(t_info->utcTime, ' ', sizeof(t_info->utcTime)); // No clock present, clear // TODO: also get token objects here? (and destroy on failure) + slot->token->objects = NULL; + slot->token->n_objects = 0; return CKR_OK; } diff --git a/ykcs11/ykcs11.c b/ykcs11/ykcs11.c index 46faef9..2ad268c 100644 --- a/ykcs11/ykcs11.c +++ b/ykcs11/ykcs11.c @@ -23,10 +23,12 @@ #define PIV_MIN_PIN_LEN 6 #define PIV_MAX_PIN_LEN 8 -#define YKCS11_MAX_SLOTS 16 +#define YKCS11_MAX_SLOTS 16 +#define YKCS11_MAX_SIG_BUF_LEN 1024 #define YKCS11_SESSION_ID 5355104 + #if YKCS11_DBG #define DBG(x) D(x); #else @@ -60,9 +62,10 @@ static struct { static CK_ULONG n_token_objects = 0;*/ static struct { - CK_BBOOL active; - CK_MECHANISM mechanism; - CK_OBJECT_HANDLE key; + CK_BBOOL active; + CK_MECHANISM mechanism; + CK_ULONG key; + CK_BYTE algo; } sign_info; extern CK_FUNCTION_LIST function_list; // TODO: check all return values @@ -269,7 +272,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)( token = get_token_vendor(slots[slotID].token->vid); memcpy(pInfo, &slots[slotID].token->info, sizeof(CK_TOKEN_INFO)); - + // Overwrite value that are application specific pInfo->ulMaxSessionCount = CK_UNAVAILABLE_INFORMATION; // TODO: should this be 1? pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION; // number of sessions that this application currently has open with the token @@ -283,7 +286,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)( pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; - + DOUT; return CKR_OK; } @@ -430,9 +433,14 @@ CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( CK_SESSION_HANDLE_PTR phSession ) { - DIN; + DIN; // TODO: pApplication and Notify token_vendor_t token; + CK_RV rv; + piv_obj_id_t *cert_ids; + CK_ULONG i; + CK_BYTE cert_data[2100]; // Max cert value for ykpiv + CK_ULONG cert_len = sizeof(cert_data); if (piv_state == NULL) { DBG(("libykpiv is not initialized or already finalized")); @@ -473,27 +481,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( session.slot = slots + slotID; //session.slot->info.slotID = slotID; // Redundant but required in CK_SESSION_INFO - // Get the number of token objects - if (token.get_token_objects_num(piv_state, &session.slot->token->n_objects) != CKR_OK) { - DBG(("Unable to retrieve number of token objects")); - return CKR_FUNCTION_FAILED; - } - - // Get memory for the objects - session.slot->token->objects = malloc(sizeof(piv_obj_id_t) * session.slot->token->n_objects); - if (session.slot->token->objects == NULL) { - DBG(("Unable to allocate memory for token objects")); - return CKR_HOST_MEMORY; - } - - // Store all the objects available in the token - if (token.get_token_object_list(piv_state, - session.slot->token->objects, - session.slot->token->n_objects) != CKR_OK) { - DBG(("Unable to retrieve token objects")); - return CKR_FUNCTION_FAILED; - } - + // Store session flags if ((flags & CKF_RW_SESSION)) { // R/W Session session.info.state = CKS_RW_PUBLIC_SESSION; // Nobody has logged in, default session @@ -506,13 +494,78 @@ CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( session.info.flags = flags; session.info.ulDeviceError = 0; + // Get the number of token objects + rv = token.get_token_objects_num(piv_state, &session.slot->token->n_objects, &session.slot->token->n_certs); + if (rv != CKR_OK) { + DBG(("Unable to retrieve number of token objects")); + return rv; + } + + // Get memory for the objects + session.slot->token->objects = malloc(sizeof(piv_obj_id_t) * session.slot->token->n_objects); + if (session.slot->token->objects == NULL) { + DBG(("Unable to allocate memory for token object ids")); + return CKR_HOST_MEMORY; + } + + // Get memory for the certificates + cert_ids = malloc(sizeof(piv_obj_id_t) * session.slot->token->n_certs); + if (cert_ids == NULL) { + DBG(("Unable to allocate memory for token certificate ids")); + return CKR_HOST_MEMORY; + } + + // Save a list of all the available objects in the token // TODO: change behavior based on login status + rv = token.get_token_object_list(piv_state, session.slot->token->objects, session.slot->token->n_objects); + if (rv != CKR_OK) { + DBG(("Unable to retrieve token objects")); + goto failure; + } + + // Get a list object ids for available certificates object from the session + rv = get_available_certificate_ids(&session, cert_ids, session.slot->token->n_certs); // TODO: better to get this from token? how? + if (rv != CKR_OK) { + DBG(("Unable to retrieve certificate ids from the session")); + goto failure; + } + + // Get the actual certificate data from the token and store it as an X509 object + for (i = 0; i < session.slot->token->n_certs; i++) { + rv = token.get_token_raw_certificate(piv_state, cert_ids[i], cert_data, cert_len); + if (rv != CKR_OK) { + DBG(("Unable to get certificate data from token")); + goto failure; + } + + rv = store_cert(cert_ids[i], cert_data, cert_len); + if (rv != CKR_OK) { + DBG(("Unable to store certificate data")); + goto failure; + } + } + session.handle = YKCS11_SESSION_ID; - // TODO: KEEP TRACK OF THE APPLICATION + // TODO: KEEP TRACK OF THE APPLICATION (possble to steal a session?) *phSession = session.handle; DOUT; return CKR_OK; + +failure: + if (session.slot->token->objects != NULL) { + free(session.slot->token->objects); + session.slot->token->objects = NULL; + } + + if (cert_ids != NULL) { + free(cert_ids); + cert_ids = NULL; + } + + free_certs(); // TODO + + return rv; } CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)( @@ -677,7 +730,9 @@ CK_DEFINE_FUNCTION(CK_RV, C_Login)( return CKR_USER_TYPE_INVALID; // TODO: only allow regular user for now } - DBG(("You win! %lu", tries)) + DBG(("You win! %lu", tries)); + + // TODO: update session objects now that we're logged in ? DOUT; return CKR_OK; @@ -856,9 +911,9 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)( // TODO: remove objects that don't match } - // TODO: do it properly here, jsut a test now + // TODO: do it properly here, just a test now //find_obj.objects = session.slot->token->objects + 3; - memmove(find_obj.objects, find_obj.objects + 3, sizeof(piv_obj_id_t) * (find_obj.num - 3)); + memmove(find_obj.objects, find_obj.objects + 14, sizeof(piv_obj_id_t) * (find_obj.num - 14)); find_obj.num = 1; DOUT; @@ -1128,33 +1183,41 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)( DBG(("Trying to sign some data with mechanism %lu and key %lu", pMechanism->mechanism, hKey)); + // Check if mechanism is supported if (check_sign_mechanism(&session, pMechanism) != CKR_OK) { DBG(("Mechanism %lu is not supported either by the token or the slot", pMechanism->mechanism)); return CKR_MECHANISM_INVALID; } - - - - sign_info.active = CK_TRUE; memcpy(&sign_info.mechanism, pMechanism, sizeof(CK_MECHANISM)); - sign_info.key = hKey; - // TODO: also allocate some space for the signature + // Get key algorithm + /*if (get_key_algo(hKey, &sign_info.algo) != CKR_OK) { + DBG(("Unable to retrieve type for key %lu", hKey)); + return CKR_FUNCTION_FAILED; + }*/ // TODO: use get attribute instead? + sign_info.algo = YKPIV_ALGO_RSA2048; // TODO: fix + + sign_info.key = piv_2_ykpiv(hKey); + if (sign_info.key == 0) { + DBG(("Incorrect key %lu", hKey)); + return CKR_KEY_HANDLE_INVALID; + } + + // Make sure that both mechanism and key have the same algorithm + if ((is_RSA_mechanism(pMechanism->mechanism) && sign_info.algo == YKPIV_ALGO_ECCP256) || + (!is_RSA_mechanism(pMechanism->mechanism) && (sign_info.algo != YKPIV_ALGO_ECCP256))) { + DBG(("Key and mechanism algorithm do not match")); + return CKR_ARGUMENTS_BAD; + } + + // TODO: also allocate some space for the signature in case of multipart + + sign_info.active = CK_TRUE; DOUT; return CKR_OK; } -/* TOTOD: DELETE */ -CK_BYTE sig_buf[1024]; -CK_ULONG sig_len = 1024; -void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, CK_BBOOL space) { - unsigned int i; - for (i = 0; i < len; i++) { - fprintf(output, "%02x%s", buf[i], space == CK_TRUE ? " " : ""); - } - fprintf(output, "\n"); -} -/* TODO: DELETE END*/ + CK_DEFINE_FUNCTION(CK_RV, C_Sign)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, @@ -1164,39 +1227,35 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( ) { DIN; + CK_BYTE buf[YKCS11_MAX_SIG_BUF_LEN]; + CK_ULONG buf_len = sizeof(buf); if (sign_info.active == CK_FALSE) return CKR_OPERATION_NOT_INITIALIZED; // TODO: check conditions - char test_buf[] = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20\xa7\x47\x16\x1b\x15\x5f\xd0\x05\xbc\xbe\x84\x4a\x28\xa9\x6c\x74\xfe\xf6\x6a\x42\x84\xa0\x4e\x05\x7a\x0c\x88\xe2\xc8\x83\xc0\x00"; - CK_ULONG sig_len_in = sizeof(test_buf) - 1; - CK_ULONG sig_len_out = 1024; ykpiv_rc r; - CK_CHAR key; + CK_CHAR algo; - DBG(("Sending %lu bytes to sign", ulDataLen/*sig_len_in*/)); + DBG(("Sending %lu bytes to sign", ulDataLen)); dump_hex(pData, ulDataLen, stderr, CK_TRUE); - if (sign_info.key == PIV_DATA_OBJ_X509_PIV_AUTH) { - key = YKPIV_KEY_AUTHENTICATION; - DBG(("Using key 9a")); - } - else { // TODO: test what happens if there is no key on the card - key = YKPIV_KEY_SIGNATURE; - DBG(("Using key 9c")); - } - - // TODO: check that mechanism makes sense for the key that we have (check in signinit). - - if ((r = ykpiv_sign_data(piv_state, /*pData*/test_buf, /*ulDataLen*/sig_len_in, sig_buf, &sig_len_out, YKPIV_ALGO_RSA2048, key)) != YKPIV_OK) { - DBG(("Sign error %s", ykpiv_strerror(r))); +/* if (do_sign_padding(&sign_info.mechanism, pData, ulDataLen, buf, buf_len, 2048 / 8) != CKR_OK) { + DBG(("Unable to apply padding scheme")); + return CKR_FUNCTION_FAILED; + }*/ + memcpy(buf, pData, ulDataLen); // ykpiv does padding already + //dump_hex(buf, 256, stderr, CK_TRUE); + //*pulSignatureLen = 256; + DBG(("Using key %lx", sign_info.key)); // TODO: test what happens if there is no key on the card + if ((r = ykpiv_sign_data(piv_state, buf, ulDataLen, pSignature, pulSignatureLen, YKPIV_ALGO_RSA2048, sign_info.key)) != YKPIV_OK) { + DBG(("Sign error, %s", ykpiv_strerror(r))); return CKR_FUNCTION_FAILED; } - DBG(("Got %lu bytes back", sig_len_out)); - dump_hex(sig_buf, sig_len_out, stderr, CK_TRUE); - memcpy(pSignature, sig_buf, sig_len_out); - *pulSignatureLen = sig_len_out; + DBG(("Got %lu bytes back", *pulSignatureLen)); + dump_hex(pSignature, *pulSignatureLen, stderr, CK_TRUE); +/* memcpy(pSignature, sig_buf, sig_len_out); + *pulSignatureLen = sig_len_out;*/ DOUT; return CKR_OK; } diff --git a/ykcs11/ykcs11.h b/ykcs11/ykcs11.h index 2c9f644..cfa22da 100644 --- a/ykcs11/ykcs11.h +++ b/ykcs11/ykcs11.h @@ -8,8 +8,9 @@ typedef struct { vendor_id_t vid; CK_TOKEN_INFO info; - piv_obj_id_t *objects; - CK_ULONG n_objects; + piv_obj_id_t *objects; // List of objects in the token + CK_ULONG n_objects; // TOTAL number of objects in the token + CK_ULONG n_certs; // Number of certificate objects in the token (portion of n_objects) } ykcs11_token_t; typedef struct { diff --git a/ykcs11/yubico_token.c b/ykcs11/yubico_token.c index 3f0be65..a70dab8 100644 --- a/ykcs11/yubico_token.c +++ b/ykcs11/yubico_token.c @@ -210,11 +210,12 @@ CK_RV YUBICO_get_token_mechanism_info(CK_MECHANISM_TYPE mec, CK_MECHANISM_INFO_P } #include // TODO: delete -static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, piv_obj_id_t *obj, CK_ULONG_PTR len) { +static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, + piv_obj_id_t *obj, CK_ULONG_PTR len, CK_ULONG_PTR num_certs) { CK_BYTE buf[2048]; CK_ULONG buf_len; - piv_obj_id_t certs[4]; + piv_obj_id_t certs[4]; // TODO: this can be > 4 if there are retired keys piv_obj_id_t pvtkeys[4]; piv_obj_id_t pubkeys[4]; CK_ULONG n_cert = 0; @@ -267,6 +268,8 @@ static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, piv_obj_id_t *ob // We just want the number of objects // Each cert object counts for 3: cert, pub key, pvt key *len = (n_cert * 3) + token_objects_num; + if (num_certs != NULL) + *num_certs = n_cert; return CKR_OK; } @@ -286,10 +289,18 @@ static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, piv_obj_id_t *ob return CKR_OK; } -CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num) { - return get_objects(state, CK_TRUE, NULL, num); +CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num, CK_ULONG_PTR num_certs) { + return get_objects(state, CK_TRUE, NULL, num, num_certs); } CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t *obj, CK_ULONG num) { - return get_objects(state, CK_FALSE, obj, &num); + return get_objects(state, CK_FALSE, obj, &num, NULL); +} + +CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_BYTE_PTR data, CK_ULONG len) { + + if (ykpiv_fetch_object(state, piv_2_ykpiv(obj), data, &len) != YKPIV_OK) + return CKR_FUNCTION_FAILED; + + return CKR_OK; } diff --git a/ykcs11/yubico_token.h b/ykcs11/yubico_token.h index d0c9f7a..c39a7d3 100644 --- a/ykcs11/yubico_token.h +++ b/ykcs11/yubico_token.h @@ -14,7 +14,8 @@ CK_RV YUBICO_get_token_version(CK_UTF8CHAR_PTR v_str, CK_ULONG v_str_len, CK_VER CK_RV YUBICO_get_token_mechanisms_num(CK_ULONG_PTR num); CK_RV YUBICO_get_token_mechanism_list(CK_MECHANISM_TYPE_PTR mec, CK_ULONG num); CK_RV YUBICO_get_token_mechanism_info(CK_MECHANISM_TYPE mec, CK_MECHANISM_INFO_PTR info); -CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num); -CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t * obj, CK_ULONG num); +CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num, CK_ULONG_PTR num_certs); +CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t *obj, CK_ULONG num); +CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_BYTE_PTR data, CK_ULONG len); #endif