Blob Blame History Raw
From cb73a14bd7ec1947871dd719536002cc4d8dc90b Mon Sep 17 00:00:00 2001
From: Raul Metsma <raul@metsma.ee>
Date: Fri, 27 Oct 2017 20:51:33 +0300
Subject: [PATCH 1/5] EstEID ECDSA token support (#1158)

---
 src/libopensc/card-mcrd.c     | 10 ++++++---
 src/libopensc/pkcs15-esteid.c | 47 +++++++++++++++++++++++++------------------
 2 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/src/libopensc/card-mcrd.c b/src/libopensc/card-mcrd.c
index cbba3fdfa..28f8abfad 100644
--- a/src/libopensc/card-mcrd.c
+++ b/src/libopensc/card-mcrd.c
@@ -304,7 +304,7 @@ static int mcrd_match_card(sc_card_t * card)
 
 static int mcrd_init(sc_card_t * card)
 {
-	unsigned long flags;
+	unsigned long flags, ext_flags;
 	struct mcrd_priv_data *priv;
 	int r;
 	sc_path_t tmppath;
@@ -329,6 +329,10 @@ static int mcrd_init(sc_card_t * card)
 			flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_SHA1 | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA256;
 			/* EstEID v3.0 has 2048 bit keys */
 			_sc_card_add_rsa_alg(card, 2048, flags, 0);
+
+			flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE;
+			ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
+			_sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL);
 			sc_reset(card, 0);
 
 			sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00);
@@ -1188,7 +1192,7 @@ static int mcrd_set_security_env(sc_card_t * card,
 	if (is_esteid_card(card)) {
 		/* some sanity checks */
 		if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
-			if (env->algorithm != SC_ALGORITHM_RSA)
+			if (env->algorithm != SC_ALGORITHM_RSA && env->algorithm != SC_ALGORITHM_EC)
 				return SC_ERROR_INVALID_ARGUMENTS;
 		}
 		if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)
@@ -1375,7 +1379,7 @@ static int mcrd_compute_signature(sc_card_t * card,
 	apdu.lc = datalen;
 	apdu.data = data;
 	apdu.datalen = datalen;
-	apdu.le = 0x80;
+	apdu.le = MIN(0x80u, outlen);
 	apdu.resp = out;
 	apdu.resplen = outlen;
 
diff --git a/src/libopensc/pkcs15-esteid.c b/src/libopensc/pkcs15-esteid.c
index 361b2525a..a4655b7f7 100644
--- a/src/libopensc/pkcs15-esteid.c
+++ b/src/libopensc/pkcs15-esteid.c
@@ -33,6 +33,7 @@
 #include "common/compat_strlcat.h"
 
 #include "internal.h"
+#include "opensc.h"
 #include "pkcs15.h"
 #include "esteid.h"
 
@@ -64,6 +65,7 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 	sc_card_t *card = p15card->card;
 	unsigned char buff[128];
 	int r, i;
+	size_t field_length = 0, modulus_length = 0;
 	sc_path_t tmppath;
 
 	set_string (&p15card->tokeninfo->label, "ID-kaart");
@@ -74,7 +76,7 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 	r = sc_select_file (card, &tmppath, NULL);
 	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "select esteid PD failed");
 
-	/* read the serial (document number) */	
+	/* read the serial (document number) */
 	r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
 	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "read document number failed");
 	buff[r] = '\0';
@@ -93,10 +95,10 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 			"3f00eeeeaace",
 			"3f00eeeeddce"};
 		static int esteid_cert_ids[2] = {1, 2};
-			
+
 		struct sc_pkcs15_cert_info cert_info;
 		struct sc_pkcs15_object cert_obj;
-		
+
 		memset(&cert_info, 0, sizeof(cert_info));
 		memset(&cert_obj, 0, sizeof(cert_obj));
 
@@ -110,6 +112,10 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 		if (i == 0) {
 			sc_pkcs15_cert_t *cert;
 			r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
+			if (cert->key->algorithm == SC_ALGORITHM_EC)
+				field_length = cert->key->u.ec.params.field_length;
+			else
+				modulus_length = cert->key->u.rsa.modulus.len * 8;
 			if (r == SC_SUCCESS) {
 				static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
 				u8 *cn_name = NULL;
@@ -155,16 +161,16 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 
 		memset(&pin_info, 0, sizeof(pin_info));
 		memset(&pin_obj, 0, sizeof(pin_obj));
-		
+
 		/* read the number of tries left for the PIN */
 		r = sc_read_record (card, i + 1, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
 		if (r < 0)
 			return SC_ERROR_INTERNAL;
 		tries_left = buff[5];
-		
+
 		pin_info.auth_id.len = 1;
 		pin_info.auth_id.value[0] = esteid_pin_authid[i];
-		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;	
+		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
 		pin_info.attrs.pin.reference = esteid_pin_ref[i];
 		pin_info.attrs.pin.flags = esteid_pin_flags[i];
 		pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
@@ -188,16 +194,11 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 		if (r < 0)
 			return SC_ERROR_INTERNAL;
 	}
-	
+
 	/* add private keys */
 	for (i = 0; i < 2; i++) {
 		static int prkey_pin[2] = {1, 2};
-		static int prkey_usage[2] = {
-			SC_PKCS15_PRKEY_USAGE_ENCRYPT
-			| SC_PKCS15_PRKEY_USAGE_DECRYPT
-			| SC_PKCS15_PRKEY_USAGE_SIGN,
-			SC_PKCS15_PRKEY_USAGE_NONREPUDIATION};
-			
+
 		static const char *prkey_name[2] = {
 			"Isikutuvastus",
 			"Allkirjastamine"};
@@ -207,16 +208,19 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 
 		memset(&prkey_info, 0, sizeof(prkey_info));
 		memset(&prkey_obj, 0, sizeof(prkey_obj));
-		
+
 		prkey_info.id.len = 1;
 		prkey_info.id.value[0] = prkey_pin[i];
-		prkey_info.usage  = prkey_usage[i];
 		prkey_info.native = 1;
 		prkey_info.key_reference = i + 1;
-		if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30)
-			prkey_info.modulus_length = 2048;
+		prkey_info.field_length = field_length;
+		prkey_info.modulus_length = modulus_length;
+		if (i == 1)
+			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+		else if(field_length > 0) // ECC has only sign usage
+			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN;
 		else
-			prkey_info.modulus_length = 1024;	
+			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;
 
 		strlcpy(prkey_obj.label, prkey_name[i], sizeof(prkey_obj.label));
 		prkey_obj.auth_id.len = 1;
@@ -224,7 +228,10 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 		prkey_obj.user_consent = 0;
 		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 
-		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
+		if(field_length > 0)
+			r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
+		else
+			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
 		if (r < 0)
 			return SC_ERROR_INTERNAL;
 	}
@@ -236,7 +243,7 @@ static int esteid_detect_card(sc_pkcs15_card_t *p15card)
 {
 	if (is_esteid_card(p15card->card))
 		return SC_SUCCESS;
-	else		
+	else
 		return SC_ERROR_WRONG_CARD;
 }
 

From bea03e86d385a7d1ec58f42a501a5c2d471357d1 Mon Sep 17 00:00:00 2001
From: Raul Metsma <raul@metsma.ee>
Date: Wed, 8 Nov 2017 14:24:18 +0200
Subject: [PATCH 2/5] Fix crash when certificate read failed (#1189)

Fixes https://github.com/OpenSC/OpenSC/issues/1176
---
 src/libopensc/pkcs15-esteid.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/libopensc/pkcs15-esteid.c b/src/libopensc/pkcs15-esteid.c
index a4655b7f7..a5f9af8b2 100644
--- a/src/libopensc/pkcs15-esteid.c
+++ b/src/libopensc/pkcs15-esteid.c
@@ -110,8 +110,10 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 		if (r < 0)
 			return SC_ERROR_INTERNAL;
 		if (i == 0) {
-			sc_pkcs15_cert_t *cert;
+			sc_pkcs15_cert_t *cert = NULL;
 			r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
+			if (r < 0)
+				return SC_ERROR_INTERNAL;
 			if (cert->key->algorithm == SC_ALGORITHM_EC)
 				field_length = cert->key->u.ec.params.field_length;
 			else

From da05d83a0d3a97eea8f33d5566c60798acc137fc Mon Sep 17 00:00:00 2001
From: Raul Metsma <raul@metsma.ee>
Date: Fri, 10 Nov 2017 09:58:31 +0200
Subject: [PATCH 3/5] EstEID ECDH token support (#1185)

---
 src/libopensc/card-mcrd.c     | 89 ++++++++++++++++++++++++++++++++++++++++---
 src/libopensc/pkcs15-esteid.c |  4 +-
 2 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/src/libopensc/card-mcrd.c b/src/libopensc/card-mcrd.c
index 28f8abfad..085d02965 100644
--- a/src/libopensc/card-mcrd.c
+++ b/src/libopensc/card-mcrd.c
@@ -59,9 +59,9 @@ static struct sc_atr_table mcrd_atrs[] = {
 	{NULL, NULL, NULL, 0, 0, NULL}
 };
 
-static unsigned char EstEID_v3_AID[] = {0xF0, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30};
-static unsigned char EstEID_v35_AID[] = {0xD2, 0x33, 0x00, 0x00, 0x00, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x33, 0x35};
-static unsigned char AzeDIT_v35_AID[] = {0xD0, 0x31, 0x00, 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x49, 0x44};
+static const unsigned char EstEID_v3_AID[] = {0xF0, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30};
+static const unsigned char EstEID_v35_AID[] = {0xD2, 0x33, 0x00, 0x00, 0x00, 0x45, 0x73, 0x74, 0x45, 0x49, 0x44, 0x20, 0x76, 0x33, 0x35};
+static const unsigned char AzeDIT_v35_AID[] = {0xD0, 0x31, 0x00, 0x00, 0x00, 0x44, 0x69, 0x67, 0x69, 0x49, 0x44};
 
 static struct sc_card_operations mcrd_ops;
 static struct sc_card_driver mcrd_drv = {
@@ -119,6 +119,24 @@ struct mcrd_priv_data {
 
 #define DRVDATA(card)        ((struct mcrd_priv_data *) ((card)->drv_data))
 
+// Control Reference Template Tag for Key Agreement (ISO 7816-4:2013 Table 54)
+static const struct sc_asn1_entry c_asn1_control[] = {
+	{ "control", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 0xA6, 0, NULL, NULL },
+	{ NULL, 0, 0, 0, NULL, NULL }
+};
+
+// Ephemeral public key Template Tag (ISO 7816-8:2016 Table 3)
+static const struct sc_asn1_entry c_asn1_ephermal[] = {
+	{ "ephemeral", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 0x7F49, 0, NULL, NULL },
+	{ NULL, 0, 0, 0, NULL, NULL }
+};
+
+// External Public Key
+static const struct sc_asn1_entry c_asn1_public[] = {
+	{ "publicKey", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x86, 0, NULL, NULL },
+	{ NULL, 0, 0, 0, NULL, NULL }
+};
+
 static int load_special_files(sc_card_t * card);
 static int select_part(sc_card_t * card, u8 kind, unsigned short int fid,
 		       sc_file_t ** file);
@@ -1208,6 +1226,7 @@ static int mcrd_set_security_env(sc_card_t * card,
 		select_esteid_df(card);
 		switch (env->operation) {
 		case SC_SEC_OPERATION_DECIPHER:
+		case SC_SEC_OPERATION_DERIVE:
 			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
 				 "Using keyref %d to dechiper\n",
 				 env->key_ref[0]);
@@ -1351,11 +1370,14 @@ static int mcrd_compute_signature(sc_card_t * card,
 				  u8 * out, size_t outlen)
 {
 	struct mcrd_priv_data *priv = DRVDATA(card);
-	sc_security_env_t *env = &priv->sec_env;
+	sc_security_env_t *env = NULL;
 	int r;
 	sc_apdu_t apdu;
 
-	assert(card != NULL && data != NULL && out != NULL);
+	if (card == NULL || data == NULL || out == NULL)
+		return SC_ERROR_INVALID_ARGUMENTS;
+	env = &priv->sec_env;
+
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
 	if (env->operation != SC_SEC_OPERATION_SIGN)
 		return SC_ERROR_INVALID_ARGUMENTS;
@@ -1391,6 +1413,62 @@ static int mcrd_compute_signature(sc_card_t * card,
 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
 }
 
+static int mcrd_decipher(struct sc_card *card,
+						 const u8 * crgram, size_t crgram_len,
+						 u8 * out, size_t outlen)
+{
+	sc_security_env_t *env = NULL;
+	int r = 0;
+	size_t sbuf_len = 0;
+	sc_apdu_t apdu;
+	u8 *sbuf = NULL;
+	struct sc_asn1_entry asn1_control[2], asn1_ephermal[2], asn1_public[2];
+
+	if (card == NULL || crgram == NULL || out == NULL)
+		return SC_ERROR_INVALID_ARGUMENTS;
+	env = &DRVDATA(card)->sec_env;
+
+	LOG_FUNC_CALLED(card->ctx);
+	if (env->operation != SC_SEC_OPERATION_DERIVE)
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, iso_ops->decipher(card, crgram, crgram_len, out, outlen));
+	if (crgram_len > 255)
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
+
+	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
+		 "Will dervie (%d) for %"SC_FORMAT_LEN_SIZE_T"u (0x%02"SC_FORMAT_LEN_SIZE_T"x) bytes using key %d algorithm %d flags %d\n",
+		 env->operation, crgram_len, crgram_len, env->key_ref[0],
+		 env->algorithm, env->algorithm_flags);
+
+	// Encode TLV
+	sc_copy_asn1_entry(c_asn1_control, asn1_control);
+	sc_copy_asn1_entry(c_asn1_ephermal, asn1_ephermal);
+	sc_copy_asn1_entry(c_asn1_public, asn1_public);
+	sc_format_asn1_entry(asn1_public + 0, (void*)crgram, &crgram_len, 1);
+	sc_format_asn1_entry(asn1_ephermal + 0, &asn1_public, NULL, 1);
+	sc_format_asn1_entry(asn1_control + 0, &asn1_ephermal, NULL, 1);
+	r = sc_asn1_encode(card->ctx, asn1_control, &sbuf, &sbuf_len);
+	LOG_TEST_RET(card->ctx, r, "Error encoding TLV.");
+
+	// Create APDU
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
+	apdu.lc = sbuf_len;
+	apdu.data = sbuf;
+	apdu.datalen = sbuf_len;
+	apdu.le = MIN(0x80u, outlen);
+	apdu.resp = out;
+	apdu.resplen = outlen;
+
+	r = sc_transmit_apdu(card, &apdu);
+	sc_mem_clear(sbuf, sbuf_len);
+	free(sbuf);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, r, "Card returned error");
+
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
+}
+
 /* added by -mp, to give pin information in the card driver (pkcs15emu->driver needed) */
 static int mcrd_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data,
 			int *tries_left)
@@ -1454,6 +1532,7 @@ static struct sc_card_driver *sc_get_driver(void)
 	mcrd_ops.select_file = mcrd_select_file;
 	mcrd_ops.set_security_env = mcrd_set_security_env;
 	mcrd_ops.compute_signature = mcrd_compute_signature;
+	mcrd_ops.decipher = mcrd_decipher;
 	mcrd_ops.pin_cmd = mcrd_pin_cmd;
 
 	return &mcrd_drv;
diff --git a/src/libopensc/pkcs15-esteid.c b/src/libopensc/pkcs15-esteid.c
index a5f9af8b2..b3cf5178f 100644
--- a/src/libopensc/pkcs15-esteid.c
+++ b/src/libopensc/pkcs15-esteid.c
@@ -219,8 +219,8 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
 		prkey_info.modulus_length = modulus_length;
 		if (i == 1)
 			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
-		else if(field_length > 0) // ECC has only sign usage
-			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN;
+		else if(field_length > 0) // ECC has sign and derive usage
+			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DERIVE;
 		else
 			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;
 

From 3b33bf0e11253302ae48c2a3027b114162b92472 Mon Sep 17 00:00:00 2001
From: Raul Metsma <raul@metsma.ee>
Date: Thu, 9 Nov 2017 14:42:30 +0200
Subject: [PATCH 4/5] Cleanup expired EstEID card ATR-s

Signed-off-by: Raul Metsma <raul@metsma.ee>
---
 etc/opensc.conf.in | 24 +-----------------------
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in
index 63abba9bf..2bbbe624c 100644
--- a/etc/opensc.conf.in
+++ b/etc/opensc.conf.in
@@ -309,33 +309,11 @@ app default {
 		# driver = "piv";
 	# }
 
-	# Estonian ID card and Micardo driver sometimes only play together with T=0
+	# Micardo driver sometimes only play together with T=0
 	# In theory only the 'cold' ATR should be specified, as T=0 will
 	# be the preferred protocol once you boot it up with T=0, but be
 	# paranoid.
 	#
-	# Warm ATR v1
-	card_atr 3b:6e:00:ff:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 {
-		force_protocol = t0;
-	}
-	# Cold ATR v1
-	card_atr 3b:fe:94:00:ff:80:b1:fa:45:1f:03:45:73:74:45:49:44:20:76:65:72:20:31:2e:30:43 {
-		force_protocol = t0;
-	}
-	# Warm ATR v2
-	card_atr 3b:5e:11:ff:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 {
-		force_protocol = t0;
-	}
-	# Cold ATR v2
-	card_atr 3b:de:18:ff:c0:80:b1:fe:45:1f:03:45:73:74:45:49:44:20:76:65:72:20:31:2e:30:2b {
-		force_protocol = t0;
-	}
-	# Digi-ID cold ATR. The same card has the same warm ATR as "Cold ATR v1" above
-	# The card is claimed to only support T=0 but in fact (sometimes) works with T=1, even if not advertised in ATR.
-	card_atr 3b:6e:00:00:45:73:74:45:49:44:20:76:65:72:20:31:2e:30 {
-		force_protocol = t0;
-	}
-
 	# D-Trust cards are also based on micardo and need T=0 for some reason
 	card_atr 3b:ff:94:00:ff:80:b1:fe:45:1f:03:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00:23 {
 		force_protocol = t0;

From 1c28c1b56a28c38d24714f1377eebe87a0371421 Mon Sep 17 00:00:00 2001
From: Raul Metsma <raul@metsma.ee>
Date: Fri, 17 Nov 2017 11:46:34 +0200
Subject: [PATCH 5/5] Fix reading EstEID certificates with T=0 (#1193)

---
 src/libopensc/card-mcrd.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/src/libopensc/card-mcrd.c b/src/libopensc/card-mcrd.c
index 085d02965..525717ce9 100644
--- a/src/libopensc/card-mcrd.c
+++ b/src/libopensc/card-mcrd.c
@@ -365,15 +365,20 @@ static int mcrd_init(sc_card_t * card)
 			if(apdu.sw1 != 0x90 && apdu.sw2 != 0x00)
 			{
 				sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00);
-	                        apdu.lc = sizeof(EstEID_v35_AID);
-        	                apdu.data = EstEID_v35_AID;
-                	        apdu.datalen = sizeof(EstEID_v35_AID);
-                        	apdu.resplen = 0;
-	                        apdu.le = 0;
+				apdu.lc = sizeof(EstEID_v35_AID);
+				apdu.data = EstEID_v35_AID;
+				apdu.datalen = sizeof(EstEID_v35_AID);
+				apdu.resplen = 0;
+				apdu.le = 0;
 				r = sc_transmit_apdu(card, &apdu);
-	                        SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
-        	                sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2);
-				if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) {
+				SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
+				sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2);
+				if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+					// Force EstEID 3.5 card recv size 255 with T=0 to avoid recursive read binary
+					// sc_read_binary cannot handle recursive 61 00 calls
+					if (card->reader && card->reader->active_protocol == SC_PROTO_T0)
+						card->max_recv_size = 255;
+				} else {
 					sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00);
 					apdu.lc = sizeof(AzeDIT_v35_AID);
 					apdu.data = AzeDIT_v35_AID;