Hi,

please find attached the third round of my patches to the OpenPGP card driver,
that now can - at least partially - deal with OpenPGP 2.0 cards while still
compatible with OpenPGP 1.1 cards (tested with both card types).

Here's what they do (copied from the commit message of each patch):

* [PATCH 01/15] OpenPGP: fix top-level DOs according to spec
  Added:
  * 00c4: new top-level DO in 2.0
          can also be found inside constructed DOs 006E/0073 in 2.0 & 1.1
  * 0101: new optional top-level DO starting in 1.1
          for private use
          max 254 bytes;
          access: read - always; write - verify CHV2
  * 0102: new optional top-level DO starting in 1.1
          for private use
          max 254 bytes;
          access: read - always; write - verify CHV3
  * 0103: new optional top-level DO starting in 1.1
          for private use
          max 254 bytes;
          access: read - verify CHV2; write - verify CHV2
  * 0104: new optional top-level DO starting in 1.1
          for private use
          max 254 bytes;
          access: read - verify CHV3; write - verify CHV3
  * 5f52: new top-level DO in 2.0
          can also be found inside constructed DOs 006E in 2.0
  * 7f21: new optional top-level DO in 2.0
          use: card holder certificate (e.g. X.509) for the AUT key in the card
  Removed:
  * 0073: never a top-level DO, but part of top-level constructed DO 006E
  Changed:
  * 005e: not a constructed DO, but a simple/primitive DO

  Note:
  Trying to read non-existent top-level DOs or top-level DOs that weren't 
defined
  in a spec version later than the current card's version does not hurt.
  They are returned as empty.

* [PATCH 02/15] OpenPGP: add indication of 2048 RSA agorithm for OpenPGP 
  2.0 cards

* [PATCH 03/15] OpenPGP: try to match flags with specification

* [PATCH 04/15] OpenPGP: re-factor pgp_enumerate_blob()
  Leverage the fact that OpenPGP cards use TLV encoding according to
  ASN.1 BER-encoding rules and use sc_asn1_read_tag() as the workhorse
  within pgp_enumerate_blob().

  There's one peculiarity though:
  OpenPGP cards expect 'cla' to be merged into 'tag'.
  This is done manually after calling sc_asn1_read_tag().

* [PATCH 05/15] OpenPGP: implement function to free the fake file system
  * pgp_iterate_blobs(): walk through the blob tree
  * pgp_free_blob(): free a blob

* [PATCH 06/15] OpenPGP: NULL-ify free()'d pointer

* [PATCH 07/15] OpenPGP: re-factor pgp_set_blob()
  * NULL-ify freed data pointer
  * avoid unnecessary malloc() calls
  * cope with malloc() errors
  * do not rely on blob->file for be set

* [PATCH 08/15] OpenPGP: add some comments

* [PATCH 09/15] OpenPGP: use symbolic names for errors/success

* [PATCH 10/15] OpenPGP: catch calloc() errors in pgp_new_blob()
  Detect and react on out of memory errors in pgp_new_blob() and its callers.

* [PATCH 11/15] OpenPGP: update card capabilities from historical bytes
  According to OpenPGP card specs 1.1 & 2.0 historical bytes in the ATR
  indicate capabilities:
  * bit 0x40 of the 3rd byte of the compact-TLV entry with TL 0x73 tells
    whether the card supports extended Lc/Le fields in APDUs.

  In addition, OpenPGP card 2.0 spec specifies the optional DO 5f52
  which also contains the histoirical bytes (just in case).
  If available use this value to override capabilties from ATR.

* [PATCH 12/15] OpenPGP: use card "extended Lc/Le" capabilities
  Adapt pgp_get_pubkey() and pgp_read_blob() to make use of the information
  about the "extended Lc/Le" capabilities.

  This allows reading OpenPGP Card v2.0 keys!   <<<< Yippie!!

* [PATCH 13/15] OpenPGP: allow extended APDUs in all functions
  Depending on the card's capabilities and the necessity (requested response
  size > 256) allow extended APDUs in all functions talking to the card.

* [PATCH 14/15] OpenPGP: free memory when selecting the application fails
  free() the memory already reserved when the file identifying the OpenPGP
  application fails & reset the pointers in the card strcuture back to NULL.

* [PATCH 15/15] OpenPGP: implement card_ctl() command SC_CARDCTL_GET_SERIALNR
  Implement card_ctl(), crrently restricted only to SC_CARDCTL_GET_SERIALNR.
  The card's serial number is copied from the respective bytes in the AID.


Please include them into the trunk as they:
a) fix lots of bugs
b) make the code conform to the ABI: free locally allocated memory, ..
c) extend features: OpenPGP Card 2.0 support (at least partially)

Thanks in advance
Peter

-- 
Peter Marschall
pe...@adpm.de
From 8319b2627fdbcf9465ffe6383d6b60cebe3da9a4 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 13 Mar 2011 21:41:12 +0100
Subject: [PATCH 01/15] OpenPGP: fix top-level DOs according to spec

Added:
* 00c4: new top-level DO in 2.0
        can also be found inside constructed DOs 006E/0073 in 2.0 & 1.1
* 0101: new optional top-level DO starting in 1.1
        for private use
        max 254 bytes;
        access: read - always; write - verify CHV2
* 0102: new optional top-level DO starting in 1.1
        for private use
        max 254 bytes;
        access: read - always; write - verify CHV3
* 0103: new optional top-level DO starting in 1.1
        for private use
        max 254 bytes;
        access: read - verify CHV2; write - verify CHV2
* 0104: new optional top-level DO starting in 1.1
        for private use
        max 254 bytes;
        access: read - verify CHV3; write - verify CHV3
* 5f52: new top-level DO in 2.0
        can also be found inside constructed DOs 006E in 2.0
* 7f21: new optional top-level DO in 2.0
        use: card holder certificate (e.g. X.509) for the AUT key in the card
Removed:
* 0073: never a top-level DO, but part of top-level constructed DO 006E
Changed:
* 005e: not a constructed DO, but a simple/primitive DO

Note:
Trying to read non-existent top-level DOs or top-level DOs that weren't defined
in a spec version later than the current card's version does not hurt.
They are returned as empty.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 386e687..0bb7f07 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -91,12 +91,18 @@ static int		pgp_get_pubkey_pem(sc_card_t *, unsigned int,
 
 static struct do_info		pgp_objects[] = {
       {	0x004f,		0, 0,	sc_get_data,	sc_put_data	},
-      {	0x005e,		1, 0,	sc_get_data,	sc_put_data	},
+      {	0x005e,		0, 0,	sc_get_data,	sc_put_data	},
       {	0x0065,		1, 0,	sc_get_data,	sc_put_data	},
       {	0x006e,		1, 0,	sc_get_data,	sc_put_data	},
-      {	0x0073,		1, 0,	sc_get_data,	sc_put_data	},
       {	0x007a,		1, 0,	sc_get_data,	sc_put_data	},
+      {	0x00c4,		0, 0,	sc_get_data,	sc_put_data	},
+      {	0x0101,		0, 0,	sc_get_data,	sc_put_data	},
+      {	0x0102,		0, 0,	sc_get_data,	sc_put_data	},
+//    {	0x0103,		0, 0,	sc_get_data,	sc_put_data	},	// needs verify with PW1
+//    {	0x0104,		0, 0,	sc_get_data,	sc_put_data	},	// needs verify with PW3
       {	0x5f50,		0, 0,	sc_get_data,	sc_put_data	},
+      {	0x5f52,		0, 0,	sc_get_data,	sc_put_data	},
+      {	0x7f21,		1, 0,	sc_get_data,	sc_put_data	},
       { 0xb600,		1, 0,	pgp_get_pubkey,	NULL		},
       { 0xb800,		1, 0,	pgp_get_pubkey,	NULL		},
       { 0xa400,		1, 0,	pgp_get_pubkey,	NULL		},
-- 
1.7.4.1

From 4ee4508f03d93e6fb5495174c0c910d286ccd9e1 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 13 Mar 2011 18:51:33 +0100
Subject: [PATCH 02/15] OpenPGP: add indication of 2048 RSA agorithm for OpenPGP 2.0 cards


Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 0bb7f07..f123914 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -160,6 +160,8 @@ pgp_init(sc_card_t *card)
         _sc_card_add_rsa_alg(card, 512, flags, 0);
         _sc_card_add_rsa_alg(card, 768, flags, 0);
         _sc_card_add_rsa_alg(card, 1024, flags, 0);
+	if (card->type == SC_CARD_TYPE_OPENPGP_V2)
+		_sc_card_add_rsa_alg(card, 2048, flags, 0);
 
 	sc_format_path("D276:0001:2401", &aid);
 	aid.type = SC_PATH_TYPE_DF_NAME;
-- 
1.7.4.1

From c9f3737f28259cc0879e8893788ce2da7814db4b Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 13 Mar 2011 19:08:16 +0100
Subject: [PATCH 06/15] OpenPGP: NULL-ify free()'d pointer


Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 111b948..b7379f2 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -221,6 +221,7 @@ pgp_finish(sc_card_t *card)
 	pgp_iterate_blobs(priv->mf, 99, pgp_free_blob);
 
 	free(priv);
+	card->drv_data = NULL;
 	return 0;
 }
 
-- 
1.7.4.1

From 6921a9391f4e7fb80e42450aa7ba8609a0accad1 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 13 Mar 2011 19:04:29 +0100
Subject: [PATCH 03/15] OpenPGP: try to match flags with specification


Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index f123914..8b893d5 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -152,8 +152,18 @@ pgp_init(sc_card_t *card)
 	card->cla = 0x00;
 
 	/* Is this correct? */
+	/* OpenPGP card spec 1.1 & 2.0, section 2.1 */
         flags = SC_ALGORITHM_RSA_RAW;
+	/* OpenPGP card spec 1.1 & 2.0, section 7.2.9 & 7.2.10 */
         flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
+	/* OpenPGP card 2.0 spec, section 7.2.8.1 */
+	flags |= SC_ALGORITHM_RSA_HASH_SHA1 |
+		 SC_ALGORITHM_RSA_HASH_RIPEMD160;
+	if (card->type == SC_CARD_TYPE_OPENPGP_V2)
+		flags |= SC_ALGORITHM_RSA_HASH_SHA224 |
+			 SC_ALGORITHM_RSA_HASH_SHA256 |
+			 SC_ALGORITHM_RSA_HASH_SHA384 |
+			 SC_ALGORITHM_RSA_HASH_SHA512;
         flags |= SC_ALGORITHM_RSA_HASH_NONE;
 
 	/* Is this correct? */
-- 
1.7.4.1

From dc825ca77d4cdad7b22a32ab2d51ebc0053233fd Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 19 Mar 2011 21:28:49 +0100
Subject: [PATCH 04/15] OpenPGP: re-factor pgp_enumerate_blob()

Leverage the fact that OpenPGP cards use TLV encoding according to
ASN.1 BER-encoding rules and use sc_asn1_read_tag() as the workhorse
within pgp_enumerate_blob().

There's one peculiarity though:
OpenPGP cards expect 'cla' to be merged into 'tag'.
This is done manually after calling sc_asn1_read_tag().

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   66 +++++++++++++++++------------------------
 1 files changed, 27 insertions(+), 39 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 8b893d5..e2b0229 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -276,12 +276,12 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
 
 /*
  * Enumerate contents of a data blob.
- * The OpenPGP card has a funny TLV encoding.
+ * The OpenPGP card has a TLV encoding according ASN.1 BER-encoding rules.
  */
 static int
 pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
 {
-	const u8	*in, *end;
+	const u8	*in;
 	int		r;
 
 	if (blob->files != NULL)
@@ -291,52 +291,40 @@ pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
 		return r;
 
 	in = blob->data;
-	end = blob->data + blob->len;
-	while (in < end) {
-		unsigned int	tag, len, type = SC_FILE_TYPE_WORKING_EF;
-		unsigned char	c;
 
-		c = *in++;
-		if (c == 0x00 || c == 0xFF)
-			continue;
+	while (blob->len > (in - blob->data)) {
+		unsigned int	cla, tag, tmptag;
+		unsigned int	type = SC_FILE_TYPE_WORKING_EF;
+		size_t		len;
+		const u8	*data = in;
+		struct blob	*new;
 
-		tag = c;
-		if (tag & 0x20)
-			type = SC_FILE_TYPE_DF;
-		while ((c & 0x1f) == 0x1f) {
-			if (in >= end)
-				goto eoc;
-			c = *in++;
-			tag = (tag << 8) | c;
+		r = sc_asn1_read_tag(&data, blob->len - (in - blob->data),
+					&cla, &tag, &len);
+		if (r < 0) {
+			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
+				 "Unexpected end of contents\n");
+			return SC_ERROR_OBJECT_NOT_VALID;
 		}
 
-		if (in >= end)
-			goto eoc;
-		c = *in++;
-		if (c < 0x80) {
-			len = c;
-		} else {
-			len = 0;
-			c &= 0x7F;
-			while (c--) {
-				if (in >= end)
-					goto eoc;
-				len = (len << 8) | *in++;
-			}
-		}
+		/* create fake file system hierarchy by
+		 * using constructed DOs as DF */
+		if (cla & SC_ASN1_TAG_CONSTRUCTED)
+			type = SC_FILE_TYPE_DF;
 
-		/* Don't search past end of content */
-		if (in + len > end)
-			goto eoc;
+		/* undo ASN1's split of tag & class */
+		for (tmptag = tag; tmptag > 0x0FF; tmptag >>= 8) {
+			cla <<= 8;
+		}
+		tag |= cla;
 
-		pgp_set_blob(pgp_new_blob(blob, tag, type, NULL), in, len);
-		in += len;
+		if ((new = pgp_new_blob(blob, tag, type, NULL)) == NULL)
+			return SC_ERROR_OUT_OF_MEMORY;
+		pgp_set_blob(new, data, len);
+		in = data + len;
 	}
 
 	return 0;
-
-eoc:	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unexpected end of contents\n");
-	return SC_ERROR_OBJECT_NOT_VALID;
 }
 
 static int
-- 
1.7.4.1

From 7b3224a7d90f71fcab7433cc517c26881b4cb983 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 19 Mar 2011 20:06:42 +0100
Subject: [PATCH 05/15] OpenPGP: implement function to free the fake file system

* pgp_iterate_blobs(): walk through the blob tree
* pgp_free_blob(): free a blob

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   57 ++++++++++++++++++++++++++++++++++++------
 1 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index e2b0229..111b948 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -82,8 +82,11 @@ struct do_info {
 	int		(*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t);
 };
 
+static void		pgp_iterate_blobs(struct blob *, int, void (*func)());
+
 static struct blob *	pgp_new_blob(struct blob *, unsigned int, int,
 				struct do_info *);
+static void		pgp_free_blob(struct blob *);
 static int		pgp_get_pubkey(sc_card_t *, unsigned int,
 				u8 *, size_t);
 static int		pgp_get_pubkey_pem(sc_card_t *, unsigned int,
@@ -115,7 +118,7 @@ static struct do_info		pgp_objects[] = {
 
 #define DRVDATA(card)        ((struct pgp_priv_data *) ((card)->drv_data))
 struct pgp_priv_data {
-	struct blob		mf;
+	struct blob *		mf;
 	struct blob *		current;
 
 	sc_security_env_t	sec_env;
@@ -148,6 +151,12 @@ pgp_init(sc_card_t *card)
 	priv = calloc (1, sizeof *priv);
 	if (!priv)
 		return SC_ERROR_OUT_OF_MEMORY;
+	priv->mf = calloc(1, sizeof(struct blob));
+	if (!priv->mf) {
+		free(priv);
+		return SC_ERROR_OUT_OF_MEMORY;
+	}
+
 	card->drv_data = priv;
 	card->cla = 0x00;
 
@@ -183,15 +192,15 @@ pgp_init(sc_card_t *card)
 	file->type = SC_FILE_TYPE_DF;
 	file->id = 0x3f00;
 
-	priv->mf.file = file;
-	priv->mf.id = 0x3F00;
+	priv->mf->file = file;
+	priv->mf->id = 0x3F00;
 
-	priv->current = &priv->mf;
+	priv->current = priv->mf;
 
 	/* Populate MF - add all blobs listed in the pgp_objects
 	 * table. */
 	for (info = pgp_objects; info->id > 0; info++) {
-		pgp_new_blob(&priv->mf, info->id,
+		pgp_new_blob(priv->mf, info->id,
 			  	info->constructed? SC_FILE_TYPE_DF
 					  	 : SC_FILE_TYPE_WORKING_EF,
 				info);
@@ -208,7 +217,8 @@ pgp_finish(sc_card_t *card)
                 return 0;
 	priv = DRVDATA (card);
 
-	/* XXX delete fake file hierarchy */
+	/* delete fake file hierarchy */
+	pgp_iterate_blobs(priv->mf, 99, pgp_free_blob);
 
 	free(priv);
 	return 0;
@@ -253,6 +263,37 @@ pgp_new_blob(struct blob *parent, unsigned int file_id,
 	return blob;
 }
 
+static void
+pgp_free_blob(struct blob *blob)
+{
+	if (blob) {
+		if (blob->file)
+			sc_file_free(blob->file);
+		if (blob->data)
+			free(blob->data);
+		free(blob);
+	}
+}
+
+
+static void
+pgp_iterate_blobs(struct blob *blob, int level, void (*func)())
+{
+	if (blob) {
+		if (level > 0) {
+			struct blob *child = blob->files;
+
+			while (child != NULL) {
+				struct blob *next = child->next;
+
+				pgp_iterate_blobs(child, level-1, func);
+				child = next;
+			}
+		}
+		func(blob);
+	}
+}
+
 static int
 pgp_read_blob(sc_card_t *card, struct blob *blob)
 {
@@ -374,7 +415,7 @@ pgp_select_file(sc_card_t *card, const sc_path_t *path, sc_file_t **ret)
 		path = &path_copy;
 	}
 
-	blob = &priv->mf;
+	blob = priv->mf;
 	for (n = 0; n < path->len; n += 2) {
 		r = pgp_get_blob(card, blob,
 				(path->value[n] << 8) | path->value[n+1],
@@ -491,7 +532,7 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
 
 	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "called, tag=%04x\n", tag);
 	
-	if ((r = pgp_get_blob(card, &priv->mf, tag & 0xFFFE, &blob)) < 0
+	if ((r = pgp_get_blob(card, priv->mf, tag & 0xFFFE, &blob)) < 0
 	 || (r = pgp_get_blob(card, blob, 0x7F49, &blob)) < 0
 	 || (r = pgp_get_blob(card, blob, 0x0081, &mod_blob)) < 0
 	 || (r = pgp_get_blob(card, blob, 0x0082, &exp_blob)) < 0
-- 
1.7.4.1

From aada01e7e189712348c5871a94685800c0331087 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 26 Mar 2011 17:40:57 +0100
Subject: [PATCH 10/15] OpenPGP: catch calloc() errors in pgp_new_blob()

Detect and react on out of memory errors in pgp_new_blob() and its callers.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   42 +++++++++++++++++++++++++++---------------
 1 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index b1fa41e..ca6ca3e 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -83,6 +83,7 @@ struct do_info {
 	int		(*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t);
 };
 
+static int		pgp_finish(sc_card_t *card);
 static void		pgp_iterate_blobs(struct blob *, int, void (*func)());
 
 static struct blob *	pgp_new_blob(struct blob *, unsigned int, int,
@@ -148,6 +149,7 @@ pgp_init(sc_card_t *card)
 	sc_file_t	*file = NULL;
 	struct do_info	*info;
 	int		r;
+	struct blob 	*child;
 
 	priv = calloc (1, sizeof *priv);
 	if (!priv)
@@ -198,14 +200,23 @@ pgp_init(sc_card_t *card)
 
 	priv->current = priv->mf;
 
-	/* Populate MF - add all blobs listed in the pgp_objects
-	 * table. */
+	/* Populate MF - add all blobs listed in the pgp_objects table. */
 	for (info = pgp_objects; info->id > 0; info++) {
-		pgp_new_blob(priv->mf, info->id,
+		child = pgp_new_blob(priv->mf, info->id,
 			  	info->constructed? SC_FILE_TYPE_DF
 					  	 : SC_FILE_TYPE_WORKING_EF,
 				info);
+		/* catch out of memory condition */
+		if (child == NULL)
+			break;
+	}
+
+	/* treat out of memory condition */
+	if (child == NULL) {
+		pgp_finish(card);
+		return SC_ERROR_OUT_OF_MEMORY;
 	}
+
 	return SC_SUCCESS;
 }
 
@@ -259,20 +270,21 @@ pgp_new_blob(struct blob *parent, unsigned int file_id,
 	sc_file_t	*file = sc_file_new();
 	struct blob	*blob, **p;
 
-	blob = calloc(1, sizeof(*blob));
-	blob->parent = parent;
-	blob->id     = file_id;
-	blob->file   = file;
-	blob->info   = info;
+	if ((blob = calloc(1, sizeof(*blob))) != NULL) {
+		blob->parent = parent;
+		blob->id     = file_id;
+		blob->file   = file;
+		blob->info   = info;
 
-	file->type   = file_type;
-	file->path   = parent->file->path;
-	file->ef_structure = SC_FILE_EF_TRANSPARENT;
-	sc_append_file_id(&file->path, file_id);
+		file->type   = file_type;
+		file->path   = parent->file->path;
+		file->ef_structure = SC_FILE_EF_TRANSPARENT;
+		sc_append_file_id(&file->path, file_id);
 
-	for (p = &parent->files; *p; p = &(*p)->next)
-		;
-	*p = blob;
+		for (p = &parent->files; *p; p = &(*p)->next)
+			;
+		*p = blob;
+	}
 
 	return blob;
 }
-- 
1.7.4.1

From af1c549f8a38972f45bf27cc0d5507e1a68b5be3 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 13 Mar 2011 19:26:35 +0100
Subject: [PATCH 07/15] OpenPGP: re-factor pgp_set_blob()

* NULL-ify freed data pointer
* avoid unnecessary malloc() calls
* cope with malloc() errors
* do not rely on blob->file for be set

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index b7379f2..c0c0e55 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -230,12 +230,24 @@ pgp_set_blob(struct blob *blob, const u8 *data, size_t len)
 {
 	if (blob->data)
 		free(blob->data);
-	blob->len    = len;
+	blob->data = NULL;
+	blob->len    = 0;
 	blob->status = 0;
-	blob->data   = malloc(len);
-	memcpy(blob->data, data, len);
 
-	blob->file->size = len;
+	if (len > 0) {
+		void *tmp = malloc(len);
+
+		if (tmp == NULL)
+			return SC_ERROR_OUT_OF_MEMORY;
+
+		blob->data = tmp;
+		blob->len  = len;
+		memcpy(blob->data, data, len);
+	}
+
+	if (blob->file)
+		blob->file->size = len;
+
 	return 0;
 }
 
-- 
1.7.4.1

From 7706c44c19da4bf172b829f5d1f700c3ada2947b Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Fri, 15 Apr 2011 18:10:07 +0200
Subject: [PATCH 11/15] OpenPGP: update card capabilities from historical bytes

According to OpenPGP card specs 1.1 & 2.0 historical bytes in the ATR
indicate capabilities:
* bit 0x40 of the 3rd byte of the compact-TLV entry with TL 0x73 tells
  whether the card supports extended Lc/Le fields in APDUs.

In addition, OpenPGP card 2.0 spec specifies the optional DO 5f52
which also contains the histoirical bytes (just in case).
If available use this value to override capabilties from ATR.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index ca6ca3e..5b0b4c7 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -89,6 +89,8 @@ static void		pgp_iterate_blobs(struct blob *, int, void (*func)());
 static struct blob *	pgp_new_blob(struct blob *, unsigned int, int,
 				struct do_info *);
 static void		pgp_free_blob(struct blob *);
+static int		pgp_get_blob(sc_card_t *, struct blob *, unsigned int,
+				struct blob **);
 static int		pgp_get_pubkey(sc_card_t *, unsigned int,
 				u8 *, size_t);
 static int		pgp_get_pubkey_pem(sc_card_t *, unsigned int,
@@ -217,6 +219,39 @@ pgp_init(sc_card_t *card)
 		return SC_ERROR_OUT_OF_MEMORY;
 	}
 
+	/* update card capabilities from ATR */
+	if (card->atr.len > 0) {
+		unsigned char *hist_bytes = card->atr.value;
+		size_t len = card->atr.len;
+		size_t i = 0;
+
+		while ((i < len) && (hist_bytes[i] != 0x73))
+			i++;
+
+		/* bit 0x40 in byte 3 of TL 0x73 means "extended Le/Lc" */
+		if ((hist_bytes[i] == 0x73) && (len > i+3) &&
+		    (hist_bytes[i+3] & 0x40))
+			card->caps |= SC_CARD_CAP_APDU_EXT;
+	}
+	/* allow capability override from DO for v2.0 cards */
+	if (card->type == SC_CARD_TYPE_OPENPGP_V2) {
+		struct blob *blob;
+
+		/* get card capabilities from "historical bytes" DO */
+		if ((pgp_get_blob(card, priv->mf, 0x5f52, &blob) >= 0) &&
+		    (blob != NULL) && (blob->data != NULL) && (blob->data[0] == 0x00)) {
+			unsigned int i = 0;
+
+			while ((i < blob->len) && (blob->data[i] != 0x73))
+				i++;
+
+			/* bit 0x40 in byte 3 of TL 0x73 means "extended Le/Lc" */
+			if ((blob->data[i] == 0x73) && (blob->len > i+3) &&
+			    (blob->data[i+3] & 0x40))
+				card->caps |= SC_CARD_CAP_APDU_EXT;
+		}
+	}
+
 	return SC_SUCCESS;
 }
 
-- 
1.7.4.1

From 8b7c6cb705cccdb3602aeecffde0b2e43a4c0049 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sun, 13 Mar 2011 19:32:05 +0100
Subject: [PATCH 08/15] OpenPGP: add some comments


Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index c0c0e55..54dd607 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -61,8 +61,8 @@ static struct sc_card_driver pgp_drv = {
  * Everything else is mapped to "file" IDs.
  */
 struct blob {
-	struct blob *	next;
-	struct blob *	parent;
+	struct blob *	next;	/* pointer to next sibling */
+	struct blob *	parent;	/* pointer to parent */
 	struct do_info *info;
 
 	sc_file_t *	file;
@@ -71,7 +71,7 @@ struct blob {
 
 	unsigned char *	data;
 	unsigned int	len;
-	struct blob *	files;
+	struct blob *	files;	/* pointer to 1st child */
 };
 
 struct do_info {
@@ -182,9 +182,9 @@ pgp_init(sc_card_t *card)
 	if (card->type == SC_CARD_TYPE_OPENPGP_V2)
 		_sc_card_add_rsa_alg(card, 2048, flags, 0);
 
+	/* select application "OpenPGP" */
 	sc_format_path("D276:0001:2401", &aid);
 	aid.type = SC_PATH_TYPE_DF_NAME;
-
 	if ((r = iso_ops->select_file(card, &aid, &file)) < 0)
 		return r;
 
-- 
1.7.4.1

From a8b788eee3bdb5c0caf3fdf125fae52ba5054690 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Fri, 15 Apr 2011 18:29:46 +0200
Subject: [PATCH 12/15] OpenPGP: use card "extended Lc/Le" capabilities

adapt pgp_get_pubkey() and pgp_read_blob() to make use of the information
about the "extended Lc/Le" capabilities.

This allows reading OpenPGP Card v2.0 keys!

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 5b0b4c7..cdaddbe 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -358,7 +358,9 @@ pgp_iterate_blobs(struct blob *blob, int level, void (*func)())
 static int
 pgp_read_blob(sc_card_t *card, struct blob *blob)
 {
-	unsigned char	buffer[256];
+	unsigned char	buffer[2048];
+	size_t		buf_len = (card->caps & SC_CARD_CAP_APDU_EXT)
+				  ? sizeof(buffer) : 256;
 	int		r;
 
 	if (blob->data != NULL)
@@ -366,7 +368,7 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
 	if (blob->info == NULL)
 		return blob->status;
 
-	r = blob->info->get_fn(card, blob->id, buffer, sizeof(buffer));
+	r = blob->info->get_fn(card, blob->id, buffer, buf_len);
 
 	if (r < 0) {	/* an error occurred */
 		blob->status = r;
@@ -559,17 +561,24 @@ pgp_get_pubkey(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
 	sc_apdu_t	apdu;
 	u8		idbuf[2];
 	int		r;
+	int		cse = SC_APDU_CASE_4_SHORT;
+	size_t		le = buf_len;
 
 	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "called, tag=%04x\n", tag);
 
 	idbuf[0] = tag >> 8;
 	idbuf[1] = tag;
 
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x47, 0x81, 0);
+	if ((buf_len > 256) && (card->caps & SC_CARD_CAP_APDU_EXT))
+		cse |= SC_APDU_EXT;
+	else
+		le = (le >= 256) ? 256 : le;
+
+	sc_format_apdu(card, &apdu, cse, 0x47, 0x81, 0);
 	apdu.lc = 2;
 	apdu.data = idbuf;
 	apdu.datalen = 2;
-	apdu.le = (buf_len > 256)? 256 : buf_len;
+	apdu.le = le;
 	apdu.resp = buf;
 	apdu.resplen = buf_len;
 
-- 
1.7.4.1

From b5cd5bad9f44ef829f755171177e58cc0852d2bf Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Thu, 24 Mar 2011 08:57:31 +0100
Subject: [PATCH 09/15] OpenPGP: use symbolic names for errors/success


Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   23 ++++++++++++-----------
 1 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 54dd607..b1fa41e 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -33,6 +33,7 @@
 #include "internal.h"
 #include "asn1.h"
 #include "cardctl.h"
+#include "errors.h"
 
 static struct sc_atr_table pgp_atrs[] = {
 	{ "3b:fa:13:00:ff:81:31:80:45:00:31:c1:73:c0:01:00:00:90:00:b1", NULL, "OpenPGP card v1.0/1.1", SC_CARD_TYPE_OPENPGP_V1, 0, NULL },
@@ -205,7 +206,7 @@ pgp_init(sc_card_t *card)
 					  	 : SC_FILE_TYPE_WORKING_EF,
 				info);
 	}
-	return 0;
+	return SC_SUCCESS;
 }
 
 static int
@@ -214,7 +215,7 @@ pgp_finish(sc_card_t *card)
         struct pgp_priv_data *priv;
 
         if (card == NULL)
-                return 0;
+                return SC_SUCCESS;
 	priv = DRVDATA (card);
 
 	/* delete fake file hierarchy */
@@ -222,7 +223,7 @@ pgp_finish(sc_card_t *card)
 
 	free(priv);
 	card->drv_data = NULL;
-	return 0;
+	return SC_SUCCESS;
 }
 
 static int
@@ -248,7 +249,7 @@ pgp_set_blob(struct blob *blob, const u8 *data, size_t len)
 	if (blob->file)
 		blob->file->size = len;
 
-	return 0;
+	return SC_SUCCESS;
 }
 
 static struct blob *
@@ -314,13 +315,13 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
 	int		r;
 
 	if (blob->data != NULL)
-		return 0;
+		return SC_SUCCESS;
 	if (blob->info == NULL)
 		return blob->status;
 
 	r = blob->info->get_fn(card, blob->id, buffer, sizeof(buffer));
 
-	if (r < 0) {
+	if (r < 0) {	/* an error occurred */
 		blob->status = r;
 		return r;
 	}
@@ -339,7 +340,7 @@ pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
 	int		r;
 
 	if (blob->files != NULL)
-		return 0;
+		return SC_SUCCESS;
 
 	if ((r = pgp_read_blob(card, blob)) < 0)
 		return r;
@@ -378,7 +379,7 @@ pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
 		in = data + len;
 	}
 
-	return 0;
+	return SC_SUCCESS;
 }
 
 static int
@@ -399,7 +400,7 @@ pgp_get_blob(sc_card_t *card, struct blob *blob, unsigned int id,
 	if (child != NULL) {
 		(void) pgp_read_blob(card, child);
 		*ret = child;
-		return 0;
+		return SC_SUCCESS;
 	}
 
 	return SC_ERROR_FILE_NOT_FOUND;
@@ -443,7 +444,7 @@ pgp_select_file(sc_card_t *card, const sc_path_t *path, sc_file_t **ret)
 
 	if (ret)
 		sc_file_dup(ret, blob->file);
-	return 0;
+	return SC_SUCCESS;
 }
 
 static int
@@ -646,7 +647,7 @@ pgp_set_security_env(sc_card_t *card,
 	}
 
 	priv->sec_env = *env;
-	return 0;
+	return SC_SUCCESS;
 }
 
 static int
-- 
1.7.4.1

From de702281a68586af5b7a9f10a13fd16ad12feddb Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Fri, 15 Apr 2011 20:30:48 +0200
Subject: [PATCH 13/15] OpenPGP: allow extended APDUs in all functions

Depending on the card's capabilities and the necessity (requested response
size > 256) allow extended APDUs in all functions talking to the card.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   39 ++++++++++++++++++++++++++++-----------
 1 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index cdaddbe..c968170 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -632,10 +632,16 @@ pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
 {
 	sc_apdu_t	apdu;
 	int		r;
+	int		cse = SC_APDU_CASE_2_SHORT;
+	size_t		le = buf_len;
 
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT,
-				0xCA, tag >> 8, tag);
-	apdu.le = (buf_len <= 255)? buf_len : 256;
+	if ((buf_len > 256) && (card->caps & SC_CARD_CAP_APDU_EXT))
+		cse |= SC_APDU_EXT;
+	else
+		le = (le >= 256) ? 256 : le;
+
+	sc_format_apdu(card, &apdu, cse, 0xCA, tag >> 8, tag);
+	apdu.le = le;
 	apdu.resp = buf;
 	apdu.resplen = buf_len;
 
@@ -714,20 +720,25 @@ pgp_compute_signature(sc_card_t *card, const u8 *data,
 	sc_security_env_t	*env = &priv->sec_env;
 	sc_apdu_t		apdu;
 	int			r;
+	int			cse = SC_APDU_CASE_4_SHORT;
+	size_t			le = outlen;
 
 	if (env->operation != SC_SEC_OPERATION_SIGN)
 		return SC_ERROR_INVALID_ARGUMENTS;
 
+	if ((outlen > 256) && (card->caps & SC_CARD_CAP_APDU_EXT))
+		cse |= SC_APDU_EXT;
+	else
+		le = (le >= 256) ? 256 : le;
+
 	switch (env->key_ref[0]) {
 	case 0x00: /* signature key */
 		/* PSO SIGNATURE */
-		sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
-				0x2A, 0x9E, 0x9A);
+		sc_format_apdu(card, &apdu, cse, 0x2A, 0x9E, 0x9A);
 		break;
 	case 0x02: /* authentication key */
 		/* INTERNAL AUTHENTICATE */
-		sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
-				0x88, 0, 0);
+		sc_format_apdu(card, &apdu, cse, 0x88, 0, 0);
 		break;
 	case 0x01:
 		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
@@ -742,7 +753,7 @@ pgp_compute_signature(sc_card_t *card, const u8 *data,
 	apdu.lc = data_len;
 	apdu.data = data;
 	apdu.datalen = data_len;
-	apdu.le      = outlen > 256 ? 256 : outlen;
+	apdu.le      = le;
 	apdu.resp    = out;
 	apdu.resplen = outlen;
 
@@ -763,6 +774,8 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
 	sc_apdu_t	apdu;
 	u8		*temp = NULL;
 	int		r;
+	int		cse = SC_APDU_CASE_4_SHORT;
+	size_t		le = outlen;
 
 	/* There's some funny padding indicator that must be
 	 * prepended... hmm. */
@@ -778,11 +791,15 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
 		return SC_ERROR_INVALID_ARGUMENTS;
 	}
 
+	if ((outlen > 256) && (card->caps & SC_CARD_CAP_APDU_EXT))
+		cse |= SC_APDU_EXT;
+	else
+		le = (le >= 256) ? 256 : le;
+
 	switch (env->key_ref[0]) {
 	case 0x01: /* Decryption key */
 		/* PSO DECIPHER */
-		sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
-				0x2A, 0x80, 0x86);
+		sc_format_apdu(card, &apdu, cse, 0x2A, 0x80, 0x86);
 		break;
 	case 0x00: /* signature key */
 	case 0x02: /* authentication key */
@@ -800,7 +817,7 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
 	apdu.lc = inlen;
 	apdu.data = in;
 	apdu.datalen = inlen;
-	apdu.le = 256;
+	apdu.le = le;
 	apdu.resp = out;
 	apdu.resplen = outlen;
 
-- 
1.7.4.1

From a7b3d3c4341d47c008f58e98d84314f10adda798 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 16 Apr 2011 19:56:03 +0200
Subject: [PATCH 14/15] OpenPGP: free memory when selecting the application fails

free() the memory already reserved when the file identifying the OpenPGP
application fails & reset the pointers in the card strcuture back to NULL.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index c968170..20be8c7 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -190,8 +190,12 @@ pgp_init(sc_card_t *card)
 	/* select application "OpenPGP" */
 	sc_format_path("D276:0001:2401", &aid);
 	aid.type = SC_PATH_TYPE_DF_NAME;
-	if ((r = iso_ops->select_file(card, &aid, &file)) < 0)
+	if ((r = iso_ops->select_file(card, &aid, &file)) < 0) {
+		free(priv->mf);
+		free(priv);
+		card->drv_data = NULL;
 		return r;
+	}
 
 	sc_format_path("3f00", &file->path);
 	file->type = SC_FILE_TYPE_DF;
-- 
1.7.4.1

From c87cb56c8d0e07ac1da72bb701a39378e33f2895 Mon Sep 17 00:00:00 2001
From: Peter Marschall <pe...@adpm.de>
Date: Sat, 16 Apr 2011 22:59:42 +0200
Subject: [PATCH 15/15] OpenPGP: implement card_ctl() command SC_CARDCTL_GET_SERIALNR

Implement card_ctl(), crrently restricted only to SC_CARDCTL_GET_SERIALNR.
The card's serial number is copied from the respective bytes in the AID.

Signed-off-by: Peter Marschall <pe...@adpm.de>
---
 src/libopensc/card-openpgp.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 20be8c7..b38f447 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -197,6 +197,13 @@ pgp_init(sc_card_t *card)
 		return r;
 	}
 
+	/* kludge: get card's serial number from manufacturer ID + serial number */
+	if (file && file->namelen == 16) {
+		/* OpenPGP card spec 1.1 & 2.0, section 4.2.1 & 4.1.2.1 */
+		memcpy(card->serialnr.value, file->name + 8, 6);
+		card->serialnr.len = 6;
+	}
+
 	sc_format_path("3f00", &file->path);
 	file->type = SC_FILE_TYPE_DF;
 	file->id = 0x3f00;
@@ -835,6 +842,20 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
 	return apdu.resplen;
 }
 
+static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
+{
+	struct pgp_priv_data	*priv = DRVDATA(card);
+
+	switch(cmd) {
+	case SC_CARDCTL_GET_SERIALNR:
+		memmove((sc_serial_number_t *) ptr, &card->serialnr, sizeof(card->serialnr));
+		return SC_SUCCESS;
+		break;
+	}
+
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
+}
+
 /* Driver binding stuff */
 static struct sc_card_driver *
 sc_get_driver(void)
@@ -857,6 +878,7 @@ sc_get_driver(void)
 	pgp_ops.set_security_env= pgp_set_security_env;
 	pgp_ops.compute_signature= pgp_compute_signature;
 	pgp_ops.decipher	= pgp_decipher;
+	pgp_ops.card_ctl	= pgp_card_ctl;
 
 	return &pgp_drv;
 }
-- 
1.7.4.1

_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to