Hello,

attached is a patch which makes it possible to explicitly request
specific algorithms for the cryptographic operations. The advantage is,
that if the token provides sufficient information about itself, then the
driver is not required to do any guess work. Which in turn could result
in a more reliable operation of libopensc. Furthermore there could be
positive effects in terms of compatibility with tokens not initialised
by opensc.

My recommendation is to test/improve this patch in an experimental
branch or something like that. The reason for this is, that
ALG_REF_PRESENT is not in use since revision 177 and I assume a lot of
drivers to misbehave or crash at first.

Regards,
Andre

Index: libopensc/pkcs15-prkey.c
===================================================================
--- libopensc/pkcs15-prkey.c	(revision 4631)
+++ libopensc/pkcs15-prkey.c	(working copy)
@@ -47,6 +47,7 @@
 static const struct sc_asn1_entry c_asn1_rsakey_attr[] = {
 	{ "value",	   SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
 	{ "modulusLength", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
+	/* In reality KeyInfo is of type CHOICE. For simplicity assume Reference to be choosen. */
 	{ "keyInfo",	   SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
@@ -82,6 +83,8 @@
 
 static const struct sc_asn1_entry c_asn1_dsakey_attr[] = {
 	{ "value",	SC_ASN1_CHOICE, 0, 0, NULL, NULL },
+	/* In reality KeyInfo is of type CHOICE. For simplicity assume Reference to be choosen. */
+	{ "keyInfo",	SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
@@ -103,13 +106,13 @@
 {
         sc_context_t *ctx = p15card->card->ctx;
         struct sc_pkcs15_prkey_info info;
-	int r, gostr3410_params[3];
+	int i, r, gostr3410_params[3], cross_reference = -1;
 	struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams;
 	size_t usage_len = sizeof(info.usage);
 	size_t af_len = sizeof(info.access_flags);
 	struct sc_asn1_entry asn1_com_key_attr[6], asn1_com_prkey_attr[2];
 	struct sc_asn1_entry asn1_rsakey_attr[4], asn1_prk_rsa_attr[2];
-	struct sc_asn1_entry asn1_dsakey_attr[2], asn1_prk_dsa_attr[2],
+	struct sc_asn1_entry asn1_dsakey_attr[3], asn1_prk_dsa_attr[2],
 			asn1_dsakey_i_p_attr[2],
 			asn1_dsakey_value_attr[3];
 	struct sc_asn1_entry asn1_gostr3410key_attr[5], asn1_prk_gostr3410_attr[2];
@@ -146,8 +149,10 @@
 
 	sc_format_asn1_entry(asn1_rsakey_attr + 0, &info.path, NULL, 0);
 	sc_format_asn1_entry(asn1_rsakey_attr + 1, &info.modulus_length, NULL, 0);
+	sc_format_asn1_entry(asn1_rsakey_attr + 2, &cross_reference, NULL, 0);
 
 	sc_format_asn1_entry(asn1_dsakey_attr + 0, asn1_dsakey_value_attr, NULL, 0);
+	sc_format_asn1_entry(asn1_dsakey_attr + 1, &cross_reference, NULL, 0);
 	sc_format_asn1_entry(asn1_dsakey_value_attr + 0, &info.path, NULL, 0);
 	sc_format_asn1_entry(asn1_dsakey_value_attr + 1, asn1_dsakey_i_p_attr, NULL, 0);
 	sc_format_asn1_entry(asn1_dsakey_i_p_attr + 0, &info.path, NULL, 0);
@@ -200,6 +205,18 @@
 		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Neither RSA or DSA or GOSTR3410 key in PrKDF entry.\n");
 		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ASN1_OBJECT);
 	}
+
+	/* Find algorithm associated with this key. If there
+	 * is no match, then info.algorithm is pointing to NULL.
+	 */
+	info.algorithm = NULL;
+	if (cross_reference >= 0 && cross_reference <= 255)
+		for (i = 0; i < SC_MAX_SUPPORTED_ALGORITHMS; i++)
+			if (p15card->supported_algos[i].reference == cross_reference) {
+				info.algorithm = p15card->supported_algos + i;
+				break;
+			}
+
 	r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path);
 	if (r < 0) {
 		if (info.params)
@@ -233,7 +250,7 @@
 {
 	struct sc_asn1_entry asn1_com_key_attr[6], asn1_com_prkey_attr[2];
 	struct sc_asn1_entry asn1_rsakey_attr[4], asn1_prk_rsa_attr[2];
-	struct sc_asn1_entry asn1_dsakey_attr[2], asn1_prk_dsa_attr[2],
+	struct sc_asn1_entry asn1_dsakey_attr[3], asn1_prk_dsa_attr[2],
 			asn1_dsakey_value_attr[3],
 			asn1_dsakey_i_p_attr[2];
 	struct sc_asn1_entry asn1_gostr3410key_attr[5], asn1_prk_gostr3410_attr[2];
@@ -271,10 +288,15 @@
 		sc_format_asn1_entry(asn1_prk_rsa_attr + 0, asn1_rsakey_attr, NULL, 1);
 		sc_format_asn1_entry(asn1_rsakey_attr + 0, &prkey->path, NULL, 1);
 		sc_format_asn1_entry(asn1_rsakey_attr + 1, &prkey->modulus_length, NULL, 1);
+		if (prkey->algorithm != NULL)
+			sc_format_asn1_entry(asn1_rsakey_attr + 2, &prkey->algorithm->algo_ref, NULL, 1);
 		break;
 	case SC_PKCS15_TYPE_PRKEY_DSA:
 		sc_format_asn1_entry(asn1_prkey + 1, &dsa_prkey_obj, NULL, 1);
-		sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_value_attr, NULL, 1);
+		sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_attr, NULL, 1);
+		sc_format_asn1_entry(asn1_dsakey_attr + 0, asn1_dsakey_value_attr, NULL, 1);
+		if (prkey->algorithm != NULL)
+			sc_format_asn1_entry(asn1_dsakey_attr + 1, &prkey->algorithm->algo_ref, NULL, 1);
 		if (prkey->path.type != SC_PATH_TYPE_PATH_PROT) {
 			/* indirect: just add the path */
 			sc_format_asn1_entry(asn1_dsakey_value_attr + 0,
Index: libopensc/pkcs15.c
===================================================================
--- libopensc/pkcs15.c	(revision 4631)
+++ libopensc/pkcs15.c	(working copy)
@@ -40,8 +40,8 @@
 	{ "algorithmPKCS#11",	SC_ASN1_INTEGER,	SC_ASN1_TAG_INTEGER,	0, NULL, NULL },
 	{ "parameters",		SC_ASN1_NULL,		SC_ASN1_TAG_NULL,	0, NULL, NULL },
 	{ "supportedOperations",SC_ASN1_BIT_FIELD,	SC_ASN1_TAG_BIT_STRING,	0, NULL, NULL },
-	{ "objId",		SC_ASN1_OBJECT,		SC_ASN1_TAG_OBJECT,	0, NULL, NULL },
-	{ "algRef",		SC_ASN1_INTEGER,	SC_ASN1_TAG_INTEGER,	0, NULL, NULL },
+	{ "algId",		SC_ASN1_OBJECT,		SC_ASN1_TAG_OBJECT,	SC_ASN1_OPTIONAL, NULL, NULL },
+	{ "algRef",		SC_ASN1_INTEGER,	SC_ASN1_TAG_INTEGER,	SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
@@ -140,7 +140,21 @@
 	sc_format_asn1_entry(asn1_toki + 11, last_update, &lupdate_len, 0);
 	sc_format_asn1_entry(asn1_toki + 12, preferred_language, &lang_length, 0);
 	sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 0);
-	
+
+	/* Initialise supported algorithms with invalid values.
+	 * Valid ones are:
+	 *	reference: 0..255
+	 *	mechanism: 0..int_max (all the CKM values to be more precise)
+	 *	algo_ref:  0..255
+	*/
+	for (ii=0; ii<SC_MAX_SUPPORTED_ALGORITHMS; ii++) {
+		ti->supported_algos[ii].reference = -1;
+		ti->supported_algos[ii].mechanism = -1;
+		ti->supported_algos[ii].operations = 0;
+		// TODO: ti->supported_algos[ii].algo_id
+		ti->supported_algos[ii].algo_ref = -1;
+	}
+
 	r = sc_asn1_decode(ctx, asn1_tokeninfo, buf, blen, NULL, NULL);
 	if (r) {
 		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "ASN.1 parsing of EF(TokenInfo) failed: %s\n",
Index: libopensc/pkcs15.h
===================================================================
--- libopensc/pkcs15.h	(revision 4631)
+++ libopensc/pkcs15.h	(working copy)
@@ -290,19 +290,26 @@
 };
 typedef struct sc_pkcs15_accessrule sc_pkcs15_accessrule_t;
 
+typedef struct sc_pkcs15_algorithm_info {
+	int reference;			/* intended for cross referencing this object */
+	int mechanism;			/* references a PKCS#11 mechanism (CKM_*) */
+	unsigned int operations;	/* bitmap of supported operations */
+	struct sc_object_id algo_id;	/* OID of the PKCS#11 mechanism OPTIONAL */
+	int algo_ref;			/* algorithm reference according ISO 7816-4 OPTIONAL */
+} sc_pkcs15_algorithm_info_t;
 
 struct sc_pkcs15_prkey_info {
-	struct sc_pkcs15_id id;	/* correlates to public certificate id */
-	unsigned int usage, access_flags;
-	int native, key_reference;
-	size_t modulus_length;
-
-	struct sc_pkcs15_der subject;
-
+	struct sc_pkcs15_id id;			/* CommonKeyAttributes.iD (correlates to public certificate id) */
+	unsigned int usage;			/* CommonKeyAttributes.usage */
+	unsigned int native;			/* CommonKeyAttributes.native DEFAULT 1 */
+	unsigned int access_flags;		/* CommonKeyAttributes.accessFlags OPTIONAL */
+	int key_reference;			/* CommonKeyAttributes.keyReference OPTIONAL */
+	struct sc_pkcs15_der subject;		/* CommonPrivateKeyAttributes.subjectName OPTIONAL */
+	struct sc_path path;			/* PrivateRSAKeyAttributes.value.indirect.path */
+	size_t modulus_length;			/* PrivateRSAKeyAttributes.modulusLength (modulus length in bits) */
+	sc_pkcs15_algorithm_info_t *algorithm;	/* PrivateRSAKeyAttributes.keyInfo.reference OPTIONAL */
 	void   *params;
 	size_t params_len;
-
-	struct sc_path path;
 };
 typedef struct sc_pkcs15_prkey_info sc_pkcs15_prkey_info_t;
 
@@ -423,8 +430,7 @@
 	char *preferred_language;
 	sc_pkcs15_sec_env_info_t **seInfo;
 	size_t num_seInfo;
-
-	struct sc_supported_algo_info supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
+	sc_pkcs15_algorithm_info_t supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
 } sc_pkcs15_tokeninfo_t;
 
 struct sc_pkcs15_operations   {
@@ -441,7 +447,7 @@
 	char *last_update;
 	unsigned int flags;
 
-	struct sc_supported_algo_info supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
+	sc_pkcs15_algorithm_info_t supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
 
 	sc_file_t *file_app;
 	sc_file_t *file_tokeninfo, *file_odf, *file_unusedspace;
Index: libopensc/pkcs15-sec.c
===================================================================
--- libopensc/pkcs15-sec.c	(revision 4631)
+++ libopensc/pkcs15-sec.c	(working copy)
@@ -98,6 +98,7 @@
 	senv.algorithm_flags = sec_flags;
 	senv.operation       = SC_SEC_OPERATION_DECIPHER;
 	senv.flags           = 0;
+
 	/* optional keyReference attribute (the default value is -1) */
 	if (prkey->key_reference >= 0) {
 		senv.key_ref_len = 1;
@@ -106,6 +107,18 @@
 	}
 	senv.flags |= SC_SEC_ENV_ALG_PRESENT;
 
+	/* Specify algorithm to use
+	 *
+	 * If the value of algo_ref is less than zero, then no specific 
+	 * algorithm is requested and the algorithm to use must be
+	 * implicitly known by the card. Values in the range of 0..255
+	 * are taken as explicit references to specific algorithms.
+	 */
+	if (prkey->algorithm != NULL && prkey->algorithm->algo_ref >= 0) {
+		senv.algorithm_ref = prkey->algorithm->algo_ref;
+		senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
+	}
+
 	r = sc_lock(p15card->card);
 	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed");
 
@@ -269,6 +282,18 @@
 	}
 	senv.flags |= SC_SEC_ENV_ALG_PRESENT;
 
+	/* Specify algorithm to use
+	 *
+	 * If the value of algo_ref is less than zero, then no specific
+	 * algorithm is requested and the algorithm to use must be
+	 * implicitly known by the card. Values in the range of 0..255
+	 * are taken as explicit references to specific algorithms.
+	 */
+	if (prkey->algorithm != NULL && prkey->algorithm->algo_ref >= 0) {
+		senv.algorithm_ref = prkey->algorithm->algo_ref;
+		senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
+	}
+
 	r = sc_lock(p15card->card);
 	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed");
 
Index: libopensc/opensc.h
===================================================================
--- libopensc/opensc.h	(revision 4631)
+++ libopensc/opensc.h	(working copy)
@@ -115,25 +115,16 @@
 #define SC_EVENT_READER_DETACHED	0x0008
 #define SC_EVENT_READER_EVENTS		SC_EVENT_READER_ATTACHED|SC_EVENT_READER_DETACHED
 
-struct sc_supported_algo_info {
-	unsigned int reference;
-	unsigned int mechanism;
-	unsigned int operations;
-	struct sc_object_id algo_id;
-	unsigned int algo_ref;
-};
-
 typedef struct sc_security_env {
-	unsigned long flags;
-	int operation;
-	unsigned int algorithm, algorithm_flags;
-
-	unsigned int algorithm_ref;
+	unsigned long flags;		/* bitmap with flags from namespace SC_SEC_ENV */
+	int operation;			/* single value from namespace SC_SEC_OPERATION */
+	int algorithm;			/* single value from namespace SC_ALGORITHM (symmetric/asymmetric/hash) */
+	unsigned int algorithm_flags;	/* bitmap with flags from namespace SC_ALGORITHM_X
+					   where X matches this.algorithm */
+	int algorithm_ref;		/* TokeInfo.supportedAlgorithms.algRef */
 	struct sc_path file_ref;
 	u8 key_ref[8];
 	size_t key_ref_len;
-
-	struct sc_supported_algo_info supported_algos[SC_MAX_SUPPORTED_ALGORITHMS];
 } sc_security_env_t;
 
 struct sc_algorithm_id {
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to