From 592a641cb9f8eb17d4d1b1c9a96a1581f61e169b Mon Sep 17 00:00:00 2001
From: Doug Engert <deengert@gmail.com>
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 <deengert@gmail.com>
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 <assert.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.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 <deengert@gmail.com>
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 <deengert@gmail.com>
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 <deengert@gmail.com>
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 <DEEngert@gmail.com>
+ * Copyright (C) 2016, Viktor Tarasov <viktor.tarasov@gmail.com>
+ * Copyright (C) 2004, Bud P. Bruegger <bud@comune.grosseto.it>
+ * Copyright (C) 2004, Antonino Iacono <ant_iacono@tin.it>
+ * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#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;