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