diff --git a/SOURCES/opensc-0.20.0-cardos.patch b/SOURCES/opensc-0.20.0-cardos.patch new file mode 100644 index 0000000..b26b4ce --- /dev/null +++ b/SOURCES/opensc-0.20.0-cardos.patch @@ -0,0 +1,1338 @@ +From 592a641cb9f8eb17d4d1b1c9a96a1581f61e169b Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Sun, 29 Mar 2020 05:56:21 -0500 +Subject: [PATCH 2/6] pkcs11-tool - use valid data for decription tests + +In tests, make sute test data is either padded, or "zero" padded +so size if data <= modlen - 11. The smallest pad in 11 bytes, +00 | NN | PS | 00. PS is at least 8 bytes. +"zero" padding has N = 00, PS >= 8 byte of 00. + + On branch cardos-5.3 + Changes to be committed: + modified: tools/pkcs11-tool.c +--- + src/tools/pkcs11-tool.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c +index 3ad9289033..b1674a76cf 100644 +--- a/src/tools/pkcs11-tool.c ++++ b/src/tools/pkcs11-tool.c +@@ -5044,8 +5044,8 @@ static int test_signature(CK_SESSION_HANDLE sess) + } + + if (firstMechType == CKM_RSA_X_509) { +- /* make sure our data is smaller than the modulus */ +- data[0] = 0x00; ++ /* make sure our data is smaller than the modulus - 11 */ ++ memset(data, 0, 11); /* in effect is zero padding */ + } + + ck_mech.mechanism = firstMechType; + +From 3043f5b8a15c7cff90adcd2d31095afa734e663c Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Sun, 5 Apr 2020 11:04:42 -0500 +Subject: [PATCH 3/6] Increase SC_MAX_SUPPORTED_ALGORITHMS from 8 to 16 + +CardOS cards may have more then 8 supported_algo_info entries in tokenInfo. +We may bemissing some. We have seen 8 in some pkcs15-tool -i -v output. + +Simple fix is to incrase the limit. More appropriate fix is to remove the limit, +much like is done with sc_algorithm_info. and use realloc of the array. + + On branch cardos-5.3 + Changes to be committed: + modified: src/libopensc/pkcs15-prkey.c + modified: src/libopensc/pkcs15-skey.c + modified: src/libopensc/pkcs15.c + modified: src/libopensc/types.h +--- + src/libopensc/pkcs15-prkey.c | 10 +++++++++- + src/libopensc/pkcs15-skey.c | 10 +++++++++- + src/libopensc/pkcs15.c | 10 +++++++++- + src/libopensc/types.h | 6 ++++-- + 4 files changed, 31 insertions(+), 5 deletions(-) + +diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c +index ed008ede14..a6c05415ec 100644 +--- a/src/libopensc/pkcs15-prkey.c ++++ b/src/libopensc/pkcs15-prkey.c +@@ -48,10 +48,18 @@ + #include "aux-data.h" + + /* +- * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 ++ * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 16 + */ + #define C_ASN1_SUPPORTED_ALGORITHMS_SIZE (SC_MAX_SUPPORTED_ALGORITHMS + 1) + static const struct sc_asn1_entry c_asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE] = { ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, +diff --git a/src/libopensc/pkcs15-skey.c b/src/libopensc/pkcs15-skey.c +index b22e619723..4e58355ad7 100644 +--- a/src/libopensc/pkcs15-skey.c ++++ b/src/libopensc/pkcs15-skey.c +@@ -28,10 +28,18 @@ + #include + + /* +- * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 ++ * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 16 + */ + #define C_ASN1_SUPPORTED_ALGORITHMS_SIZE (SC_MAX_SUPPORTED_ALGORITHMS + 1) + static const struct sc_asn1_entry c_asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE] = { ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmReference", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, +diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c +index ba04f531ef..d4a4496980 100644 +--- a/src/libopensc/pkcs15.c ++++ b/src/libopensc/pkcs15.c +@@ -64,9 +64,17 @@ static const struct sc_asn1_entry c_asn1_algorithm_info_parameters[3] = { + }; + + /* +- * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 8 ++ * in src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as 16 + */ + static const struct sc_asn1_entry c_asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1] = { ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, ++ { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, + { "algorithmInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, +diff --git a/src/libopensc/types.h b/src/libopensc/types.h +index 76cf4c1a71..17035b5505 100644 +--- a/src/libopensc/types.h ++++ b/src/libopensc/types.h +@@ -52,9 +52,11 @@ typedef unsigned char u8; + + /* When changing this value, pay attention to the initialization of the ASN1 + * static variables that use this macro, like, for example, +- * 'c_asn1_supported_algorithms' in src/libopensc/pkcs15.c ++ * 'c_asn1_supported_algorithms' in src/libopensc/pkcs15.c, ++ * src/libopensc/pkcs15-prkey.c and src/libopensc/pkcs15-skey.c ++ * `grep "src/libopensc/types.h SC_MAX_SUPPORTED_ALGORITHMS defined as"' + */ +-#define SC_MAX_SUPPORTED_ALGORITHMS 8 ++#define SC_MAX_SUPPORTED_ALGORITHMS 16 + + struct sc_lv_data { + unsigned char *value; + +From 8292ff57ad581995eca8209764813725594dd34f Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Fri, 17 Apr 2020 12:26:14 -0500 +Subject: [PATCH 4/6] sc_supported_algo_info - Put ECDSA OID as inline + + Mismatch of ASN1 parsing of tokeninfo.supported_algos[n].paramters + in one place parameter was treated as a pointer to sc_object_id + and in another as inline structure. This caused segfaults + in pkcs15-tool when it tried to print the OID. + + Changes to be committed: + modified: src/libopensc/opensc.h + modified: src/libopensc/pkcs15.c +--- + src/libopensc/opensc.h | 2 +- + src/libopensc/pkcs15.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h +index 9e764665b2..0c3c73e229 100644 +--- a/src/libopensc/opensc.h ++++ b/src/libopensc/opensc.h +@@ -223,7 +223,7 @@ extern "C" { + struct sc_supported_algo_info { + unsigned int reference; + unsigned int mechanism; +- struct sc_object_id *parameters; /* OID for ECC, NULL for RSA */ ++ struct sc_object_id parameters; /* OID for ECC */ + unsigned int operations; + struct sc_object_id algo_id; + unsigned int algo_ref; +diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c +index d4a4496980..c58c34fd13 100644 +--- a/src/libopensc/pkcs15.c ++++ b/src/libopensc/pkcs15.c +@@ -318,7 +318,7 @@ sc_pkcs15_encode_tokeninfo(sc_context_t *ctx, sc_pkcs15_tokeninfo_t *ti, + sc_format_asn1_entry(asn1_algo_infos[ii] + 1, &ti->supported_algos[ii].mechanism, &mechanism_len, 1); + sc_format_asn1_entry(asn1_algo_infos[ii] + 2, + asn1_algo_infos_parameters[ii], NULL, 1); +- if (!ti->supported_algos[ii].parameters) { ++ if (!sc_valid_oid(&ti->supported_algos[ii].parameters)) { + sc_format_asn1_entry(asn1_algo_infos_parameters[ii] + 0, + NULL, NULL, 1); + } + +From f9665e4d46ed278b6cf1188e0e7adb5b6e119ac9 Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Thu, 26 Mar 2020 13:51:33 -0500 +Subject: [PATCH 5/6] pkcs15-tool.c - print Supported_algorithms from tokenInfo + +Some cards can provide supported algorithms in tokenInfo +which contain ECDSA OID, and PKCS11 mechanism + +Don't know how many Algo_refs were actually read, +and a ref of 0 may be valid. print at least one Algo_refs. + +Print the mechanism from PKCS11, and print operations +Use the $(top_srcdir)/src/pkcs11/pkcs11-display.c on Unix +Use the $(TOPDIR)\src\pkcs11\pkcs11-display.obj on Windows + +pkcs15.tool.c treat ECDSA OID as inline + +pkcs15-tool prints PKCS11 mechanisms using pkcs11-display.c +Automake now warns that the default will change, in the future +so "[subdir-objects]" is added to configure.ac + + Changes to be committed: + modified: configure.ac + modified: src/tools/Makefile.am + modified: src/tools/Makefile.mak + modified: src/tools/pkcs15-tool.c +--- + configure.ac | 2 +- + src/tools/Makefile.am | 2 +- + src/tools/Makefile.mak | 5 ++++ + src/tools/pkcs15-tool.c | 57 +++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 64 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 705bc027f1..f54093b0aa 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -27,7 +27,7 @@ AC_INIT([PRODUCT_NAME],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERS + AC_CONFIG_AUX_DIR([.]) + AC_CONFIG_HEADERS([config.h]) + AC_CONFIG_MACRO_DIR([m4]) +-AM_INIT_AUTOMAKE(foreign 1.10) ++AM_INIT_AUTOMAKE(foreign 1.10 [subdir-objects]) + + OPENSC_VERSION_MAJOR="PACKAGE_VERSION_MAJOR" + OPENSC_VERSION_MINOR="PACKAGE_VERSION_MINOR" +diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am +index 5ee5edfb29..55beb631d5 100644 +--- a/src/tools/Makefile.am ++++ b/src/tools/Makefile.am +@@ -52,7 +52,7 @@ piv_tool_SOURCES = piv-tool.c util.c + piv_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) + opensc_explorer_SOURCES = opensc-explorer.c util.c + opensc_explorer_LDADD = $(OPTIONAL_READLINE_LIBS) +-pkcs15_tool_SOURCES = pkcs15-tool.c util.c ++pkcs15_tool_SOURCES = pkcs15-tool.c util.c ../pkcs11/pkcs11-display.c ../pkcs11/pkcs11-display.h + pkcs15_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) + pkcs11_tool_SOURCES = pkcs11-tool.c util.c + pkcs11_tool_LDADD = \ +diff --git a/src/tools/Makefile.mak b/src/tools/Makefile.mak +index 4637a44dc6..38e5ba4e7e 100644 +--- a/src/tools/Makefile.mak ++++ b/src/tools/Makefile.mak +@@ -52,6 +52,11 @@ pkcs11-register.exe: pkcs11-register-cmdline.obj fread_to_eof.obj $(LIBS) + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj pkcs11-register-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib + mt -manifest exe.manifest -outputresource:$@;1 + ++pkcs15-tool.exe: pkcs15-tool.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj ++ cl $(COPTS) /c $*.c ++ link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib ++ mt -manifest exe.manifest -outputresource:$@;1 ++ + .c.exe: + cl $(COPTS) /c $< + link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib +diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c +index e901e17d0d..363bfb8272 100644 +--- a/src/tools/pkcs15-tool.c ++++ b/src/tools/pkcs15-tool.c +@@ -57,6 +57,7 @@ typedef unsigned __int32 uint32_t; + #include "libopensc/pkcs15.h" + #include "libopensc/asn1.h" + #include "util.h" ++#include "pkcs11/pkcs11-display.h" + + static const char *app_name = "pkcs15-tool"; + +@@ -607,6 +608,8 @@ static void print_prkey_info(const struct sc_pkcs15_object *obj) + struct sc_pkcs15_prkey_info *prkey = (struct sc_pkcs15_prkey_info *) obj->data; + unsigned char guid[40]; + size_t guid_len; ++ int i; ++ int last_algo_refs = 0; + + if (compact) { + printf("\t%-3s", key_types[7 & obj->type]); +@@ -635,6 +638,16 @@ static void print_prkey_info(const struct sc_pkcs15_object *obj) + printf("\tAccess Flags : [0x%02X]", prkey->access_flags); + print_key_access_flags(prkey->access_flags); + printf("\n"); ++ printf("\tAlgo_refs : "); ++ /* zero may be valid and don't know how many were read print at least 1*/ ++ for (i = 0; i< SC_MAX_SUPPORTED_ALGORITHMS; i++) { ++ if (prkey->algo_refs[i] != 0) ++ last_algo_refs = i; ++ } ++ for (i = 0; i< last_algo_refs + 1; i++) { ++ printf("%s%u", (i == 0) ? "" : ", ", prkey->algo_refs[i]); ++ } ++ printf("\n"); + + print_access_rules(obj->access_rules, SC_PKCS15_MAX_ACCESS_RULES); + +@@ -1645,6 +1658,21 @@ static int list_apps(FILE *fout) + return 0; + } + ++ ++static void print_supported_algo_info_operations(unsigned int operation) ++ ++{ ++ size_t i; ++ const char *operations[] = { ++ "compute_checksum", "compute_signature", "verify_checksum", "verify_signature", ++ "encipher", "decipher", "hash", "generate/derive_key" ++ }; ++ const size_t operations_count = NELEMENTS(operations); ++ for (i = 0; i < operations_count; i++) ++ if (operation & (1 << i)) ++ printf(", %s", operations[i]); ++} ++ + static void list_info(void) + { + const char *flags[] = { +@@ -1655,6 +1683,7 @@ static void list_info(void) + }; + char *last_update = sc_pkcs15_get_lastupdate(p15card); + int i, count = 0; ++ int idx; + + printf("PKCS#15 Card [%s]:\n", p15card->tokeninfo->label); + printf("\tVersion : %d\n", p15card->tokeninfo->version); +@@ -1675,6 +1704,34 @@ static void list_info(void) + count++; + } + } ++ printf("\n"); ++ for (i = 0; i < SC_MAX_SUPPORTED_ALGORITHMS; i++) { ++ struct sc_supported_algo_info * sa = &p15card->tokeninfo->supported_algos[i]; ++ ++ if (sa->reference == 0 && sa->reference == 0 && sa->mechanism == 0 ++ && sa->operations == 0 && sa->algo_ref == 0) ++ break; ++ printf("\t\t sc_supported_algo_info[%d]:\n", i); ++ printf("\t\t\t reference : %u (0x%02x)\n", sa->reference, sa->reference); ++ printf("\t\t\t mechanism : [0x%02x] %s\n", sa->mechanism, lookup_enum(MEC_T, sa->mechanism)); ++ if (sc_valid_oid(&sa->parameters)) { ++ printf("\t\t\t parameters: %i", sa->parameters.value[0]); ++ for (idx = 1; idx < SC_MAX_OBJECT_ID_OCTETS && sa->parameters.value[idx] != -1 ; idx++) ++ printf(".%i", sa->parameters.value[idx]); ++ printf("\n"); ++ } ++ printf("\t\t\t operations : [0x%2.2x]",sa->operations); ++ print_supported_algo_info_operations(sa->operations); ++ printf("\n"); ++ if (sc_valid_oid((const struct sc_object_id*)&sa->algo_id)) { ++ printf("\t\t\t algo_id : %i", sa->algo_id.value[0]); ++ for (idx = 1; idx < SC_MAX_OBJECT_ID_OCTETS && sa->algo_id.value[idx] != -1 ; idx++) ++ printf(".%i", sa->algo_id.value[idx]); ++ printf("\n"); ++ } ++ printf("\t\t\t algo_ref : [0x%02x]\n",sa->algo_ref); ++ } ++ + printf((compact) ? "\n" : "\n\n"); + } + + +From f472f0ec213adc096508997bf7e1786ffb557d52 Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Fri, 17 Apr 2020 11:36:48 -0500 +Subject: [PATCH 6/6] Various CardOS V5_* improvements +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Treat CardOS V5_0 and V5_3 cards differently then older versions: + +Use card->dvr_data as a pointer to cardos_data_t to store private driver +data to pass internally, especially between set security environment +and the crypto operations. Sc_get_encoding_flags sets sec_flags from +algo_info->flags in pkcs15-sec.c and it passed to decipher. + +Some cards when doing a decipher may drop leading 00 byte when +returning data from RSA_RAW decipher. Add leading byte(s) as needed. + +Get Cryptographic Mechanism Reference from Key Reference: + +Key reference byte appears to be a 4 bit Cryptographic Mechanism Reference +and a 4 bit key reference. + +This is only done if key reference & 0xF0 != 0 i.e. default Cryptographic +mechanism reference is 0. which appears to be the case for RSA RAW. +PKCS1 appears to be 0x10 and ECDSA 0x30 + + See iso 7816-4 table 55 for DST: + 84 Reference of a private key + 95 Usage qualifier byte - Table 57 - 40 looks OK + 80 Cryptographic mechanism reference and referes to section 9.2 + +The 4 bit key reference limits card to 16 keys. In future this may not work, +but we can derive a Cryptographic Mechanism Reference from what OpenSC +thinks the card needs to do. Only know RSA RAW, PKCS1 and ECDSA. + +ECDSA code has not been tested, but expected to work. + +Allow setting CardOS type and flags from opensc.conf using card_atr stanza +This is a fallback if newer cards are added or older cards have problems +giving us time to make need changes in next release. + +It will help in identifying what flags are needed for each card. +As user can report what combination of flags work for them. They do this by +adding to opensc.conf with something like this. (Change the ATR to your card's ATR): + + card_atr 3b:d2:18:00:81:31:fe:58:c9:03:16 { + driver = "cardos"; + # type is decimal from cards.h: + # SC_CARD_TYPE_CARDOS_V5_0 is 1009 + # SC_CARD_TYPE_CARDOS_V5_3 is 1010 + type = 1010; + + # flags is hex from opensc.h: + #define SC_ALGORITHM_ONBOARD_KEY_GEN 0x80000000 + #define SC_ALGORITHM_NEED_USAGE 0x40000000 + + #define SC_ALGORITHM_RSA_RAW 0x00000001 /* RSA_RAW is PAD_NONE */ + #define SC_ALGORITHM_RSA_PAD_NONE 0x00000001 + #define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 /* PKCS#1 v1.5 padding */ + #define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004 + #define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008 + #define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 /* PKCS#1 v2.0 PSS */ + #define SC_ALGORITHM_RSA_PAD_OAEP 0x00000020 /* PKCS#1 v2.0 OAEP */ + #define SC_ALGORITHM_RSA_HASH_NONE 0x00000100 /* only applies to PKCS1 padding */ + # example: SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_RAW + flags = 80000101; + #example: SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_PAD_PKCS1 + flags = 80000002; + } + +For V5_0 and v5_3 cards, use sc_get_max_send_size and sc_get_max_recv_size +which takes care or reader sizes even on Windows where SCardControl can not get PART_10 sizes. + +(commit eddea6f3c2d3dafc2c09eba6695c745a61b5186f on Windows forces reader sizes to 255, 256 +in reader-pcsc.c if not already set. It should not do this, but leave that up to card drivers.) + +pkcs15-cardos.c added: + +New file, pkcs15-cardos.c, added as emulation only for CardOS +V5_0 and V5_3 cards. + +sc_pkcs15_bind_internal is called to get tokenInfo as CardOS +cards are substantially PKCS15 cards. But some V5_* cards have +errors in the tokenInfo, Which are corrected. + +For older CardOS cards, card-cardos.c will create all the +card->algorithms. + +Pkcs15-cardos.c will check for card->algorithms and if there +are none, it will do the following: + +SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS is called twice. First to get +the flags as set by user via opensc.conf card_atr or default +flags set by the card driver. Then after determining from the +tokenInfo what algorithms the card can support, the new flags +are passed to card_cardos.c to create card->algorithms. + +https://atos.net/wp-content/uploads/2018/11/CT_181026_LPM_CardOS_V5-3_Multifunctionality_FS_en3_web.pdf +says card supports: "“Command chaining” in accordance with ISO/IEC 7816-4" + +To take advantage of this with older readers, max_send_size and max_recv_size +is now based on minimum of reader limits and "data_field_length" from card. +This should allow card to work in older readers not capable of extended APDU. +So far current cards we have seen do no appear to support “Command chaining”. + + Changes to be committed: + modified: src/libopensc/Makefile.am + modified: src/libopensc/Makefile.mak + modified: src/libopensc/card-cardos.c + modified: src/libopensc/cardctl.h + modified: src/libopensc/cards.h + new file: src/libopensc/pkcs15-cardos.c + modified: src/libopensc/pkcs15-syn.c + modified: src/libopensc/pkcs15-syn.h +--- + src/libopensc/Makefile.am | 4 +- + src/libopensc/Makefile.mak | 2 +- + src/libopensc/card-cardos.c | 336 +++++++++++++++++++++++++++++----- + src/libopensc/cardctl.h | 18 ++ + src/libopensc/cards.h | 1 + + src/libopensc/pkcs15-cardos.c | 177 ++++++++++++++++++ + src/libopensc/pkcs15-syn.c | 3 + + src/libopensc/pkcs15-syn.h | 1 + + 8 files changed, 492 insertions(+), 50 deletions(-) + create mode 100644 src/libopensc/pkcs15-cardos.c + +diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am +index 140665c8a6..9f0dda5ecb 100644 +--- a/src/libopensc/Makefile.am ++++ b/src/libopensc/Makefile.am +@@ -51,7 +51,7 @@ libopensc_la_SOURCES_BASE = \ + ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c reader-tr03119.c \ + \ + card-setcos.c card-miocos.c card-flex.c card-gpk.c \ +- card-cardos.c card-tcos.c card-default.c \ ++ card-cardos.c card-tcos.c pkcs15-cardos.c card-default.c \ + card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \ + card-oberthur.c card-belpic.c card-atrust-acos.c \ + card-entersafe.c card-epass2003.c card-coolkey.c card-incrypto34.c \ +@@ -134,7 +134,7 @@ TIDY_FILES = \ + card-npa.c card-esteid2018.c card-idprime.c \ + \ + pkcs15-openpgp.c \ +- pkcs15-tcos.c pkcs15-esteid.c \ ++ pkcs15-tcos.c pkcs15-esteid.c pkcs15-cardos.c \ + pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c \ + pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \ + pkcs15-oberthur.c pkcs15-itacns.c pkcs15-sc-hsm.c \ +diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak +index 2e3c30c22b..1b0ff45c9b 100644 +--- a/src/libopensc/Makefile.mak ++++ b/src/libopensc/Makefile.mak +@@ -29,7 +29,7 @@ OBJECTS = \ + card-masktech.obj card-gids.obj card-jpki.obj \ + card-npa.obj card-esteid2018.obj card-idprime.obj \ + \ +- pkcs15-openpgp.obj pkcs15-starcert.obj \ ++ pkcs15-openpgp.obj pkcs15-starcert.obj pkcs15-cardos.obj \ + pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-gemsafeGPK.obj \ + pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \ + pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \ +diff --git a/src/libopensc/card-cardos.c b/src/libopensc/card-cardos.c +index 306822b974..4ef6ead0d2 100644 +--- a/src/libopensc/card-cardos.c ++++ b/src/libopensc/card-cardos.c +@@ -53,13 +53,42 @@ static const struct sc_atr_table cardos_atrs[] = { + /* CardOS v5.0 */ + { "3b:d2:18:00:81:31:fe:58:c9:01:14", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, + /* CardOS v5.3 */ +- { "3b:d2:18:00:81:31:fe:58:c9:02:17", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, +- { "3b:d2:18:00:81:31:fe:58:c9:03:16", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_0, 0, NULL}, ++ { "3b:d2:18:00:81:31:fe:58:c9:02:17", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_3, 0, NULL}, ++ { "3b:d2:18:00:81:31:fe:58:c9:03:16", NULL, NULL, SC_CARD_TYPE_CARDOS_V5_3, 0, NULL}, + { NULL, NULL, NULL, 0, 0, NULL } + }; + +-static unsigned int algorithm_ids_in_tokeninfo[SC_MAX_SUPPORTED_ALGORITHMS]; +-static unsigned int algorithm_ids_in_tokeninfo_count=0; ++/* private data for cardos driver */ ++typedef struct cardos_data { ++ /* constructed internally */ ++ unsigned int algorithm_ids_in_tokeninfo[SC_MAX_SUPPORTED_ALGORITHMS]; ++ unsigned int algorithm_ids_in_tokeninfo_count; ++ unsigned long flags; /* flags used by init to create sc_algorithms */ ++ unsigned long ec_flags; ++ unsigned long ext_flags; ++ int rsa_2048; ++ const sc_security_env_t * sec_env; ++} cardos_data_t; ++ ++/* copied from iso7816.c */ ++static void fixup_transceive_length(const struct sc_card *card, ++ struct sc_apdu *apdu) ++{ ++ if (card == NULL || apdu == NULL) { ++ return; ++ } ++ ++ if (apdu->lc > sc_get_max_send_size(card)) { ++ /* The lower layers will automatically do chaining */ ++ apdu->flags |= SC_APDU_FLAGS_CHAINING; ++ } ++ ++ if (apdu->le > sc_get_max_recv_size(card)) { ++ /* The lower layers will automatically do a GET RESPONSE, if possible. ++ * All other workarounds must be carried out by the upper layers. */ ++ apdu->le = sc_get_max_recv_size(card); ++ } ++} + + static int cardos_match_card(sc_card_t *card) + { +@@ -79,6 +108,8 @@ static int cardos_match_card(sc_card_t *card) + return 1; + if (card->type == SC_CARD_TYPE_CARDOS_V5_0) + return 1; ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_3) ++ return 1; + if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { + int rv; + sc_apdu_t apdu; +@@ -159,42 +190,102 @@ static int cardos_have_2048bit_package(sc_card_t *card) + return 0; + } + ++ ++/* Called from cardos_init for old cards, from cardos_cardctl_parsed_token_info for new cards */ ++/* TODO see if works from old cards too */ ++static int cardos_add_algs(sc_card_t *card, unsigned long flags, unsigned long ec_flags, unsigned long ext_flags) ++{ ++ ++ cardos_data_t * priv = (cardos_data_t *)card->drv_data; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ _sc_card_add_rsa_alg(card, 512, flags, 0); ++ _sc_card_add_rsa_alg(card, 768, flags, 0); ++ _sc_card_add_rsa_alg(card, 1024, flags, 0); ++ if (priv->rsa_2048 == 1) { ++ _sc_card_add_rsa_alg(card, 1280, flags, 0); ++ _sc_card_add_rsa_alg(card, 1536, flags, 0); ++ _sc_card_add_rsa_alg(card, 1792, flags, 0); ++ _sc_card_add_rsa_alg(card, 2048, flags, 0); ++ } ++ ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ /* Starting with CardOS 5, the card supports PIN query commands */ ++ card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; ++ _sc_card_add_rsa_alg(card, 3072, flags, 0); ++ _sc_card_add_rsa_alg(card, 4096, flags, 0); ++ } ++ ++ /* TODO need to get sizes from supported_algos too */ ++ if (ec_flags != 0) { ++ _sc_card_add_ec_alg(card, 256, ec_flags, priv->ext_flags, NULL); ++ _sc_card_add_ec_alg(card, 384, ec_flags, priv->ext_flags, NULL); ++ } ++ ++ return 0; ++} ++ + static int cardos_init(sc_card_t *card) + { +- unsigned long flags = 0, rsa_2048 = 0; ++ cardos_data_t * priv = NULL; ++ unsigned long flags = 0; + size_t data_field_length; + sc_apdu_t apdu; + u8 rbuf[2]; + int r; + ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ priv = calloc(1, sizeof(cardos_data_t)); ++ if (!priv) ++ LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); ++ card->drv_data = priv; ++ + card->name = "Atos CardOS"; + card->cla = 0x00; + +- /* Set up algorithm info. */ +- flags = 0; +- if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { +- flags |= SC_ALGORITHM_RSA_PAD_PKCS1; ++ /* let user override flags and type from opensc.conf */ ++ /* user can override card->type too.*/ ++ if (card->flags) { ++ flags = card->flags; + } else { +- flags |= SC_ALGORITHM_RSA_RAW +- | SC_ALGORITHM_RSA_HASH_NONE +- | SC_ALGORITHM_NEED_USAGE +- | SC_ALGORITHM_ONBOARD_KEY_GEN; ++ ++ /* Set up algorithm info. */ ++ flags = 0; ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { ++ flags |= SC_ALGORITHM_RSA_PAD_PKCS1; ++ } else if(card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ flags |= SC_ALGORITHM_RSA_RAW ++ | SC_ALGORITHM_RSA_HASH_NONE ++ | SC_ALGORITHM_ONBOARD_KEY_GEN; ++ } else { ++ flags |= SC_ALGORITHM_RSA_RAW ++ | SC_ALGORITHM_RSA_HASH_NONE ++ | SC_ALGORITHM_NEED_USAGE ++ | SC_ALGORITHM_ONBOARD_KEY_GEN; ++ } + } + ++ priv->flags = flags; ++ + if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { + r = cardos_have_2048bit_package(card); + if (r < 0) + return SC_ERROR_INVALID_CARD; + if (r == 1) +- rsa_2048 = 1; ++ priv->rsa_2048 = 1; + card->caps |= SC_CARD_CAP_APDU_EXT; +- } else if (card->type == SC_CARD_TYPE_CARDOS_M4_3 ++ } else if (card->type == SC_CARD_TYPE_CARDOS_M4_3 + || card->type == SC_CARD_TYPE_CARDOS_M4_2B + || card->type == SC_CARD_TYPE_CARDOS_M4_2C + || card->type == SC_CARD_TYPE_CARDOS_M4_4 +- || card->type == SC_CARD_TYPE_CARDOS_V5_0) { +- rsa_2048 = 1; ++ || card->type == SC_CARD_TYPE_CARDOS_V5_0 ++ || card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ priv->rsa_2048 = 1; + card->caps |= SC_CARD_CAP_APDU_EXT; ++ /* TODO check this. EC only if in supported_algo */ ++ priv->ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; + } + + /* probe DATA FIELD LENGTH with GET DATA */ +@@ -202,6 +293,7 @@ static int cardos_init(sc_card_t *card) + apdu.le = sizeof rbuf; + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); ++ + r = sc_transmit_apdu(card, &apdu); + if (r < 0) + LOG_TEST_RET(card->ctx, +@@ -216,34 +308,99 @@ static int cardos_init(sc_card_t *card) + return SC_ERROR_INVALID_CARD; + data_field_length = ((rbuf[0] << 8) | rbuf[1]); + +- /* strip the length of possible Lc and Le bytes */ +- if (card->caps & SC_CARD_CAP_APDU_EXT) +- card->max_send_size = data_field_length - 6; +- else +- card->max_send_size = data_field_length - 3; +- /* strip the length of SW bytes */ +- card->max_recv_size = data_field_length - 2; ++ /* TODO is this really needed? strip the length of possible Lc and Le bytes */ ++ ++ /* Use Min card sizes and reader too. for V5_3 at least*/ ++ ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "data_field_length:%"SC_FORMAT_LEN_SIZE_T"u " ++ "card->reader->max_send_size:%"SC_FORMAT_LEN_SIZE_T"u " ++ "card->reader->max_recv_size:%"SC_FORMAT_LEN_SIZE_T"u %s", ++ data_field_length, card->reader->max_send_size, card->reader->max_recv_size, ++ (card->caps & SC_CARD_CAP_APDU_EXT) ? "SC_CARD_CAP_APDU_EXT" : " "); ++ ++ if (card->caps & SC_CARD_CAP_APDU_EXT) { ++ card->max_send_size = data_field_length - 6; ++#ifdef _WIN32 ++ /* Windows does not support PCSC PART_10 and may have forced reader to 255/256 ++ * https://github.com/OpenSC/OpenSC/commit/eddea6f3c2d3dafc2c09eba6695c745a61b5186f ++ * may have reset this. if so, will override and force extended ++ * Most, if not all, cardos cards do extended, but not chaining ++ */ ++ if (card->reader->max_send_size == 255 && card->reader->max_recv_size == 256) { ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "reseting reader to use data_field_length"); ++ card->reader->max_send_size = data_field_length - 6; ++ card->reader->max_recv_size = data_field_length - 3; ++ } ++#endif ++ } else ++ card->max_send_size = data_field_length - 3; + +- _sc_card_add_rsa_alg(card, 512, flags, 0); +- _sc_card_add_rsa_alg(card, 768, flags, 0); +- _sc_card_add_rsa_alg(card, 1024, flags, 0); +- if (rsa_2048 == 1) { +- _sc_card_add_rsa_alg(card, 1280, flags, 0); +- _sc_card_add_rsa_alg(card, 1536, flags, 0); +- _sc_card_add_rsa_alg(card, 1792, flags, 0); +- _sc_card_add_rsa_alg(card, 2048, flags, 0); ++ card->max_send_size = sc_get_max_send_size(card); /* include reader sizes and protocol */ ++ card->max_recv_size = data_field_length - 2; ++ card->max_recv_size = sc_get_max_recv_size(card); ++ } else { ++ /* old way, disregards reader capabilities */ ++ if (card->caps & SC_CARD_CAP_APDU_EXT) ++ card->max_send_size = data_field_length - 6; ++ else ++ card->max_send_size = data_field_length - 3; ++ /* strip the length of SW bytes */ ++ card->max_recv_size = data_field_length - 2; + } + +- if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { +- /* Starting with CardOS 5, the card supports PIN query commands */ +- card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; +- _sc_card_add_rsa_alg(card, 3072, flags, 0); +- _sc_card_add_rsa_alg(card, 4096, flags, 0); ++ /*for new cards, wait till after sc_pkcs15_bind_internal reads tokeninfo */ ++ if (card->type != SC_CARD_TYPE_CARDOS_V5_0 && card->type != SC_CARD_TYPE_CARDOS_V5_3) { ++ r = cardos_add_algs(card, flags, 0, 0); + } + + return 0; + } + ++static int cardos_pass_algo_flags(sc_card_t *card, struct sc_cardctl_cardos_pass_algo_flags * ptr) ++{ ++ cardos_data_t * priv = (cardos_data_t *)card->drv_data; ++ int r = 0; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ switch (ptr->pass) { ++ case 1: ++ ptr->card_flags = card->flags; ++ ptr->used_flags = priv->flags; ++ ptr->ec_flags = priv->ec_flags; ++ ptr->ext_flags = priv->ext_flags; ++ break; ++ case 2: ++ r = cardos_add_algs(card,ptr->new_flags, ptr->ec_flags, ptr->ext_flags); ++ break; ++ default: ++ sc_log(card->ctx, "ptr->pass: %ul invalid", ptr->pass); ++ r = SC_ERROR_INTERNAL; ++ } ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ ++ ++static int cardos_finish(sc_card_t *card) ++{ ++ int r = 0; ++ ++ if (card) ++ return 0; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ /* free priv data */ ++ if (card->drv_data) { /* priv */ ++ free(card->drv_data); ++ card->drv_data = NULL; ++ } ++ ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); ++} ++ ++ ++ + static const struct sc_card_error cardos_errors[] = { + /* some error inside the card */ + /* i.e. nothing you can do */ +@@ -772,8 +929,9 @@ cardos_set_security_env(sc_card_t *card, + const sc_security_env_t *env, + int se_num) + { ++ cardos_data_t* priv = (cardos_data_t*)card->drv_data; + sc_apdu_t apdu; +- u8 data[6]; ++ u8 data[9]; + int key_id, r; + + assert(card != NULL && env != NULL); +@@ -782,6 +940,15 @@ cardos_set_security_env(sc_card_t *card, + sc_log(card->ctx, "No or invalid key reference\n"); + return SC_ERROR_INVALID_ARGUMENTS; + } ++ priv->sec_env = env; /* pass on to crypto routines */ ++ ++ /* key_ref includes card mechanism and key number ++ * But newer cards appear to get this some other way, ++ * We can use flags passed to know what OpenSC expects from the card ++ * and have derived what these machanisums are. ++ * Newer cards may change how this is done ++ */ ++ + key_id = env->key_ref[0]; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0); +@@ -802,16 +969,39 @@ cardos_set_security_env(sc_card_t *card, + return SC_ERROR_INVALID_ARGUMENTS; + } + +- if (card->type == SC_CARD_TYPE_CARDOS_V5_0) { ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ /* some cards appear to have key_id be both Cryptographic mechanism reference 4 bits ++ * and key_ref 4 bits. But this limits card to 16 keys. ++ * TODO may need to be looked at at a later time ++ */ + /* Private key reference */ + data[0] = 0x84; + data[1] = 0x01; +- data[2] = key_id; ++ data[2] = key_id & 0x0F; + /* Usage qualifier byte */ + data[3] = 0x95; + data[4] = 0x01; + data[5] = 0x40; + apdu.lc = apdu.datalen = 6; ++ if (key_id & 0xF0) { ++ /* Cryptographic mechanism reference */ ++ data[6] = 0x80; ++ data[7] = 0x01; ++ data[8] = key_id & 0xF0; ++ apdu.lc = apdu.datalen = 9; ++ } else if (priv->sec_env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { ++ /* TODO this may only apply to c903 cards */ ++ /* TODO or only for cards without any supported_algos or EIDComplient only */ ++ data[6] = 0x80; ++ data[7] = 0x01; ++ data[8] = 0x10; ++ apdu.lc = apdu.datalen = 9; ++ } else if (priv->sec_env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW) { ++ data[6] = 0x80; ++ data[7] = 0x01; ++ data[8] = 0x30; ++ apdu.lc = apdu.datalen = 9; ++ } + } else { + data[0] = 0x83; + data[1] = 0x01; +@@ -839,12 +1029,12 @@ cardos_set_security_env(sc_card_t *card, + + sc_log(card->ctx, "is signature"); + sc_log(card->ctx, "Adding ID %d at index %d", algorithm_id, algorithm_id_count); +- algorithm_ids_in_tokeninfo[algorithm_id_count++] = algorithm_id; ++ priv->algorithm_ids_in_tokeninfo[algorithm_id_count++] = algorithm_id; + } + sc_log(card->ctx, "reference=%d, mechanism=%d, operations=%d, algo_ref=%d", + alg.reference, alg.mechanism, alg.operations, alg.algo_ref); + } +- algorithm_ids_in_tokeninfo_count = algorithm_id_count; ++ priv -> algorithm_ids_in_tokeninfo_count = algorithm_id_count; + } while (0); + + LOG_FUNC_RETURN(card->ctx, r); +@@ -859,6 +1049,7 @@ static int + do_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, + u8 *out, size_t outlen) + { ++ /* cardos_data_t* priv = (cardos_data_t*)card->drv_dataa */; + int r; + sc_apdu_t apdu; + +@@ -873,6 +1064,7 @@ do_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, + apdu.data = data; + apdu.lc = datalen; + apdu.datalen = datalen; ++ fixup_transceive_length(card, &apdu); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + +@@ -886,6 +1078,7 @@ static int + cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, + u8 *out, size_t outlen) + { ++ cardos_data_t* priv; + int r; + sc_context_t *ctx; + int do_rsa_pure_sig = 0; +@@ -895,8 +1088,21 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, + + assert(card != NULL && data != NULL && out != NULL); + ctx = card->ctx; ++ priv = (cardos_data_t*)card->drv_data; + SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); + ++ /* sec_env has algorithm_flags set from sc_get_encoding_flags sec_flags ++ * If flags are set correctly we don't need to test anything ++ * TODO this assumes RSA is PSS, PKCS1 or RAW and we are passing ++ * the correct data. Should work for ECDSA too. ++ * use for V5 cards and TODO should for older cards too ++ */ ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ ++ r = do_compute_signature(card, data, datalen, out, outlen); ++ LOG_FUNC_RETURN(ctx, r); ++ } ++ + /* There are two ways to create a signature, depending on the way, + * the key was created: RSA_SIG and RSA_PURE_SIG. + * We can use the following reasoning, to determine the correct operation: +@@ -913,8 +1119,8 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen, + */ + + /* check the the algorithmIDs from the AlgorithmInfo */ +- for (i = 0; i < algorithm_ids_in_tokeninfo_count; ++i) { +- unsigned int id = algorithm_ids_in_tokeninfo[i]; ++ for (i = 0; i < priv->algorithm_ids_in_tokeninfo_count; ++i) { ++ unsigned int id = priv->algorithm_ids_in_tokeninfo[i]; + if (id == 0x86 || id == 0x88) { + do_rsa_sig = 1; + } else if (id == 0x8C || id == 0x8A) { +@@ -985,10 +1191,41 @@ cardos_decipher(struct sc_card *card, + const u8 * crgram, size_t crgram_len, + u8 * out, size_t outlen) + { ++ cardos_data_t* priv = (cardos_data_t*)card->drv_data; + int r; + size_t card_max_send_size = card->max_send_size; + size_t reader_max_send_size = card->reader->max_send_size; + ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ /* 5.3 supports command chaining. Others may also ++ * card_max_send_size for 5.3 is already based on reader max_send_size */ ++ ++ if (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3) { ++ ++ r = iso_ops->decipher(card, crgram, crgram_len, out, outlen); ++ /* ++ * 5.3 supports RAW as well as PKCS1 and PSS ++ * decription may strip padding if card supports it ++ * with cards that support RAW, it always appears to ++ * drop first 00 that is start of padding. ++ */ ++ ++ if (r > 0 && priv->sec_env->algorithm_flags & SC_ALGORITHM_RSA_RAW) { ++ size_t rsize = r; ++ /* RSA RAW crgram_len == modlen */ ++ /* removed padding is always > 1 byte */ ++ /* add back missing leading zero if card dropped it */ ++ if (rsize == crgram_len - 1 && rsize < outlen) { ++ memmove(out+1, out, rsize); ++ out[0] =0x00; ++ r++; ++ } ++ } ++ ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); ++ } ++ + if (sc_get_max_send_size(card) < crgram_len + 1) { + /* CardOS doesn't support chaining for PSO:DEC, so we just _hope_ + * that both, the reader and the card are able to send enough data. +@@ -1003,7 +1240,7 @@ cardos_decipher(struct sc_card *card, + card->max_send_size = card_max_send_size; + card->reader->max_send_size = reader_max_send_size; + +- return r; ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); + } + + static int +@@ -1188,7 +1425,7 @@ static int cardos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) + return SC_ERROR_INTERNAL; +- if ((apdu.resplen == 8) && (card->type == SC_CARD_TYPE_CARDOS_V5_0)) { ++ if ((apdu.resplen == 8) && (card->type == SC_CARD_TYPE_CARDOS_V5_0 || card->type == SC_CARD_TYPE_CARDOS_V5_3)) { + /* cache serial number */ + memcpy(card->serialnr.value, rbuf, 8); + card->serialnr.len = 8; +@@ -1223,6 +1460,9 @@ cardos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) + case SC_CARDCTL_CARDOS_GENERATE_KEY: + return cardos_generate_key(card, + (struct sc_cardctl_cardos_genkey_info *) ptr); ++ case SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS: ++ return cardos_pass_algo_flags(card, ++ (struct sc_cardctl_cardos_pass_algo_flags *) ptr); + case SC_CARDCTL_LIFECYCLE_GET: + return cardos_lifecycle_get(card, (int *) ptr); + case SC_CARDCTL_LIFECYCLE_SET: +@@ -1279,7 +1519,8 @@ cardos_logout(sc_card_t *card) + || card->type == SC_CARD_TYPE_CARDOS_M4_2C + || card->type == SC_CARD_TYPE_CARDOS_M4_3 + || card->type == SC_CARD_TYPE_CARDOS_M4_4 +- || card->type == SC_CARD_TYPE_CARDOS_V5_0) { ++ || card->type == SC_CARD_TYPE_CARDOS_V5_0 ++ || card->type == SC_CARD_TYPE_CARDOS_V5_3) { + sc_apdu_t apdu; + int r; + sc_path_t path; +@@ -1309,6 +1550,7 @@ static struct sc_card_driver * sc_get_driver(void) + cardos_ops = *iso_ops; + cardos_ops.match_card = cardos_match_card; + cardos_ops.init = cardos_init; ++ cardos_ops.finish = cardos_finish; + cardos_ops.select_file = cardos_select_file; + cardos_ops.create_file = cardos_create_file; + cardos_ops.set_security_env = cardos_set_security_env; +diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h +index 0c68c4c625..10ddfa0545 100644 +--- a/src/libopensc/cardctl.h ++++ b/src/libopensc/cardctl.h +@@ -83,6 +83,7 @@ enum { + SC_CARDCTL_CARDOS_PUT_DATA_OCI, + SC_CARDCTL_CARDOS_PUT_DATA_SECI, + SC_CARDCTL_CARDOS_GENERATE_KEY, ++ SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, + + /* + * Starcos SPK 2.3 specific calls +@@ -350,6 +351,14 @@ typedef struct sc_cardctl_pkcs11_init_pin { + size_t pin_len; + } sc_cardctl_pkcs11_init_pin_t; + ++/* ++ * Generic cardctl - card driver can examine token info ++ */ ++struct sc_cardctl_parsed_token_info { ++ unsigned int flags; ++ struct sc_pkcs15_tokeninfo * tokeninfo; ++}; ++ + /* + * GPK lock file. + * Parent DF of file must be selected. +@@ -419,6 +428,15 @@ struct sc_cardctl_cardos_genkey_info { + unsigned short fid; + }; + ++struct sc_cardctl_cardos_pass_algo_flags { ++ unsigned int pass; ++ unsigned long card_flags; /* from card->flags i.e. user set */ ++ unsigned long used_flags; /* as set by default */ ++ unsigned long new_flags; /* set in pkcs15-cardos.c */ ++ unsigned long ec_flags; /* for EC keys */ ++ unsigned long ext_flags; /* for EC keys */ ++}; ++ + /* + * Incrypto34 PIN info + */ +diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h +index cb0501c3aa..8d58fb9368 100644 +--- a/src/libopensc/cards.h ++++ b/src/libopensc/cards.h +@@ -47,6 +47,7 @@ enum { + SC_CARD_TYPE_CARDOS_CIE_V1, /* Italian CIE (eID) v1 */ + SC_CARD_TYPE_CARDOS_M4_4, + SC_CARD_TYPE_CARDOS_V5_0, ++ SC_CARD_TYPE_CARDOS_V5_3, + + /* flex/cyberflex drivers */ + SC_CARD_TYPE_FLEX_BASE = 2000, +diff --git a/src/libopensc/pkcs15-cardos.c b/src/libopensc/pkcs15-cardos.c +new file mode 100644 +index 0000000000..752631ce88 +--- /dev/null ++++ b/src/libopensc/pkcs15-cardos.c +@@ -0,0 +1,177 @@ ++/* ++ * PKCS15 emulation layer for CardOS cards ++ * Adapted from PKCS15 emulation layer for IAS/ECC card. ++ * ++ * Copyright (C) 2020, Douglas E. Engert ++ * Copyright (C) 2016, Viktor Tarasov ++ * Copyright (C) 2004, Bud P. Bruegger ++ * Copyright (C) 2004, Antonino Iacono ++ * Copyright (C) 2003, Olaf Kirch ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#if HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++ ++#include "internal.h" ++#include "pkcs15.h" ++ ++ ++/* ++ * Called after sc_pkcs15_bind_internal ++ * Create new flags based on supported_algos. ++ */ ++static int cardos_fix_token_info(sc_pkcs15_card_t *p15card) ++{ ++ sc_card_t *card; ++ struct sc_supported_algo_info (*saa)[SC_MAX_SUPPORTED_ALGORITHMS]; ++ struct sc_supported_algo_info *sa; ++ struct sc_cardctl_cardos_pass_algo_flags *passed = NULL; ++ int r = 0; ++ int i; ++ ++ card = p15card->card; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ passed = calloc(1, sizeof(struct sc_cardctl_cardos_pass_algo_flags)); ++ if (!passed) ++ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); ++ ++ passed->pass = 1; /* get used_flags and card_flags from card */ ++ r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, passed); ++ if (r < 0) { ++ free(passed); ++ LOG_FUNC_RETURN(card->ctx, r); ++ } ++ ++ saa = &(p15card->tokeninfo->supported_algos); ++ ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Original Flags: 0x%8.8lx card->flags:0x%8.8lx", passed->used_flags, passed->card_flags); ++ ++ if (passed->card_flags) { /* user forced the flags, use them */ ++ passed->new_flags = passed->card_flags; /* from card_atr flags */ ++ } else { ++ ++ for (i = 0, sa = saa[0]; i < SC_MAX_SUPPORTED_ALGORITHMS; i++, sa++) { ++ ++ if (sa->reference == 0 && sa->reference == 0 && sa->mechanism == 0 ++ && sa->operations == 0 && sa->algo_ref == 0) ++ break; ++ ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "supported_algos[%d] mechamism:0x%8.8x", i, sa->mechanism); ++ switch(sa->mechanism) { ++ case 0x01 : ++ /* ++ * Card appears to use lower 4 bits of reference as key, and upper ++ * 4 bits as mech for card. ++ * Also has a bug if mechanism = 1 (CKM_RSA_PKCS1) and reference 0x10 ++ * bit is set mechanism should be 3 (CKM_RSA_X_509) ++ * correct the mechanism in tokenInfo ++ */ ++ if (sa->reference & 0x10) { ++ sc_log(card->ctx, "Changeing mechanism to CKM_RSA_X_509 based on reference"); ++ passed->new_flags |= SC_ALGORITHM_RSA_RAW ++ | SC_ALGORITHM_RSA_PAD_NONE; ++ sa->mechanism = 0x03; ++ } else ++ passed->new_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; ++ break; ++ case 0x03 : ++ passed->new_flags |= SC_ALGORITHM_RSA_RAW ++ | SC_ALGORITHM_RSA_PAD_NONE; ++ break; ++ case 0x06 : ++ passed->new_flags |= SC_ALGORITHM_RSA_HASH_SHA1; ++ break; ++ case 0x1041: ++ passed->ec_flags |= SC_ALGORITHM_ECDSA_RAW; ++ /* no old_ec_flags */ ++ /* TODO turn on sizes from ec curves OIDS */ ++ break; ++ default: ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "UNKNOWN MECH: 0x%8.8x", sa->mechanism); ++ } ++ ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "New_flags 0x%8.8lx New_ec_flags: 0x%8.8lx", ++ passed->new_flags, passed->ec_flags); ++ } ++ ++ if (passed->new_flags == 0) { ++ if (p15card->tokeninfo && p15card->tokeninfo->flags & SC_PKCS15_TOKEN_EID_COMPLIANT) { ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EID_COMPLIANT flag found"); ++ passed->new_flags = (passed->used_flags & ~SC_ALGORITHM_SPECIFIC_FLAGS) | SC_ALGORITHM_RSA_PAD_PKCS1; ++ } else ++ passed->new_flags = passed->used_flags; /* from default cardos_init */ ++ } ++ } ++ ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Final New_flags 0x%8.8lx New_ec_flags: 0x%8.8lx", passed->new_flags, passed->ec_flags); ++ ++ passed->pass = 2; /* tell card driver to use the new flags */ ++ r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, passed); ++ ++ free(passed); ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ ++static int ++cardos_pkcs15emu_detect_card(sc_pkcs15_card_t *p15card) ++{ ++ if (p15card->card->type < SC_CARD_TYPE_CARDOS_BASE) ++ return SC_ERROR_WRONG_CARD; ++ ++ if (p15card->card->type >= SC_CARD_TYPE_CARDOS_BASE + 1000) ++ return SC_ERROR_WRONG_CARD; ++ ++ return SC_SUCCESS; ++} ++ ++ ++static int ++sc_pkcs15emu_cardos_init(struct sc_pkcs15_card *p15card, struct sc_aid *aid) ++{ ++ sc_card_t *card = p15card->card; ++ int r; ++ ++ LOG_FUNC_CALLED(card->ctx); ++ ++ r = sc_pkcs15_bind_internal(p15card, aid); ++ LOG_TEST_RET(card->ctx, r, "sc_pkcs15_bind_internal failed"); ++ ++ /* If card has created algorithms, return */ ++ sc_log(card->ctx, " card->algorithms:%p card->algorithm_count:%d", card->algorithms, card->algorithm_count); ++ if (!card->algorithms && card->algorithm_count == 0) { ++ r = cardos_fix_token_info(p15card); ++ } ++ ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ ++ ++int ++sc_pkcs15emu_cardos_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid) ++{ ++ if (cardos_pkcs15emu_detect_card(p15card)) ++ return SC_ERROR_WRONG_CARD; ++ ++ return sc_pkcs15emu_cardos_init(p15card, aid); ++} +diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c +index aba6f52c0e..ecd06b13c6 100644 +--- a/src/libopensc/pkcs15-syn.c ++++ b/src/libopensc/pkcs15-syn.c +@@ -60,6 +60,7 @@ struct sc_pkcs15_emulator_handler builtin_emulators[] = { + { "coolkey", sc_pkcs15emu_coolkey_init_ex }, + { "din66291", sc_pkcs15emu_din_66291_init_ex }, + { "esteid2018", sc_pkcs15emu_esteid2018_init_ex }, ++ { "cardos", sc_pkcs15emu_cardos_init_ex }, + + { NULL, NULL } + }; +@@ -95,6 +96,8 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card) + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: + case SC_CARD_TYPE_ESTEID_2018: ++ case SC_CARD_TYPE_CARDOS_V5_0: ++ case SC_CARD_TYPE_CARDOS_V5_3: + + return 1; + default: +diff --git a/src/libopensc/pkcs15-syn.h b/src/libopensc/pkcs15-syn.h +index ccaf693ca4..a15e0d95cf 100644 +--- a/src/libopensc/pkcs15-syn.h ++++ b/src/libopensc/pkcs15-syn.h +@@ -54,6 +54,7 @@ int sc_pkcs15emu_jpki_init_ex(sc_pkcs15_card_t *, struct sc_aid *); + int sc_pkcs15emu_coolkey_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); + int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); + int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); ++int sc_pkcs15emu_cardos_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *); + + struct sc_pkcs15_emulator_handler { + const char *name; + diff --git a/SPECS/opensc.spec b/SPECS/opensc.spec index aa96c96..dd17e23 100644 --- a/SPECS/opensc.spec +++ b/SPECS/opensc.spec @@ -3,7 +3,7 @@ Name: opensc Version: 0.20.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Smart card library and applications Group: System Environment/Libraries @@ -14,6 +14,8 @@ Source1: opensc.module Patch6: opensc-0.19.0-pinpad.patch # https://github.com/OpenSC/OpenSC/pull/1772 Patch8: opensc-0.19.0-idprime.patch +# https://github.com/OpenSC/OpenSC/pull/1987 +Patch9: opensc-0.20.0-cardos.patch BuildRequires: pcsc-lite-devel BuildRequires: readline-devel @@ -44,6 +46,7 @@ every software/card that does so, too. %setup -q %patch6 -p1 -b .pinpad %patch8 -p1 -b .idprime +%patch9 -p1 -b .cardos cp -p src/pkcs15init/README ./README.pkcs15init cp -p src/scconf/README.scconf . @@ -202,6 +205,9 @@ fi %changelog +* Wed May 27 2020 Jakub Jelen - 0.20.0-2 +- Unbreak different CardOS 5 configurations supporting raw RSA (#1830856) + * Wed Apr 22 2020 Jakub Jelen - 0.20.0-1 - Rebase to current upstream release (#1810660)