diff --git a/.gitignore b/.gitignore index 8ca8bbd..f9e3e3d 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,10 @@ tool/tests/parse_name tool/tests/parse_name.log tool/tests/parse_name.o tool/tests/parse_name.trs +tool/tests/test_inout +tool/tests/test_inout.log +tool/tests/test_inout.o +tool/tests/test_inout.trs coverage/ lib/error.gcno lib/version.gcno diff --git a/Makefile.am b/Makefile.am index b4f185c..5cecf0d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,8 @@ ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = windows.mk mac.mk tool/tests/basic.sh tools/fasc.pl -EXTRA_DIST += doc/Certificate_Authority.adoc doc/OS_X_code_signing.adoc doc/SSH_with_PIV_and_PKCS11.adoc doc/Windows_certificate.adoc doc/YKCS11_release_notes.adoc doc/YubiKey_PIV_introduction.adoc +EXTRA_DIST += doc/Android_code_signing.adoc doc/Certificate_Authority.adoc doc/OS_X_code_signing.adoc doc/SSH_with_PIV_and_PKCS11.adoc doc/Windows_certificate.adoc doc/YKCS11_release_notes.adoc doc/YubiKey_PIV_introduction.adoc + if ENABLE_COV cov-reset: diff --git a/NEWS b/NEWS index cb3ff65..d52ed2f 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,49 @@ yubico-piv-tool NEWS -- History of user-visible changes. -*- outline -*- -* Version 1.1.3 (unreleased) +* Version 1.3.1 (unreleased) + +* Version 1.3.0 (released 2016-02-19) + +** Fixed extraction of RSA modulus and exponent for pkcs11. + +** Implemented C_SetPIN for pkcs11. + +** Add generic write and read object actions for the tool. +Supports hex/binary/base64 formats + +** Add ykpiv_change_pin(), ykpiv_change_puk() and ykpiv_unblock_pin() + +** Print CCC with status action. + +** Address bugs with pkcs11 on windows. + +** Add --valid-days and --serial to tool for selfsign-certificate action. + +** Ask for password for pkcs12 if none is given. + +* Version 1.2.2 (released 2015-12-08) + +** Fix old buffer overflow in change-pin functionality. + +* Version 1.2.1 (released 2015-12-08) + +** Fix issue with big certificates and status. + +* Version 1.2.0 (released 2015-12-07) + +** On OSX use @loader_path instead of @executable_path for ykcs11. + +** Add ykpiv_import_private_key to libykpiv. + +** Raise buffer sizes to support bigger objects. + +** Change behavior of action status, only list populated slots. + +** Add retired keys to ykcs11. + +** In ykcs11 support login with non null terminated pin. + +** Add a new action set-ccc to yubico-piv-tool to set the CCC. * Version 1.1.2 (released 2015-11-13) diff --git a/configure.ac b/configure.ac index 9b6c506..52795cc 100644 --- a/configure.ac +++ b/configure.ac @@ -26,7 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -AC_INIT([yubico-piv-tool], [1.1.3]) +AC_INIT([yubico-piv-tool], [1.3.1]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) @@ -34,9 +34,9 @@ AC_CONFIG_MACRO_DIR([m4]) # Interfaces changed/added/removed: CURRENT++ REVISION=0 # Interfaces added: AGE++ # Interfaces removed: AGE=0 -AC_SUBST([LT_CURRENT], 2) +AC_SUBST([LT_CURRENT], 4) AC_SUBST([LT_REVISION], 1) -AC_SUBST([LT_AGE], 1) +AC_SUBST([LT_AGE], 3) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AM_SILENT_RULES([yes]) @@ -52,8 +52,6 @@ PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(OPENSSL, libcrypto) -#PKG_CHECK_MODULES([LIBNSPR], [nspr], [], []) - gl_LD_VERSION_SCRIPT gl_VALGRIND_TESTS @@ -190,10 +188,24 @@ AC_ARG_ENABLE([ykcs11-debug], AS_IF([test "x$enable_ykcs11_debug" != xno], [AC_DEFINE([YKCS11_DBG], [1], [Regular debug flag]) - AC_DEFINE([YKCS11_DINOUT], [1], [Function accessed/left debug flag])], + AC_DEFINE([YKCS11_DINOUT], [1], [Function accessed/left debug flag]) + ykcs11_debug="ENABLED"], [true], [AC_DEFINE([YKCS11_DBG], [0], [Regular debug flag]) - AC_DEFINE([YKCS11_DINOUT], [0], [Function accessed/left debug flag])]) + AC_DEFINE([YKCS11_DINOUT], [0], [Function accessed/left debug flag]) + ykcs11_debug="DISABLED"]) + +AC_ARG_ENABLE([hardware-tests], + [AS_HELP_STRING([--enable-hardware-tests], + [enables tests that require a YubiKey to be plugged in])], + [enable_hardware_tests="$enableval"], + [enable_hardware_tests="no"]) + +AS_IF([test "x$enable_hardware_tests" != xno], + [AC_DEFINE([HW_TESTS], [1], [Flag for hardware tests]) + hw_tests="ENABLED"], + [true], + [hw_tests="DISABLED"]) AC_SUBST(YKPIV_VERSION_MAJOR, `echo $PACKAGE_VERSION | sed 's/\(.*\)\..*\..*/\1/g'`) AC_SUBST(YKPIV_VERSION_MINOR, `echo $PACKAGE_VERSION | sed 's/.*\.\(.*\)\..*/\1/g'`) @@ -238,4 +250,6 @@ AC_MSG_NOTICE([summary of build options: Mac PCSC LIBS: ${PCSC_MACOSX_LIBS} + YKCS11 debug: ${ykcs11_debug} + Hardware tests: ${hw_tests} ]) diff --git a/doc/Android_code_signing.adoc b/doc/Android_code_signing.adoc new file mode 100644 index 0000000..1826b67 --- /dev/null +++ b/doc/Android_code_signing.adoc @@ -0,0 +1,73 @@ +Load and use Android code signing certificate +--------------------------------------------- + +This is a step-by-step guide on how to load and use an android code signing +key and certificate. + +Prerequisites +------------- + +* a YubiKey with the PIV application +* the yubico-piv-tool software +* the OpenSC software +* jarsigner and keytool from the JDK (OpenJDK 8 used here) + +Steps +----- + +1. Import the key and cert, do one of the below: +a. Import the key and cert (PEM format) in slot 9a: ++ +---- + $ yubico-piv-tool -s 9a -a import-key -i key.pem + $ yubico-piv-tool -s 9a -a import-certificate -i cert.pem +---- + +b. Import the key and cert (PKCS12 format) in slot 9a: ++ +---- + $ yubico-piv-tool -s 9a -a import-key -a import-cert -i key.p12 -K PKCS12 +---- + +2. Create a java pkcs11 configuration file: ++ +---- + cat > /tmp/pkcs11_java.cfg + name = OpenSC-PKCS11 + description = SunPKCS11 via OpenSC + library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so + slotListIndex = 1 +---- + +3. Check that keytool can see the key: ++ +---- + $ keytool -providerClass sun.security.pkcs11.SunPKCS11 -providerArg /tmp/pkcs11_java.cfg \ + -keystore NONE -storetype PKCS11 -list + Enter keystore password: + + Keystore type: PKCS11 + Keystore provider: SunPKCS11-OpenSC-PKCS11 + + Your keystore contains 1 entry + + Certificate for PIV Authentication, PrivateKeyEntry, + Certificate fingerprint (SHA1): 26:D7:CB:71:6D:42:3C:AB:58:69:E0:9D:F0:16:DF:84:7E:1C:5A:9A +---- ++ +Password here is the PIN of the key (default 123456). + +4. Sign the apk with jarsigner: ++ +---- + $ jarsigner -providerClass sun.security.pkcs11.SunPKCS11 -providerArg /tmp/pkcs11_java.cfg \ + -keystore NONE -storetype PKCS11 app.apk "Certificate for PIV Authentication" + Enter Passphrase for keystore: + jar signed. +---- + +5. Verify the signature with jarsigner: ++ +---- + $ jarsigner -verify app.apk +---- diff --git a/lib/internal.h b/lib/internal.h index 4ceafc3..4395347 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -46,12 +46,9 @@ #define MAX_READERS 16 struct ykpiv_state { - SCARDCONTEXT context; - SCARDHANDLE card; - unsigned long n_readers; - char readers[MAX_READERS][READER_LEN]; - unsigned long tot_readers_len; - int verbose; + SCARDCONTEXT context; + SCARDHANDLE card; + int verbose; }; union u_APDU { diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 51aeb5d..1a76965 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -5,15 +5,15 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -258,7 +258,7 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ, rc = SCardBeginTransaction(state->card); if(rc != SCARD_S_SUCCESS) { if(state->verbose) { - fprintf(stderr, "error: Failed to being pcsc transaction, rc=%08lx\n", rc); + fprintf(stderr, "error: Failed to begin pcsc transaction, rc=%08lx\n", rc); } return YKPIV_PCSC_ERROR; } @@ -716,6 +716,68 @@ ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) { } } +#define CHREF_ACT_CHANGE_PIN 0 +#define CHREF_ACT_UNBLOCK_PIN 1 +#define CHREF_ACT_CHANGE_PUK 2 + +static ykpiv_rc _change_pin_internal(ykpiv_state *state, int action, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) { + int sw; + unsigned char templ[] = {0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80}; + unsigned char indata[0x10]; + unsigned char data[0xff]; + unsigned long recv_len = sizeof(data); + ykpiv_rc res; + if (current_pin_len > 8) { + return YKPIV_SIZE_ERROR; + } + if (new_pin_len > 8) { + return YKPIV_SIZE_ERROR; + } + if(action == CHREF_ACT_UNBLOCK_PIN) { + templ[1] = YKPIV_INS_RESET_RETRY; + } + else if(action == CHREF_ACT_CHANGE_PUK) { + templ[3] = 0x81; + } + memcpy(indata, current_pin, current_pin_len); + if(current_pin_len < 8) { + memset(indata + current_pin_len, 0xff, 8 - current_pin_len); + } + memcpy(indata + 8, new_pin, new_pin_len); + if(new_pin_len < 8) { + memset(indata + 8 + new_pin_len, 0xff, 8 - new_pin_len); + } + res = ykpiv_transfer_data(state, templ, indata, sizeof(indata), data, &recv_len, &sw); + if(res != YKPIV_OK) { + return res; + } else if(sw != 0x9000) { + if((sw >> 8) == 0x63) { + *tries = sw & 0xf; + return YKPIV_WRONG_PIN; + } else if(sw == 0x6983) { + return YKPIV_PIN_LOCKED; + } else { + if(state->verbose) { + fprintf(stderr, "Failed changing pin, token response code: %x.\n", sw); + } + return YKPIV_GENERIC_ERROR; + } + } + return YKPIV_OK; +} + +ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) { + return _change_pin_internal(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries); +} + +ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t current_puk_len, const char * new_puk, size_t new_puk_len, int *tries) { + return _change_pin_internal(state, CHREF_ACT_CHANGE_PUK, current_puk, current_puk_len, new_puk, new_puk_len, tries); +} + +ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len, const char * new_pin, size_t new_pin_len, int *tries) { + return _change_pin_internal(state, CHREF_ACT_CHANGE_PUK, puk, puk_len, new_pin, new_pin_len, tries); +} + ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, unsigned char *data, unsigned long *len) { int sw; @@ -751,7 +813,7 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id, unsigned char *indata, size_t len) { - unsigned char data[2048]; + unsigned char data[3072]; unsigned char *dataptr = data; unsigned char templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff}; int sw; @@ -781,3 +843,124 @@ ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id, return YKPIV_GENERIC_ERROR; } } + +ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, unsigned char algorithm, + const unsigned char *p, size_t p_len, + const unsigned char *q, size_t q_len, + const unsigned char *dp, size_t dp_len, + const unsigned char *dq, size_t dq_len, + const unsigned char *qinv, size_t qinv_len, + const unsigned char *ec_data, unsigned char ec_data_len, + const unsigned char pin_policy, const unsigned char touch_policy) { + + unsigned char key_data[1024]; + unsigned char *in_ptr = key_data; + unsigned char templ[] = {0, YKPIV_INS_IMPORT_KEY, algorithm, key}; + unsigned char data[256]; + unsigned long recv_len = sizeof(data); + unsigned elem_len; + int sw; + const unsigned char *params[5]; + size_t lens[5]; + size_t padding; + unsigned char n_params; + int i; + int param_tag; + + if (state == NULL) + return YKPIV_GENERIC_ERROR; + + if (key == YKPIV_KEY_CARDMGM || + key < YKPIV_KEY_RETIRED1 || + (key > YKPIV_KEY_RETIRED20 && key < YKPIV_KEY_AUTHENTICATION) || + key > YKPIV_KEY_CARDAUTH) { + return YKPIV_KEY_ERROR; + } + + if (pin_policy != YKPIV_PINPOLICY_DEFAULT && + pin_policy != YKPIV_PINPOLICY_NEVER && + pin_policy != YKPIV_PINPOLICY_ONCE && + pin_policy != YKPIV_PINPOLICY_ALWAYS) + return YKPIV_GENERIC_ERROR; + + if (touch_policy != YKPIV_TOUCHPOLICY_DEFAULT && + touch_policy != YKPIV_TOUCHPOLICY_NEVER && + touch_policy != YKPIV_TOUCHPOLICY_ALWAYS) + return YKPIV_GENERIC_ERROR; + + if (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) { + + if (algorithm == YKPIV_ALGO_RSA1024) + elem_len = 64; + if (algorithm == YKPIV_ALGO_RSA2048) + elem_len = 128; + + if (p == NULL || q == NULL || dp == NULL || + dq == NULL || qinv == NULL) + return YKPIV_GENERIC_ERROR; + + params[0] = p; + lens[0] = p_len; + params[1] = q; + lens[1] = q_len; + params[2] = dp; + lens[2] = dp_len; + params[3] = dq; + lens[3] = dq_len; + params[4] = qinv; + lens[4] = qinv_len; + param_tag = 0x01; + + n_params = 5; + } + else if (algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) { + if (algorithm == YKPIV_ALGO_ECCP256) + elem_len = 32; + if (algorithm == YKPIV_ALGO_ECCP384) + elem_len = 48; + + if (ec_data == NULL) + return YKPIV_GENERIC_ERROR; + + params[0] = ec_data; + lens[0] = ec_data_len; + param_tag = 0x06; + n_params = 1; + } + else + return YKPIV_ALGORITHM_ERROR; + + for (i = 0; i < n_params; i++) { + *in_ptr++ = param_tag + i; + in_ptr += set_length(in_ptr, elem_len); + padding = elem_len - lens[i]; + memset(in_ptr, 0, padding); + in_ptr += padding; + memcpy(in_ptr, params[i], lens[i]); + in_ptr += lens[i]; + } + + if (pin_policy != YKPIV_PINPOLICY_DEFAULT) { + *in_ptr++ = YKPIV_PINPOLICY_TAG; + *in_ptr++ = 0x01; + *in_ptr++ = pin_policy; + } + + if (touch_policy != YKPIV_TOUCHPOLICY_DEFAULT) { + *in_ptr++ = YKPIV_TOUCHPOLICY_TAG; + *in_ptr++ = 0x01; + *in_ptr++ = touch_policy; + } + + if (ykpiv_transfer_data(state, templ, key_data, in_ptr - key_data, data, &recv_len, &sw) != YKPIV_OK) + return YKPIV_GENERIC_ERROR; + + if (sw == 0x6982) + return YKPIV_AUTHENTICATION_ERROR; + + if (sw != 0x9000) + return YKPIV_GENERIC_ERROR; + + return YKPIV_OK; + +} diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 530c59c..3358e49 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -57,6 +57,7 @@ extern "C" YKPIV_WRONG_PIN = -10, YKPIV_INVALID_OBJECT = -11, YKPIV_ALGORITHM_ERROR = -12, + YKPIV_PIN_LOCKED = -13, } ykpiv_rc; const char *ykpiv_strerror(ykpiv_rc err); @@ -85,12 +86,29 @@ extern "C" unsigned char algorithm, unsigned char key); ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len); ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries); + ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t current_pin_len, + const char * new_pin, size_t new_pin_len, + int *tries); + ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t current_puk_len, + const char * new_puk, size_t new_puk_len, + int *tries); + ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len, + const char * new_pin, size_t new_pin_len, + int *tries); ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, unsigned char *data, unsigned long *len); ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key, const unsigned char touch); ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id, unsigned char *indata, size_t len); + ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, unsigned char algorithm, + const unsigned char *p, size_t p_len, + const unsigned char *q, size_t q_len, + const unsigned char *dp, size_t dp_len, + const unsigned char *dq, size_t dq_len, + const unsigned char *qinv, size_t qinv_len, + const unsigned char *ec_data, unsigned char ec_data_len, + const unsigned char pin_policy, const unsigned char touch_policy); #define YKPIV_ALGO_3DES 0x03 #define YKPIV_ALGO_RSA1024 0x06 @@ -103,6 +121,26 @@ extern "C" #define YKPIV_KEY_SIGNATURE 0x9c #define YKPIV_KEY_KEYMGM 0x9d #define YKPIV_KEY_CARDAUTH 0x9e +#define YKPIV_KEY_RETIRED1 0x82 +#define YKPIV_KEY_RETIRED2 0x83 +#define YKPIV_KEY_RETIRED3 0x84 +#define YKPIV_KEY_RETIRED4 0x85 +#define YKPIV_KEY_RETIRED5 0x86 +#define YKPIV_KEY_RETIRED6 0x87 +#define YKPIV_KEY_RETIRED7 0x88 +#define YKPIV_KEY_RETIRED8 0x89 +#define YKPIV_KEY_RETIRED9 0x8a +#define YKPIV_KEY_RETIRED10 0x8b +#define YKPIV_KEY_RETIRED11 0x8c +#define YKPIV_KEY_RETIRED12 0x8d +#define YKPIV_KEY_RETIRED13 0x8e +#define YKPIV_KEY_RETIRED14 0x8f +#define YKPIV_KEY_RETIRED15 0x90 +#define YKPIV_KEY_RETIRED16 0x91 +#define YKPIV_KEY_RETIRED17 0x92 +#define YKPIV_KEY_RETIRED18 0x93 +#define YKPIV_KEY_RETIRED19 0x94 +#define YKPIV_KEY_RETIRED20 0x95 #define YKPIV_OBJ_CAPABILITY 0x5fc107 #define YKPIV_OBJ_CHUID 0x5fc102 @@ -158,11 +196,13 @@ extern "C" #define YKPIV_INS_ATTEST 0xf9 #define YKPIV_PINPOLICY_TAG 0xaa +#define YKPIV_PINPOLICY_DEFAULT 0 #define YKPIV_PINPOLICY_NEVER 1 #define YKPIV_PINPOLICY_ONCE 2 #define YKPIV_PINPOLICY_ALWAYS 3 #define YKPIV_TOUCHPOLICY_TAG 0xab +#define YKPIV_TOUCHPOLICY_DEFAULT 0 #define YKPIV_TOUCHPOLICY_NEVER 1 #define YKPIV_TOUCHPOLICY_ALWAYS 2 diff --git a/lib/ykpiv.map b/lib/ykpiv.map index c647a5a..7c71de8 100644 --- a/lib/ykpiv.map +++ b/lib/ykpiv.map @@ -28,36 +28,50 @@ YKPIV_0.1.0 { global: - ykpiv_check_version; - ykpiv_strerror_name; - ykpiv_strerror; - ykpiv_init; - ykpiv_done; - ykpiv_connect; - ykpiv_disconnect; - ykpiv_transfer_data; - ykpiv_authenticate; - ykpiv_set_mgmkey; - ykpiv_sign_data; - ykpiv_get_version; - ykpiv_verify; - ykpiv_fetch_object; - ykpiv_save_object; - ykpiv_hex_decode; + ykpiv_check_version; + ykpiv_strerror_name; + ykpiv_strerror; + ykpiv_init; + ykpiv_done; + ykpiv_connect; + ykpiv_disconnect; + ykpiv_transfer_data; + ykpiv_authenticate; + ykpiv_set_mgmkey; + ykpiv_sign_data; + ykpiv_get_version; + ykpiv_verify; + ykpiv_fetch_object; + ykpiv_save_object; + ykpiv_hex_decode; local: - *; + *; }; YKPIV_0.2.0 { global: - ykpiv_decipher_data; + ykpiv_decipher_data; } YKPIV_0.1.0; YKPIV_1.1.0 { global: - ykpiv_set_mgmkey2; - ykpiv_list_readers; -} YKPIV_0.1.0; + ykpiv_set_mgmkey2; + ykpiv_list_readers; +} YKPIV_0.2.0; + +YKPIV_1.2.0 +{ +global: + ykpiv_import_private_key; +} YKPIV_1.1.0; + +YKPIV_1.3.0 +{ +global: + ykpiv_change_pin; + ykpiv_change_puk; + ykpiv_unblock_pin; +} YKPIV_1.2.0; diff --git a/mac.mk b/mac.mk index 94549e7..7e99eb4 100644 --- a/mac.mk +++ b/mac.mk @@ -26,7 +26,8 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PACKAGE=yubico-piv-tool -OPENSSLVERSION=1.0.1p +OPENSSLVERSION=1.0.1r +CFLAGS="-mmacosx-version-min=10.6" all: usage mac @@ -47,7 +48,7 @@ doit: curl -L -O "https://www.openssl.org/source/openssl-$(OPENSSLVERSION).tar.gz" && \ tar xfz openssl-$(OPENSSLVERSION).tar.gz && \ cd openssl-$(OPENSSLVERSION) && \ - ./Configure darwin64-x86_64-cc shared no-ssl2 no-ssl3 no-engines --prefix=$(PWD)/tmp/root && \ + ./Configure darwin64-x86_64-cc shared no-ssl2 no-ssl3 no-engines --prefix=$(PWD)/tmp/root $(CFLAGS) && \ make all install_sw && \ cp LICENSE $(PWD)/tmp$(ARCH)/root/licenses/openssl.txt && \ rm -rf $(PWD)/tmp/root/ssl/ && \ @@ -60,16 +61,16 @@ doit: cp ../$(PACKAGE)-$(VERSION).tar.gz . && \ tar xfz $(PACKAGE)-$(VERSION).tar.gz && \ cd $(PACKAGE)-$(VERSION)/ && \ - PKG_CONFIG_PATH=$(PWD)/tmp/root/lib/pkgconfig ./configure --prefix=$(PWD)/tmp/root && \ + CFLAGS=$(CFLAGS) PKG_CONFIG_PATH=$(PWD)/tmp/root/lib/pkgconfig ./configure --prefix=$(PWD)/tmp/root && \ make install $(CHECK) && \ chmod u+w $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib && \ - install_name_tool -id @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib && \ - install_name_tool -id @executable_path/../lib/libykpiv.1.dylib $(PWD)/tmp/root/lib/libykpiv.1.dylib && \ - install_name_tool -id @executable_path/../lib/libykcs11.1.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \ - install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libykpiv.1.dylib && \ - install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \ + install_name_tool -id @loader_path/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib && \ + install_name_tool -id @loader_path/libykpiv.1.dylib $(PWD)/tmp/root/lib/libykpiv.1.dylib && \ + install_name_tool -id @loader_path/libykcs11.1.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \ + install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @loader_path/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libykpiv.1.dylib && \ + install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @loader_path/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \ install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/bin/yubico-piv-tool && \ - install_name_tool -change $(PWD)/tmp/root/lib/libykpiv.1.dylib @executable_path/../lib/libykpiv.1.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \ + install_name_tool -change $(PWD)/tmp/root/lib/libykpiv.1.dylib @loader_path/libykpiv.1.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \ install_name_tool -change $(PWD)/tmp/root/lib/libykpiv.1.dylib @executable_path/../lib/libykpiv.1.dylib $(PWD)/tmp/root/bin/yubico-piv-tool ; \ if otool -L $(PWD)/tmp/root/lib/*.dylib $(PWD)/tmp/root/bin/* | grep '$(PWD)/tmp/root' | grep -q compatibility; then \ echo "something is incorrectly linked!"; \ diff --git a/tool/Makefile.am b/tool/Makefile.am index 3a9c760..392ac30 100644 --- a/tool/Makefile.am +++ b/tool/Makefile.am @@ -33,7 +33,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/lib -I$(top_builddir)/lib bin_PROGRAMS = yubico-piv-tool yubico_piv_tool_SOURCES = yubico-piv-tool.c yubico-piv-tool.h2m -yubico_piv_tool_LDADD = $(OPENSSL_LIBS) ../lib/libykpiv.la +yubico_piv_tool_LDADD = $(OPENSSL_LIBS) $(top_builddir)/lib/libykpiv.la yubico_piv_tool_LDADD += libpiv_cmd.la libpiv_util.la noinst_LTLIBRARIES = libpiv_cmd.la libpiv_util.la @@ -41,9 +41,9 @@ libpiv_cmd_la_SOURCES = cmdline.ggo cmdline.c cmdline.h libpiv_cmd_la_CFLAGS = libpiv_util_la_SOURCES = util.c util.h -libpiv_util_la_LIBADD = $(OPENSSL_LIBS) +libpiv_util_la_LIBADD = $(top_builddir)/lib/libykpiv.la $(OPENSSL_LIBS) -cmdline.c cmdline.h: cmdline.ggo Makefile.am +cmdline.c cmdline.h: cmdline.ggo Makefile.am $(top_srcdir)/configure.ac $(GENGETOPT) --input $^ BUILT_SOURCES = cmdline.c cmdline.h @@ -54,8 +54,7 @@ MAINTAINERCLEANFILES = $(BUILT_SOURCES) dist_man_MANS = yubico-piv-tool.1 MAINTAINERCLEANFILES += $(dist_man_MANS) -yubico-piv-tool.1: $(yubico_piv_tool_SOURCES) \ - $(top_srcdir)/configure.ac +yubico-piv-tool.1: $(yubico_piv_tool_SOURCES) $(libpiv_cmd_la_SOURCES) $(HELP2MAN) --no-info \ --name="Yubico PIV tool" \ --include=$(srcdir)/yubico-piv-tool.h2m \ diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index 498861d..fb503b2 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -32,7 +32,8 @@ option "action" a "Action to take" values="version","generate","set-mgm-key", "reset","pin-retries","import-key","import-certificate","set-chuid", "request-certificate","verify-pin","change-pin","change-puk","unblock-pin", "selfsign-certificate","delete-certificate","read-certificate","status", - "test-signature","test-decipher","list-readers","attest" enum multiple + "test-signature","test-decipher","list-readers","set-ccc","write-object", + "read-object","attest" enum multiple text " Multiple actions may be given at once and will be executed in order for example --action=verify-pin --action=request-certificate\n" @@ -56,8 +57,12 @@ option "subject" S "The subject to use for certificate request" string optional text " The subject must be written as: /CN=host.example.com/OU=test/O=example.com/\n" +option "serial" - "Serial number of the self-signed certificate" int optional default="1" +option "valid-days" - "Time (in days) until the self-signed certificate expires" int optional default="365" option "pin" P "Pin/puk code for verification" string optional option "new-pin" N "New pin/puk code for changing" string optional dependon="pin" option "pin-policy" - "Set pin policy for action generate or import-key" values="never","once","always" enum optional option "touch-policy" - "Set touch policy for action generate, import-key or set-mgm-key" values="never","always" enum optional +option "id" - "Id of object for write/read object" int optional +option "format" f "Format of data for write/read object" values="hex","base64","binary" enum optional default="hex" option "sign" - "Sign data" flag off hidden diff --git a/tool/tests/Makefile.am b/tool/tests/Makefile.am index 7148d1d..7c1ac31 100644 --- a/tool/tests/Makefile.am +++ b/tool/tests/Makefile.am @@ -37,8 +37,9 @@ AM_CPPFLAGS += $(OPENSSL_CFLAGS) AM_LDFLAGS = -no-install parse_name_LDADD = ../libpiv_util.la $(OPENSSL_LIBS) +test_inout_LDADD = ../libpiv_util.la -check_PROGRAMS = parse_name +check_PROGRAMS = parse_name test_inout TESTS = basic.sh $(check_PROGRAMS) if ENABLE_COV diff --git a/tool/tests/test_inout.c b/tool/tests/test_inout.c new file mode 100644 index 0000000..50a5ed2 --- /dev/null +++ b/tool/tests/test_inout.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "util.h" + +#ifdef _WIN32 +#define pipe(fds) _pipe(fds,4096, 0) +#endif + +static void test_inout(enum enum_format format) { + const unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + unsigned char buf2[sizeof(buf)]; + int pipefd[2]; + FILE *tmp1, *tmp2; + + assert(pipe(pipefd) == 0); + tmp1 = fdopen(pipefd[1], "w"); + dump_data(buf, sizeof(buf), tmp1, false, format); + fclose(tmp1); + tmp2 = fdopen(pipefd[0], "r"); + read_data(buf2, sizeof(buf2), tmp2, format); + assert(memcmp(buf, buf2, sizeof(buf)) == 0); + fclose(tmp2); +} + +int main(void) { + test_inout(format_arg_base64); + test_inout(format_arg_hex); + test_inout(format_arg_binary); + exit(0); +} diff --git a/tool/util.c b/tool/util.c index 4e2a719..17f4af9 100644 --- a/tool/util.c +++ b/tool/util.c @@ -148,12 +148,80 @@ parse_err: return NULL; } -void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, bool space) { - unsigned int i; - for (i = 0; i < len; i++) { - fprintf(output, "%02x%s", buf[i], space == true ? " " : ""); +size_t read_data(unsigned char *buf, size_t len, FILE* input, enum enum_format format) { + char raw_buf[3072 * 2]; + size_t raw_len = sizeof(raw_buf); + raw_len = fread(raw_buf, 1, raw_len, input); + switch(format) { + case format_arg_hex: + if(raw_buf[raw_len - 1] == '\n') { + raw_len -= 1; + } + if(ykpiv_hex_decode(raw_buf, raw_len, buf, &len) != YKPIV_OK) { + return 0; + } + return len; + case format_arg_base64: + { + int read; + BIO *b64 = BIO_new(BIO_f_base64()); + BIO *bio = BIO_new_mem_buf(raw_buf, raw_len); + BIO_push(b64, bio); + read = BIO_read(b64, buf, len); + BIO_free_all(b64); + if(read <= 0) { + return 0; + } else { + return (size_t)read; + } + } + break; + case format_arg_binary: + if(raw_len > len) { + return 0; + } + memcpy(buf, raw_buf, raw_len); + return raw_len; + case format__NULL: + default: + return 0; + } +} + +void dump_data(const unsigned char *buf, unsigned int len, FILE *output, bool space, enum enum_format format) { + switch(format) { + case format_arg_hex: + { + char tmp[3072 * 3 + 1]; + unsigned int i; + unsigned int step = 2; + if(space) step += 1; + if(len > 3072) { + return; + } + for (i = 0; i < len; i++) { + sprintf(tmp + i * step, "%02x%s", buf[i], space == true ? " " : ""); + } + fprintf(output, "%s\n", tmp); + } + return; + case format_arg_base64: + { + BIO *b64 = BIO_new(BIO_f_base64()); + BIO *bio = BIO_new_fp(output, BIO_NOCLOSE); + BIO_push(b64, bio); + BIO_write(b64, buf, (int)len); + BIO_flush(b64); + BIO_free_all(b64); + } + return; + case format_arg_binary: + fwrite(buf, 1, len, output); + return; + case format__NULL: + default: + return; } - fprintf(output, "\n"); } int get_length(const unsigned char *buffer, int *len) { @@ -276,33 +344,94 @@ int key_to_object_id(int key) { int object; switch(key) { - case 0x9a: + case YKPIV_KEY_AUTHENTICATION: object = YKPIV_OBJ_AUTHENTICATION; break; - case 0x9c: + case YKPIV_KEY_CARDMGM: object = YKPIV_OBJ_SIGNATURE; break; - case 0x9d: + case YKPIV_KEY_KEYMGM: object = YKPIV_OBJ_KEY_MANAGEMENT; break; - case 0x9e: + case YKPIV_KEY_CARDAUTH: object = YKPIV_OBJ_CARD_AUTH; break; + case YKPIV_KEY_RETIRED1: + object = YKPIV_OBJ_RETIRED1; + break; + case YKPIV_KEY_RETIRED2: + object = YKPIV_OBJ_RETIRED2; + break; + case YKPIV_KEY_RETIRED3: + object = YKPIV_OBJ_RETIRED3; + break; + case YKPIV_KEY_RETIRED4: + object = YKPIV_OBJ_RETIRED4; + break; + case YKPIV_KEY_RETIRED5: + object = YKPIV_OBJ_RETIRED5; + break; + case YKPIV_KEY_RETIRED6: + object = YKPIV_OBJ_RETIRED6; + break; + case YKPIV_KEY_RETIRED7: + object = YKPIV_OBJ_RETIRED7; + break; + case YKPIV_KEY_RETIRED8: + object = YKPIV_OBJ_RETIRED8; + break; + case YKPIV_KEY_RETIRED9: + object = YKPIV_OBJ_RETIRED9; + break; + case YKPIV_KEY_RETIRED10: + object = YKPIV_OBJ_RETIRED10; + break; + case YKPIV_KEY_RETIRED11: + object = YKPIV_OBJ_RETIRED11; + break; + case YKPIV_KEY_RETIRED12: + object = YKPIV_OBJ_RETIRED12; + break; + case YKPIV_KEY_RETIRED13: + object = YKPIV_OBJ_RETIRED13; + break; + case YKPIV_KEY_RETIRED14: + object = YKPIV_OBJ_RETIRED14; + break; + case YKPIV_KEY_RETIRED15: + object = YKPIV_OBJ_RETIRED15; + break; + case YKPIV_KEY_RETIRED16: + object = YKPIV_OBJ_RETIRED16; + break; + case YKPIV_KEY_RETIRED17: + object = YKPIV_OBJ_RETIRED17; + break; + case YKPIV_KEY_RETIRED18: + object = YKPIV_OBJ_RETIRED18; + break; + case YKPIV_KEY_RETIRED19: + object = YKPIV_OBJ_RETIRED19; + break; + case YKPIV_KEY_RETIRED20: + object = YKPIV_OBJ_RETIRED20; + break; default: object = 0; } return object; } -bool set_component_with_len(unsigned char **in_ptr, const BIGNUM *bn, int element_len) { +bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len) { int real_len = BN_num_bytes(bn); - *in_ptr += set_length(*in_ptr, element_len); + if(real_len > element_len) { return false; } - memset(*in_ptr, 0, (size_t)(element_len - real_len)); - *in_ptr += element_len - real_len; - *in_ptr += BN_bn2bin(bn, *in_ptr); + memset(in_ptr, 0, (size_t)(element_len - real_len)); + in_ptr += element_len - real_len; + BN_bn2bin(bn, in_ptr); + return true; } diff --git a/tool/util.h b/tool/util.h index f6d984d..d9284f8 100644 --- a/tool/util.h +++ b/tool/util.h @@ -31,6 +31,8 @@ #ifndef YUBICO_PIV_TOOL_INTERNAL_H #define YUBICO_PIV_TOOL_INTERNAL_H +#include + #include #include "cmdline.h" @@ -38,7 +40,8 @@ #define INPUT 1 #define OUTPUT 2 -void dump_hex(unsigned const char*, unsigned int, FILE*, bool); +size_t read_data(unsigned char*, size_t, FILE*, enum enum_format); +void dump_data(unsigned const char*, unsigned int, FILE*, bool, enum enum_format); int set_length(unsigned char*, int); int get_length(const unsigned char*, int*); X509_NAME *parse_name(const char*); @@ -46,7 +49,7 @@ unsigned char get_algorithm(EVP_PKEY*); FILE *open_file(const char*, int); int get_object_id(enum enum_slot slot); int key_to_object_id(int key); -bool set_component_with_len(unsigned char**, const BIGNUM*, int); +bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len); bool prepare_rsa_signature(const unsigned char*, unsigned int, unsigned char*, unsigned int*, int); bool read_pw(const char*, char*, size_t, int); diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 02191c8..f3b6465 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -5,15 +5,15 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -63,6 +63,17 @@ unsigned const char chuid_tmpl[] = { }; #define CHUID_GUID_OFFS 29 +unsigned const char ccc_tmpl[] = { + 0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21, + 0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4, 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00, + 0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00 +}; +#define CCC_ID_OFFS 9 + +#define CHUID 0 +#define CCC 1 + #define MAX_OID_LEN 19 #define KEY_LEN 24 @@ -71,7 +82,7 @@ static void print_version(ykpiv_state *state, const char *output_file_name) { char version[7]; FILE *output_file = open_file(output_file_name, OUTPUT); if(!output_file) { - fprintf(stderr, "Failed opening output_file_name\n"); + return; } if(ykpiv_get_version(state, version, sizeof(version)) == YKPIV_OK) { @@ -316,14 +327,15 @@ static bool set_pin_retries(ykpiv_state *state, int pin_retries, int puk_retries } static bool import_key(ykpiv_state *state, enum enum_key_format key_format, - const char *input_file_name, const char *slot, char *password, - enum enum_pin_policy pin_policy, enum enum_touch_policy touch_policy) { + const char *input_file_name, const char *slot, char *password, + enum enum_pin_policy pin_policy, enum enum_touch_policy touch_policy) { int key = 0; FILE *input_file = NULL; EVP_PKEY *private_key = NULL; PKCS12 *p12 = NULL; X509 *cert = NULL; bool ret = false; + ykpiv_rc rc = YKPIV_GENERIC_ERROR; sscanf(slot, "%2x", &key); @@ -360,119 +372,123 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format, { unsigned char algorithm = get_algorithm(private_key); + unsigned char pp = YKPIV_PINPOLICY_DEFAULT; + unsigned char tp = YKPIV_TOUCHPOLICY_DEFAULT; + if(algorithm == 0) { goto import_out; } - { - unsigned char data[0xff]; - unsigned long recv_len = sizeof(data); - unsigned char in_data[1024]; - unsigned char *in_ptr = in_data; - unsigned char templ[] = {0, YKPIV_INS_IMPORT_KEY, algorithm, key}; - int sw; - if(YKPIV_IS_RSA(algorithm)) { - RSA *rsa_private_key = EVP_PKEY_get1_RSA(private_key); - unsigned char e[4]; - unsigned char *e_ptr = e; - int element_len = 128; - if(algorithm == YKPIV_ALGO_RSA1024) { - element_len = 64; - } - if((set_component_with_len(&e_ptr, rsa_private_key->e, 3) == false) || - !(e[1] == 0x01 && e[2] == 0x00 && e[3] == 0x01)) { - fprintf(stderr, "Invalid public exponent for import (only 0x10001 supported)\n"); - goto import_out; - } + if(pin_policy != pin_policy__NULL) { + pp = get_pin_policy(pin_policy); + } - *in_ptr++ = 0x01; - if(set_component_with_len(&in_ptr, rsa_private_key->p, element_len) == false) { - fprintf(stderr, "Failed setting p component.\n"); - goto import_out; - } + if(touch_policy != touch_policy__NULL) { + tp = get_touch_policy(touch_policy); + } - *in_ptr++ = 0x02; - if(set_component_with_len(&in_ptr, rsa_private_key->q, element_len) == false) { - fprintf(stderr, "Failed setting q component.\n"); - goto import_out; - } + if(YKPIV_IS_RSA(algorithm)) { + RSA *rsa_private_key = EVP_PKEY_get1_RSA(private_key); + unsigned char e[4]; + unsigned char p[128]; + unsigned char q[128]; + unsigned char dmp1[128]; + unsigned char dmq1[128]; + unsigned char iqmp[128]; - *in_ptr++ = 0x03; - if(set_component_with_len(&in_ptr, rsa_private_key->dmp1, element_len) == false) { - fprintf(stderr, "Failed setting dmp1 component.\n"); - goto import_out; - } - - *in_ptr++ = 0x04; - if(set_component_with_len(&in_ptr, rsa_private_key->dmq1, element_len) == false) { - fprintf(stderr, "Failed setting dmq1 component.\n"); - goto import_out; - } - - *in_ptr++ = 0x05; - if(set_component_with_len(&in_ptr, rsa_private_key->iqmp, element_len) == false) { - fprintf(stderr, "Failed setting iqmp component.\n"); - goto import_out; - } - } else if(YKPIV_IS_EC(algorithm)) { - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(private_key); - const BIGNUM *s = EC_KEY_get0_private_key(ec); - int element_len = 32; - - if(algorithm == YKPIV_ALGO_ECCP384) { - element_len = 48; - } - - *in_ptr++ = 0x06; - if(set_component_with_len(&in_ptr, s, element_len) == false) { - fprintf(stderr, "Failed setting ec private key.\n"); - goto import_out; - } + int element_len = 128; + if(algorithm == YKPIV_ALGO_RSA1024) { + element_len = 64; } - if(pin_policy != pin_policy__NULL) { - *in_ptr++ = YKPIV_PINPOLICY_TAG; - *in_ptr++ = 1; - *in_ptr++ = get_pin_policy(pin_policy); - } - if(touch_policy != touch_policy__NULL) { - *in_ptr++ = YKPIV_TOUCHPOLICY_TAG; - *in_ptr++ = 1; - *in_ptr++ = get_touch_policy(touch_policy); + if((set_component(e, rsa_private_key->e, 3) == false) || + !(e[0] == 0x01 && e[1] == 0x00 && e[2] == 0x01)) { + fprintf(stderr, "Invalid public exponent for import (only 0x10001 supported)\n"); + goto import_out; } - if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data, - &recv_len, &sw) != YKPIV_OK) { - return false; - } else if(sw == 0x6a80) { - fprintf(stderr, "Failed import."); - if(pin_policy != pin_policy__NULL) { - fprintf(stderr, "Maybe pin-policy is not supported on this key?\n"); - } else if(touch_policy != touch_policy__NULL) { - fprintf(stderr, "Maybe touch-policy is not supported on this key?\n"); - } else { - fprintf(stderr, "Maybe algorithm is not supported on this key?\n"); - } - } else if(sw != 0x9000) { - fprintf(stderr, "Failed import command with code %x.\n", sw); - } else { - ret = true; + if(set_component(p, rsa_private_key->p, element_len) == false) { + fprintf(stderr, "Failed setting p component.\n"); + goto import_out; } + + if(set_component(q, rsa_private_key->q, element_len) == false) { + fprintf(stderr, "Failed setting q component.\n"); + goto import_out; + } + + if(set_component(dmp1, rsa_private_key->dmp1, element_len) == false) { + fprintf(stderr, "Failed setting dmp1 component.\n"); + goto import_out; + } + + if(set_component(dmq1, rsa_private_key->dmq1, element_len) == false) { + fprintf(stderr, "Failed setting dmq1 component.\n"); + goto import_out; + } + + if(set_component(iqmp, rsa_private_key->iqmp, element_len) == false) { + fprintf(stderr, "Failed setting iqmp component.\n"); + goto import_out; + } + + rc = ykpiv_import_private_key(state, key, algorithm, + p, element_len, + q, element_len, + dmp1, element_len, + dmq1, element_len, + iqmp, element_len, + NULL, 0, + pp, tp); + } + else if(YKPIV_IS_EC(algorithm)) { + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(private_key); + const BIGNUM *s = EC_KEY_get0_private_key(ec); + unsigned char s_ptr[48]; + + int element_len = 32; + if(algorithm == YKPIV_ALGO_ECCP384) { + element_len = 48; + } + + if(set_component(s_ptr, s, element_len) == false) { + fprintf(stderr, "Failed setting ec private key.\n"); + goto import_out; + } + + rc = ykpiv_import_private_key(state, key, algorithm, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + s_ptr, element_len, + pp, tp); + } + + ret = true; + if(rc != YKPIV_OK) { + ret = false; } } + import_out: if(private_key) { EVP_PKEY_free(private_key); } + if(p12) { PKCS12_free(p12); } + if(cert) { X509_free(cert); } + if(input_file != stdin) { fclose(input_file); } + return ret; } @@ -536,15 +552,16 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, } { - unsigned char certdata[2100]; + unsigned char certdata[3072]; unsigned char *certptr = certdata; int object = get_object_id(slot); ykpiv_rc res; - if(cert_len > 2048) { - fprintf(stderr, "Certificate to large, maximum 2048 bytes (was %d bytes).\n", cert_len); + if(4 + cert_len + 5 > 3072) { /* 4 is prefix size, 5 is postfix size */ + fprintf(stderr, "Certificate is to large to fit in buffer.\n"); goto import_cert_out; } + *certptr++ = 0x70; certptr += set_length(certptr, cert_len); if (compress) { @@ -587,20 +604,36 @@ import_cert_out: return ret; } -static bool set_chuid(ykpiv_state *state, int verbose) { - unsigned char chuid[sizeof(chuid_tmpl)]; +static bool set_dataobject(ykpiv_state *state, int verbose, int type) { + unsigned char obj[1024]; ykpiv_rc res; + size_t offs, rand_len, len; + const unsigned char *tmpl; + int id; - memcpy(chuid, chuid_tmpl, sizeof(chuid)); - if(RAND_pseudo_bytes(chuid + CHUID_GUID_OFFS, 0x10) == -1) { + if(type == CHUID) { + offs = CHUID_GUID_OFFS; + len = sizeof(chuid_tmpl); + rand_len = 0x10; + tmpl = chuid_tmpl; + id = YKPIV_OBJ_CHUID; + } else { + offs = CCC_ID_OFFS; + rand_len = 0xe; + len = sizeof(ccc_tmpl); + tmpl = ccc_tmpl; + id = YKPIV_OBJ_CAPABILITY; + } + memcpy(obj, tmpl, len); + if(RAND_pseudo_bytes(obj + offs, rand_len) == -1) { fprintf(stderr, "error: no randomness.\n"); return false; } if(verbose) { - fprintf(stderr, "Setting the CHUID to: "); - dump_hex(chuid, sizeof(chuid), stderr, true); + fprintf(stderr, "Setting the %s to: ", type == CHUID ? "CHUID" : "CCC"); + dump_data(obj, len, stderr, true, format_arg_hex); } - if((res = ykpiv_save_object(state, YKPIV_OBJ_CHUID, chuid, sizeof(chuid))) != YKPIV_OK) { + if((res = ykpiv_save_object(state, id, obj, len)) != YKPIV_OK) { fprintf(stderr, "Failed communicating with device: %s\n", ykpiv_strerror(res)); return false; } @@ -689,7 +722,7 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for memcpy(digest, oid, oid_len); /* XXX: this should probably use X509_REQ_digest() but that's buggy */ if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ_INFO), md, req->req_info, - digest + oid_len, &digest_len)) { + digest + oid_len, &digest_len)) { fprintf(stderr, "Failed doing digest of request.\n"); goto request_out; } @@ -748,7 +781,7 @@ request_out: static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_format, const char *input_file_name, const char *slot, char *subject, enum enum_hash hash, - const char *output_file_name) { + int serial, int validDays, const char *output_file_name) { FILE *input_file = NULL; FILE *output_file = NULL; bool ret = false; @@ -814,7 +847,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo fprintf(stderr, "Failed to set the certificate public key.\n"); goto selfsign_out; } - if(!ASN1_INTEGER_set(X509_get_serialNumber(x509), 1)) { + if(!ASN1_INTEGER_set(X509_get_serialNumber(x509), serial)) { fprintf(stderr, "Failed to set certificate serial.\n"); goto selfsign_out; } @@ -822,7 +855,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo fprintf(stderr, "Failed to set certificate notBefore.\n"); goto selfsign_out; } - if(!X509_gmtime_adj(X509_get_notAfter(x509), 31536000L)) { + if(!X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * validDays)) { fprintf(stderr, "Failed to set certificate notAfter.\n"); goto selfsign_out; } @@ -856,7 +889,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo memcpy(digest, oid, oid_len); /* XXX: this should probably use X509_digest() but that looks buggy */ if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_CINF), md, x509->cert_info, - digest + oid_len, &digest_len)) { + digest + oid_len, &digest_len)) { fprintf(stderr, "Failed doing digest of certificate.\n"); goto selfsign_out; } @@ -936,17 +969,16 @@ static bool verify_pin(ykpiv_state *state, const char *pin) { * since they're very similar in what data they use. */ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *pin, const char *new_pin) { - unsigned char templ[] = {0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80}; - unsigned char indata[0x10]; - unsigned char data[0xff]; - unsigned long recv_len = sizeof(data); char pinbuf[9] = {0}; char new_pinbuf[9] = {0}; const char *name = action == action_arg_changeMINUS_pin ? "pin" : "puk"; const char *new_name = action == action_arg_changeMINUS_puk ? "new puk" : "new pin"; - int sw; + int (*op)(ykpiv_state *state, const char * puk, size_t puk_len, + const char * new_pin, size_t new_pin_len, int *tries) = ykpiv_change_pin; size_t pin_len; size_t new_len; + int tries; + ykpiv_rc res; if(!pin) { if (!read_pw(name, pinbuf, sizeof(pinbuf), false)) { @@ -969,38 +1001,33 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char * } if(action == action_arg_unblockMINUS_pin) { - templ[1] = YKPIV_INS_RESET_RETRY; + op = ykpiv_unblock_pin; } else if(action == action_arg_changeMINUS_puk) { - templ[3] = 0x81; + op = ykpiv_change_puk; } - memcpy(indata, pin, pin_len); - if(pin_len < 8) { - memset(indata + pin_len, 0xff, 8 - pin_len); - } - memcpy(indata + 8, new_pin, new_len); - if(new_len < 8) { - memset(indata + 8 + new_len, 0xff, 16 - new_len); - } - if(ykpiv_transfer_data(state, templ, indata, sizeof(indata), data, &recv_len, &sw) != YKPIV_OK) { - return false; - } else if(sw != 0x9000) { - if((sw >> 8) == 0x63) { - int tries = sw & 0xf; + res = op(state, pin, pin_len, new_pin, new_len, &tries); + switch (res) { + case YKPIV_OK: + return true; + + case YKPIV_WRONG_PIN: fprintf(stderr, "Failed verifying %s code, now %d tries left before blocked.\n", - name, tries); - } else if(sw == 0x6983) { + name, tries); + return false; + + case YKPIV_PIN_LOCKED: if(action == action_arg_changeMINUS_pin) { fprintf(stderr, "The pin code is blocked, use the unblock-pin action to unblock it.\n"); } else { fprintf(stderr, "The puk code is blocked, you will have to reinitialize the application.\n"); } - } else { - fprintf(stderr, "Failed changing/unblocking code, error: %x\n", sw); - } - return false; + return false; + + default: + fprintf(stderr, "Failed changing/unblocking code, error: %x\n", res); + return false; } - return true; } static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) { @@ -1019,7 +1046,7 @@ static bool read_certificate(ykpiv_state *state, enum enum_slot slot, enum enum_key_format key_format, const char *output_file_name) { FILE *output_file; int object = get_object_id(slot); - unsigned char data[2048]; + unsigned char data[3072]; const unsigned char *ptr = data; unsigned long len = sizeof(data); int cert_len; @@ -1100,6 +1127,9 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output, output_file = open_file(output, OUTPUT); if(!output_file) { + if(input_file && input_file != stdin) { + fclose(input_file); + } return false; } @@ -1127,7 +1157,7 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output, if(verbosity) { fprintf(stderr, "file hashed as: "); - dump_hex(hashed, hash_len, stderr, true); + dump_data(hashed, hash_len, stderr, true, format_arg_hex); } EVP_MD_CTX_destroy(mdctx); } @@ -1146,7 +1176,7 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output, if(verbosity) { fprintf(stderr, "file signed as: "); - dump_hex(buf, len, stderr, true); + dump_data(buf, len, stderr, true, format_arg_hex); } fwrite(buf, 1, len, output_file); ret = true; @@ -1167,7 +1197,8 @@ out: static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_MD *md, FILE *output) { int object = get_object_id(slot); - unsigned char data[2048]; + int slot_name; + unsigned char data[3072]; const unsigned char *ptr = data; unsigned long len = sizeof(data); int cert_len; @@ -1176,10 +1207,18 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M BIO *bio = NULL; if(ykpiv_fetch_object(state, object, data, &len) != YKPIV_OK) { - fprintf(output, "No data available.\n"); return; } + if (slot == slot_arg_9a) + slot_name = 0x9a; + else if (slot >= slot_arg_9c && slot <= slot_arg_9e) + slot_name = 0x9b + slot; + else + slot_name = 0x82 + (slot - slot_arg_82); + + fprintf(output, "Slot %x:\t", slot_name); + if(*ptr++ == 0x70) { unsigned int md_len = sizeof(data); ASN1_TIME *not_before, *not_after; @@ -1237,7 +1276,7 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M fprintf(output, "\n"); X509_digest(x509, md, data, &md_len); fprintf(output, "\tFingerprint:\t"); - dump_hex(data, md_len, output, false); + dump_data(data, md_len, output, false, format_arg_hex); bio = BIO_new_fp(output, BIO_NOCLOSE | BIO_FP_TEXT); not_before = X509_get_notBefore(x509); @@ -1266,10 +1305,12 @@ cert_out: } static bool status(ykpiv_state *state, enum enum_hash hash, - const char *output_file_name) { + enum enum_slot slot, + const char *output_file_name) { const EVP_MD *md; - unsigned char chuid[2048]; - long unsigned len = sizeof(chuid); + unsigned char buf[3072]; + long unsigned len = sizeof(buf); + int i; FILE *output_file = open_file(output_file_name, OUTPUT); if(!output_file) { return false; @@ -1281,20 +1322,26 @@ static bool status(ykpiv_state *state, enum enum_hash hash, } fprintf(output_file, "CHUID:\t"); - if(ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, chuid, &len) != YKPIV_OK) { + if(ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, &len) != YKPIV_OK) { fprintf(output_file, "No data available\n"); } else { - dump_hex(chuid, len, output_file, false); + dump_data(buf, len, output_file, false, format_arg_hex); } - fprintf(output_file, "Slot 9a:\t"); - print_cert_info(state, slot_arg_9a, md, output_file); - fprintf(output_file, "Slot 9c:\t"); - print_cert_info(state, slot_arg_9c, md, output_file); - fprintf(output_file, "Slot 9d:\t"); - print_cert_info(state, slot_arg_9d, md, output_file); - fprintf(output_file, "Slot 9e:\t"); - print_cert_info(state, slot_arg_9e, md, output_file); + len = sizeof(buf); + fprintf(output_file, "CCC:\t"); + if(ykpiv_fetch_object(state, YKPIV_OBJ_CAPABILITY, buf, &len) != YKPIV_OK) { + fprintf(output_file, "No data available\n"); + } else { + dump_data(buf, len, output_file, false, format_arg_hex); + } + + if (slot == slot__NULL) + for (i = 0; i < 24; i++) { + print_cert_info(state, i, md, output_file); + } + else + print_cert_info(state, slot, md, output_file); { int tries; @@ -1360,7 +1407,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot, EVP_DigestFinal_ex(mdctx, data, &data_len); if(verbose) { fprintf(stderr, "Test data hashes as: "); - dump_hex(data, data_len, stderr, true); + dump_data(data, data_len, stderr, true, format_arg_hex); } } @@ -1516,9 +1563,9 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot, if(len == sizeof(secret)) { if(verbose) { fprintf(stderr, "Generated nonce: "); - dump_hex(secret, sizeof(secret), stderr, true); + dump_data(secret, sizeof(secret), stderr, true, format_arg_hex); fprintf(stderr, "Decrypted nonce: "); - dump_hex(secret2, sizeof(secret2), stderr, true); + dump_data(secret2, sizeof(secret2), stderr, true, format_arg_hex); } if(memcmp(secret, secret2, sizeof(secret)) == 0) { fprintf(stderr, "Successfully performed RSA decryption!\n"); @@ -1558,9 +1605,9 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot, } if(verbose) { fprintf(stderr, "ECDH host generated: "); - dump_hex(secret, len, stderr, true); + dump_data(secret, len, stderr, true, format_arg_hex); fprintf(stderr, "ECDH card generated: "); - dump_hex(secret2, len, stderr, true); + dump_data(secret2, len, stderr, true, format_arg_hex); } if(memcmp(secret, secret2, key_len) == 0) { fprintf(stderr, "Successfully performed ECDH exchange with card.\n"); @@ -1618,11 +1665,6 @@ static bool attest(ykpiv_state *state, const char *slot, return false; } - output_file = open_file(output_file_name, OUTPUT); - if(!output_file) { - return false; - } - if(ykpiv_transfer_data(state, templ, NULL, 0, data, &len, &sw) != YKPIV_OK) { fprintf(stderr, "Failed to communicate.\n"); goto attest_out; @@ -1660,7 +1702,73 @@ attest_out: if(x509) { X509_free(x509); } + return ret; +} +static bool write_object(ykpiv_state *state, int id, + const char *input_file_name, int verbosity, enum enum_format format) { + bool ret = false; + FILE *input_file = NULL; + unsigned char data[3072]; + size_t len = sizeof(data); + ykpiv_rc res; + + input_file = open_file(input_file_name, INPUT); + if(!input_file) { + return false; + } + + if(isatty(fileno(input_file))) { + fprintf(stderr, "Please paste the data...\n"); + } + + len = read_data(data, len, input_file, format); + if(len == 0) { + fprintf(stderr, "Failed reading data\n"); + goto write_out; + } + + if(verbosity) { + fprintf(stderr, "Writing %lu bytes of data to object %x.\n", len, id); + } + + if((res = ykpiv_save_object(state, id, data, len)) != YKPIV_OK) { + fprintf(stderr, "Failed writing data to device: %s\n", ykpiv_strerror(res)); + } else { + ret = true; + } + +write_out: + if(input_file != stdin) { + fclose(input_file); + } + return ret; +} + +static bool read_object(ykpiv_state *state, int id, const char *output_file_name, + enum enum_format format) { + FILE *output_file = NULL; + unsigned char data[3072]; + unsigned long len = sizeof(data); + bool ret = false; + + output_file = open_file(output_file_name, OUTPUT); + if(!output_file) { + return false; + } + + if(ykpiv_fetch_object(state, id, data, &len) != YKPIV_OK) { + fprintf(stderr, "Failed fetching object.\n"); + goto read_out; + } + + dump_data(data, len, output_file, false, format); + ret = true; + +read_out: + if(output_file != stdout) { + fclose(output_file); + } return ret; } @@ -1671,12 +1779,16 @@ int main(int argc, char *argv[]) { enum enum_action action; unsigned int i; int ret = EXIT_SUCCESS; + bool authed = false; + char pwbuf[128]; + char *password; if(cmdline_parser(argc, argv, &args_info) != 0) { return EXIT_FAILURE; } verbosity = args_info.verbose_arg + (int)args_info.verbose_given; + password = args_info.password_arg; for(i = 0; i < args_info.action_given; i++) { action = *(args_info.action_arg + i); @@ -1709,12 +1821,21 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } break; + case action_arg_writeMINUS_object: + case action_arg_readMINUS_object: + if(!args_info.id_given) { + fprintf(stderr, "The '%s' action needs the --id argument.\n", + cmdline_parser_action_values[action]); + return EXIT_FAILURE; + } + break; case action_arg_changeMINUS_pin: case action_arg_changeMINUS_puk: case action_arg_unblockMINUS_pin: case action_arg_verifyMINUS_pin: case action_arg_setMINUS_mgmMINUS_key: case action_arg_setMINUS_chuid: + case action_arg_setMINUS_ccc: case action_arg_version: case action_arg_reset: case action_arg_status: @@ -1736,20 +1857,60 @@ int main(int argc, char *argv[]) { } for(i = 0; i < args_info.action_given; i++) { - bool needs_auth = false; action = *(args_info.action_arg + i); switch(action) { + case action_arg_importMINUS_key: + case action_arg_importMINUS_certificate: + if(args_info.key_format_arg == key_format_arg_PKCS12 && !password) { + if(verbosity) { + fprintf(stderr, "Asking for password since '%s' needs it.\n", cmdline_parser_action_values[action]); + } + if(!read_pw("Password", pwbuf, sizeof(pwbuf), false)) { + fprintf(stderr, "Failed to get password.\n"); + return false; + } + password = pwbuf; + } case action_arg_generate: case action_arg_setMINUS_mgmMINUS_key: case action_arg_pinMINUS_retries: - case action_arg_importMINUS_key: - case action_arg_importMINUS_certificate: case action_arg_setMINUS_chuid: + case action_arg_setMINUS_ccc: case action_arg_deleteMINUS_certificate: - if(verbosity) { - fprintf(stderr, "Authenticating since action '%s' needs that.\n", cmdline_parser_action_values[action]); + case action_arg_writeMINUS_object: + if(!authed) { + unsigned char key[KEY_LEN]; + size_t key_len = sizeof(key); + char keybuf[KEY_LEN*2+1]; + char *key_ptr = args_info.key_arg; + if(verbosity) { + fprintf(stderr, "Authenticating since action '%s' needs that.\n", cmdline_parser_action_values[action]); + } + if(args_info.key_given && args_info.key_orig == NULL) { + if(!read_pw("management key", keybuf, sizeof(keybuf), false)) { + fprintf(stderr, "Failed to read management key from stdin,\n"); + return EXIT_FAILURE; + } + key_ptr = keybuf; + } + if(ykpiv_hex_decode(key_ptr, strlen(key_ptr), key, &key_len) != YKPIV_OK) { + fprintf(stderr, "Failed decoding key!\n"); + return EXIT_FAILURE; + } + + if(ykpiv_authenticate(state, key) != YKPIV_OK) { + fprintf(stderr, "Failed authentication with the application.\n"); + return EXIT_FAILURE; + } + if(verbosity) { + fprintf(stderr, "Successful application authentication.\n"); + } + authed = true; + } else { + if(verbosity) { + fprintf(stderr, "Skipping authentication for '%s' since it's already done.\n", cmdline_parser_action_values[action]); + } } - needs_auth = true; break; case action_arg_version: case action_arg_reset: @@ -1765,44 +1926,20 @@ int main(int argc, char *argv[]) { case action_arg_testMINUS_decipher: case action_arg_listMINUS_readers: case action_arg_attest: + case action_arg_readMINUS_object: case action__NULL: default: if(verbosity) { fprintf(stderr, "Action '%s' does not need authentication.\n", cmdline_parser_action_values[action]); } - continue; - } - if(needs_auth) { - unsigned char key[KEY_LEN]; - size_t key_len = sizeof(key); - char keybuf[KEY_LEN*2+1]; - char *key_ptr = args_info.key_arg; - if(args_info.key_given && args_info.key_orig == NULL) { - if(!read_pw("management key", keybuf, sizeof(keybuf), false)) { - fprintf(stderr, "Failed to read management key from stdin,\n"); - return EXIT_FAILURE; - } - key_ptr = keybuf; - } - if(ykpiv_hex_decode(key_ptr, strlen(key_ptr), key, &key_len) != YKPIV_OK) { - fprintf(stderr, "Failed decoding key!\n"); - return EXIT_FAILURE; - } - - if(ykpiv_authenticate(state, key) != YKPIV_OK) { - fprintf(stderr, "Failed authentication with the application.\n"); - return EXIT_FAILURE; - } - if(verbosity) { - fprintf(stderr, "Successful application authentication.\n"); - } - break; } } + /* openssl setup.. */ OpenSSL_add_all_algorithms(); + for(i = 0; i < args_info.action_given; i++) { char new_keybuf[KEY_LEN*2+1] = {0}; char *new_mgm_key = args_info.new_key_arg; @@ -1855,7 +1992,7 @@ int main(int argc, char *argv[]) { break; case action_arg_reset: if(reset(state) == false) { - fprintf(stderr, "Reset failed, are pincodes blocked?\n"); + fprintf(stderr, "Reset failed, are pincodes blocked?\n"); ret = EXIT_FAILURE; } else { fprintf(stderr, "Successfully reset the application.\n"); @@ -1871,25 +2008,27 @@ int main(int argc, char *argv[]) { } break; case action_arg_importMINUS_key: - if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, args_info.password_arg, + if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, password, args_info.pin_policy_arg, args_info.touch_policy_arg) == false) { + fprintf(stderr, "Unable to import private key\n"); ret = EXIT_FAILURE; } else { fprintf(stderr, "Successfully imported a new private key.\n"); } break; case action_arg_importMINUS_certificate: - if(import_cert(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_arg, args_info.password_arg) == false) { + if(import_cert(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_arg, password) == false) { ret = EXIT_FAILURE; } else { fprintf(stderr, "Successfully imported a new certificate.\n"); } break; + case action_arg_setMINUS_ccc: case action_arg_setMINUS_chuid: - if(set_chuid(state, verbosity) == false) { + if(set_dataobject(state, verbosity, action == action_arg_setMINUS_chuid ? CHUID : CCC) == false) { ret = EXIT_FAILURE; } else { - fprintf(stderr, "Successfully set new CHUID.\n"); + fprintf(stderr, "Successfully set new %s.\n", action == action_arg_setMINUS_chuid ? "CHUID" : "CCC"); } break; case action_arg_requestMINUS_certificate: @@ -1925,6 +2064,7 @@ int main(int argc, char *argv[]) { case action_arg_selfsignMINUS_certificate: if(selfsign_certificate(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, args_info.subject_arg, args_info.hash_arg, + args_info.serial_arg, args_info.valid_days_arg, args_info.output_arg) == false) { ret = EXIT_FAILURE; } else { @@ -1943,7 +2083,7 @@ int main(int argc, char *argv[]) { } break; case action_arg_status: - if(status(state, args_info.hash_arg, args_info.output_arg) == false) { + if(status(state, args_info.hash_arg, args_info.slot_arg, args_info.output_arg) == false) { ret = EXIT_FAILURE; } break; @@ -1963,6 +2103,17 @@ int main(int argc, char *argv[]) { if(list_readers(state) == false) { ret = EXIT_FAILURE; } + case action_arg_writeMINUS_object: + if(write_object(state, args_info.id_arg, args_info.input_arg, verbosity, + args_info.format_arg) == false) { + ret = EXIT_FAILURE; + } + break; + case action_arg_readMINUS_object: + if(read_object(state, args_info.id_arg, args_info.output_arg, + args_info.format_arg) == false) { + ret = EXIT_FAILURE; + } break; case action_arg_attest: if(attest(state, args_info.slot_orig, args_info.key_format_arg, diff --git a/windows.mk b/windows.mk index af2de79..9612f98 100644 --- a/windows.mk +++ b/windows.mk @@ -26,7 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PACKAGE=yubico-piv-tool -OPENSSLVERSION=1.0.1p +OPENSSLVERSION=1.0.1r all: usage 32bit 64bit @@ -53,17 +53,14 @@ doit: rm -rf $(PWD)/tmp$(ARCH)/root/ssl/ && \ rm $(PWD)/tmp$(ARCH)/root/bin/openssl.exe && \ rm $(PWD)/tmp$(ARCH)/root/bin/c_rehash && \ - rm $(PWD)/tmp$(ARCH)/root/bin/ssleay32.dll && \ rm -rf $(PWD)/tmp$(ARCH)/root/lib/engines/ && \ - rm -rf $(PWD)/tmp$(ARCH)/root/lib/libssl* && \ - rm $(PWD)/tmp$(ARCH)/root/lib/pkgconfig/libssl.pc && \ - rm $(PWD)/tmp$(ARCH)/root/lib/pkgconfig/openssl.pc && \ cd .. && \ cp ../$(PACKAGE)-$(VERSION).tar.gz . && \ tar xfa $(PACKAGE)-$(VERSION).tar.gz && \ cd $(PACKAGE)-$(VERSION)/ && \ CC=$(HOST)-gcc PKG_CONFIG_PATH=$(PWD)/tmp$(ARCH)/root/lib/pkgconfig lt_cv_deplibs_check_method=pass_all ./configure --host=$(HOST) --build=x86_64-unknown-linux-gnu --prefix=$(PWD)/tmp$(ARCH)/root LDFLAGS=-L$(PWD)/tmp$(ARCH)/root/lib CPPFLAGS=-I$(PWD)/tmp$(ARCH)/root/include && \ make install $(CHECK) && \ + rm -rf $(PWD)/tmp$(ARCH)/root/lib/pkgconfig/ && \ cp COPYING $(PWD)/tmp$(ARCH)/root/licenses/$(PACKAGE).txt && \ cd .. && \ cd root && \ diff --git a/ykcs11/obj_types.h b/ykcs11/obj_types.h index ca4fc09..f861123 100644 --- a/ykcs11/obj_types.h +++ b/ykcs11/obj_types.h @@ -8,9 +8,29 @@ // TODO: this is mostly from OpenSC, how to give credit? typedef enum { PIV_DATA_OBJ_X509_PIV_AUTH = 0, // PIV authentication - PIV_DATA_OBJ_X509_CARD_AUTH, // Certificate for card authentication - PIV_DATA_OBJ_X509_DS, // Certificate for digital signature - PIV_DATA_OBJ_X509_KM, // Certificate for key management + PIV_DATA_OBJ_X509_CARD_AUTH, // Card authentication + PIV_DATA_OBJ_X509_DS, // Digital signature + PIV_DATA_OBJ_X509_KM, // Key management + PIV_DATA_OBJ_X509_RETIRED1, // Retired key 1 + PIV_DATA_OBJ_X509_RETIRED2, // Retired key 2 + PIV_DATA_OBJ_X509_RETIRED3, // Retired key 3 + PIV_DATA_OBJ_X509_RETIRED4, // Retired key 4 + PIV_DATA_OBJ_X509_RETIRED5, // Retired key 5 + PIV_DATA_OBJ_X509_RETIRED6, // Retired key 6 + PIV_DATA_OBJ_X509_RETIRED7, // Retired key 7 + PIV_DATA_OBJ_X509_RETIRED8, // Retired key 8 + PIV_DATA_OBJ_X509_RETIRED9, // Retired key 9 + PIV_DATA_OBJ_X509_RETIRED10, // Retired key 10 + PIV_DATA_OBJ_X509_RETIRED11, // Retired key 11 + PIV_DATA_OBJ_X509_RETIRED12, // Retired key 12 + PIV_DATA_OBJ_X509_RETIRED13, // Retired key 13 + PIV_DATA_OBJ_X509_RETIRED14, // Retired key 14 + PIV_DATA_OBJ_X509_RETIRED15, // Retired key 15 + PIV_DATA_OBJ_X509_RETIRED16, // Retired key 16 + PIV_DATA_OBJ_X509_RETIRED17, // Retired key 17 + PIV_DATA_OBJ_X509_RETIRED18, // Retired key 18 + PIV_DATA_OBJ_X509_RETIRED19, // Retired key 19 + PIV_DATA_OBJ_X509_RETIRED20, // Retired key 20 PIV_DATA_OBJ_CCC, // Card capability container PIV_DATA_OBJ_CHUI, // Cardholder unique id PIV_DATA_OBJ_CHF, // Cardholder fingerprints @@ -19,73 +39,88 @@ typedef enum { PIV_DATA_OBJ_PI, // Cardholder printed information PIV_DATA_OBJ_DISCOVERY, // Discovery object PIV_DATA_OBJ_HISTORY, // History object - PIV_DATA_OBJ_RETIRED_X509_1, // Retired certificate for KM 1 - PIV_DATA_OBJ_RETIRED_X509_2, // Retired certificate for KM 2 - PIV_DATA_OBJ_RETIRED_X509_3, // Retired certificate for KM 3 - PIV_DATA_OBJ_RETIRED_X509_4, // Retired certificate for KM 4 - PIV_DATA_OBJ_RETIRED_X509_5, // Retired certificate for KM 5 - PIV_DATA_OBJ_RETIRED_X509_6, // Retired certificate for KM 6 - PIV_DATA_OBJ_RETIRED_X509_7, // Retired certificate for KM 7 - PIV_DATA_OBJ_RETIRED_X509_8, // Retired certificate for KM 8 - PIV_DATA_OBJ_RETIRED_X509_9, // Retired certificate for KM 9 - PIV_DATA_OBJ_RETIRED_X509_10, // Retired certificate for KM 10 - PIV_DATA_OBJ_RETIRED_X509_11, // Retired certificate for KM 11 - PIV_DATA_OBJ_RETIRED_X509_12, // Retired certificate for KM 12 - PIV_DATA_OBJ_RETIRED_X509_13, // Retired certificate for KM 13 - PIV_DATA_OBJ_RETIRED_X509_14, // Retired certificate for KM 14 - PIV_DATA_OBJ_RETIRED_X509_15, // Retired certificate for KM 15 - PIV_DATA_OBJ_RETIRED_X509_16, // Retired certificate for KM 16 - PIV_DATA_OBJ_RETIRED_X509_17, // Retired certificate for KM 17 - PIV_DATA_OBJ_RETIRED_X509_18, // Retired certificate for KM 18 - PIV_DATA_OBJ_RETIRED_X509_19, // Retired certificate for KM 19 - PIV_DATA_OBJ_RETIRED_X509_20, // Retired certificate for KM 20 PIV_DATA_OBJ_IRIS_IMAGE, // Cardholder iris images PIV_DATA_OBJ_BITGT, // Biometric information templates group template PIV_DATA_OBJ_SM_SIGNER, // Secure messaging signer PIV_DATA_OBJ_PC_REF_DATA, // Pairing code reference data -/* PIV_DATA_OBJ_9B03, // NON-STANDARD TODO: remove? - PIV_DATA_OBJ_9A06, // NON-STANDARD - PIV_DATA_OBJ_9C06, // NON-STANDARD - PIV_DATA_OBJ_9D06, // NON-STANDARD - PIV_DATA_OBJ_9E06, // NON-STANDARD - PIV_DATA_OBJ_8206, // NON-STANDARD - PIV_DATA_OBJ_8306, // NON-STANDARD - PIV_DATA_OBJ_8406, // NON-STANDARD - PIV_DATA_OBJ_8506, // NON-STANDARD - PIV_DATA_OBJ_8606, // NON-STANDARD - PIV_DATA_OBJ_8706, // NON-STANDARD - PIV_DATA_OBJ_8806, // NON-STANDARD - PIV_DATA_OBJ_8906, // NON-STANDARD - PIV_DATA_OBJ_8A06, // NON-STANDARD - PIV_DATA_OBJ_8B06, // NON-STANDARD - PIV_DATA_OBJ_8C06, // NON-STANDARD - PIV_DATA_OBJ_8D06, // NON-STANDARD - PIV_DATA_OBJ_8E06, // NON-STANDARD - PIV_DATA_OBJ_8F06, // NON-STANDARD - PIV_DATA_OBJ_9006, // NON-STANDARD - PIV_DATA_OBJ_9106, // NON-STANDARD - PIV_DATA_OBJ_9206, // NON-STANDARD - PIV_DATA_OBJ_9306, // NON-STANDARD - PIV_DATA_OBJ_9406, // NON-STANDARD - PIV_DATA_OBJ_9506, // NON-STANDARD*/ PIV_DATA_OBJ_LAST, - PIV_CERT_OBJ_X509_PIV_AUTH, // PIV authentication + PIV_CERT_OBJ_X509_PIV_AUTH, // Certificate for PIV authentication PIV_CERT_OBJ_X509_CARD_AUTH, // Certificate for card authentication PIV_CERT_OBJ_X509_DS, // Certificate for digital signature PIV_CERT_OBJ_X509_KM, // Certificate for key management + PIV_CERT_OBJ_X509_RETIRED1, // Certificate for retired key 1 + PIV_CERT_OBJ_X509_RETIRED2, // Certificate for retired key 2 + PIV_CERT_OBJ_X509_RETIRED3, // Certificate for retired key 3 + PIV_CERT_OBJ_X509_RETIRED4, // Certificate for retired key 4 + PIV_CERT_OBJ_X509_RETIRED5, // Certificate for retired key 5 + PIV_CERT_OBJ_X509_RETIRED6, // Certificate for retired key 6 + PIV_CERT_OBJ_X509_RETIRED7, // Certificate for retired key 7 + PIV_CERT_OBJ_X509_RETIRED8, // Certificate for retired key 8 + PIV_CERT_OBJ_X509_RETIRED9, // Certificate for retired key 9 + PIV_CERT_OBJ_X509_RETIRED10, // Certificate for retired key 10 + PIV_CERT_OBJ_X509_RETIRED11, // Certificate for retired key 11 + PIV_CERT_OBJ_X509_RETIRED12, // Certificate for retired key 12 + PIV_CERT_OBJ_X509_RETIRED13, // Certificate for retired key 13 + PIV_CERT_OBJ_X509_RETIRED14, // Certificate for retired key 14 + PIV_CERT_OBJ_X509_RETIRED15, // Certificate for retired key 15 + PIV_CERT_OBJ_X509_RETIRED16, // Certificate for retired key 16 + PIV_CERT_OBJ_X509_RETIRED17, // Certificate for retired key 17 + PIV_CERT_OBJ_X509_RETIRED18, // Certificate for retired key 18 + PIV_CERT_OBJ_X509_RETIRED19, // Certificate for retired key 19 + PIV_CERT_OBJ_X509_RETIRED20, // Certificate for retired key 20 PIV_CERT_OBJ_LAST, PIV_PVTK_OBJ_PIV_AUTH, // Private key for PIV authentication - PIV_PVTK_OBJ_CARD_AUTH, // Private Key for card authentication - PIV_PVTK_OBJ_DS, // Private Key for digital signature - PIV_PVTK_OBJ_KM, // Private Key for key management + PIV_PVTK_OBJ_CARD_AUTH, // Private key for card authentication + PIV_PVTK_OBJ_DS, // Private key for digital signature + PIV_PVTK_OBJ_KM, // Private key for key management + PIV_PVTK_OBJ_RETIRED1, // Private key for retired key 1 + PIV_PVTK_OBJ_RETIRED2, // Private key for retired key 2 + PIV_PVTK_OBJ_RETIRED3, // Private key for retired key 3 + PIV_PVTK_OBJ_RETIRED4, // Private key for retired key 4 + PIV_PVTK_OBJ_RETIRED5, // Private key for retired key 5 + PIV_PVTK_OBJ_RETIRED6, // Private key for retired key 6 + PIV_PVTK_OBJ_RETIRED7, // Private key for retired key 7 + PIV_PVTK_OBJ_RETIRED8, // Private key for retired key 8 + PIV_PVTK_OBJ_RETIRED9, // Private key for retired key 9 + PIV_PVTK_OBJ_RETIRED10, // Private key for retired key 10 + PIV_PVTK_OBJ_RETIRED11, // Private key for retired key 11 + PIV_PVTK_OBJ_RETIRED12, // Private key for retired key 12 + PIV_PVTK_OBJ_RETIRED13, // Private key for retired key 13 + PIV_PVTK_OBJ_RETIRED14, // Private key for retired key 14 + PIV_PVTK_OBJ_RETIRED15, // Private key for retired key 15 + PIV_PVTK_OBJ_RETIRED16, // Private key for retired key 16 + PIV_PVTK_OBJ_RETIRED17, // Private key for retired key 17 + PIV_PVTK_OBJ_RETIRED18, // Private key for retired key 18 + PIV_PVTK_OBJ_RETIRED19, // Private key for retired key 19 + PIV_PVTK_OBJ_RETIRED20, // Private key for retired key 20 PIV_PVTK_OBJ_LAST, PIV_PUBK_OBJ_PIV_AUTH, // Public key for PIV authentication - PIV_PUBK_OBJ_CARD_AUTH, // Public Key for card authentication - PIV_PUBK_OBJ_DS, // Public Key for digital signature - PIV_PUBK_OBJ_KM, // Public Key for key management + PIV_PUBK_OBJ_CARD_AUTH, // Public key for card authentication + PIV_PUBK_OBJ_DS, // Public key for digital signature + PIV_PUBK_OBJ_KM, // Public key for key management + PIV_PUBK_OBJ_RETIRED1, // Public key for retired key 1 + PIV_PUBK_OBJ_RETIRED2, // Public key for retired key 2 + PIV_PUBK_OBJ_RETIRED3, // Public key for retired key 3 + PIV_PUBK_OBJ_RETIRED4, // Public key for retired key 4 + PIV_PUBK_OBJ_RETIRED5, // Public key for retired key 5 + PIV_PUBK_OBJ_RETIRED6, // Public key for retired key 6 + PIV_PUBK_OBJ_RETIRED7, // Public key for retired key 7 + PIV_PUBK_OBJ_RETIRED8, // Public key for retired key 8 + PIV_PUBK_OBJ_RETIRED9, // Public key for retired key 9 + PIV_PUBK_OBJ_RETIRED10, // Public key for retired key 10 + PIV_PUBK_OBJ_RETIRED11, // Public key for retired key 11 + PIV_PUBK_OBJ_RETIRED12, // Public key for retired key 12 + PIV_PUBK_OBJ_RETIRED13, // Public key for retired key 13 + PIV_PUBK_OBJ_RETIRED14, // Public key for retired key 14 + PIV_PUBK_OBJ_RETIRED15, // Public key for retired key 15 + PIV_PUBK_OBJ_RETIRED16, // Public key for retired key 16 + PIV_PUBK_OBJ_RETIRED17, // Public key for retired key 17 + PIV_PUBK_OBJ_RETIRED18, // Public key for retired key 18 + PIV_PUBK_OBJ_RETIRED19, // Public key for retired key 19 + PIV_PUBK_OBJ_RETIRED20, // Public key for retired key 20 PIV_PUBK_OBJ_LAST } piv_obj_id_t; diff --git a/ykcs11/objects.c b/ykcs11/objects.c index b18fee4..c94af52 100644 --- a/ykcs11/objects.c +++ b/ykcs11/objects.c @@ -24,34 +24,34 @@ static piv_obj_t piv_objects[] = { {PIV_DATA_OBJ_X509_CARD_AUTH, 1, 0, 0, "X.509 Certificate for Card Authentication", 0, 0, get_doa, 1}, {PIV_DATA_OBJ_X509_DS, 1, 0, 0, "X.509 Certificate for Digital Signature", 0, 0, get_doa, 2}, {PIV_DATA_OBJ_X509_KM, 1, 0, 0, "X.509 Certificate for Key Management", 0, 0, get_doa, 3}, - {PIV_DATA_OBJ_CCC, 1, 0, 0, "Card Capability Container", 0, 0, get_doa, 4}, - {PIV_DATA_OBJ_CHUI, 1, 0, 0, "Card Holder Unique Identifier", 0, 0, get_doa, 5}, - {PIV_DATA_OBJ_CHF, 1, 1, 0, "Card Holder Fingerprints", 0, 0, get_doa, 6}, - {PIV_DATA_OBJ_SEC_OBJ, 1, 0, 0, "Security Object", 0, 0, get_doa, 7}, - {PIV_DATA_OBJ_CHFI, 1, 1, 0, "Cardholder Facial Images", 0, 0, get_doa, 8}, - {PIV_DATA_OBJ_PI, 1, 1, 0, "Printed Information", 0, 0, get_doa, 9}, - {PIV_DATA_OBJ_DISCOVERY, 1, 0, 0, "Discovery Object", 0, 0, get_doa, 10}, - {PIV_DATA_OBJ_HISTORY, 1, 0, 0, "Key History Object", 0, 0, get_doa, 11}, - {PIV_DATA_OBJ_RETIRED_X509_1, 1, 0, 0, "Retired X.509 Certificate for Key Management 1", 0, 0, get_doa, 12}, - {PIV_DATA_OBJ_RETIRED_X509_2, 1, 0, 0, "Retired X.509 Certificate for Key Management 2", 0, 0, get_doa, 13}, - {PIV_DATA_OBJ_RETIRED_X509_3, 1, 0, 0, "Retired X.509 Certificate for Key Management 3", 0, 0, get_doa, 14}, - {PIV_DATA_OBJ_RETIRED_X509_4, 1, 0, 0, "Retired X.509 Certificate for Key Management 4", 0, 0, get_doa, 15}, - {PIV_DATA_OBJ_RETIRED_X509_5, 1, 0, 0, "Retired X.509 Certificate for Key Management 5", 0, 0, get_doa, 16}, - {PIV_DATA_OBJ_RETIRED_X509_6, 1, 0, 0, "Retired X.509 Certificate for Key Management 6", 0, 0, get_doa, 17}, - {PIV_DATA_OBJ_RETIRED_X509_7, 1, 0, 0, "Retired X.509 Certificate for Key Management 7", 0, 0, get_doa, 18}, - {PIV_DATA_OBJ_RETIRED_X509_8, 1, 0, 0, "Retired X.509 Certificate for Key Management 8", 0, 0, get_doa, 19}, - {PIV_DATA_OBJ_RETIRED_X509_9, 1, 0, 0, "Retired X.509 Certificate for Key Management 9", 0, 0, get_doa, 20}, - {PIV_DATA_OBJ_RETIRED_X509_10, 1, 0, 0, "Retired X.509 Certificate for Key Management 10", 0, 0, get_doa, 21}, - {PIV_DATA_OBJ_RETIRED_X509_11, 1, 0, 0, "Retired X.509 Certificate for Key Management 11", 0, 0, get_doa, 22}, - {PIV_DATA_OBJ_RETIRED_X509_12, 1, 0, 0, "Retired X.509 Certificate for Key Management 12", 0, 0, get_doa, 23}, - {PIV_DATA_OBJ_RETIRED_X509_13, 1, 0, 0, "Retired X.509 Certificate for Key Management 13", 0, 0, get_doa, 24}, - {PIV_DATA_OBJ_RETIRED_X509_14, 1, 0, 0, "Retired X.509 Certificate for Key Management 14", 0, 0, get_doa, 25}, - {PIV_DATA_OBJ_RETIRED_X509_15, 1, 0, 0, "Retired X.509 Certificate for Key Management 15", 0, 0, get_doa, 26}, - {PIV_DATA_OBJ_RETIRED_X509_16, 1, 0, 0, "Retired X.509 Certificate for Key Management 16", 0, 0, get_doa, 27}, - {PIV_DATA_OBJ_RETIRED_X509_17, 1, 0, 0, "Retired X.509 Certificate for Key Management 17", 0, 0, get_doa, 28}, - {PIV_DATA_OBJ_RETIRED_X509_18, 1, 0, 0, "Retired X.509 Certificate for Key Management 18", 0, 0, get_doa, 29}, - {PIV_DATA_OBJ_RETIRED_X509_19, 1, 0, 0, "Retired X.509 Certificate for Key Management 19", 0, 0, get_doa, 30}, - {PIV_DATA_OBJ_RETIRED_X509_20, 1, 0, 0, "Retired X.509 Certificate for Key Management 20", 0, 0, get_doa, 31}, + {PIV_DATA_OBJ_X509_RETIRED1, 1, 0, 0, "X.509 Certificate for Retired Key 1", 0, 0, get_doa, 4}, + {PIV_DATA_OBJ_X509_RETIRED2, 1, 0, 0, "X.509 Certificate for Retired Key 2", 0, 0, get_doa, 5}, + {PIV_DATA_OBJ_X509_RETIRED3, 1, 0, 0, "X.509 Certificate for Retired Key 3", 0, 0, get_doa, 6}, + {PIV_DATA_OBJ_X509_RETIRED4, 1, 0, 0, "X.509 Certificate for Retired Key 4", 0, 0, get_doa, 7}, + {PIV_DATA_OBJ_X509_RETIRED5, 1, 0, 0, "X.509 Certificate for Retired Key 5", 0, 0, get_doa, 8}, + {PIV_DATA_OBJ_X509_RETIRED6, 1, 0, 0, "X.509 Certificate for Retired Key 6", 0, 0, get_doa, 9}, + {PIV_DATA_OBJ_X509_RETIRED7, 1, 0, 0, "X.509 Certificate for Retired Key 7", 0, 0, get_doa, 10}, + {PIV_DATA_OBJ_X509_RETIRED8, 1, 0, 0, "X.509 Certificate for Retired Key 8", 0, 0, get_doa, 11}, + {PIV_DATA_OBJ_X509_RETIRED9, 1, 0, 0, "X.509 Certificate for Retired Key 9", 0, 0, get_doa, 12}, + {PIV_DATA_OBJ_X509_RETIRED10, 1, 0, 0, "X.509 Certificate for Retired Key 10", 0, 0, get_doa, 13}, + {PIV_DATA_OBJ_X509_RETIRED11, 1, 0, 0, "X.509 Certificate for Retired Key 11", 0, 0, get_doa, 14}, + {PIV_DATA_OBJ_X509_RETIRED12, 1, 0, 0, "X.509 Certificate for Retired Key 12", 0, 0, get_doa, 15}, + {PIV_DATA_OBJ_X509_RETIRED13, 1, 0, 0, "X.509 Certificate for Retired Key 13", 0, 0, get_doa, 16}, + {PIV_DATA_OBJ_X509_RETIRED14, 1, 0, 0, "X.509 Certificate for Retired Key 14", 0, 0, get_doa, 17}, + {PIV_DATA_OBJ_X509_RETIRED15, 1, 0, 0, "X.509 Certificate for Retired Key 15", 0, 0, get_doa, 18}, + {PIV_DATA_OBJ_X509_RETIRED16, 1, 0, 0, "X.509 Certificate for Retired Key 16", 0, 0, get_doa, 19}, + {PIV_DATA_OBJ_X509_RETIRED17, 1, 0, 0, "X.509 Certificate for Retired Key 17", 0, 0, get_doa, 20}, + {PIV_DATA_OBJ_X509_RETIRED18, 1, 0, 0, "X.509 Certificate for Retired Key 18", 0, 0, get_doa, 21}, + {PIV_DATA_OBJ_X509_RETIRED19, 1, 0, 0, "X.509 Certificate for Retired Key 19", 0, 0, get_doa, 22}, + {PIV_DATA_OBJ_X509_RETIRED20, 1, 0, 0, "X.509 Certificate for Retired Key 20", 0, 0, get_doa, 23}, + {PIV_DATA_OBJ_CCC, 1, 0, 0, "Card Capability Container", 0, 0, get_doa, 24}, + {PIV_DATA_OBJ_CHUI, 1, 0, 0, "Card Holder Unique Identifier", 0, 0, get_doa, 25}, + {PIV_DATA_OBJ_CHF, 1, 1, 0, "Card Holder Fingerprints", 0, 0, get_doa, 26}, + {PIV_DATA_OBJ_SEC_OBJ, 1, 0, 0, "Security Object", 0, 0, get_doa, 27}, + {PIV_DATA_OBJ_CHFI, 1, 1, 0, "Cardholder Facial Images", 0, 0, get_doa, 28}, + {PIV_DATA_OBJ_PI, 1, 1, 0, "Printed Information", 0, 0, get_doa, 29}, + {PIV_DATA_OBJ_DISCOVERY, 1, 0, 0, "Discovery Object", 0, 0, get_doa, 30}, + {PIV_DATA_OBJ_HISTORY, 1, 0, 0, "Key History Object", 0, 0, get_doa, 31}, {PIV_DATA_OBJ_IRIS_IMAGE, 1, 1, 0, "Cardholder Iris Images", 0, 0, get_doa, 32}, {PIV_DATA_OBJ_BITGT, 1, 0, 0, "Biometric Information Templates Group Template", 0, 0, get_doa, 33}, {PIV_DATA_OBJ_SM_SIGNER, 1, 0, 0, "Secure Messaging Certificate Signer", 0, 0, get_doa, 34}, @@ -62,63 +62,142 @@ static piv_obj_t piv_objects[] = { {PIV_CERT_OBJ_X509_CARD_AUTH, 1, 0, 0, "X.509 Certificate for Card Authentication", 0, 0, get_coa, 1}, {PIV_CERT_OBJ_X509_DS, 1, 0, 0, "X.509 Certificate for Digital Signature", 0, 0, get_coa, 2}, {PIV_CERT_OBJ_X509_KM, 1, 0, 0, "X.509 Certificate for Key Management", 0, 0, get_coa, 3}, - {PIV_CERT_OBJ_LAST, 1, 0, 0, "", 0, 0, NULL, 4}, + {PIV_CERT_OBJ_X509_RETIRED1, 1, 0, 0, "X.509 Certificate for Retired Key 1", 0, 0, get_coa, 4}, + {PIV_CERT_OBJ_X509_RETIRED2, 1, 0, 0, "X.509 Certificate for Retired Key 2", 0, 0, get_coa, 5}, + {PIV_CERT_OBJ_X509_RETIRED3, 1, 0, 0, "X.509 Certificate for Retired Key 3", 0, 0, get_coa, 6}, + {PIV_CERT_OBJ_X509_RETIRED4, 1, 0, 0, "X.509 Certificate for Retired Key 4", 0, 0, get_coa, 7}, + {PIV_CERT_OBJ_X509_RETIRED5, 1, 0, 0, "X.509 Certificate for Retired Key 5", 0, 0, get_coa, 8}, + {PIV_CERT_OBJ_X509_RETIRED6, 1, 0, 0, "X.509 Certificate for Retired Key 6", 0, 0, get_coa, 9}, + {PIV_CERT_OBJ_X509_RETIRED7, 1, 0, 0, "X.509 Certificate for Retired Key 7", 0, 0, get_coa, 10}, + {PIV_CERT_OBJ_X509_RETIRED8, 1, 0, 0, "X.509 Certificate for Retired Key 8", 0, 0, get_coa, 11}, + {PIV_CERT_OBJ_X509_RETIRED9, 1, 0, 0, "X.509 Certificate for Retired Key 9", 0, 0, get_coa, 12}, + {PIV_CERT_OBJ_X509_RETIRED10, 1, 0, 0, "X.509 Certificate for Retired Key 10", 0, 0, get_coa, 13}, + {PIV_CERT_OBJ_X509_RETIRED11, 1, 0, 0, "X.509 Certificate for Retired Key 11", 0, 0, get_coa, 14}, + {PIV_CERT_OBJ_X509_RETIRED12, 1, 0, 0, "X.509 Certificate for Retired Key 12", 0, 0, get_coa, 15}, + {PIV_CERT_OBJ_X509_RETIRED13, 1, 0, 0, "X.509 Certificate for Retired Key 13", 0, 0, get_coa, 16}, + {PIV_CERT_OBJ_X509_RETIRED14, 1, 0, 0, "X.509 Certificate for Retired Key 14", 0, 0, get_coa, 17}, + {PIV_CERT_OBJ_X509_RETIRED15, 1, 0, 0, "X.509 Certificate for Retired Key 15", 0, 0, get_coa, 18}, + {PIV_CERT_OBJ_X509_RETIRED16, 1, 0, 0, "X.509 Certificate for Retired Key 16", 0, 0, get_coa, 19}, + {PIV_CERT_OBJ_X509_RETIRED17, 1, 0, 0, "X.509 Certificate for Retired Key 17", 0, 0, get_coa, 20}, + {PIV_CERT_OBJ_X509_RETIRED18, 1, 0, 0, "X.509 Certificate for Retired Key 18", 0, 0, get_coa, 21}, + {PIV_CERT_OBJ_X509_RETIRED19, 1, 0, 0, "X.509 Certificate for Retired Key 19", 0, 0, get_coa, 22}, + {PIV_CERT_OBJ_X509_RETIRED20, 1, 0, 0, "X.509 Certificate for Retired Key 20", 0, 0, get_coa, 23}, + {PIV_CERT_OBJ_LAST, 1, 0, 0, "", 0, 0, NULL, 24}, {PIV_PVTK_OBJ_PIV_AUTH, 1, 1, 0, "Private key for PIV Authentication", 0, 0, get_proa, 0}, // 9a {PIV_PVTK_OBJ_CARD_AUTH, 1, 0, 0, "Private key for Card Authentication", 0, 0, get_proa, 1}, // 9e {PIV_PVTK_OBJ_DS, 1, 1, 0, "Private key for Digital Signature", 0, 0, get_proa, 2}, // 9c {PIV_PVTK_OBJ_KM, 1, 1, 0, "Private key for Key Management", 0, 0, get_proa, 3}, // 9d - {PIV_PVTK_OBJ_LAST, 1, 0, 0, "", 0, 0, NULL, 4}, + {PIV_PVTK_OBJ_RETIRED1, 1, 1, 0, "Private key for Retired Key 1", 0, 0, get_proa, 4}, + {PIV_PVTK_OBJ_RETIRED2, 1, 1, 0, "Private key for Retired Key 2", 0, 0, get_proa, 5}, + {PIV_PVTK_OBJ_RETIRED3, 1, 1, 0, "Private key for Retired Key 3", 0, 0, get_proa, 6}, + {PIV_PVTK_OBJ_RETIRED4, 1, 1, 0, "Private key for Retired Key 4", 0, 0, get_proa, 7}, + {PIV_PVTK_OBJ_RETIRED5, 1, 1, 0, "Private key for Retired Key 5", 0, 0, get_proa, 8}, + {PIV_PVTK_OBJ_RETIRED6, 1, 1, 0, "Private key for Retired Key 6", 0, 0, get_proa, 9}, + {PIV_PVTK_OBJ_RETIRED7, 1, 1, 0, "Private key for Retired Key 7", 0, 0, get_proa, 10}, + {PIV_PVTK_OBJ_RETIRED8, 1, 1, 0, "Private key for Retired Key 8", 0, 0, get_proa, 11}, + {PIV_PVTK_OBJ_RETIRED9, 1, 1, 0, "Private key for Retired Key 9", 0, 0, get_proa, 12}, + {PIV_PVTK_OBJ_RETIRED10, 1, 1, 0, "Private key forRretired Key 10", 0, 0, get_proa, 13}, + {PIV_PVTK_OBJ_RETIRED11, 1, 1, 0, "Private key forRretired Key 11", 0, 0, get_proa, 14}, + {PIV_PVTK_OBJ_RETIRED12, 1, 1, 0, "Private key forRretired Key 12", 0, 0, get_proa, 15}, + {PIV_PVTK_OBJ_RETIRED13, 1, 1, 0, "Private key forRretired Key 13", 0, 0, get_proa, 16}, + {PIV_PVTK_OBJ_RETIRED14, 1, 1, 0, "Private key forRretired Key 14", 0, 0, get_proa, 17}, + {PIV_PVTK_OBJ_RETIRED15, 1, 1, 0, "Private key forRretired Key 15", 0, 0, get_proa, 18}, + {PIV_PVTK_OBJ_RETIRED16, 1, 1, 0, "Private key forRretired Key 16", 0, 0, get_proa, 19}, + {PIV_PVTK_OBJ_RETIRED17, 1, 1, 0, "Private key forRretired Key 17", 0, 0, get_proa, 20}, + {PIV_PVTK_OBJ_RETIRED18, 1, 1, 0, "Private key forRretired Key 18", 0, 0, get_proa, 21}, + {PIV_PVTK_OBJ_RETIRED19, 1, 1, 0, "Private key forRretired Key 19", 0, 0, get_proa, 22}, + {PIV_PVTK_OBJ_RETIRED20, 1, 1, 0, "Private key forRretired Key 20", 0, 0, get_proa, 23}, + {PIV_PVTK_OBJ_LAST, 1, 0, 0, "", 0, 0, NULL, 24}, {PIV_PUBK_OBJ_PIV_AUTH, 1, 0, 0, "Public key for PIV Authentication", 0, 0, get_puoa, 0}, {PIV_PUBK_OBJ_CARD_AUTH, 1, 0, 0, "Public key for Card Authentication", 0, 0, get_puoa, 1}, {PIV_PUBK_OBJ_DS, 1, 0, 0, "Public key for Digital Signature", 0, 0, get_puoa, 2}, {PIV_PUBK_OBJ_KM, 1, 0, 0, "Public key for Key Management", 0, 0, get_puoa, 3}, - {PIV_PUBK_OBJ_LAST, 1, 0, 0, "", 0, 0, NULL, 4} + {PIV_PUBK_OBJ_RETIRED1, 1, 0, 0, "Public key for Retired Key 1", 0, 0, get_puoa, 4}, + {PIV_PUBK_OBJ_RETIRED2, 1, 0, 0, "Public key for Retired Key 2", 0, 0, get_puoa, 5}, + {PIV_PUBK_OBJ_RETIRED3, 1, 0, 0, "Public key for Retired Key 3", 0, 0, get_puoa, 6}, + {PIV_PUBK_OBJ_RETIRED4, 1, 0, 0, "Public key for Retired Key 4", 0, 0, get_puoa, 7}, + {PIV_PUBK_OBJ_RETIRED5, 1, 0, 0, "Public key for Retired Key 5", 0, 0, get_puoa, 8}, + {PIV_PUBK_OBJ_RETIRED6, 1, 0, 0, "Public key for Retired Key 6", 0, 0, get_puoa, 9}, + {PIV_PUBK_OBJ_RETIRED7, 1, 0, 0, "Public key for Retired Key 7", 0, 0, get_puoa, 10}, + {PIV_PUBK_OBJ_RETIRED8, 1, 0, 0, "Public key for Retired Key 8", 0, 0, get_puoa, 11}, + {PIV_PUBK_OBJ_RETIRED9, 1, 0, 0, "Public key for Retired Key 9", 0, 0, get_puoa, 12}, + {PIV_PUBK_OBJ_RETIRED10, 1, 0, 0, "Public key for Retired Key 10", 0, 0, get_puoa, 13}, + {PIV_PUBK_OBJ_RETIRED11, 1, 0, 0, "Public key for Retired Key 11", 0, 0, get_puoa, 14}, + {PIV_PUBK_OBJ_RETIRED12, 1, 0, 0, "Public key for Retired Key 12", 0, 0, get_puoa, 15}, + {PIV_PUBK_OBJ_RETIRED13, 1, 0, 0, "Public key for Retired Key 13", 0, 0, get_puoa, 16}, + {PIV_PUBK_OBJ_RETIRED14, 1, 0, 0, "Public key for Retired Key 14", 0, 0, get_puoa, 17}, + {PIV_PUBK_OBJ_RETIRED15, 1, 0, 0, "Public key for Retired Key 15", 0, 0, get_puoa, 18}, + {PIV_PUBK_OBJ_RETIRED16, 1, 0, 0, "Public key for Retired Key 16", 0, 0, get_puoa, 19}, + {PIV_PUBK_OBJ_RETIRED17, 1, 0, 0, "Public key for Retired Key 17", 0, 0, get_puoa, 20}, + {PIV_PUBK_OBJ_RETIRED18, 1, 0, 0, "Public key for Retired Key 18", 0, 0, get_puoa, 21}, + {PIV_PUBK_OBJ_RETIRED19, 1, 0, 0, "Public key for Retired Key 19", 0, 0, get_puoa, 22}, + {PIV_PUBK_OBJ_RETIRED20, 1, 0, 0, "Public key for Retired Key 20", 0, 0, get_puoa, 23}, + {PIV_PUBK_OBJ_LAST, 1, 0, 0, "", 0, 0, NULL, 24} }; static piv_data_obj_t data_objects[] = { - {"2.16.840.1.101.3.7.2.1.1", 3, "\x5F\xC1\x05", "\x01\x01"}, - {"2.16.840.1.101.3.7.2.5.0", 3, "\x5F\xC1\x01", "\x05\x00"}, - {"2.16.840.1.101.3.7.2.1.0", 3, "\x5F\xC1\x0A", "\x01\x00"}, - {"2.16.840.1.101.3.7.2.1.2", 3, "\x5F\xC1\x0B", "\x01\x02"}, - {"2.16.840.1.101.3.7.1.219.0", 3, "\x5F\xC1\x07", "\xDB\x00"}, - {"2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00"}, - {"2.16.840.1.101.3.7.2.96.16", 3, "\x5F\xC1\x03", "\x60\x10"}, - {"2.16.840.1.101.3.7.2.144.0", 3, "\x5F\xC1\x06", "\x90\x00"}, - {"2.16.840.1.101.3.7.2.96.48", 3, "\x5F\xC1\x08", "\x60\x30"}, - {"2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x09", "\x30\x01"}, - {"2.16.840.1.101.3.7.2.96.80", 1, "\x7E", "\x60\x50"}, - {"2.16.840.1.101.3.7.2.96.96", 3, "\x5F\xC1\x0C", "\x60\x60"}, - -/* 800-73-3, 21 new objects, 20 history certificates */ - {"2.16.840.1.101.3.7.2.16.1", 3, "\x5F\xC1\x0D", "\x10\x01"}, - {"2.16.840.1.101.3.7.2.16.2", 3, "\x5F\xC1\x0E", "\x10\x02"}, - {"2.16.840.1.101.3.7.2.16.3", 3, "\x5F\xC1\x0F", "\x10\x03"}, - {"2.16.840.1.101.3.7.2.16.4", 3, "\x5F\xC1\x10", "\x10\x04"}, - {"2.16.840.1.101.3.7.2.16.5", 3, "\x5F\xC1\x11", "\x10\x05"}, - {"2.16.840.1.101.3.7.2.16.7", 3, "\x5F\xC1\x13", "\x10\x07"}, - {"2.16.840.1.101.3.7.2.16.8", 3, "\x5F\xC1\x14", "\x10\x08"}, - {"2.16.840.1.101.3.7.2.16.9", 3, "\x5F\xC1\x15", "\x10\x09"}, - {"2.16.840.1.101.3.7.2.16.10", 3, "\x5F\xC1\x16", "\x10\x0A"}, - {"2.16.840.1.101.3.7.2.16.11", 3, "\x5F\xC1\x17", "\x10\x0B"}, - {"2.16.840.1.101.3.7.2.16.12", 3, "\x5F\xC1\x18", "\x10\x0C"}, - {"2.16.840.1.101.3.7.2.16.13", 3, "\x5F\xC1\x19", "\x10\x0D"}, - {"2.16.840.1.101.3.7.2.16.14", 3, "\x5F\xC1\x1A", "\x10\x0E"}, - {"2.16.840.1.101.3.7.2.16.15", 3, "\x5F\xC1\x1B", "\x10\x0F"}, - {"2.16.840.1.101.3.7.2.16.16", 3, "\x5F\xC1\x1C", "\x10\x10"}, - {"2.16.840.1.101.3.7.2.16.17", 3, "\x5F\xC1\x1D", "\x10\x11"}, - {"2.16.840.1.101.3.7.2.16.18", 3, "\x5F\xC1\x1E", "\x10\x12"}, - {"2.16.840.1.101.3.7.2.16.19", 3, "\x5F\xC1\x1F", "\x10\x13"}, - {"2.16.840.1.101.3.7.2.16.20", 3, "\x5F\xC1\x20", "\x10\x14"}, - {"2.16.840.1.101.3.7.2.16.21", 3, "\x5F\xC1\x21", "\x10\x15"}, - {"2.16.840.1.101.3.7.2.16.22", 2, "\x7F\x61", "\x10\x16"}, - {"2.16.840.1.101.3.7.2.16.23", 3, "\x5F\xC1\x22", "\x10\x17"}, - {"2.16.840.1.101.3.7.2.16.24", 3, "\x5F\xC1\x23", "\x10\x18"}, + {"2.16.840.1.101.3.7.2.1.1", 3, "\x5F\xC1\x05", "\x01\x01"}, // PIV Authentication + {"2.16.840.1.101.3.7.2.5.0", 3, "\x5F\xC1\x01", "\x05\x00"}, // Card Authentication + {"2.16.840.1.101.3.7.2.1.0", 3, "\x5F\xC1\x0A", "\x01\x00"}, // Digital Signature + {"2.16.840.1.101.3.7.2.1.2", 3, "\x5F\xC1\x0B", "\x01\x02"}, // Key Management + {"2.16.840.1.101.3.7.2.16.1", 3, "\x5F\xC1\x0D", "\x10\x01"}, // Retired Key 1 + {"2.16.840.1.101.3.7.2.16.2", 3, "\x5F\xC1\x0E", "\x10\x02"}, // Retired Key 2 + {"2.16.840.1.101.3.7.2.16.3", 3, "\x5F\xC1\x0F", "\x10\x03"}, // Retired Key 3 + {"2.16.840.1.101.3.7.2.16.4", 3, "\x5F\xC1\x10", "\x10\x04"}, // Retired Key 4 + {"2.16.840.1.101.3.7.2.16.5", 3, "\x5F\xC1\x11", "\x10\x05"}, // Retired Key 5 + {"2.16.840.1.101.3.7.2.16.6", 3, "\x5F\xC1\x12", "\x10\x06"}, // Retired Key 6 + {"2.16.840.1.101.3.7.2.16.7", 3, "\x5F\xC1\x13", "\x10\x07"}, // Retired Key 7 + {"2.16.840.1.101.3.7.2.16.8", 3, "\x5F\xC1\x14", "\x10\x08"}, // Retired Key 8 + {"2.16.840.1.101.3.7.2.16.9", 3, "\x5F\xC1\x15", "\x10\x09"}, // Retired Key 9 + {"2.16.840.1.101.3.7.2.16.10", 3, "\x5F\xC1\x16", "\x10\x0A"}, // Retired Key 10 + {"2.16.840.1.101.3.7.2.16.11", 3, "\x5F\xC1\x17", "\x10\x0B"}, // Retired Key 11 + {"2.16.840.1.101.3.7.2.16.12", 3, "\x5F\xC1\x18", "\x10\x0C"}, // Retired Key 12 + {"2.16.840.1.101.3.7.2.16.13", 3, "\x5F\xC1\x19", "\x10\x0D"}, // Retired Key 13 + {"2.16.840.1.101.3.7.2.16.14", 3, "\x5F\xC1\x1A", "\x10\x0E"}, // Retired Key 14 + {"2.16.840.1.101.3.7.2.16.15", 3, "\x5F\xC1\x1B", "\x10\x0F"}, // Retired Key 15 + {"2.16.840.1.101.3.7.2.16.16", 3, "\x5F\xC1\x1C", "\x10\x10"}, // Retired Key 16 + {"2.16.840.1.101.3.7.2.16.17", 3, "\x5F\xC1\x1D", "\x10\x11"}, // Retired Key 17 + {"2.16.840.1.101.3.7.2.16.18", 3, "\x5F\xC1\x1E", "\x10\x12"}, // Retired Key 18 + {"2.16.840.1.101.3.7.2.16.19", 3, "\x5F\xC1\x1F", "\x10\x13"}, // Retired Key 19 + {"2.16.840.1.101.3.7.2.16.20", 3, "\x5F\xC1\x20", "\x10\x14"}, // Retired Key 20 + {"2.16.840.1.101.3.7.1.219.0", 3, "\x5F\xC1\x07", "\xDB\x00"}, // CCC + {"2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00"}, // CHUID + {"2.16.840.1.101.3.7.2.96.16", 3, "\x5F\xC1\x03", "\x60\x10"}, // CHFP + {"2.16.840.1.101.3.7.2.144.0", 3, "\x5F\xC1\x06", "\x90\x00"}, // Security Object + {"2.16.840.1.101.3.7.2.96.48", 3, "\x5F\xC1\x08", "\x60\x30"}, // CHFI + {"2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x09", "\x30\x01"}, // Printed Information + {"2.16.840.1.101.3.7.2.96.80", 1, "\x7E", "\x60\x50"}, // Discovery Object + {"2.16.840.1.101.3.7.2.96.96", 3, "\x5F\xC1\x0C", "\x60\x60"}, // Key History Object + {"2.16.840.1.101.3.7.2.16.21", 3, "\x5F\xC1\x21", "\x10\x15"}, // CHII + {"2.16.840.1.101.3.7.2.16.22", 2, "\x7F\x61", "\x10\x16"}, // Biometric Information + {"2.16.840.1.101.3.7.2.16.23", 3, "\x5F\xC1\x22", "\x10\x17"}, // Secure Messaging Certificate Signer + {"2.16.840.1.101.3.7.2.16.24", 3, "\x5F\xC1\x23", "\x10\x18"}, // Pairing Code Reference Data Container {"", 0, "", ""} }; static piv_cert_obj_t cert_objects[] = { + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, {NULL}, {NULL}, {NULL}, @@ -131,10 +210,50 @@ static piv_pvtk_obj_t pvtkey_objects[] = { {1, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {1, 1, 0, 0, 1}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, {1, 1, 0, 0, 0} }; static piv_pubk_obj_t pubkey_objects[] = { + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, + {NULL, 1, 1, 0, 0}, {NULL, 1, 1, 0, 0}, {NULL, 1, 1, 0, 0}, {NULL, 1, 1, 0, 0}, @@ -221,8 +340,12 @@ static CK_ULONG get_modulus_bits(EVP_PKEY *key) { return do_get_rsa_modulus_length(key); } -static CK_ULONG get_public_exponent(EVP_PKEY *key) { - return do_get_public_exponent(key); +static CK_RV get_public_exponent(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) { + return do_get_public_exponent(key, data, len); +} + +static CK_RV get_modulus(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) { + return do_get_modulus(key, data, len); } static CK_RV get_public_key(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) { @@ -285,7 +408,7 @@ CK_RV get_doa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_OBJECT_ID: // TODO: how about just storing the OID in DER ? DBG("OID"); - strcpy((char *)tmp, data_objects[piv_objects[obj].sub_id].oid); + memcpy((char *)tmp, data_objects[piv_objects[obj].sub_id].oid, sizeof(tmp)); asn1_encode_oid(tmp, tmp, &len); data = tmp; break; @@ -374,15 +497,15 @@ CK_RV get_coa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_ISSUER: DBG("ISSUER TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_SERIAL_NUMBER: DBG("SERIAL NUMBER TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_SUBJECT: DBG("SUBJECT TODO"); // Required - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_ID: DBG("ID"); @@ -393,11 +516,11 @@ CK_RV get_coa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_START_DATE: DBG("START DATE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_END_DATE: DBG("END DATE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_MODIFIABLE: DBG("MODIFIABLE"); @@ -477,7 +600,7 @@ CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_SUBJECT: DBG("SUBJECT TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_ID: DBG("ID"); @@ -488,7 +611,7 @@ CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_SENSITIVE: DBG("SENSITIVE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_DECRYPT: DBG("DECRYPT"); // Default empy @@ -513,7 +636,7 @@ CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_SIGN_RECOVER: DBG("SIGN RECOVER TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_DERIVE: DBG("DERIVE"); // Default false @@ -524,11 +647,11 @@ CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_START_DATE: DBG("START DATE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_END_DATE: DBG("END DATE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_MODULUS: DBG("MODULUS"); @@ -608,10 +731,9 @@ CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { if (ul_tmp != CKK_RSA) return CKR_ATTRIBUTE_VALUE_INVALID; - ul_tmp = get_public_exponent(pubkey_objects[piv_objects[obj].sub_id].data); // Getting the info from the pubk - if (ul_tmp == 0) + if (get_public_exponent(pubkey_objects[piv_objects[obj].sub_id].data, b_tmp, &len) != CKR_OK) return CKR_FUNCTION_FAILED; - data = (CK_BYTE_PTR) &ul_tmp; + data = b_tmp; break; /* case CKA_PRIVATE_EXPONENT: */ @@ -628,7 +750,7 @@ CK_RV get_proa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { /* case CKA_EXTRACTABLE: */ case CKA_LOCAL: DBG("LOCAL TODO"); // Required - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; /* case CKA_NEVER_EXTRACTABLE: */ /*case CKA_ALWAYS_SENSITIVE:*/ @@ -719,7 +841,7 @@ CK_RV get_puoa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_SUBJECT: DBG("SUBJECT TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_ID: DBG("ID"); @@ -758,11 +880,11 @@ CK_RV get_puoa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { case CKA_START_DATE: DBG("START DATE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_END_DATE: DBG("END DATE TODO"); // Default empty - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_EC_POINT: DBG("EC_POINT"); @@ -809,7 +931,7 @@ CK_RV get_puoa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { if (ul_tmp != CKK_RSA) return CKR_ATTRIBUTE_VALUE_INVALID; - if (get_public_key(pubkey_objects[piv_objects[obj].sub_id].data, b_tmp, &len) != CKR_OK) + if (get_modulus(pubkey_objects[piv_objects[obj].sub_id].data, b_tmp, &len) != CKR_OK) return CKR_FUNCTION_FAILED; data = b_tmp; break; @@ -842,15 +964,14 @@ CK_RV get_puoa(CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template) { if (ul_tmp != CKK_RSA) return CKR_ATTRIBUTE_VALUE_INVALID; - ul_tmp = get_public_exponent(pubkey_objects[piv_objects[obj].sub_id].data); // Getting the info from the pubk - if (ul_tmp == 0) + if (get_public_exponent(pubkey_objects[piv_objects[obj].sub_id].data, b_tmp, &len) != CKR_OK) return CKR_FUNCTION_FAILED; - data = (CK_BYTE_PTR) &ul_tmp; + data = b_tmp; break; case CKA_LOCAL: DBG("LOCAL TODO"); // Required - return CKR_FUNCTION_FAILED; + return CKR_ATTRIBUTE_TYPE_INVALID; case CKA_MODIFIABLE: DBG("MODIFIABLE"); @@ -883,7 +1004,6 @@ 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; @@ -897,6 +1017,66 @@ CK_ULONG piv_2_ykpiv(piv_obj_id_t id) { case PIV_CERT_OBJ_X509_KM: return YKPIV_OBJ_KEY_MANAGEMENT; + case PIV_CERT_OBJ_X509_RETIRED1: + return YKPIV_OBJ_RETIRED1; + + case PIV_CERT_OBJ_X509_RETIRED2: + return YKPIV_OBJ_RETIRED2; + + case PIV_CERT_OBJ_X509_RETIRED3: + return YKPIV_OBJ_RETIRED3; + + case PIV_CERT_OBJ_X509_RETIRED4: + return YKPIV_OBJ_RETIRED4; + + case PIV_CERT_OBJ_X509_RETIRED5: + return YKPIV_OBJ_RETIRED5; + + case PIV_CERT_OBJ_X509_RETIRED6: + return YKPIV_OBJ_RETIRED6; + + case PIV_CERT_OBJ_X509_RETIRED7: + return YKPIV_OBJ_RETIRED7; + + case PIV_CERT_OBJ_X509_RETIRED8: + return YKPIV_OBJ_RETIRED8; + + case PIV_CERT_OBJ_X509_RETIRED9: + return YKPIV_OBJ_RETIRED9; + + case PIV_CERT_OBJ_X509_RETIRED10: + return YKPIV_OBJ_RETIRED10; + + case PIV_CERT_OBJ_X509_RETIRED11: + return YKPIV_OBJ_RETIRED11; + + case PIV_CERT_OBJ_X509_RETIRED12: + return YKPIV_OBJ_RETIRED12; + + case PIV_CERT_OBJ_X509_RETIRED13: + return YKPIV_OBJ_RETIRED13; + + case PIV_CERT_OBJ_X509_RETIRED14: + return YKPIV_OBJ_RETIRED14; + + case PIV_CERT_OBJ_X509_RETIRED15: + return YKPIV_OBJ_RETIRED15; + + case PIV_CERT_OBJ_X509_RETIRED16: + return YKPIV_OBJ_RETIRED16; + + case PIV_CERT_OBJ_X509_RETIRED17: + return YKPIV_OBJ_RETIRED17; + + case PIV_CERT_OBJ_X509_RETIRED18: + return YKPIV_OBJ_RETIRED18; + + case PIV_CERT_OBJ_X509_RETIRED19: + return YKPIV_OBJ_RETIRED19; + + case PIV_CERT_OBJ_X509_RETIRED20: + return YKPIV_OBJ_RETIRED20; + case PIV_PVTK_OBJ_PIV_AUTH: return YKPIV_KEY_AUTHENTICATION; @@ -909,6 +1089,66 @@ CK_ULONG piv_2_ykpiv(piv_obj_id_t id) { case PIV_PVTK_OBJ_KM: return YKPIV_KEY_KEYMGM; + case PIV_PVTK_OBJ_RETIRED1: + return YKPIV_KEY_RETIRED1; + + case PIV_PVTK_OBJ_RETIRED2: + return YKPIV_KEY_RETIRED2; + + case PIV_PVTK_OBJ_RETIRED3: + return YKPIV_KEY_RETIRED3; + + case PIV_PVTK_OBJ_RETIRED4: + return YKPIV_KEY_RETIRED4; + + case PIV_PVTK_OBJ_RETIRED5: + return YKPIV_KEY_RETIRED5; + + case PIV_PVTK_OBJ_RETIRED6: + return YKPIV_KEY_RETIRED6; + + case PIV_PVTK_OBJ_RETIRED7: + return YKPIV_KEY_RETIRED7; + + case PIV_PVTK_OBJ_RETIRED8: + return YKPIV_KEY_RETIRED8; + + case PIV_PVTK_OBJ_RETIRED9: + return YKPIV_KEY_RETIRED9; + + case PIV_PVTK_OBJ_RETIRED10: + return YKPIV_KEY_RETIRED10; + + case PIV_PVTK_OBJ_RETIRED11: + return YKPIV_KEY_RETIRED11; + + case PIV_PVTK_OBJ_RETIRED12: + return YKPIV_KEY_RETIRED12; + + case PIV_PVTK_OBJ_RETIRED13: + return YKPIV_KEY_RETIRED13; + + case PIV_PVTK_OBJ_RETIRED14: + return YKPIV_KEY_RETIRED14; + + case PIV_PVTK_OBJ_RETIRED15: + return YKPIV_KEY_RETIRED15; + + case PIV_PVTK_OBJ_RETIRED16: + return YKPIV_KEY_RETIRED16; + + case PIV_PVTK_OBJ_RETIRED17: + return YKPIV_KEY_RETIRED17; + + case PIV_PVTK_OBJ_RETIRED18: + return YKPIV_KEY_RETIRED18; + + case PIV_PVTK_OBJ_RETIRED19: + return YKPIV_KEY_RETIRED19; + + case PIV_PVTK_OBJ_RETIRED20: + return YKPIV_KEY_RETIRED20; + default: return 0ul; } @@ -1063,6 +1303,8 @@ CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, case CKA_TOKEN: case CKA_LABEL: case CKA_SUBJECT: + case CKA_ISSUER: + case CKA_CERTIFICATE_TYPE: // Ignore other attributes break; @@ -1150,18 +1392,23 @@ CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, has_params == CK_FALSE) return CKR_TEMPLATE_INCOMPLETE; - if (*value_len != 32) + if (*value_len == 32 || *value_len == 31) { + if (ec_params_len != 10 || memcmp(ec_params, PRIME256V1, ec_params_len) != 0) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + else /*if () TODO: P384*/ 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 *p, CK_BYTE_PTR *q, CK_BYTE_PTR *dp, - CK_BYTE_PTR *dq, CK_BYTE_PTR *qinv, CK_ULONG_PTR value_len, CK_ULONG_PTR vendor_defined) { + 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_PTR vendor_defined) { CK_ULONG i; CK_BBOOL has_id = CK_FALSE; @@ -1171,11 +1418,6 @@ 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 = 0; - CK_ULONG q_len = 0; - CK_ULONG dp_len = 0; - CK_ULONG dq_len = 0; - CK_ULONG qinv_len = 0; *vendor_defined = 0; @@ -1210,35 +1452,35 @@ CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, 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; @@ -1269,13 +1511,12 @@ CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, has_qinv == CK_FALSE) return CKR_TEMPLATE_INCOMPLETE; - if (p_len != 64 && p_len != 128) + 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) + 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 be9db19..0780503 100644 --- a/ykcs11/objects.h +++ b/ykcs11/objects.h @@ -18,8 +18,12 @@ CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, CK_BYTE_PTR *value, CK_ULONG_PTR value_len, CK_ULONG_PTR vendor_defined); CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id, - 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_PTR vendor_defined); + 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_PTR vendor_defined); CK_RV check_delete_cert(CK_OBJECT_HANDLE hObject, CK_BYTE_PTR id); #endif diff --git a/ykcs11/openssl_utils.c b/ykcs11/openssl_utils.c index 353c29f..43a4550 100644 --- a/ykcs11/openssl_utils.c +++ b/ykcs11/openssl_utils.c @@ -317,16 +317,43 @@ CK_ULONG do_get_rsa_modulus_length(EVP_PKEY *key) { } -CK_ULONG do_get_public_exponent(EVP_PKEY *key) { +CK_RV do_get_modulus(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) { + RSA *rsa; + + rsa = EVP_PKEY_get1_RSA(key); + if (rsa == NULL) + return CKR_FUNCTION_FAILED; + + if ((CK_ULONG)BN_num_bytes(rsa->n) > *len) { + RSA_free(rsa); + rsa = NULL; + return CKR_BUFFER_TOO_SMALL; + } + + *len = (CK_ULONG)BN_bn2bin(rsa->n, data); + + RSA_free(rsa); + rsa = NULL; + + return CKR_OK; +} + +CK_RV do_get_public_exponent(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) { CK_ULONG e = 0; RSA *rsa; rsa = EVP_PKEY_get1_RSA(key); if (rsa == NULL) - return 0; + return CKR_FUNCTION_FAILED; - BN_bn2bin(rsa->e, (unsigned char *)&e); + if ((CK_ULONG)BN_num_bytes(rsa->e) > *len) { + RSA_free(rsa); + rsa = NULL; + return CKR_BUFFER_TOO_SMALL; + } + + *len = (CK_ULONG)BN_bn2bin(rsa->e, data); RSA_free(rsa); rsa = NULL; diff --git a/ykcs11/openssl_utils.h b/ykcs11/openssl_utils.h index 35461a5..8281be3 100644 --- a/ykcs11/openssl_utils.h +++ b/ykcs11/openssl_utils.h @@ -20,8 +20,9 @@ CK_RV do_delete_cert(X509 **cert); CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key); CK_KEY_TYPE do_get_key_type(EVP_PKEY *key); CK_ULONG do_get_rsa_modulus_length(EVP_PKEY *key); -CK_ULONG do_get_public_exponent(EVP_PKEY *key); +CK_RV do_get_public_exponent(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len); CK_RV do_get_public_key(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len); +CK_RV do_get_modulus(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len); CK_RV do_encode_rsa_public_key(CK_BYTE_PTR data, CK_ULONG len, RSA **key); CK_RV do_get_curve_parameters(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len); CK_RV do_delete_pubk(EVP_PKEY **key); diff --git a/ykcs11/pkcs11.h b/ykcs11/pkcs11.h index 3d7e166..53b8df4 100644 --- a/ykcs11/pkcs11.h +++ b/ykcs11/pkcs11.h @@ -239,6 +239,9 @@ extern "C" { #define __PASTE(x,y) x##y +#if defined _WIN32 || _WIN64 +#pragma pack(push, cryptoki, 1) +#endif /* packing defines */ //#include "pkcs11p.h" // TODO: msc specific? @@ -309,6 +312,11 @@ struct CK_FUNCTION_LIST { /* unpack */ //#include "pkcs11u.h" // TODO: msc specific? +#if defined _WIN32 || _WIN64 +#pragma pack(pop, cryptoki) +#endif + + #ifdef __cplusplus } #endif diff --git a/ykcs11/pkcs11t.h b/ykcs11/pkcs11t.h index d357092..92d7678 100644 --- a/ykcs11/pkcs11t.h +++ b/ykcs11/pkcs11t.h @@ -108,7 +108,9 @@ typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; /* pack */ -//#include "pkcs11p.h" // TODO: msc specific? +#if defined _WIN32 || _WIN64 +#pragma pack(push, cryptoki, 1) +#endif typedef struct CK_VERSION { CK_BYTE major; /* integer portion of version number */ @@ -1163,33 +1165,36 @@ typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; * PKCS #11 interface. Most of these are place holders for other mechanism * and will change in the future. */ -#define CKM_NETSCAPE_PBE_KEY_GEN 0x80000001UL -#define CKM_NETSCAPE_PBE_SHA1_DES_CBC 0x80000002UL -#define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC 0x80000003UL -#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC 0x80000004UL -#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC 0x80000005UL -#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4 0x80000006UL -#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4 0x80000007UL -#define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC 0x80000008UL -#define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN 0x80000009UL -#define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN 0x8000000aUL -#define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN 0x8000000bUL -#define CKM_TLS_MASTER_KEY_DERIVE 0x80000371UL -#define CKM_TLS_KEY_AND_MAC_DERIVE 0x80000372UL -#define CKM_TLS_PRF_GENERAL 0x80000373UL +#define CKM_NETSCAPE_PBE_KEY_GEN 0x80000001UL +#define CKM_NETSCAPE_PBE_SHA1_DES_CBC 0x80000002UL +#define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC 0x80000003UL +#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC 0x80000004UL +#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC 0x80000005UL +#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4 0x80000006UL +#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4 0x80000007UL +#define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC 0x80000008UL +#define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN 0x80000009UL +#define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN 0x8000000aUL +#define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN 0x8000000bUL +#define CKM_TLS_MASTER_KEY_DERIVE 0x80000371UL +#define CKM_TLS_KEY_AND_MAC_DERIVE 0x80000372UL +#define CKM_TLS_PRF_GENERAL 0x80000373UL /* define used to pass in the database key for DSA private keys */ -#define CKA_NETSCAPE_DB 0xD5A0DB00UL -#define CKA_NETSCAPE_TRUST 0x80000001UL - -/* undo packing */ -//#include "pkcs11u.h" // TODO: msc specific? +#define CKA_NETSCAPE_DB 0xD5A0DB00UL +#define CKA_NETSCAPE_TRUST 0x80000001UL // YUBICO specific attributes #define CKA_TOUCH_PIN_DEFAULT 0x00000000U #define CKA_TOUCH_ALWAYS 0x00000001U #define CKA_PIN_ONCE 0x00000002U #define CKA_PIN_ALWAYS 0x00000004U +#define CKA_PIN_NEVER 0x00000008U +#define CKA_TOUCH_NEVER 0x00000016U +/* undo packing */ +#if defined _WIN32 || _WIN64 +#pragma pack(pop, cryptoki) +#endif #endif diff --git a/ykcs11/tests/ykcs11_tests.c b/ykcs11/tests/ykcs11_tests.c index 3013d5b..8495456 100644 --- a/ykcs11/tests/ykcs11_tests.c +++ b/ykcs11/tests/ykcs11_tests.c @@ -3,54 +3,617 @@ #include -#define MANUFACTURER_ID "Yubico (www.yubico.com)" -#define YKCS11_DESCRIPTION "PKCS#11 PIV Library (SP-800-73)" -#define CRYPTOKI_VERSION_MAJ 2 -#define CRYPTOKI_VERSION_MIN 40 +#include +#include +#include +#include +#include +void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, int space) { + unsigned int i; + for (i = 0; i < len; i++) { + fprintf(output, "%02x%s", buf[i], space == 1 ? " " : ""); + } + fprintf(output, "\n"); +} -static void lib_info() { +CK_FUNCTION_LIST_PTR funcs; - CK_INFO info; - CK_FUNCTION_LIST_PTR funcs; +#define asrt(c, e, m) _asrt(__LINE__, c, e, m); - if (C_GetFunctionList(&funcs) != CKR_OK) { +static void _asrt(int line, CK_ULONG check, CK_ULONG expected, CK_CHAR_PTR msg) { + + if (check == expected) + return; + + fprintf(stderr, "<%s>:%d check failed with value %lu (0x%lx), expected %lu (0x%lx)\n", + msg, line, check, check, expected, expected); + + exit(EXIT_FAILURE); + +} + +static void get_functions(CK_FUNCTION_LIST_PTR_PTR funcs) { + + if (C_GetFunctionList(funcs) != CKR_OK) { fprintf(stderr, "Get function list failed\n"); exit(EXIT_FAILURE); } - if (funcs->C_GetInfo(&info) != CKR_OK) { - fprintf(stderr, "GetInfo failed\n"); - exit(EXIT_FAILURE); - } +} - if (strcmp(info.manufacturerID, MANUFACTURER_ID) != 0) { - fprintf(stderr, "unexpected manufacturer ID %s\n", info.manufacturerID); - exit(EXIT_FAILURE); - } +static void test_lib_info() { - if (info.cryptokiVersion.major != CRYPTOKI_VERSION_MAJ || - info.cryptokiVersion.minor != CRYPTOKI_VERSION_MIN ) { - fprintf(stderr, "unexpected Cryptoki version %d.%d\n", info.cryptokiVersion.major, info.cryptokiVersion.minor); - exit(EXIT_FAILURE); - } + const CK_CHAR_PTR MANUFACTURER_ID = "Yubico (www.yubico.com)"; + const CK_CHAR_PTR YKCS11_DESCRIPTION = "PKCS#11 PIV Library (SP-800-73)"; + const CK_ULONG CRYPTOKI_VERSION_MAJ = 2; + const CK_ULONG CRYPTOKI_VERSION_MIN = 40; - if (info.libraryVersion.major != YKCS11_VERSION_MAJOR || - info.libraryVersion.minor != ((YKCS11_VERSION_MINOR * 100) + YKCS11_VERSION_PATCH )) { - fprintf(stderr, "unexpected YKCS11 version %d.%d\n", info.libraryVersion.major, info.libraryVersion.minor); - exit(EXIT_FAILURE); - } - if (strcmp(info.libraryDescription, YKCS11_DESCRIPTION) != 0) { - fprintf(stderr, "unexpected description %s\n", info.libraryDescription); - exit(EXIT_FAILURE); - } + CK_INFO info; + + asrt(funcs->C_GetInfo(&info), CKR_OK, "GET_INFO"); + + asrt(strcmp(info.manufacturerID, MANUFACTURER_ID), 0, "MANUFACTURER"); + + asrt(info.cryptokiVersion.major, CRYPTOKI_VERSION_MAJ, "CK_MAJ"); + asrt(info.cryptokiVersion.minor, CRYPTOKI_VERSION_MIN, "CK_MIN"); + + asrt(info.libraryVersion.major, YKCS11_VERSION_MAJOR, "LIB_MAJ"); + asrt(info.libraryVersion.minor, ((YKCS11_VERSION_MINOR * 10) + YKCS11_VERSION_PATCH ), "LIB_MIN"); + + asrt(strcmp(info.libraryDescription, YKCS11_DESCRIPTION), 0, "LIB_DESC"); +} + +#ifdef HW_TESTS +static void test_initalize() { + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); } +static void test_token_info() { + + const CK_CHAR_PTR TOKEN_LABEL = "YubiKey PIV"; + const CK_CHAR_PTR TOKEN_MODEL = "YubiKey "; // Skip last 3 characters (version dependent) + const CK_CHAR_PTR TOKEN_SERIAL = "1234"; + const CK_FLAGS TOKEN_FLAGS = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED; + const CK_VERSION HW = {0, 0}; + const CK_CHAR_PTR TOKEN_TIME = " "; + CK_TOKEN_INFO info; + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + + asrt(funcs->C_GetTokenInfo(0, &info), CKR_OK, "GetTokeninfo"); + asrt(strncmp(info.label, TOKEN_LABEL, strlen(TOKEN_LABEL)), 0, "TOKEN_LABEL"); + // Skip manufacturer id (not used) + asrt(strncmp(info.model, TOKEN_MODEL, strlen(TOKEN_MODEL)), 0, "TOKEN_MODEL"); + asrt(strncmp(info.serialNumber, TOKEN_SERIAL, strlen(TOKEN_SERIAL)), 0, "SERIAL_NUMBER"); + asrt(info.flags, TOKEN_FLAGS, "TOKEN_FLAGS"); + asrt(info.ulMaxSessionCount, CK_UNAVAILABLE_INFORMATION, "MAX_SESSION_COUNT"); + asrt(info.ulSessionCount, CK_UNAVAILABLE_INFORMATION, "SESSION_COUNT"); + asrt(info.ulMaxRwSessionCount, CK_UNAVAILABLE_INFORMATION, "MAX_RW_SESSION_COUNT"); + asrt(info.ulRwSessionCount, CK_UNAVAILABLE_INFORMATION, "RW_SESSION_COUNT"); + asrt(info.ulMaxPinLen, 8, "MAX_PIN_LEN"); + asrt(info.ulMinPinLen, 6, "MIN_PIN_LEN"); + asrt(info.ulTotalPublicMemory, CK_UNAVAILABLE_INFORMATION, "TOTAL_PUB_MEM"); + asrt(info.ulFreePublicMemory, CK_UNAVAILABLE_INFORMATION, "FREE_PUB_MEM"); + asrt(info.ulTotalPrivateMemory, CK_UNAVAILABLE_INFORMATION, "TOTAL_PVT_MEM"); + asrt(info.ulFreePrivateMemory, CK_UNAVAILABLE_INFORMATION, "FREE_PVT_MEM"); + asrt(info.hardwareVersion.major, HW.major, "HW_MAJ"); + asrt(info.hardwareVersion.minor, HW.minor, "HW_MIN"); + + if (info.firmwareVersion.major != 4 && info.firmwareVersion.major != 0) + asrt(info.firmwareVersion.major, 4, "FW_MAJ"); + + asrt(strcmp(info.utcTime, TOKEN_TIME), 0, "TOKEN_TIME"); + + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); + +} + +static void test_mechanism_list_and_info() { + + CK_MECHANISM_TYPE_PTR mechs; + CK_ULONG n_mechs; + CK_MECHANISM_INFO info; + CK_ULONG i; + + static const CK_MECHANISM_TYPE token_mechanisms[] = { + CKM_RSA_PKCS_KEY_PAIR_GEN, + CKM_RSA_PKCS, + CKM_RSA_PKCS_PSS, + CKM_RSA_X_509, + CKM_SHA1_RSA_PKCS, + CKM_SHA256_RSA_PKCS, + CKM_SHA384_RSA_PKCS, + CKM_SHA512_RSA_PKCS, + CKM_SHA1_RSA_PKCS_PSS, + CKM_SHA256_RSA_PKCS_PSS, + CKM_SHA384_RSA_PKCS_PSS, + CKM_SHA512_RSA_PKCS_PSS, + CKM_EC_KEY_PAIR_GEN, + CKM_ECDSA, + CKM_ECDSA_SHA1, + CKM_ECDSA_SHA256, + CKM_SHA_1, + CKM_SHA256, + CKM_SHA384, + CKM_SHA512 + }; + + static const CK_MECHANISM_INFO token_mechanism_infos[] = { // KEEP ALIGNED WITH token_mechanisms + {1024, 2048, CKF_HW | CKF_GENERATE_KEY_PAIR}, + {1024, 2048, CKF_HW | CKF_DECRYPT | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_DECRYPT | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {1024, 2048, CKF_HW | CKF_SIGN}, + {256, 384, CKF_HW | CKF_GENERATE_KEY_PAIR}, + {256, 384, CKF_HW | CKF_SIGN}, + {256, 384, CKF_HW | CKF_SIGN}, + {256, 384, CKF_HW | CKF_SIGN}, + {0, 0, CKF_DIGEST}, + {0, 0, CKF_DIGEST}, + {0, 0, CKF_DIGEST}, + {0, 0, CKF_DIGEST} +}; + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + + asrt(funcs->C_GetMechanismList(0, NULL, &n_mechs), CKR_OK, "GetMechanismList"); + + mechs = malloc(n_mechs * sizeof(CK_MECHANISM_TYPE)); + asrt(funcs->C_GetMechanismList(0, mechs, &n_mechs), CKR_OK, "GetMechanismList"); + + asrt(memcmp(token_mechanisms, mechs, sizeof(token_mechanisms)), 0, "CHECK MECHS"); + + for (i = 0; i < n_mechs; i++) { + asrt(funcs->C_GetMechanismInfo(0, mechs[i], &info), CKR_OK, "GET MECH INFO"); + asrt(memcmp(token_mechanism_infos + i, &info, sizeof(CK_MECHANISM_INFO)), 0, "CHECK MECH INFO"); + } + + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); +} + +static void test_session() { + + CK_SESSION_HANDLE session; + CK_SESSION_INFO info; + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + + asrt(funcs->C_OpenSession(0, CKF_SERIAL_SESSION, NULL, NULL, &session), CKR_OK, "OpenSession1"); + asrt(funcs->C_CloseSession(session), CKR_OK, "CloseSession"); + + asrt(funcs->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session), CKR_OK, "OpenSession2"); + asrt(funcs->C_GetSessionInfo(session, &info), CKR_OK, "GetSessionInfo"); + asrt(info.state, CKS_RW_PUBLIC_SESSION, "CHECK STATE"); + asrt(info.flags, CKF_SERIAL_SESSION | CKF_RW_SESSION, "CHECK FLAGS"); + asrt(info.ulDeviceError, 0, "CHECK DEVICE ERROR"); + asrt(funcs->C_CloseSession(session), CKR_OK, "CloseSession"); + + asrt(funcs->C_OpenSession(0, CKF_SERIAL_SESSION, NULL, NULL, &session), CKR_OK, "OpenSession3"); + asrt(funcs->C_CloseAllSessions(0), CKR_OK, "CloseAllSessions"); + + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); + +} + +static void test_login() { + + CK_SESSION_HANDLE session; + CK_SESSION_INFO info; + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + + asrt(funcs->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session), CKR_OK, "OpenSession1"); + + asrt(funcs->C_Login(session, CKU_USER, "123456", 6), CKR_OK, "Login USER"); + asrt(funcs->C_Logout(session), CKR_OK, "Logout USER"); + + asrt(funcs->C_Login(session, CKU_SO, "010203040506070801020304050607080102030405060708", 48), CKR_OK, "Login SO"); + asrt(funcs->C_Logout(session), CKR_OK, "Logout SO"); + + asrt(funcs->C_CloseSession(session), CKR_OK, "CloseSession"); + + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); + +} + +// Import a newly generated P256 pvt key and a certificate +// to every slot and use the key to sign some data +static void test_import_and_sign_all_10() { + + EVP_PKEY *evp; + EC_KEY *eck; + const EC_POINT *ecp; + const BIGNUM *bn; + char pvt[32]; + X509 *cert; + ASN1_TIME *tm; + CK_BYTE i, j; + CK_BYTE some_data[32]; + + CK_ULONG class_k = CKO_PRIVATE_KEY; + CK_ULONG class_c = CKO_CERTIFICATE; + CK_ULONG kt = CKK_ECDSA; + CK_BYTE id = 0; + CK_BYTE params[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; + CK_BYTE sig[64]; + CK_ULONG recv_len; + CK_BYTE value_c[3100]; + CK_ULONG cert_len; + CK_BYTE der_encoded[80]; + CK_BYTE_PTR der_ptr; + CK_BYTE_PTR r_ptr; + CK_BYTE_PTR s_ptr; + CK_ULONG r_len; + CK_ULONG s_len; + + unsigned char *p; + + CK_ATTRIBUTE privateKeyTemplate[] = { + {CKA_CLASS, &class_k, sizeof(class_k)}, + {CKA_KEY_TYPE, &kt, sizeof(kt)}, + {CKA_ID, &id, sizeof(id)}, + {CKA_EC_PARAMS, ¶ms, sizeof(params)}, + {CKA_VALUE, pvt, sizeof(pvt)} + }; + + CK_ATTRIBUTE publicKeyTemplate[] = { + {CKA_CLASS, &class_c, sizeof(class_c)}, + {CKA_ID, &id, sizeof(id)}, + {CKA_VALUE, value_c, sizeof(value_c)} + }; + + CK_OBJECT_HANDLE obj[24]; + CK_SESSION_HANDLE session; + CK_MECHANISM mech = {CKM_ECDSA, NULL}; + + evp = EVP_PKEY_new(); + + if (evp == NULL) + exit(EXIT_FAILURE); + + eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + + if (eck == NULL) + exit(EXIT_FAILURE); + + asrt(EC_KEY_generate_key(eck), 1, "GENERATE ECK"); + + bn = EC_KEY_get0_private_key(eck); + + asrt(BN_bn2bin(bn, pvt), 32, "EXTRACT PVT"); + + if (EVP_PKEY_set1_EC_KEY(evp, eck) == 0) + exit(EXIT_FAILURE); + + cert = X509_new(); + + if (cert == NULL) + exit(EXIT_FAILURE); + + if (X509_set_pubkey(cert, evp) == 0) + exit(EXIT_FAILURE); + + tm = ASN1_TIME_new(); + if (tm == NULL) + exit(EXIT_FAILURE); + + ASN1_TIME_set_string(tm, "000001010000Z"); + X509_set_notBefore(cert, tm); + X509_set_notAfter(cert, tm); + + cert->sig_alg->algorithm = OBJ_nid2obj(8); + cert->cert_info->signature->algorithm = OBJ_nid2obj(8); + + ASN1_BIT_STRING_set_bit(cert->signature, 8, 1); + ASN1_BIT_STRING_set(cert->signature, "\x00", 1); + + p = value_c; + if ((cert_len = (CK_ULONG) i2d_X509(cert, &p)) == 0 || cert_len > sizeof(value_c)) + exit(EXIT_FAILURE); + + publicKeyTemplate[2].ulValueLen = cert_len; + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + asrt(funcs->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session), CKR_OK, "OpenSession1"); + asrt(funcs->C_Login(session, CKU_SO, "010203040506070801020304050607080102030405060708", 48), CKR_OK, "Login SO"); + + for (i = 0; i < 24; i++) { + id = i; + asrt(funcs->C_CreateObject(session, publicKeyTemplate, 3, obj + i), CKR_OK, "IMPORT CERT"); + asrt(funcs->C_CreateObject(session, privateKeyTemplate, 5, obj + i), CKR_OK, "IMPORT KEY"); + } + + asrt(funcs->C_Logout(session), CKR_OK, "Logout SO"); + + for (i = 0; i < 24; i++) { + for (j = 0; j < 10; j++) { + + if(RAND_pseudo_bytes(some_data, sizeof(some_data)) == -1) + exit(EXIT_FAILURE); + + asrt(funcs->C_Login(session, CKU_USER, "123456", 6), CKR_OK, "Login USER"); + asrt(funcs->C_SignInit(session, &mech, obj[i]), CKR_OK, "SignInit"); + + recv_len = sizeof(sig); + asrt(funcs->C_Sign(session, some_data, sizeof(some_data), sig, &recv_len), CKR_OK, "Sign"); + + r_len = 32; + s_len = 32; + + der_ptr = der_encoded; + *der_ptr++ = 0x30; + *der_ptr++ = 0xff; // placeholder, fix below + + r_ptr = sig; + + *der_ptr++ = 0x02; + *der_ptr++ = r_len; + if (*r_ptr >= 0x80) { + *(der_ptr - 1) = *(der_ptr - 1) + 1; + *der_ptr++ = 0x00; + } + else if (*r_ptr == 0x00 && *(r_ptr + 1) < 0x80) { + r_len--; + *(der_ptr - 1) = *(der_ptr - 1) - 1; + r_ptr++; + } + memcpy(der_ptr, r_ptr, r_len); + der_ptr+= r_len; + + s_ptr = sig + 32; + + *der_ptr++ = 0x02; + *der_ptr++ = s_len; + if (*s_ptr >= 0x80) { + *(der_ptr - 1) = *(der_ptr - 1) + 1; + *der_ptr++ = 0x00; + } + else if (*s_ptr == 0x00 && *(s_ptr + 1) < 0x80) { + s_len--; + *(der_ptr - 1) = *(der_ptr - 1) - 1; + s_ptr++; + } + memcpy(der_ptr, s_ptr, s_len); + der_ptr+= s_len; + + der_encoded[1] = der_ptr - der_encoded - 2; + + dump_hex(der_encoded, der_encoded[1] + 2, stderr, 1); + + asrt(ECDSA_verify(0, some_data, sizeof(some_data), der_encoded, der_encoded[1] + 2, eck), 1, "ECDSA VERIFICATION"); + + } + } + + asrt(funcs->C_Logout(session), CKR_OK, "Logout USER"); + + asrt(funcs->C_CloseSession(session), CKR_OK, "CloseSession"); + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); + +} + +// Import a newly generated RSA1024 pvt key and a certificate +// to every slot and use the key to sign some data +static void test_import_and_sign_all_10_RSA() { + + EVP_PKEY *evp; + RSA *rsak; + X509 *cert; + ASN1_TIME *tm; + CK_BYTE i, j; + CK_BYTE some_data[32]; + CK_BYTE e[] = {0x01, 0x00, 0x01}; + CK_BYTE p[64]; + CK_BYTE q[64]; + CK_BYTE dp[64]; + CK_BYTE dq[64]; + CK_BYTE qinv[64]; + BIGNUM *e_bn; + CK_ULONG class_k = CKO_PRIVATE_KEY; + CK_ULONG class_c = CKO_CERTIFICATE; + CK_ULONG kt = CKK_RSA; + CK_BYTE id = 0; + CK_BYTE sig[64]; + CK_ULONG recv_len; + CK_BYTE value_c[3100]; + CK_ULONG cert_len; + CK_BYTE der_encoded[80]; + CK_BYTE_PTR der_ptr; + CK_BYTE_PTR r_ptr; + CK_BYTE_PTR s_ptr; + CK_ULONG r_len; + CK_ULONG s_len; + + unsigned char *px; + + CK_ATTRIBUTE privateKeyTemplate[] = { + {CKA_CLASS, &class_k, sizeof(class_k)}, + {CKA_KEY_TYPE, &kt, sizeof(kt)}, + {CKA_ID, &id, sizeof(id)}, + {CKA_PUBLIC_EXPONENT, e, sizeof(e)}, + {CKA_PRIME_1, p, sizeof(p)}, + {CKA_PRIME_2, q, sizeof(q)}, + {CKA_EXPONENT_1, dp, sizeof(dp)}, + {CKA_EXPONENT_2, dq, sizeof(dq)}, + {CKA_COEFFICIENT, qinv, sizeof(qinv)} + }; + + CK_ATTRIBUTE publicKeyTemplate[] = { + {CKA_CLASS, &class_c, sizeof(class_c)}, + {CKA_ID, &id, sizeof(id)}, + {CKA_VALUE, value_c, sizeof(value_c)} + }; + + CK_OBJECT_HANDLE obj[24]; + CK_SESSION_HANDLE session; + CK_MECHANISM mech = {CKM_RSA_PKCS, NULL}; + + evp = EVP_PKEY_new(); + + if (evp == NULL) + exit(EXIT_FAILURE); + + rsak = RSA_new(); + + if (rsak == NULL) + exit(EXIT_FAILURE); + + e_bn = BN_bin2bn(e, 3, NULL); + + if (e_bn == NULL) + exit(EXIT_FAILURE); + + asrt(RSA_generate_key_ex(rsak, 1024, e_bn, NULL), 1, "GENERATE RSAK"); + + asrt(BN_bn2bin(rsak->p, p), 64, "GET P"); + asrt(BN_bn2bin(rsak->q, q), 64, "GET Q"); + asrt(BN_bn2bin(rsak->dmp1, dp), 64, "GET DP"); + asrt(BN_bn2bin(rsak->dmq1, dp), 64, "GET DQ"); + asrt(BN_bn2bin(rsak->iqmp, qinv), 64, "GET QINV"); + + + + if (EVP_PKEY_set1_RSA(evp, rsak) == 0) + exit(EXIT_FAILURE); + + cert = X509_new(); + + if (cert == NULL) + exit(EXIT_FAILURE); + + if (X509_set_pubkey(cert, evp) == 0) + exit(EXIT_FAILURE); + + tm = ASN1_TIME_new(); + if (tm == NULL) + exit(EXIT_FAILURE); + + ASN1_TIME_set_string(tm, "000001010000Z"); + X509_set_notBefore(cert, tm); + X509_set_notAfter(cert, tm); + + cert->sig_alg->algorithm = OBJ_nid2obj(8); + cert->cert_info->signature->algorithm = OBJ_nid2obj(8); + + ASN1_BIT_STRING_set_bit(cert->signature, 8, 1); + ASN1_BIT_STRING_set(cert->signature, "\x00", 1); + + px = value_c; + if ((cert_len = (CK_ULONG) i2d_X509(cert, &px)) == 0 || cert_len > sizeof(value_c)) + exit(EXIT_FAILURE); + + publicKeyTemplate[2].ulValueLen = cert_len; + + asrt(funcs->C_Initialize(NULL), CKR_OK, "INITIALIZE"); + asrt(funcs->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session), CKR_OK, "OpenSession1"); + asrt(funcs->C_Login(session, CKU_SO, "010203040506070801020304050607080102030405060708", 48), CKR_OK, "Login SO"); + + for (i = 0; i < 24; i++) { + id = i; + asrt(funcs->C_CreateObject(session, publicKeyTemplate, 3, obj + i), CKR_OK, "IMPORT CERT"); + asrt(funcs->C_CreateObject(session, privateKeyTemplate, 9, obj + i), CKR_OK, "IMPORT KEY"); + } + + asrt(funcs->C_Logout(session), CKR_OK, "Logout SO"); + + for (i = 0; i < 24; i++) { + for (j = 0; j < 10; j++) { + + if(RAND_pseudo_bytes(some_data, sizeof(some_data)) == -1) + exit(EXIT_FAILURE); + + asrt(funcs->C_Login(session, CKU_USER, "123456", 6), CKR_OK, "Login USER"); + asrt(funcs->C_SignInit(session, &mech, obj[i]), CKR_OK, "SignInit"); + + recv_len = sizeof(sig); + asrt(funcs->C_Sign(session, some_data, sizeof(some_data), sig, &recv_len), CKR_OK, "Sign"); + + /* r_len = 32; */ + /* s_len = 32; */ + + /* der_ptr = der_encoded; */ + /* *der_ptr++ = 0x30; */ + /* *der_ptr++ = 0xff; // placeholder, fix below */ + + /* r_ptr = sig; */ + + /* *der_ptr++ = 0x02; */ + /* *der_ptr++ = r_len; */ + /* if (*r_ptr >= 0x80) { */ + /* *(der_ptr - 1) = *(der_ptr - 1) + 1; */ + /* *der_ptr++ = 0x00; */ + /* } */ + /* else if (*r_ptr == 0x00 && *(r_ptr + 1) < 0x80) { */ + /* r_len--; */ + /* *(der_ptr - 1) = *(der_ptr - 1) - 1; */ + /* r_ptr++; */ + /* } */ + /* memcpy(der_ptr, r_ptr, r_len); */ + /* der_ptr+= r_len; */ + + /* s_ptr = sig + 32; */ + + /* *der_ptr++ = 0x02; */ + /* *der_ptr++ = s_len; */ + /* if (*s_ptr >= 0x80) { */ + /* *(der_ptr - 1) = *(der_ptr - 1) + 1; */ + /* *der_ptr++ = 0x00; */ + /* } */ + /* else if (*s_ptr == 0x00 && *(s_ptr + 1) < 0x80) { */ + /* s_len--; */ + /* *(der_ptr - 1) = *(der_ptr - 1) - 1; */ + /* s_ptr++; */ + /* } */ + /* memcpy(der_ptr, s_ptr, s_len); */ + /* der_ptr+= s_len; */ + + /* der_encoded[1] = der_ptr - der_encoded - 2; */ + + /* dump_hex(der_encoded, der_encoded[1] + 2, stderr, 1); */ + + /* asrt(ECDSA_verify(0, some_data, sizeof(some_data), der_encoded, der_encoded[1] + 2, eck), 1, "ECDSA VERIFICATION"); */ + + } + } + + asrt(funcs->C_Logout(session), CKR_OK, "Logout USER"); + + asrt(funcs->C_CloseSession(session), CKR_OK, "CloseSession"); + asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE"); + +} +#endif + int main(void) { - lib_info(); + get_functions(&funcs); + + test_lib_info(); + +#ifdef HW_TESTS + test_initalize(); + test_token_info(); + test_mechanism_list_and_info(); + test_session(); + test_login(); + test_import_and_sign_all_10(); + test_import_and_sign_all_10_RSA(); +#else + fprintf(stderr, "HARDWARE TESTS DISABLED!, skipping...\n"); +#endif return EXIT_SUCCESS; diff --git a/ykcs11/token_vendors.c b/ykcs11/token_vendors.c index 25db6d7..9cda842 100644 --- a/ykcs11/token_vendors.c +++ b/ykcs11/token_vendors.c @@ -12,9 +12,24 @@ static CK_RV COMMON_token_login(ykpiv_state *state, CK_USER_TYPE user, CK_UTF8CH int tries = 0; // TODO: this is effectively disregarded, should we add a better value in ykpiv_verify? unsigned char key[24]; size_t key_len = sizeof(key); + unsigned char *term_pin; + ykpiv_rc res; if (user == CKU_USER) { - if (ykpiv_verify(state, (char *)pin, &tries) != YKPIV_OK) { + // add null termination for the pin + term_pin = malloc(pin_len + 1); + if (term_pin == NULL) { + return CKR_HOST_MEMORY; + } + memcpy(term_pin, pin, pin_len); + term_pin[pin_len] = 0; + + res = ykpiv_verify(state, (char *)term_pin, &tries); + + OPENSSL_cleanse(term_pin, pin_len); + free(term_pin); + + if (res != YKPIV_OK) { DBG("Failed to login"); return CKR_PIN_INCORRECT; } @@ -58,7 +73,7 @@ static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa, switch(key_len) { case 2048: if (rsa == CK_TRUE) - in_data[4] = YKPIV_ALGO_RSA2048; + *in_ptr++ = YKPIV_ALGO_RSA2048; else return CKR_FUNCTION_FAILED; @@ -143,7 +158,7 @@ static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa, static CK_RV COMMON_token_import_cert(ykpiv_state *state, CK_ULONG cert_id, CK_BYTE_PTR in) { - unsigned char certdata[2100]; + unsigned char certdata[3072]; unsigned char *certptr; CK_ULONG cert_len; @@ -153,7 +168,7 @@ static CK_RV COMMON_token_import_cert(ykpiv_state *state, CK_ULONG cert_id, CK_B if ((rv = do_check_cert(in, &cert_len)) != CKR_OK) return rv; - if (cert_len > 2100) + if (cert_len > 3072) return CKR_FUNCTION_FAILED; certptr = certdata; @@ -176,85 +191,73 @@ 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 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, CK_ULONG vendor_defined) { +CK_RV COMMON_token_import_private_key(ykpiv_state *state, CK_BYTE 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_ULONG vendor_defined) { - 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; + CK_BYTE pin_policy; + CK_BYTE touch_policy; + CK_BYTE algo; + ykpiv_rc rc; - if (elem_len == 128) // TODO: add a flag to check algo type ? - 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; + if (p == NULL) { + if (ec_data_len == 32 || ec_data_len == 31) + algo = YKPIV_ALGO_ECCP256; + else + algo = YKPIV_ALGO_ECCP384; } - 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; + else if (ec_data == NULL) { + if (p_len == 64) + algo = YKPIV_ALGO_RSA1024; + else + algo = YKPIV_ALGO_RSA2048; } - - // PIN policy and touch - if (vendor_defined != 0) { - if (vendor_defined & CKA_PIN_ONCE) { - *in_ptr++ = YKPIV_PINPOLICY_TAG; - *in_ptr++ = 0x01; - *in_ptr++ = YKPIV_PINPOLICY_ONCE; - } - else if (vendor_defined & CKA_PIN_ALWAYS) { - *in_ptr++ = YKPIV_PINPOLICY_TAG; - *in_ptr++ = 0x01; - *in_ptr++ = YKPIV_PINPOLICY_ALWAYS; - } - - if (vendor_defined & CKA_TOUCH_ALWAYS) { - *in_ptr++ = YKPIV_TOUCHPOLICY_TAG; - *in_ptr++ = 0x01; - *in_ptr++ = YKPIV_TOUCHPOLICY_ALWAYS; - } - } - - if (ykpiv_transfer_data(state, templ, key_data, in_ptr - key_data, data, &recv_len, &sw) != YKPIV_OK) + else return CKR_FUNCTION_FAILED; - if (sw != 0x9000) - return CKR_DEVICE_ERROR; + pin_policy = YKPIV_PINPOLICY_DEFAULT; + touch_policy = YKPIV_TOUCHPOLICY_DEFAULT; + if (vendor_defined != 0) { + if (vendor_defined & CKA_PIN_ONCE) { + pin_policy = YKPIV_PINPOLICY_ONCE; + } + else if (vendor_defined & CKA_PIN_ALWAYS) { + pin_policy = YKPIV_PINPOLICY_ALWAYS; + } + else if (vendor_defined & CKA_PIN_NEVER) { + pin_policy = YKPIV_PINPOLICY_NEVER; + } + else + return CKR_ATTRIBUTE_VALUE_INVALID; - return CKR_OK; + if (vendor_defined & CKA_TOUCH_ALWAYS) { + touch_policy = YKPIV_TOUCHPOLICY_ALWAYS; + } + else if (vendor_defined & CKA_TOUCH_NEVER) { + touch_policy = YKPIV_TOUCHPOLICY_NEVER; + } + else + return CKR_ATTRIBUTE_VALUE_INVALID; + } + rc = ykpiv_import_private_key(state, key_id, algo, + p, p_len, + q, q_len, + dp, dp_len, + dq, dq_len, + qinv, qinv_len, + ec_data, ec_data_len, + pin_policy, touch_policy); + + if (rc != YKPIV_OK) + return CKR_FUNCTION_FAILED; + + return CKR_OK; } CK_RV COMMON_token_delete_cert(ykpiv_state *state, CK_ULONG cert_id) { @@ -287,6 +290,7 @@ token_vendor_t get_token_vendor(vendor_id_t vid) { v.token_import_cert = COMMON_token_import_cert; v.token_import_private_key = COMMON_token_import_private_key; v.token_delete_cert = COMMON_token_delete_cert; + v.token_change_pin = YUBICO_token_change_pin; break; case UNKNOWN: diff --git a/ykcs11/token_vendors.h b/ykcs11/token_vendors.h index 3b57209..528b2c5 100644 --- a/ykcs11/token_vendors.h +++ b/ykcs11/token_vendors.h @@ -10,7 +10,7 @@ typedef CK_RV (*get_t_label_f)(CK_UTF8CHAR_PTR, CK_ULONG); typedef CK_RV (*get_t_manufacturer_f)(CK_UTF8CHAR_PTR, CK_ULONG); typedef CK_RV (*get_t_model_f)(ykpiv_state *, CK_UTF8CHAR_PTR, CK_ULONG); typedef CK_RV (*get_t_flags_f)(CK_FLAGS_PTR); -typedef CK_RV (*get_t_version_f)(CK_UTF8CHAR_PTR, CK_ULONG, CK_VERSION_PTR); +typedef CK_RV (*get_t_version_f)(ykpiv_state *, CK_VERSION_PTR); 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); @@ -18,13 +18,20 @@ 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, 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_PTR); +typedef CK_RV (*t_change_pin_f)(ykpiv_state *, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG, CK_UTF8CHAR_PTR, CK_ULONG); // Common token functions below typedef CK_RV (*t_login_f)(ykpiv_state *, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG); typedef CK_RV (*t_generate_key_f)(ykpiv_state *, CK_BBOOL, CK_BYTE, CK_ULONG, 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, CK_BYTE_PTR, CK_BYTE_PTR, CK_BYTE_PTR, - CK_BYTE_PTR, CK_BYTE_PTR, CK_BYTE_PTR, CK_ULONG, CK_ULONG); +typedef CK_RV (*t_import_private_key_f)(ykpiv_state *, CK_BYTE, + 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, + CK_ULONG); typedef CK_RV (*t_delete_cert_f)(ykpiv_state *, CK_ULONG); // TODO: replace all the common calls with functions defined in .c that use libykpiv @@ -47,6 +54,7 @@ typedef struct { t_import_cert_f token_import_cert; t_import_private_key_f token_import_private_key; t_delete_cert_f token_delete_cert; + t_change_pin_f token_change_pin; } token_vendor_t; token_vendor_t get_token_vendor(vendor_id_t vid); diff --git a/ykcs11/utils.c b/ykcs11/utils.c index dd90a67..7053456 100644 --- a/ykcs11/utils.c +++ b/ykcs11/utils.c @@ -29,16 +29,16 @@ CK_RV parse_readers(ykpiv_state *state, const CK_BYTE_PTR readers, const CK_ULON for (i = 0; i < len; i++) if (readers[i] == '\0' && i != len - 1) { - slots[*n_slots].vid = get_vendor_id(p); + slots[*n_slots].vid = get_vendor_id((char *)p); if (slots[*n_slots].vid == UNKNOWN) { // TODO: distinguish between tokenless and unsupported? // Unknown slot, just save what info we have memset(&slots[*n_slots].info, 0, sizeof(CK_SLOT_INFO)); memset(slots[*n_slots].info.slotDescription, ' ', sizeof(slots[*n_slots].info.slotDescription)); - if (strlen(p) <= sizeof(slots[*n_slots].info.slotDescription)) - strncpy(slots[*n_slots].info.slotDescription, p, strlen(p)); + if (strlen((char *)p) <= sizeof(slots[*n_slots].info.slotDescription)) + memcpy(slots[*n_slots].info.slotDescription, p, strlen((char *)p)); else - strncpy(slots[*n_slots].info.slotDescription, p, sizeof(slots[*n_slots].info.slotDescription)); + memcpy(slots[*n_slots].info.slotDescription, p, sizeof(slots[*n_slots].info.slotDescription)); } else { // Supported slot @@ -49,7 +49,7 @@ CK_RV parse_readers(ykpiv_state *state, const CK_BYTE_PTR readers, const CK_ULON memset(slots[*n_slots].info.slotDescription, ' ', sizeof(slots[*n_slots].info.slotDescription)); s = slots[*n_slots].info.slotDescription; l = sizeof(slots[*n_slots].info.slotDescription); - strncpy((char *)s, (char*)p, l); + memcpy((char *)s, (char*)p, l); memset(slots[*n_slots].info.manufacturerID, ' ', sizeof(slots[*n_slots].info.manufacturerID)); s = slots[*n_slots].info.manufacturerID; @@ -76,7 +76,7 @@ CK_RV parse_readers(ykpiv_state *state, const CK_BYTE_PTR readers, const CK_ULON } } (*n_slots)++; - p += i + 1; + p = readers + i + 1; } return CKR_OK; @@ -92,7 +92,7 @@ failure: CK_RV create_token(ykpiv_state *state, CK_BYTE_PTR p, ykcs11_slot_t *slot) { - token_vendor_t token; + token_vendor_t token; CK_TOKEN_INFO_PTR t_info; slot->token = malloc(sizeof(ykcs11_token_t)); // TODO: free @@ -114,17 +114,23 @@ CK_RV create_token(ykpiv_state *state, CK_BYTE_PTR p, ykcs11_slot_t *slot) { if (ykpiv_connect(state, (char *)p) != YKPIV_OK) return CKR_FUNCTION_FAILED; + memset(t_info->model, ' ', sizeof(t_info->model)); - if(token.get_token_model(state, t_info->model, sizeof(t_info->model)) != CKR_OK) + if(token.get_token_model(state, t_info->model, sizeof(t_info->model)) != CKR_OK) { + ykpiv_disconnect(state); return CKR_FUNCTION_FAILED; - ykpiv_disconnect(state); + } memset(t_info->serialNumber, ' ', sizeof(t_info->serialNumber)); - if(token.get_token_serial(t_info->serialNumber, sizeof(t_info->serialNumber)) != CKR_OK) + if(token.get_token_serial(t_info->serialNumber, sizeof(t_info->serialNumber)) != CKR_OK) { + ykpiv_disconnect(state); return CKR_FUNCTION_FAILED; + } - if (token.get_token_flags(&t_info->flags) != CKR_OK) + if (token.get_token_flags(&t_info->flags) != CKR_OK) { + ykpiv_disconnect(state); return CKR_FUNCTION_FAILED; + } t_info->ulMaxSessionCount = CK_UNAVAILABLE_INFORMATION; @@ -146,20 +152,19 @@ CK_RV create_token(ykpiv_state *state, CK_BYTE_PTR p, ykcs11_slot_t *slot) { t_info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; - //ykpiv_get_version(piv_state, buf, sizeof(buf)); - //if (token_vendor.get_token_version(buf, strlen(buf), &ver) != CKR_OK) // TODO: fix this - // return CKR_FUNCTION_FAILED; - - //t_info->hardwareVersion = ver; // version number of hardware // TODO: fix - - //t_info->firmwareVersion = ver; // version number of firmware // TODO: fix + // Ignore hardware version, report firmware version + if (token.get_token_version(state, &t_info->firmwareVersion) != CKR_OK) { + ykpiv_disconnect(state); + return CKR_FUNCTION_FAILED; + } 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; + ykpiv_disconnect(state); + return CKR_OK; } @@ -170,8 +175,8 @@ void destroy_token(ykcs11_slot_t *slot) { CK_BBOOL is_valid_key_id(CK_BYTE id) { - // Valid ids are 0, 1, 2, 3 - if (id > 3) + // Valid ids are [0, 23] aka [0x00, 0x17] + if (id > 23) return CK_FALSE; return CK_TRUE; diff --git a/ykcs11/ykcs11.c b/ykcs11/ykcs11.c index 739df2b..19fd60b 100644 --- a/ykcs11/ykcs11.c +++ b/ykcs11/ykcs11.c @@ -51,7 +51,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( ) { CK_BYTE readers[2048]; - CK_ULONG len = sizeof(readers); + size_t len = sizeof(readers); DIN; @@ -114,7 +114,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)( CK_INFO_PTR pInfo ) { - CK_VERSION ver = {YKCS11_VERSION_MAJOR, (YKCS11_VERSION_MINOR * 100) + YKCS11_VERSION_PATCH}; + CK_VERSION ver = {YKCS11_VERSION_MAJOR, (YKCS11_VERSION_MINOR * 10) + YKCS11_VERSION_PATCH}; DIN; @@ -421,7 +421,36 @@ CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)( ) { DIN; - DBG("TODO!!!"); + CK_RV rv; + token_vendor_t token; + + if (piv_state == NULL) { + DBG("libykpiv is not initialized or already finalized"); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (session.handle == CK_INVALID_HANDLE) { + DBG("User called SetPIN on closed session"); + return CKR_SESSION_CLOSED; + } + + if (hSession != YKCS11_SESSION_ID) { + DBG("Unknown session %lu", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + + CK_USER_TYPE user_type = CKU_USER; + if (session.info.state == CKS_RW_SO_FUNCTIONS) { + user_type = CKU_SO; + } + + token = get_token_vendor(session.slot->token->vid); + rv = token.token_change_pin(piv_state, user_type, pOldPin, ulOldLen, pNewPin, ulNewLen); + if (rv != CKR_OK) { + DBG("Pin change failed %lx", rv); + return rv; + } + DOUT; return CKR_OK; } @@ -438,7 +467,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( CK_RV rv; piv_obj_id_t *cert_ids; CK_ULONG i; - CK_BYTE cert_data[2100]; // Max cert value for ykpiv + CK_BYTE cert_data[3072]; // Max cert value for ykpiv CK_ULONG cert_len = sizeof(cert_data); DIN; // TODO: pApplication and Notify @@ -479,7 +508,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( } if ((flags & CKF_SERIAL_SESSION) == 0) { - DBG("Open session called without CKF_SERIAL_SESSION set"); // Reuired by spes + DBG("Open session called without CKF_SERIAL_SESSION set"); // Required by specs return CKR_SESSION_PARALLEL_NOT_SUPPORTED; } @@ -507,6 +536,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( session.info.state = CKS_RO_PUBLIC_SESSION; // Nobody has logged in, default RW session } + session.info.slotID = slotID; session.info.flags = flags; session.info.ulDeviceError = 0; @@ -731,8 +761,8 @@ CK_DEFINE_FUNCTION(CK_RV, C_Login)( return CKR_SESSION_HANDLE_INVALID; } - if ((session.info.flags & CKF_RW_SESSION) == 0) { // TODO: make macros for these? - DBG("Tried to log-in to a read-only session"); + if (userType == CKU_SO && (session.info.flags & CKF_RW_SESSION) == 0) { // TODO: make macros for these? + DBG("Tried to log-in SO user to a read-only session"); return CKR_SESSION_READ_ONLY_EXISTS; } @@ -858,6 +888,13 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( CK_BYTE_PTR dp; CK_BYTE_PTR dq; CK_BYTE_PTR qinv; + CK_ULONG p_len; + CK_ULONG q_len; + CK_ULONG dp_len; + CK_ULONG dq_len; + CK_ULONG qinv_len; + CK_BYTE_PTR ec_data; + CK_ULONG ec_data_len; CK_ULONG vendor_defined; token_vendor_t token; CK_BBOOL is_new; @@ -972,6 +1009,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( DBG("Unable to store certificate data"); return CKR_FUNCTION_FAILED; } + *phObject = cert_id; break; @@ -980,11 +1018,17 @@ 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, &vendor_defined); + rv = check_create_ec_key(pTemplate, ulCount, &id, &ec_data, &ec_data_len, &vendor_defined); if (rv != CKR_OK) { // Try to parse the key as RSA is_rsa = CK_TRUE; - rv = check_create_rsa_key(pTemplate, ulCount, &id, &p, &q, &dp, &dq, &qinv, &value_len, &vendor_defined); + rv = check_create_rsa_key(pTemplate, ulCount, &id, + &p, &p_len, + &q, &q_len, + &dp, &dp_len, + &dq, &dq_len, + &qinv, &qinv_len, + &vendor_defined); if (rv != CKR_OK) { DBG("Private key template not valid"); return rv; @@ -997,9 +1041,14 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( if (is_rsa == CK_TRUE) { DBG("Key is RSA"); - rv = token.token_import_private_key(piv_state, piv_2_ykpiv(object), p, q, dp, dq, qinv, - NULL, - value_len, vendor_defined); + rv = token.token_import_private_key(piv_state, piv_2_ykpiv(object), + p, p_len, + q, q_len, + dp, dp_len, + dq, dq_len, + qinv, qinv_len, + NULL, 0, + vendor_defined); if (rv != CKR_OK) { DBG("Unable to import RSA private key"); return rv; @@ -1007,14 +1056,22 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( } 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, vendor_defined); + rv = token.token_import_private_key(piv_state, piv_2_ykpiv(object), + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + ec_data, ec_data_len, + vendor_defined); if (rv != CKR_OK) { DBG("Unable to import ECDSA private key"); return rv; } } + + *phObject = PIV_PVTK_OBJ_PIV_AUTH + id; + break; default: @@ -1627,8 +1684,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)( return CKR_OPERATION_ACTIVE; } - if (pMechanism == NULL_PTR || - hKey == NULL_PTR) + if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; DBG("Trying to sign some data with mechanism %lu and key %lu", pMechanism->mechanism, hKey); @@ -1785,7 +1841,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("Sending %lu bytes to sign", ulDataLen); #if YKCS11_DBG == 1 - dump_hex(pData, ulDataLen, stderr, CK_TRUE); + dump_data(pData, ulDataLen, stderr, CK_TRUE, format_arg_hex); #endif if (is_hashed_mechanism(op_info.mechanism.mechanism) == CK_TRUE) { @@ -1827,7 +1883,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("Using key %lx", op_info.op.sign.key_id); DBG("After padding and transformation there are %lu bytes", op_info.buf_len); #if YKCS11_DBG == 1 - dump_hex(op_info.buf, op_info.buf_len, stderr, CK_TRUE); + dump_data(op_info.buf, op_info.buf_len, stderr, CK_TRUE, format_arg_hex); #endif *pulSignatureLen = sizeof(op_info.buf); @@ -1848,7 +1904,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("Got %lu bytes back", *pulSignatureLen); #if YKCS11_DBG == 1 - dump_hex(pSignature, *pulSignatureLen, stderr, CK_TRUE); + dump_data(pSignature, *pulSignatureLen, stderr, CK_TRUE, format_arg_hex); #endif if (!is_RSA_mechanism(op_info.mechanism.mechanism)) { @@ -1858,7 +1914,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("After removing DER encoding %lu", *pulSignatureLen); #if YKCS11_DBG == 1 - dump_hex(pSignature, *pulSignatureLen, stderr, CK_TRUE); + dump_data(pSignature, *pulSignatureLen, stderr, CK_TRUE, format_arg_hex); #endif } @@ -2090,7 +2146,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)( CK_ULONG pvtk_id; CK_ULONG pubk_id; piv_obj_id_t *obj_ptr; - CK_BYTE cert_data[2100]; + CK_BYTE cert_data[3072]; CK_ULONG cert_len; DIN; diff --git a/ykcs11/yubico_token.c b/ykcs11/yubico_token.c index 7210a29..a85a26a 100644 --- a/ykcs11/yubico_token.c +++ b/ykcs11/yubico_token.c @@ -66,43 +66,44 @@ static const CK_MECHANISM_INFO token_mechanism_infos[] = { // KEEP ALIGNED WITH static const piv_obj_id_t token_objects[] = { // TODO: is there a way to get this from the token? PIV_DATA_OBJ_X509_PIV_AUTH, // PIV authentication - PIV_DATA_OBJ_X509_CARD_AUTH, // Certificate for card authentication - PIV_DATA_OBJ_X509_DS, // Certificate for digital signature - PIV_DATA_OBJ_X509_KM, // Certificate for key management + PIV_DATA_OBJ_X509_CARD_AUTH, // card authentication + PIV_DATA_OBJ_X509_DS, // digital signature + PIV_DATA_OBJ_X509_KM, // key management + PIV_DATA_OBJ_X509_RETIRED1, // Retired key 1 + PIV_DATA_OBJ_X509_RETIRED2, // Retired key 2 + PIV_DATA_OBJ_X509_RETIRED3, // Retired key 3 + PIV_DATA_OBJ_X509_RETIRED4, // Retired key 4 + PIV_DATA_OBJ_X509_RETIRED5, // Retired key 5 + PIV_DATA_OBJ_X509_RETIRED6, // Retired key 6 + PIV_DATA_OBJ_X509_RETIRED7, // Retired key 7 + PIV_DATA_OBJ_X509_RETIRED8, // Retired key 8 + PIV_DATA_OBJ_X509_RETIRED9, // Retired key 9 + PIV_DATA_OBJ_X509_RETIRED10, // Retired key 10 + PIV_DATA_OBJ_X509_RETIRED11, // Retired key 11 + PIV_DATA_OBJ_X509_RETIRED12, // Retired key 12 + PIV_DATA_OBJ_X509_RETIRED13, // Retired key 13 + PIV_DATA_OBJ_X509_RETIRED14, // Retired key 14 + PIV_DATA_OBJ_X509_RETIRED15, // Retired key 15 + PIV_DATA_OBJ_X509_RETIRED16, // Retired key 16 + PIV_DATA_OBJ_X509_RETIRED17, // Retired key 17 + PIV_DATA_OBJ_X509_RETIRED18, // Retired key 18 + PIV_DATA_OBJ_X509_RETIRED19, // Retired key 19 + PIV_DATA_OBJ_X509_RETIRED20, // Retired key 20 PIV_DATA_OBJ_CCC, // Card capability container PIV_DATA_OBJ_CHUI, // Cardholder unique id PIV_DATA_OBJ_CHF, // Cardholder fingerprints PIV_DATA_OBJ_SEC_OBJ, // Security object PIV_DATA_OBJ_CHFI, // Cardholder facial images - //PIV_DATA_OBJ_PI, // Cardholder printed information - //PIV_DATA_OBJ_DISCOVERY, // Discovery object - //PIV_DATA_OBJ_HISTORY, // History object -/* PIV_DATA_OBJ_RETIRED_X509_1, // Retired certificate for KM 1 - PIV_DATA_OBJ_RETIRED_X509_2, // Retired certificate for KM 2 - PIV_DATA_OBJ_RETIRED_X509_3, // Retired certificate for KM 3 - PIV_DATA_OBJ_RETIRED_X509_4, // Retired certificate for KM 4 - PIV_DATA_OBJ_RETIRED_X509_5, // Retired certificate for KM 5 - PIV_DATA_OBJ_RETIRED_X509_6, // Retired certificate for KM 6 - PIV_DATA_OBJ_RETIRED_X509_7, // Retired certificate for KM 7 - PIV_DATA_OBJ_RETIRED_X509_8, // Retired certificate for KM 8 - PIV_DATA_OBJ_RETIRED_X509_9, // Retired certificate for KM 9 - PIV_DATA_OBJ_RETIRED_X509_10, // Retired certificate for KM 10 - PIV_DATA_OBJ_RETIRED_X509_11, // Retired certificate for KM 11 - PIV_DATA_OBJ_RETIRED_X509_12, // Retired certificate for KM 12 - PIV_DATA_OBJ_RETIRED_X509_13, // Retired certificate for KM 13 - PIV_DATA_OBJ_RETIRED_X509_14, // Retired certificate for KM 14 - PIV_DATA_OBJ_RETIRED_X509_15, // Retired certificate for KM 15 - PIV_DATA_OBJ_RETIRED_X509_16, // Retired certificate for KM 16 - PIV_DATA_OBJ_RETIRED_X509_17, // Retired certificate for KM 17 - PIV_DATA_OBJ_RETIRED_X509_18, // Retired certificate for KM 18 - PIV_DATA_OBJ_RETIRED_X509_19, // Retired certificate for KM 19 - PIV_DATA_OBJ_RETIRED_X509_20, // Retired certificate for KM 20*/ - //PIV_DATA_OBJ_IRIS_IMAGE, // Cardholder iris images - //PIV_DATA_OBJ_BITGT, // Biometric information templates group template - //PIV_DATA_OBJ_SM_SIGNER, // Secure messaging signer - //PIV_DATA_OBJ_PC_REF_DATA, // Pairing code reference data + //PIV_DATA_OBJ_PI, // Cardholder printed information + //PIV_DATA_OBJ_DISCOVERY, // Discovery object + //PIV_DATA_OBJ_HISTORY, // History object + //PIV_DATA_OBJ_IRIS_IMAGE, // Cardholder iris images + //PIV_DATA_OBJ_BITGT, // Biometric information templates group template + //PIV_DATA_OBJ_SM_SIGNER, // Secure messaging signer + //PIV_DATA_OBJ_PC_REF_DATA, // Pairing code reference data }; -static const CK_ULONG token_objects_num = sizeof(token_objects) / sizeof(piv_obj_id_t); +static const CK_ULONG neo_token_objects_num = sizeof(token_objects) / sizeof(piv_obj_id_t) - 20; +static const CK_ULONG yk4_token_objects_num = sizeof(token_objects) / sizeof(piv_obj_id_t); CK_RV YUBICO_get_token_label(CK_UTF8CHAR_PTR str, CK_ULONG len) { @@ -152,32 +153,18 @@ CK_RV YUBICO_get_token_flags(CK_FLAGS_PTR flags) { } -CK_RV YUBICO_get_token_version(CK_UTF8CHAR_PTR v_str, CK_ULONG len, CK_VERSION_PTR version) { +CK_RV YUBICO_get_token_version(ykpiv_state *state, CK_VERSION_PTR version) { - CK_VERSION v = {0, 0}; - unsigned int i = 0; + char buf[16]; - while (i < len && v_str[i] != '.') { - v.major *= 10; - v.major += v_str[i++] - '0'; - } + if (version == NULL) + return CKR_ARGUMENTS_BAD; - i++; + if (ykpiv_get_version(state, buf, sizeof(buf)) != YKPIV_OK) + return CKR_FUNCTION_FAILED; - while (i < len && v_str[i] != '.') { - v.minor *= 10; - v.minor += v_str[i++] - '0'; - } - - i++; - - while (i < len && v_str[i] != '.') { - v.minor *= 10; - v.minor += v_str[i++] - '0'; - } - - version->major = v.major; - version->minor = v.minor; + version->major = (buf[0] - '0'); + version->minor = (buf[2] - '0') * 100 + (buf[4] - '0'); return CKR_OK; } @@ -225,13 +212,16 @@ CK_RV YUBICO_get_token_mechanism_info(CK_MECHANISM_TYPE mec, CK_MECHANISM_INFO_P 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; + CK_BYTE buf[2048]; + CK_ULONG buf_len; + CK_BYTE major; + CK_ULONG i; - 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; + piv_obj_id_t certs[24]; + piv_obj_id_t pvtkeys[24]; + piv_obj_id_t pubkeys[24]; + CK_ULONG n_cert = 0; + CK_ULONG token_objects_num = neo_token_objects_num; if (state == NULL || len == NULL_PTR) return CKR_ARGUMENTS_BAD; @@ -239,6 +229,11 @@ static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, if (num_only == CK_FALSE && obj == NULL) return CKR_ARGUMENTS_BAD; + if (ykpiv_get_version(state, (char *) buf, sizeof(buf)) != YKPIV_OK) + return CKR_FUNCTION_FAILED; + + major = buf[0] - '0'; + buf_len = sizeof(buf); if (ykpiv_fetch_object(state, YKPIV_OBJ_AUTHENTICATION, buf, &buf_len) == YKPIV_OK) { certs[n_cert] = PIV_CERT_OBJ_X509_PIV_AUTH; @@ -275,6 +270,20 @@ static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, DBG("Found KMK cert (9d)"); } + if (major >= 4) { + for (i = 0; i < 20; i++) { + buf_len = sizeof(buf); + if (ykpiv_fetch_object(state, YKPIV_OBJ_RETIRED1 + i, buf, &buf_len) == YKPIV_OK) { + certs[n_cert] = PIV_CERT_OBJ_X509_RETIRED1 + i; + pvtkeys[n_cert] = PIV_PVTK_OBJ_RETIRED1 + i; + pubkeys[n_cert] = PIV_PUBK_OBJ_RETIRED1 + i; + n_cert++; + DBG("Found RETIRED cert (%lx)", 0x82 + i); + } + } + token_objects_num = yk4_token_objects_num; + } + DBG("The total number of objects for this token is %lu", (n_cert * 3) + token_objects_num); if (num_only == CK_TRUE) { @@ -289,8 +298,16 @@ static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only, if (*len < (n_cert * 3) + token_objects_num) return CKR_BUFFER_TOO_SMALL; - // Copy mandatory data objects - memcpy(obj, token_objects, token_objects_num * sizeof(piv_obj_id_t)); + // Copy data objects + if (major >= 4) { + // YK4: just copy all the objects + memcpy(obj, token_objects, token_objects_num * sizeof(piv_obj_id_t)); + } + else { + // NEO: remove retired keys + memcpy(obj, token_objects, 4 * sizeof(piv_obj_id_t)); + memcpy(obj + 4, token_objects + 24, (neo_token_objects_num - 4) * sizeof(piv_obj_id_t)); + } // Copy certificates if (n_cert > 0) { @@ -317,3 +334,25 @@ CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_ return CKR_OK; } + +CK_RV YUBICO_token_change_pin(ykpiv_state *state, CK_USER_TYPE user_type, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen) { + int tries; + ykpiv_rc res; + if (user_type != CKU_USER) { + DBG("TODO implement other users pin change"); + return CKR_FUNCTION_FAILED; + } + res = ykpiv_change_pin(state, pOldPin, ulOldLen, pNewPin, ulNewLen, &tries); + switch (res) { + case YKPIV_OK: + return CKR_OK; + case YKPIV_SIZE_ERROR: + return CKR_PIN_LEN_RANGE; + case YKPIV_WRONG_PIN: + return CKR_PIN_INCORRECT; + case YKPIV_PIN_LOCKED: + return CKR_PIN_LOCKED; + default: + return CKR_FUNCTION_FAILED; + } +} diff --git a/ykcs11/yubico_token.h b/ykcs11/yubico_token.h index e95c8e3..37f90a2 100644 --- a/ykcs11/yubico_token.h +++ b/ykcs11/yubico_token.h @@ -10,12 +10,14 @@ CK_RV YUBICO_get_token_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len); CK_RV YUBICO_get_token_model(ykpiv_state *state, CK_UTF8CHAR_PTR str, CK_ULONG len); CK_RV YUBICO_get_token_flags(CK_FLAGS_PTR flags); CK_RV YUBICO_get_token_serial(CK_CHAR_PTR str, CK_ULONG len); -CK_RV YUBICO_get_token_version(CK_UTF8CHAR_PTR v_str, CK_ULONG v_str_len, CK_VERSION_PTR version); +CK_RV YUBICO_get_token_version(ykpiv_state *state, CK_VERSION_PTR version); 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_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_PTR len); +CK_RV YUBICO_token_change_pin(ykpiv_state *state, CK_USER_TYPE user_type, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, + CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen); #endif