[pkg-opensc-commit] [opensc] 283/295: Support SKDF and secret key upload for MyEID cards

Eric Dorland eric at moszumanska.debian.org
Sat Jun 24 21:11:40 UTC 2017


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository opensc.

commit 94973809c20d0290e4633f68219cae12b9c65325
Author: Timo Teräs <timo.teras at iki.fi>
Date:   Fri Apr 14 10:42:30 2017 +0300

    Support SKDF and secret key upload for MyEID cards
---
 src/libopensc/card-myeid.c    |  46 +++++++++---
 src/libopensc/cardctl.h       |   8 +-
 src/pkcs15init/myeid.profile  |  27 ++++++-
 src/pkcs15init/pkcs15-myeid.c | 167 +++++++++++++++++++++++++-----------------
 4 files changed, 160 insertions(+), 88 deletions(-)

diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c
index 65c108f..80c2821 100644
--- a/src/libopensc/card-myeid.c
+++ b/src/libopensc/card-myeid.c
@@ -43,6 +43,8 @@
 #define LOAD_KEY_EC_PRIVATE	0x97
 #define LOAD_KEY_EC_PUBLIC	0x96
 
+#define LOAD_KEY_SYMMETRIC	0xa0
+
 #define MYEID_STATE_CREATION	0x01
 #define MYEID_STATE_ACTIVATED	0x07
 
@@ -148,7 +150,6 @@ static int myeid_init(struct sc_card *card)
 	u8 appletInfo[20];
 	size_t appletInfoLen;
 	int r;
-	unsigned short max_ecc_key_length = 256;
 	myeid_card_caps_t card_caps;
 
 	LOG_FUNC_CALLED(card->ctx);
@@ -183,16 +184,15 @@ static int myeid_init(struct sc_card *card)
 	_sc_card_add_rsa_alg(card, 2048, flags, 0);
 	
 	memset(&card_caps, 0, sizeof(myeid_card_caps_t));
+	card_caps.max_ecc_key_length = 256;
+	card_caps.max_rsa_key_length = 2048;
 
 	if (card->version.fw_major >= 40) {
 	    /* Since 4.0, we can query available algorithms and key sizes.
 	     * Since 3.5.0 RSA up to 2048 and ECC up to 256 are always supported, so we check only max ECC key length. */
 	    r = myeid_get_card_caps(card, &card_caps);
 
-	    if (r == SC_SUCCESS) {
-		max_ecc_key_length = card_caps.max_ecc_key_length;
-	    }
-	    else {
+	    if (r != SC_SUCCESS) {
 		sc_log(card->ctx, "Failed to get card capabilities. Using default max ECC key length 256.");
 	    }
 	}
@@ -206,15 +206,28 @@ static int myeid_init(struct sc_card *card)
 		ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
 
 		for (i=0; ec_curves[i].curve_name != NULL; i++) {
-			if (i == 2 && max_ecc_key_length < 384)
-				continue;
-			else if (i == 3 && max_ecc_key_length < 521)
-				continue;
-			else
-				_sc_card_add_ec_alg(card,  ec_curves[i].size, flags, ext_flags, &ec_curves[i].curve_oid);
+			if (card_caps.max_ecc_key_length >= ec_curves[i].size)
+				_sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].curve_oid);
 		}
 	}
 
+	/* show supported symmetric algorithms */
+	flags = 0;
+	if (card_caps.card_supported_features & MYEID_CARD_CAP_3DES) {
+		if (card_caps.max_des_key_length >= 56)
+			_sc_card_add_symmetric_alg(card, SC_ALGORITHM_DES, 56, flags);
+		if (card_caps.max_des_key_length >= 128)
+			_sc_card_add_symmetric_alg(card, SC_ALGORITHM_3DES, 128, flags);
+		if (card_caps.max_des_key_length >= 192)
+			_sc_card_add_symmetric_alg(card, SC_ALGORITHM_3DES, 192, flags);
+	}
+	if (card_caps.card_supported_features & MYEID_CARD_CAP_AES) {
+		if (card_caps.max_aes_key_length >= 128)
+			_sc_card_add_symmetric_alg(card, SC_ALGORITHM_AES, 128, flags);
+		if (card_caps.max_aes_key_length >= 256)
+			_sc_card_add_symmetric_alg(card, SC_ALGORITHM_AES, 256, flags);
+	}
+
 	/* State that we have an RNG */
 	card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
 
@@ -439,6 +452,8 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
 	else   {
 		delete = sc_file_get_acl_entry(file, SC_AC_OP_DELETE);
 
+		sc_log(card->ctx, "id (%X), type (%X)", file->id, file->type);
+
 		switch (file->type) {
 		case SC_FILE_TYPE_WORKING_EF:
 
@@ -1188,7 +1203,8 @@ static int myeid_loadkey(sc_card_t *card, int mode, u8* value, int value_len)
 
 	if(value    != NULL &&
 	   value[0] != 0x0 &&
-	   mode     != LOAD_KEY_PUBLIC_EXPONENT)
+	   mode     != LOAD_KEY_PUBLIC_EXPONENT &&
+	   mode     != LOAD_KEY_SYMMETRIC)
 		sbuf[len++] = 0x0;
 
 	if(mode == LOAD_KEY_MODULUS && value_len >= 256)
@@ -1328,6 +1344,12 @@ static int myeid_generate_store_key(struct sc_card *card,
 					data->ecpublic_point_len)) >= 0)
 			LOG_FUNC_RETURN(card->ctx, r);
 		}
+		else if(data->key_type == SC_CARDCTL_MYEID_KEY_AES ||
+			data->key_type == SC_CARDCTL_MYEID_KEY_DES) {
+			if((r = myeid_loadkey(card, LOAD_KEY_SYMMETRIC, data->d,
+					data->d_len)) >= 0)
+			LOG_FUNC_RETURN(card->ctx, r);
+		}
 	}
 
 	LOG_FUNC_RETURN(card->ctx, r);
diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h
index d67a83c..9a58427 100644
--- a/src/libopensc/cardctl.h
+++ b/src/libopensc/cardctl.h
@@ -878,7 +878,9 @@ typedef struct sc_rtecp_genkey_data {
  */
 	enum SC_CARDCTL_MYEID_KEY_TYPE {
 		SC_CARDCTL_MYEID_KEY_RSA = 0x11,
-		SC_CARDCTL_MYEID_KEY_EC  = 0x22
+		SC_CARDCTL_MYEID_KEY_DES = 0x19,
+		SC_CARDCTL_MYEID_KEY_EC  = 0x22,
+		SC_CARDCTL_MYEID_KEY_AES = 0x29
 	};
 
 	struct sc_cardctl_myeid_data_obj {
@@ -907,8 +909,8 @@ typedef struct sc_rtecp_genkey_data {
 		unsigned int    invq_len;  
 		unsigned char  *invq;
 		/* new for MyEID > 3.6.0 */
-		unsigned char  *d;                  /* EC private key */
-		unsigned int    d_len;              /* EC */ 
+		unsigned char  *d;                  /* EC private key / Symmetric key */
+		unsigned int    d_len;              /* EC / Symmetric */
 		unsigned char  *ecpublic_point;     /* EC public key */
 		unsigned int    ecpublic_point_len; /* EC */
     };
diff --git a/src/pkcs15init/myeid.profile b/src/pkcs15init/myeid.profile
index 8b84c95..2645261 100644
--- a/src/pkcs15init/myeid.profile
+++ b/src/pkcs15init/myeid.profile
@@ -36,6 +36,7 @@ option default {
 	cdf-trusted-size = 510;
 	prkdf-size	     = 1530;
 	pukdf-size	     = 1530;
+	skdf-size	     = 1530;
 	dodf-size	     = 1530;
     }
 }
@@ -136,6 +137,13 @@ filesystem {
                 acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
             }
 
+            EF PKCS15-SKDF {
+                file-id	  = 4407;
+                structure = transparent;
+                size	  = $skdf-size;
+                acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+            }
+
             EF PKCS15-CDF {
                 file-id	  = 4403;
                 structure = transparent;
@@ -159,8 +167,14 @@ filesystem {
             
             EF template-private-key {
                 type      = internal-ef;
-    	        file-id   = 4B01;	
-    	        acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+                file-id   = 4B01;
+                acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+            }
+            
+            EF template-secret-key {
+                type      = internal-ef;
+                file-id   = 4D01;
+                acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
             }
             
             EF template-public-key {
@@ -181,13 +195,18 @@ filesystem {
                 EF private-key {
                     file-id   = 4B01;
                     type      = internal-ef;
-                    acl       = READ=NONE, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+                    acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
                 }
                 EF public-key {
-                    file-id	  = 5501;
+                    file-id   = 5501;
                     structure = transparent;
                     acl       = READ=NONE, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
                 }
+                EF secret-key {
+                    file-id   = 4D01;
+                    type      = internal-ef;
+                    acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+                }
 		
                 # Certificate template
                 EF certificate {
diff --git a/src/pkcs15init/pkcs15-myeid.c b/src/pkcs15init/pkcs15-myeid.c
index 200009a..3e4bb19 100644
--- a/src/pkcs15init/pkcs15-myeid.c
+++ b/src/pkcs15init/pkcs15-myeid.c
@@ -201,6 +201,7 @@ myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df
 	static const char *create_dfs[] = {
 		"PKCS15-PrKDF",
 		"PKCS15-PuKDF",
+		"PKCS15-SKDF",
 		"PKCS15-CDF",
 		"PKCS15-CDF-TRUSTED",
 		"PKCS15-DODF",
@@ -210,6 +211,7 @@ myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df
 	static const int create_dfs_val[] = {
 		SC_PKCS15_PRKDF,
 		SC_PKCS15_PUKDF,
+		SC_PKCS15_SKDF,
 		SC_PKCS15_CDF,
 		SC_PKCS15_CDF_TRUSTED,
 		SC_PKCS15_DODF
@@ -349,19 +351,33 @@ myeid_new_file(sc_profile_t *profile, sc_card_t *card,
 	sc_file_t *file;
 	sc_path_t *p;
 	char name[64];
-	const char *tag;
+	const char *tag = NULL;
 	int r;
 
 	LOG_FUNC_CALLED(card->ctx);
-	if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC)
+	switch (type) {
+	case SC_PKCS15_TYPE_PRKEY_RSA:
+	case SC_PKCS15_TYPE_PRKEY_EC:
 		tag = "private-key";
-	else if (type == SC_PKCS15_TYPE_PUBKEY_RSA || type == SC_PKCS15_TYPE_PUBKEY_EC)
+		break;
+	case SC_PKCS15_TYPE_PUBKEY_RSA:
+	case SC_PKCS15_TYPE_PUBKEY_EC:
 		tag = "public-key";
-	else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT)
-		tag = "certificate";
-	else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_DATA_OBJECT)
-		tag = "data";
-	else {
+		break;
+	case SC_PKCS15_TYPE_SKEY_GENERIC:
+	case SC_PKCS15_TYPE_SKEY_DES:
+	case SC_PKCS15_TYPE_SKEY_3DES:
+		tag = "secret-key";
+		break;
+	default:
+		if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT)
+			tag = "certificate";
+		else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_DATA_OBJECT)
+			tag = "data";
+		break;
+	}
+
+	if (!tag) {
 		sc_log(card->ctx, "Unsupported file type");
 		return SC_ERROR_INVALID_ARGUMENTS;
 	}
@@ -418,36 +434,37 @@ myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
 		struct sc_pkcs15_object *object) {
 	struct sc_context *ctx = p15card->card->ctx;
 	struct sc_card *card = p15card->card;
-	struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data;
+	struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) object->data;
+	struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data;
+	struct sc_pkcs15_id *id;
+	struct sc_path *path;
+	int *key_reference;
 	struct sc_file *file = NULL;
 	struct sc_pkcs15_object *pin_object = NULL;
 	struct sc_pkcs15_auth_info *pkcs15_auth_info = NULL;
-	int keybits = key_info->modulus_length, r;
-	int pin_reference = -1;
 	unsigned char sec_attrs[] = {0xFF, 0xFF, 0xFF};
+	int r, ef_structure, keybits = 0, pin_reference = -1;
 
 	LOG_FUNC_CALLED(card->ctx);
 
-	/* Check that the card supports the requested modulus length */
 	switch (object->type) {
 		case SC_PKCS15_TYPE_PRKEY_RSA:
-			if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL)
-				LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS,
-					"Unsupported RSA key size");
+			ef_structure = SC_CARDCTL_MYEID_KEY_RSA;
+			keybits = prkey_info->modulus_length;
 			break;
 		case SC_PKCS15_TYPE_PRKEY_EC:
-			/* 
-			   Here the information about curve is not available, that's why algorithm is checked
-			   without curve OID. 	  			   
-                         */
-                    
-			if (key_info->field_length != 0)
-				keybits = key_info->field_length;
-			else 
-				key_info->field_length = keybits;
-			
-			if (sc_card_find_ec_alg(p15card->card, keybits, NULL) == NULL)
-				LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size");
+			ef_structure = SC_CARDCTL_MYEID_KEY_EC;
+			keybits = prkey_info->field_length;
+			break;
+		case SC_PKCS15_TYPE_SKEY_DES:
+		case SC_PKCS15_TYPE_SKEY_3DES:
+			ef_structure = SC_CARDCTL_MYEID_KEY_DES;
+			keybits = skey_info->value_len;
+			break;
+		case SC_PKCS15_TYPE_SKEY_GENERIC:
+			keybits = skey_info->value_len;
+			/* FIXME */
+			ef_structure = SC_CARDCTL_MYEID_KEY_AES;
 			break;
 		default:
 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS,
@@ -455,27 +472,33 @@ myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
 			break;
 	}
 
-	sc_log(ctx, "create MyEID private key ID:%s", sc_pkcs15_print_id(&key_info->id));
+	if ((object->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) {
+		id = &prkey_info->id;
+		path = &prkey_info->path;
+		key_reference = &prkey_info->key_reference;
+	} else {
+		id = &skey_info->id;
+		path = &skey_info->path;
+		key_reference = &skey_info->key_reference;
+	}
+
+	sc_log(ctx, "create MyEID key ID:%s", sc_pkcs15_print_id(id));
 
 	/* Get the private key file */
-	r = myeid_new_file(profile, card, object->type, key_info->key_reference, &file);
-	LOG_TEST_RET(ctx, r, "Cannot get new MyEID private key file");
+	r = myeid_new_file(profile, card, object->type, *key_reference, &file);
+	LOG_TEST_RET(ctx, r, "Cannot get new MyEID key file");
 
 	if (!file || !file->path.len)
-		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot determine private key file");
+		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot determine key file");
 
 	sc_log(ctx, "Key file size %d", keybits);
 	file->size = keybits;
+	file->ef_structure = ef_structure;
 
-	if (object->type == SC_PKCS15_TYPE_PRKEY_RSA)
-		file->ef_structure = SC_CARDCTL_MYEID_KEY_RSA;
-	else if (object->type == SC_PKCS15_TYPE_PRKEY_EC)
-		file->ef_structure = SC_CARDCTL_MYEID_KEY_EC;
-
-	memcpy(&key_info->path.value, &file->path.value, file->path.len);
-	key_info->key_reference = file->path.value[file->path.len - 1] & 0xFF;
+	memcpy(path->value, &file->path.value, file->path.len);
+	*key_reference = file->path.value[file->path.len - 1] & 0xFF;
 
-	sc_log(ctx, "Path of MyEID private key file to create %s",
+	sc_log(ctx, "Path of MyEID key file to create %s",
 			sc_print_path(&file->path));
 
 	if (object->auth_id.len >= 1) {
@@ -513,7 +536,7 @@ myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
 	/* Now create the key file */
 	r = sc_pkcs15init_create_file(profile, p15card, file);
 	sc_file_free(file);
-	LOG_TEST_RET(ctx, r, "Cannot create MyEID private key file");
+	LOG_TEST_RET(ctx, r, "Cannot create MyEID key file");
 
 	LOG_FUNC_RETURN(ctx, r);
 }
@@ -527,40 +550,28 @@ myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
 		struct sc_pkcs15_prkey *prkey) {
 	struct sc_context *ctx = p15card->card->ctx;
 	struct sc_card *card = p15card->card;
-	struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data;
 	struct sc_cardctl_myeid_gen_store_key_info args;
 	struct sc_file *file = NULL;
-	int r, keybits = key_info->modulus_length;
+	struct sc_pkcs15_id *id;
+	struct sc_path *path;
+	int r;
 
 	LOG_FUNC_CALLED(ctx);
 
-	switch (object->type) {
-		case SC_PKCS15_TYPE_PRKEY_RSA:
-			if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL)
-				LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size");
-			break;
-		case SC_PKCS15_TYPE_PRKEY_EC:
-			if (!sc_valid_oid(&prkey->u.ec.params.id))
-                                if (sc_pkcs15_fix_ec_parameters(ctx, &prkey->u.ec.params))
-                                        LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID);
-						
-			if(key_info->field_length != 0)
-				keybits = key_info->field_length;
-			else
-				key_info->field_length = keybits;
-
-			if (sc_card_find_ec_alg(p15card->card, keybits, &prkey->u.ec.params.id) == NULL)
-				LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported algorithm or key size");			
-			break;
-		default:
-			LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Store key failed: Unsupported key type");
-			break;
+	if ((object->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) {
+		struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) object->data;
+		id = &prkey_info->id;
+		path = &prkey_info->path;
+	} else {
+		struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data;
+		id = &skey_info->id;
+		path = &skey_info->path;
 	}
 
 	sc_log(ctx, "store MyEID key with ID:%s and path:%s",
-			sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path));
+			sc_pkcs15_print_id(id), sc_print_path(path));
 
-	r = sc_select_file(card, &key_info->path, &file);
+	r = sc_select_file(card, path, &file);
 	LOG_TEST_RET(ctx, r, "Cannot store MyEID key: select key file failed");
 
 	r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
@@ -572,8 +583,9 @@ myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
 	memset(&args, 0, sizeof (args));
 
 	args.op_type = OP_TYPE_STORE;
-	if(object->type == SC_PKCS15_TYPE_PRKEY_RSA) {
-		//args.key_len_bits = keybits;
+
+	switch (object->type) {
+	case SC_PKCS15_TYPE_PRKEY_RSA:
 		args.key_type = SC_CARDCTL_MYEID_KEY_RSA;
 		args.pubexp_len = prkey->u.rsa.exponent.len;
 		args.pubexp = prkey->u.rsa.exponent.data;
@@ -589,16 +601,33 @@ myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
 		args.invq_len = prkey->u.rsa.iqmp.len;
 		args.invq = prkey->u.rsa.iqmp.data;
 
+		//args.key_len_bits = keybits;
 		args.key_len_bits = prkey->u.rsa.modulus.len;
 		args.mod = prkey->u.rsa.modulus.data;
-	}
-	else {
+		break;
+	case SC_PKCS15_TYPE_PRKEY_EC:
 		args.key_type = SC_CARDCTL_MYEID_KEY_EC;
 		args.d = prkey->u.ec.privateD.data;
 		args.d_len = prkey->u.ec.privateD.len;
 		args.ecpublic_point = prkey->u.ec.ecpointQ.value;
 		args.ecpublic_point_len = prkey->u.ec.ecpointQ.len;
 		args.key_len_bits = prkey->u.ec.params.field_length;
+		break;
+	case SC_PKCS15_TYPE_SKEY_GENERIC:
+	case SC_PKCS15_TYPE_SKEY_DES:
+	case SC_PKCS15_TYPE_SKEY_2DES:
+	case SC_PKCS15_TYPE_SKEY_3DES:
+		switch (prkey->algorithm) {
+		case SC_ALGORITHM_AES:
+			args.key_type = SC_CARDCTL_MYEID_KEY_AES;
+			break;
+		case SC_ALGORITHM_DES:
+			args.key_type = SC_CARDCTL_MYEID_KEY_DES;
+			break;
+		}
+		args.d = prkey->u.secret.data;
+		args.d_len = prkey->u.secret.data_len;
+		break;
 	}
 	/* Store RSA key  */
 	r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git



More information about the pkg-opensc-commit mailing list