add OpenSC package
authorDaniel Golle <[email protected]>
Mon, 16 Jun 2014 12:16:59 +0000 (14:16 +0200)
committerDaniel Golle <[email protected]>
Mon, 16 Jun 2014 23:50:13 +0000 (01:50 +0200)
OpenSC is a smart card middleware.
Patches for support of the GnuK USB token have been added.

Signed-off-by: Daniel Golle <[email protected]>
19 files changed:
utils/opensc/Makefile [new file with mode: 0644]
utils/opensc/patches/0001-OpenPGP-Detect-and-support-Gnuk-Token.patch [new file with mode: 0644]
utils/opensc/patches/0002-OpenPGP-Add-Gnuk-in-pkcs15-emulation-layer.patch [new file with mode: 0644]
utils/opensc/patches/0003-OpenPGP-Include-private-DO-to-filesystem-at-driver-i.patch [new file with mode: 0644]
utils/opensc/patches/0004-PKCS15-OpenPGP-Declare-DATA-objects.patch [new file with mode: 0644]
utils/opensc/patches/0005-OpenPGP-Support-erasing-reset-card.patch [new file with mode: 0644]
utils/opensc/patches/0006-openpgp-tool-Support-deleting-key-in-Gnuk.patch [new file with mode: 0644]
utils/opensc/patches/0007-OpenPGP-Correct-building-Extended-Header-List-when-i.patch [new file with mode: 0644]
utils/opensc/patches/0008-OpenPGP-Read-some-empty-DOs-from-Gnuk.patch [new file with mode: 0644]
utils/opensc/patches/0009-PKCS15-OpenPGP-Do-not-show-empty-DO-in-pkcs15-emu_in.patch [new file with mode: 0644]
utils/opensc/patches/0010-PKCS15-OpenPGP-Allow-to-store-data-to-pkcs15-data-ob.patch [new file with mode: 0644]
utils/opensc/patches/0011-OpenPGP-Provide-enough-buffer-to-read-pubkey-from-Gn.patch [new file with mode: 0644]
utils/opensc/patches/0012-OpenPGP-Support-write-certificate-for-Gnuk.patch [new file with mode: 0644]
utils/opensc/patches/0013-pkcs15-openpgp-Change-to-sc_put_data-instead-of-sc_u.patch [new file with mode: 0644]
utils/opensc/patches/0014-OpenPGP-Overcome-the-restriction-of-even-data-length.patch [new file with mode: 0644]
utils/opensc/patches/0015-OpenPGP-Delete-key-as-file-for-Gnuk.patch [new file with mode: 0644]
utils/opensc/patches/0016-OpenPGP-Correct-parameter-checking.patch [new file with mode: 0644]
utils/opensc/patches/0017-OpenPGP-Make-code-neater.patch [new file with mode: 0644]
utils/opensc/patches/0018-Move-declaration-to-top-of-block.patch [new file with mode: 0644]

diff --git a/utils/opensc/Makefile b/utils/opensc/Makefile
new file mode 100644 (file)
index 0000000..b004a91
--- /dev/null
@@ -0,0 +1,224 @@
+#
+# Copyright (C) 2011-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=opensc
+PKG_VERSION:=20140317
+PKG_RELEASE:=1
+PKG_MAINTAINER:=Daniel Golle <[email protected]>
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/OpenSC/OpenSC.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=de6d61405b271e22244376e4817e16b49018e1ce
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_BUILD_DEPENDS:=+libpcsclite
+PKG_FIXUP:=libtool
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libopensc
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=OpenSC libraries for smart cards
+  URL:=https://www.opensc-project.org/opensc/wiki/
+  DEPENDS:=+libopenssl +libpthread
+  MENU:=1
+endef
+
+define Package/libopensc/description
+  OpenSC provides a set of libraries and utilities to work with smart cards.
+  Its main focus is on cards that support cryptographic operations, and
+  facilitate their use in security applications such as authentication,
+  mail encryption and digital signatures.
+endef
+
+define Package/libopensc-pkcs11
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=OpenSC - PKCS11 provider
+  URL:=https://www.opensc-project.org/opensc/wiki/
+  DEPENDS:=libopensc
+endef
+
+define Package/libopensc-pkcs11/description
+  OpenSC PKCS#11 provider
+endef
+
+define Package/libpkcs11-spy
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=PKCS11 spying wrapper
+  URL:=https://www.opensc-project.org/opensc/wiki/
+endef
+
+define Package/libpkcs11-spy/dscription
+  PKCS#11 spying wrapper
+endef
+
+define Package/opensc-utils
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=OpenSC - tools for smart cards
+  URL:=https://www.opensc-project.org/opensc/wiki/
+  DEPENDS:=+libopensc
+  MENU:=1
+endef
+
+define Package/opensc-utils/description
+  OpenSC utilities
+endef
+
+define ToolGen
+define Package/opensc-utils-$(subst _,-,$(firstword $(subst :, ,$(1))))
+  TITLE:=$(firstword $(subst :, ,$(1))) utility from opensc
+  URL:=https://www.opensc-project.org/opensc/wiki/
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=opensc-utils $(wordlist 2,$(words $(subst :, ,$(1))),$(subst :, ,$(1)))
+endef
+endef
+
+define ProfileGen
+define Package/libopensc-profile-$(subst _,-,$(firstword $(subst :, ,$(1))))
+  TITLE:=$(firstword $(subst :, ,$(1))) card profile for opensc
+  URL:=https://www.opensc-project.org/opensc/wiki/
+  SECTION:=lib
+  CATEGORY:=Libraries
+  DEPENDS:=libopensc
+endef
+endef
+
+TOOLS:= \
+       cardos-tool \
+       cryptoflex-tool \
+       dnie-tool \
+       eidenv \
+       iasecc-tool \
+       netkey-tool \
+       openpgp-tool \
+       opensc-tool \
+       opensc-explorer:+libncurses:+libreadline \
+       piv-tool \
+       pkcs11-tool \
+       pkcs15-crypt \
+       pkcs15-init \
+       pkcs15-tool \
+       sc-hsm-tool \
+       westcos-tool
+
+PROFILES:= \
+       asepcos \
+       authentic \
+       cardos \
+       cyberflex \
+       entersafe \
+       epass2003 \
+       flex \
+       gpk \
+       ias_adele_admin1 \
+       ias_adele_admin2 \
+       ias_adele_common \
+       iasecc_admin_eid \
+       iasecc_generic_oberthur \
+       iasecc_generic_pki \
+       iasecc \
+       incrypto34 \
+       jcop \
+       miocos \
+       muscle \
+       myeid \
+       oberthur \
+       openpgp \
+       pkcs15 \
+       rutoken_ecp \
+       rutoken \
+       sc-hsm \
+       setcos \
+       starcos \
+       westcos
+
+$(foreach file,$(TOOLS),$(eval $(call ToolGen,$(file))))
+$(foreach file,$(PROFILES),$(eval $(call ProfileGen,$(file))))
+
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libopensc.{a,so}* $(1)/usr/lib/
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libsmm-local.{a,so}* $(1)/usr/lib/
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/opensc-pkcs11.so $(1)/usr/lib/
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkcs11-spy.so $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/usr/lib/pkcs11
+       $(LN) ../pkcs11-spy.so $(1)/usr/lib/pkcs11/
+       $(LN) ../opensc-pkcs11.so $(1)/usr/lib/pkcs11/
+       $(INSTALL_DIR) $(1)/usr/share/opensc
+       $(CP) $(PKG_INSTALL_DIR)/usr/share/opensc/* $(1)/usr/share/opensc/
+endef
+
+define Package/libopensc/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libopensc.so* $(1)/usr/lib/
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libsmm-local.so* $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/etc
+       $(CP) $(PKG_INSTALL_DIR)/etc/opensc.conf $(1)/etc/
+endef
+
+define Package/libopensc-pkcs11/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/opensc-pkcs11.so $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/usr/lib/pkcs11
+       $(LN) ../opensc-pkcs11.so $(1)/usr/lib/pkcs11/
+endef
+
+define Package/libpkcs11-spy/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkcs11-spy.so $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/usr/lib/pkcs11
+       $(LN) ../pkcs11-spy.so $(1)/usr/lib/pkcs11/
+endef
+
+define Package/opensc-card-profiles
+       $(INSTALL_DIR) $(1)/usr/share/opensc
+       $(CP) $(PKG_INSTALL_DIR)/usr/share/opensc/* $(1)/usr/share/opensc/
+endef
+
+define Package/opensc-utils/install
+       true
+endef
+
+define ToolInstall
+define Package/opensc-utils-$(subst _,-,$(firstword $(subst :, ,$(1))))/install
+       $(INSTALL_DIR) $$(1)/usr/bin
+       $(INSTALL_BIN) \
+               $(PKG_INSTALL_DIR)/usr/bin/$(firstword $(subst :, ,$(1))) \
+               $$(1)/usr/bin/
+endef
+endef
+
+define ProfileInstall
+define Package/libopensc-profile-$(subst _,-,$(firstword $(subst :, ,$(1))))/install
+       $(INSTALL_DIR) $$(1)/usr/share/opensc
+       $(INSTALL_BIN) \
+               $(PKG_INSTALL_DIR)/usr/share/opensc/$(firstword $(subst :, ,$(1))).profile \
+               $$(1)/usr/share/opensc
+endef
+endef
+
+$(foreach file,$(TOOLS),$(eval $(call ToolInstall,$(file))))
+$(foreach file,$(PROFILES),$(eval $(call ProfileInstall,$(file))))
+
+$(eval $(call BuildPackage,libopensc))
+$(eval $(call BuildPackage,libopensc-pkcs11))
+$(eval $(call BuildPackage,libpkcs11-spy))
+
+$(eval $(call BuildPackage,opensc-utils))
+$(foreach file,$(TOOLS),$(eval $(call BuildPackage,opensc-utils-$(subst _,-,$(firstword $(subst :, ,$(file)))))))
+$(foreach file,$(PROFILES),$(eval $(call BuildPackage,libopensc-profile-$(subst _,-,$(firstword $(subst :, ,$(file)))))))
diff --git a/utils/opensc/patches/0001-OpenPGP-Detect-and-support-Gnuk-Token.patch b/utils/opensc/patches/0001-OpenPGP-Detect-and-support-Gnuk-Token.patch
new file mode 100644 (file)
index 0000000..0d79422
--- /dev/null
@@ -0,0 +1,267 @@
+From c706491fc9b08d4cc6d7b254cf936d6b8d8691bc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Wed, 20 Feb 2013 11:54:30 +0700
+Subject: [PATCH 01/18] OpenPGP: Detect and support Gnuk Token.
+
+http://www.fsij.org/gnuk/
+---
+ src/libopensc/card-openpgp.c | 61 ++++++++++++++++++++++++++++++++++----------
+ src/libopensc/cards.h        |  1 +
+ src/tools/openpgp-tool.c     |  9 +++++--
+ 3 files changed, 56 insertions(+), 15 deletions(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 743e79c..716052b 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -43,6 +43,7 @@
+ 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 },
+       { "3b:da:18:ff:81:b1:fe:75:1f:03:00:31:c5:73:c0:01:40:00:90:00:0c", NULL, "CryptoStick v1.2 (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_V2, 0, NULL },
++      { "3b:da:11:ff:81:b1:fe:55:1f:03:00:31:84:73:80:01:80:00:90:00:e4", NULL, "Gnuk v1.0.x (OpenPGP v2.0)", SC_CARD_TYPE_OPENPGP_GNUK, 0, NULL },
+       { NULL, NULL, NULL, 0, 0, NULL }
+ };
+@@ -307,6 +308,8 @@ pgp_init(sc_card_t *card)
+       int             r;
+       struct blob     *child = NULL;
++      LOG_FUNC_CALLED(card->ctx);
++
+       priv = calloc (1, sizeof *priv);
+       if (!priv)
+               return SC_ERROR_OUT_OF_MEMORY;
+@@ -315,11 +318,11 @@ pgp_init(sc_card_t *card)
+       card->cla = 0x00;
+       /* set pointer to correct list of card objects */
+-      priv->pgp_objects = (card->type == SC_CARD_TYPE_OPENPGP_V2)
++      priv->pgp_objects = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)
+                               ? pgp2_objects : pgp1_objects;
+       /* set detailed card version */
+-      priv->bcd_version = (card->type == SC_CARD_TYPE_OPENPGP_V2)
++      priv->bcd_version = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)
+                               ? OPENPGP_CARD_2_0 : OPENPGP_CARD_1_1;
+       /* select application "OpenPGP" */
+@@ -428,7 +431,8 @@ pgp_get_card_features(sc_card_t *card)
+               if ((pgp_get_blob(card, blob73, 0x00c0, &blob) >= 0) &&
+                   (blob->data != NULL) && (blob->len > 0)) {
+                       /* in v2.0 bit 0x04 in first byte means "algorithm attributes changeable */
+-                      if ((blob->data[0] & 0x04) && (card->type == SC_CARD_TYPE_OPENPGP_V2))
++                      if ((blob->data[0] & 0x04) &&
++                          (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK))
+                               priv->ext_caps |= EXT_CAP_ALG_ATTR_CHANGEABLE;
+                       /* bit 0x08 in first byte means "support for private use DOs" */
+                       if (blob->data[0] & 0x08)
+@@ -445,7 +449,8 @@ pgp_get_card_features(sc_card_t *card)
+                               priv->ext_caps |= EXT_CAP_GET_CHALLENGE;
+                       }
+                       /* in v2.0 bit 0x80 in first byte means "support Secure Messaging" */
+-                      if ((blob->data[0] & 0x80) && (card->type == SC_CARD_TYPE_OPENPGP_V2))
++                      if ((blob->data[0] & 0x80) &&
++                          (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK))
+                               priv->ext_caps |= EXT_CAP_SM;
+                       if ((priv->bcd_version >= OPENPGP_CARD_2_0) && (blob->len >= 10)) {
+@@ -1055,12 +1060,18 @@ static int
+ pgp_get_pubkey(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
+ {
+       sc_apdu_t       apdu;
++      u8 apdu_case = SC_APDU_CASE_4;
+       u8              idbuf[2];
+       int             r;
+       sc_log(card->ctx, "called, tag=%04x\n", tag);
+-      sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x47, 0x81, 0);
++      /* With Gnuk token, force to use short APDU */
++      if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
++              apdu_case = SC_APDU_CASE_4_SHORT;
++      }
++
++      sc_format_apdu(card, &apdu, apdu_case, 0x47, 0x81, 0);
+       apdu.lc = 2;
+       apdu.data = ushort2bebytes(idbuf, tag);
+       apdu.datalen = 2;
+@@ -1152,6 +1163,7 @@ pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
+       u8 ins = 0xDA;
+       u8 p1 = tag >> 8;
+       u8 p2 = tag & 0xFF;
++      u8 apdu_case = SC_APDU_CASE_3;
+       int r;
+       LOG_FUNC_CALLED(card->ctx);
+@@ -1193,13 +1205,17 @@ pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
+       /* Build APDU */
+       if (buf != NULL && buf_len > 0) {
+-              sc_format_apdu(card, &apdu, SC_APDU_CASE_3, ins, p1, p2);
++              /* Force short APDU for Gnuk */
++              if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
++                      apdu_case = SC_APDU_CASE_3_SHORT;
++              }
++              sc_format_apdu(card, &apdu, apdu_case, ins, p1, p2);
+               /* if card/reader does not support extended APDUs, but chaining, then set it */
+               if (((card->caps & SC_CARD_CAP_APDU_EXT) == 0) && (priv->ext_caps & EXT_CAP_CHAINING))
+                       apdu.flags |= SC_APDU_FLAGS_CHAINING;
+-              apdu.data = buf;
++              apdu.data = (u8 *)buf;
+               apdu.datalen = buf_len;
+               apdu.lc = buf_len;
+       }
+@@ -1326,6 +1342,7 @@ pgp_compute_signature(sc_card_t *card, const u8 *data,
+       struct pgp_priv_data    *priv = DRVDATA(card);
+       sc_security_env_t       *env = &priv->sec_env;
+       sc_apdu_t               apdu;
++      u8 apdu_case = SC_APDU_CASE_4;
+       int                     r;
+       LOG_FUNC_CALLED(card->ctx);
+@@ -1334,14 +1351,19 @@ pgp_compute_signature(sc_card_t *card, const u8 *data,
+               LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
+                               "invalid operation");
++      /* Force short APDU for Gnuk Token */
++      if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
++              apdu_case = SC_APDU_CASE_4_SHORT;
++      }
++
+       switch (env->key_ref[0]) {
+       case 0x00: /* signature key */
+               /* PSO SIGNATURE */
+-              sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x9E, 0x9A);
++              sc_format_apdu(card, &apdu, apdu_case, 0x2A, 0x9E, 0x9A);
+               break;
+       case 0x02: /* authentication key */
+               /* INTERNAL AUTHENTICATE */
+-              sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x88, 0, 0);
++              sc_format_apdu(card, &apdu, apdu_case, 0x88, 0, 0);
+               break;
+       case 0x01:
+       default:
+@@ -1350,7 +1372,7 @@ pgp_compute_signature(sc_card_t *card, const u8 *data,
+       }
+       apdu.lc = data_len;
+-      apdu.data = data;
++      apdu.data = (u8 *)data;
+       apdu.datalen = data_len;
+       apdu.le = ((outlen >= 256) && !(card->caps & SC_CARD_CAP_APDU_EXT)) ? 256 : outlen;
+       apdu.resp    = out;
+@@ -1374,6 +1396,7 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
+       struct pgp_priv_data    *priv = DRVDATA(card);
+       sc_security_env_t       *env = &priv->sec_env;
+       sc_apdu_t       apdu;
++      u8 apdu_case = SC_APDU_CASE_4;
+       u8              *temp = NULL;
+       int             r;
+@@ -1398,7 +1421,7 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
+       case 0x01: /* Decryption key */
+       case 0x02: /* authentication key */
+               /* PSO DECIPHER */
+-              sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
++              sc_format_apdu(card, &apdu, apdu_case, 0x2A, 0x80, 0x86);
+               break;
+       case 0x00: /* signature key */
+       default:
+@@ -1407,8 +1430,13 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
+                               "invalid key reference");
+       }
++      /* Gnuk only supports short APDU, so we need to use command chaining */
++      if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
++              apdu.flags |= SC_APDU_FLAGS_CHAINING;
++      }
++
+       apdu.lc = inlen;
+-      apdu.data = in;
++      apdu.data = (u8 *)in;
+       apdu.datalen = inlen;
+       apdu.le = ((outlen >= 256) && !(card->caps & SC_CARD_CAP_APDU_EXT)) ? 256 : outlen;
+       apdu.resp = out;
+@@ -1794,6 +1822,11 @@ static int pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in
+               LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+       }
++      if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && key_info->modulus_len != 2048) {
++              sc_log(card->ctx, "Gnuk does not support other key length than 2048.");
++              LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
++      }
++
+       /* Set attributes for new-generated key */
+       r = pgp_update_new_algo_attr(card, key_info);
+       LOG_TEST_RET(card->ctx, r, "Cannot set attributes for new-generated key");
+@@ -1801,7 +1834,9 @@ static int pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in
+       /* Test whether we will need extended APDU. 1900 is an
+        * arbitrary modulus length which for sure fits into a short APDU.
+        * This idea is borrowed from GnuPG code.  */
+-      if (card->caps & SC_CARD_CAP_APDU_EXT && key_info->modulus_len > 1900) {
++      if (card->caps & SC_CARD_CAP_APDU_EXT
++          && key_info->modulus_len > 1900
++          && card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
+               /* We won't store to apdu variable yet, because it will be reset in
+                * sc_format_apdu() */
+               apdu_le = card->max_recv_size;
+diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h
+index 0fbf9ca..01b08fd 100644
+--- a/src/libopensc/cards.h
++++ b/src/libopensc/cards.h
+@@ -104,6 +104,7 @@ enum {
+       SC_CARD_TYPE_OPENPGP_BASE = 9000,
+       SC_CARD_TYPE_OPENPGP_V1,
+       SC_CARD_TYPE_OPENPGP_V2,
++      SC_CARD_TYPE_OPENPGP_GNUK,
+       /* jcop driver */
+       SC_CARD_TYPE_JCOP_BASE = 10000,
+diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c
+index 7058aaa..8b5e327 100644
+--- a/src/tools/openpgp-tool.c
++++ b/src/tools/openpgp-tool.c
+@@ -32,6 +32,7 @@
+ #include "libopensc/asn1.h"
+ #include "libopensc/cards.h"
+ #include "libopensc/cardctl.h"
++#include "libopensc/log.h"
+ #include "util.h"
+ #define       OPT_RAW         256
+@@ -216,7 +217,7 @@ static void display_data(const struct ef_name_map *mapping, char *value)
+                       } else {
+                               const char *label = mapping->name;
+-                              printf("%s:%*s%s\n", label, 10-strlen(label), "", value);
++                              printf("%s:%*s%s\n", label, 10 - (int)strlen(label), "", value);
+                       }
+               }
+       }
+@@ -390,6 +391,8 @@ int do_genkey(sc_card_t *card, u8 key_id, unsigned int key_len)
+       sc_path_t path;
+       sc_file_t *file;
++      LOG_FUNC_CALLED(card->ctx);
++
+       if (key_id < 1 || key_id > 3) {
+               printf("Unknown key ID %d.\n", key_id);
+               return 1;
+@@ -481,8 +484,10 @@ int main(int argc, char **argv)
+       /* check card type */
+       if ((card->type != SC_CARD_TYPE_OPENPGP_V1) &&
+-          (card->type != SC_CARD_TYPE_OPENPGP_V2)) {
++          (card->type != SC_CARD_TYPE_OPENPGP_V2) &&
++          (card->type != SC_CARD_TYPE_OPENPGP_GNUK)) {
+               util_error("not an OpenPGP card");
++              sc_log(card->ctx, "Card type %X", card->type);
+               exit_status = EXIT_FAILURE;
+               goto out;
+       }
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0002-OpenPGP-Add-Gnuk-in-pkcs15-emulation-layer.patch b/utils/opensc/patches/0002-OpenPGP-Add-Gnuk-in-pkcs15-emulation-layer.patch
new file mode 100644 (file)
index 0000000..cf8cae6
--- /dev/null
@@ -0,0 +1,50 @@
+From ecc6460d17147b37def27a9b776e1fc5a61408d0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Fri, 12 Apr 2013 17:24:00 +0700
+Subject: [PATCH 02/18] OpenPGP: Add Gnuk in pkcs15 emulation layer.
+
+---
+ src/libopensc/pkcs15-openpgp.c | 6 ++++--
+ src/libopensc/pkcs15-syn.c     | 1 +
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c
+index d9dc074..5a8a1ca 100644
+--- a/src/libopensc/pkcs15-openpgp.c
++++ b/src/libopensc/pkcs15-openpgp.c
+@@ -155,7 +155,8 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
+       u8              c4data[10];
+       u8              c5data[70];
+       int             r, i;
+-      const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V2) ? pin_cfg_v2 : pin_cfg_v1;
++      const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V2 || card->type == SC_CARD_TYPE_OPENPGP_GNUK)
++                                     ? pin_cfg_v2 : pin_cfg_v1;
+       sc_path_t path;
+       sc_file_t *file;
+@@ -367,7 +368,8 @@ failed:    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP e
+ static int openpgp_detect_card(sc_pkcs15_card_t *p15card)
+ {
+-      if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2)
++      if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2
++          || p15card->card->type == SC_CARD_TYPE_OPENPGP_GNUK)
+               return SC_SUCCESS;
+       else
+               return SC_ERROR_WRONG_CARD;
+diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c
+index e2f6004..a9f8c0b 100644
+--- a/src/libopensc/pkcs15-syn.c
++++ b/src/libopensc/pkcs15-syn.c
+@@ -112,6 +112,7 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card)
+               case SC_CARD_TYPE_GEMSAFEV1_PTEID:
+               case SC_CARD_TYPE_OPENPGP_V1:
+               case SC_CARD_TYPE_OPENPGP_V2:
++              case SC_CARD_TYPE_OPENPGP_GNUK:
+               case SC_CARD_TYPE_SC_HSM:
+                       return 1;
+               default:
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0003-OpenPGP-Include-private-DO-to-filesystem-at-driver-i.patch b/utils/opensc/patches/0003-OpenPGP-Include-private-DO-to-filesystem-at-driver-i.patch
new file mode 100644 (file)
index 0000000..fa15d79
--- /dev/null
@@ -0,0 +1,30 @@
+From 5f751ba5628f9d85e9d8dca9939a93f49d2525d0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Fri, 22 Mar 2013 17:37:16 +0700
+Subject: [PATCH 03/18] OpenPGP: Include private DO to filesystem at driver
+ initialization.
+
+In old implementation, the DOs which their access is restricted by
+PIN (like DOs 0101 -> 0104) were excluded from the fake filesystem,
+leading to that we cannot read their data later, even if we verified PIN.
+---
+ src/libopensc/card-openpgp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 716052b..ead07ae 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -357,7 +357,7 @@ pgp_init(sc_card_t *card)
+       /* Populate MF - add matching blobs listed in the pgp_objects table. */
+       for (info = priv->pgp_objects; (info != NULL) && (info->id > 0); info++) {
+-              if (((info->access & READ_MASK) == READ_ALWAYS) &&
++              if (((info->access & READ_MASK) != READ_NEVER) &&
+                   (info->get_fn != NULL)) {
+                       child = pgp_new_blob(card, priv->mf, info->id, sc_file_new());
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0004-PKCS15-OpenPGP-Declare-DATA-objects.patch b/utils/opensc/patches/0004-PKCS15-OpenPGP-Declare-DATA-objects.patch
new file mode 100644 (file)
index 0000000..114412f
--- /dev/null
@@ -0,0 +1,82 @@
+From fbf8e392db4456de97796259a62ccb972fe24df8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Tue, 26 Feb 2013 17:37:16 +0700
+Subject: [PATCH 04/18] PKCS15-OpenPGP: Declare DATA objects.
+
+Begin to support read/write DATA object for PKCS-OpenPGP binding.
+This object is used by TrueCrypt.
+---
+ src/libopensc/pkcs15-openpgp.c | 35 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c
+index 5a8a1ca..9f239ef 100644
+--- a/src/libopensc/pkcs15-openpgp.c
++++ b/src/libopensc/pkcs15-openpgp.c
+@@ -36,6 +36,7 @@ typedef USHORT ushort;
+ #endif
+ int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
++static int sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *);
+ #define       PGP_USER_PIN_FLAGS      (SC_PKCS15_PIN_FLAG_CASE_SENSITIVE \
+@@ -45,6 +46,8 @@ int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
+                               | SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED \
+                               | SC_PKCS15_PIN_FLAG_SO_PIN)
++#define PGP_NUM_PRIVDO       4
++
+ typedef struct _pgp_pin_cfg {
+       const char      *label;
+       int             reference;
+@@ -359,6 +362,9 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
+                       goto failed;
+       }
++      /* PKCS#15 DATA object from OpenPGP private DOs */
++      r = sc_pkcs15emu_openpgp_add_data(p15card);
++
+       return 0;
+ failed:       sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP emulation: %s\n",
+@@ -366,6 +372,35 @@ failed:   sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to initialize OpenPGP e
+       return r;
+ }
++static int
++sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *p15card)
++{
++      sc_context_t *ctx = p15card->card->ctx;
++      int i, r;
++
++      LOG_FUNC_CALLED(ctx);
++      /* There is 4 private DO from 0101 to 0104 */
++      for (i = 1; i <= PGP_NUM_PRIVDO; i++) {
++              sc_pkcs15_data_info_t dat_info;
++              sc_pkcs15_object_t dat_obj;
++              char name[8];
++              char path[9];
++              memset(&dat_info, 0, sizeof(dat_info));
++              memset(&dat_obj, 0, sizeof(dat_obj));
++
++              sprintf(name, "PrivDO%d", i);
++              sprintf(path, "3F00010%d", i);
++
++              sc_format_path(path, &dat_info.path);
++              strlcpy(dat_obj.label, name, sizeof(dat_obj.label));
++              strlcpy(dat_info.app_label, name, sizeof(dat_info.app_label));
++
++              sc_log(ctx, "Add %s data object", name);
++              r = sc_pkcs15emu_add_data_object(p15card, &dat_obj, &dat_info);
++      }
++      LOG_FUNC_RETURN(ctx, r);
++}
++
+ static int openpgp_detect_card(sc_pkcs15_card_t *p15card)
+ {
+       if (p15card->card->type == SC_CARD_TYPE_OPENPGP_V1 || p15card->card->type == SC_CARD_TYPE_OPENPGP_V2
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0005-OpenPGP-Support-erasing-reset-card.patch b/utils/opensc/patches/0005-OpenPGP-Support-erasing-reset-card.patch
new file mode 100644 (file)
index 0000000..c28ed10
--- /dev/null
@@ -0,0 +1,173 @@
+From 4cdc5f3102f5ad93d263eea2f8206bb5e9fffc6c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Mon, 4 Mar 2013 11:28:08 +0700
+Subject: [PATCH 05/18] OpenPGP: Support erasing (reset) card.
+
+Command: openpgp-tool --erase
+---
+ src/libopensc/card-openpgp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
+ src/tools/openpgp-tool.c     | 23 +++++++++++++++-
+ 2 files changed, 86 insertions(+), 1 deletion(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index ead07ae..42a9684 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -2197,6 +2197,66 @@ out:
+ #endif /* ENABLE_OPENSSL */
++/**
++ * Erase card
++ **/
++static int pgp_erase_card(sc_card_t *card)
++{
++      sc_context_t *ctx = card->ctx;
++      u8 *apdustring[10] = {
++              "00:20:00:81:08:40:40:40:40:40:40:40:40",
++              "00:20:00:81:08:40:40:40:40:40:40:40:40",
++              "00:20:00:81:08:40:40:40:40:40:40:40:40",
++              "00:20:00:81:08:40:40:40:40:40:40:40:40",
++              "00:20:00:83:08:40:40:40:40:40:40:40:40",
++              "00:20:00:83:08:40:40:40:40:40:40:40:40",
++              "00:20:00:83:08:40:40:40:40:40:40:40:40",
++              "00:20:00:83:08:40:40:40:40:40:40:40:40",
++              "00:e6:00:00",
++              "00:44:00:00"
++      };
++      u8 buf[SC_MAX_APDU_BUFFER_SIZE];
++      u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
++      sc_apdu_t apdu;
++      size_t len0;
++      int commandsnum = 10;
++      int i, r;
++
++      LOG_FUNC_CALLED(ctx);
++
++      /* Check card version */
++      if (card->type != SC_CARD_TYPE_OPENPGP_V2) {
++              sc_log(ctx, "Card is not OpenPGP v2");
++              LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT);
++      }
++      sc_log(ctx, "Card is OpenPGP v2. Erase card.");
++
++      /* Iterate over 10 commands above */
++      for (i = 0; i < commandsnum; i++) {
++              /* Convert the string to binary array */
++              len0 = sizeof(buf);
++              sc_hex_to_bin(apdustring[i], buf, &len0);
++              printf("Sending: ");
++              for (r = 0; r < len0; r++)
++                      printf("%02X ", buf[r]);
++              printf("\n");
++
++              /* Build APDU from binary array */
++              r = sc_bytes2apdu(card->ctx, buf, len0, &apdu);
++              if (r) {
++                      sc_log(ctx, "Failed to build APDU");
++                      LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
++              }
++              apdu.resp = rbuf;
++              apdu.resplen = sizeof(rbuf);
++
++              /* Send APDU to card */
++              r = sc_transmit_apdu(card, &apdu);
++              LOG_TEST_RET(ctx, r, "Transmiting APDU failed");
++      }
++      LOG_FUNC_RETURN(ctx, r);
++}
++
+ /* ABI: card ctl: perform special card-specific operations */
+ static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
+ {
+@@ -2221,6 +2281,10 @@ static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
+               LOG_FUNC_RETURN(card->ctx, r);
+               break;
+ #endif /* ENABLE_OPENSSL */
++      case SC_CARDCTL_ERASE_CARD:
++              r = pgp_erase_card(card);
++              LOG_FUNC_RETURN(card->ctx, r);
++              break;
+       }
+       LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c
+index 8b5e327..0d360a3 100644
+--- a/src/tools/openpgp-tool.c
++++ b/src/tools/openpgp-tool.c
+@@ -76,6 +76,7 @@ static int opt_verify = 0;
+ static char *verifytype = NULL;
+ static int opt_pin = 0;
+ static char *pin = NULL;
++static int opt_erase = 0;
+ static const char *app_name = "openpgp-tool";
+@@ -92,6 +93,7 @@ static const struct option options[] = {
+       { "help",      no_argument,       NULL, 'h'        },
+       { "verbose",   no_argument,       NULL, 'v'        },
+       { "version",   no_argument,       NULL, 'V'        },
++      { "erase",     no_argument,       NULL, 'E'        },
+       { "verify",    required_argument, NULL, OPT_VERIFY },
+       { "pin",       required_argument, NULL, OPT_PIN },
+       { NULL, 0, NULL, 0 }
+@@ -110,6 +112,7 @@ static const char *option_help[] = {
+ /* h */       "Print this help message",
+ /* v */       "Verbose operation. Use several times to enable debug output.",
+ /* V */       "Show version number",
++/* E */       "Erase (reset) the card",
+       "Verify PIN (CHV1, CHV2, CHV3...)",
+       "PIN string"
+ };
+@@ -228,7 +231,7 @@ static int decode_options(int argc, char **argv)
+ {
+       int c;
+-      while ((c = getopt_long(argc, argv,"r:x:CUG:L:hwvV", options, (int *) 0)) != EOF) {
++      while ((c = getopt_long(argc, argv,"r:x:CUG:L:hwvVE", options, (int *) 0)) != EOF) {
+               switch (c) {
+               case 'r':
+                       opt_reader = optarg;
+@@ -288,6 +291,9 @@ static int decode_options(int argc, char **argv)
+                       show_version();
+                       exit(EXIT_SUCCESS);
+                       break;
++              case 'E':
++                      opt_erase++;
++                      break;
+               default:
+                       util_print_usage_and_die(app_name, options, option_help, NULL);
+               }
+@@ -446,6 +452,18 @@ int do_verify(sc_card_t *card, u8 *type, u8* pin)
+       return r;
+ }
++int do_erase(sc_card_t *card)
++{
++      int r;
++      /* Check card version */
++      if (card->type != SC_CARD_TYPE_OPENPGP_V2) {
++              printf("Do not erase card which is not OpenPGP v2\n");
++      }
++      printf("Erase card\n");
++      r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);
++      return r;
++}
++
+ int main(int argc, char **argv)
+ {
+       sc_context_t *ctx = NULL;
+@@ -521,6 +539,9 @@ int main(int argc, char **argv)
+               exit(EXIT_FAILURE);
+       }
++      if (opt_erase)
++              exit_status != do_erase(card);
++
+ out:
+       sc_unlock(card);
+       sc_disconnect_card(card);
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0006-openpgp-tool-Support-deleting-key-in-Gnuk.patch b/utils/opensc/patches/0006-openpgp-tool-Support-deleting-key-in-Gnuk.patch
new file mode 100644 (file)
index 0000000..f73cb22
--- /dev/null
@@ -0,0 +1,210 @@
+From bbbedd3b358f80a7f98df2b22cf541cb007dd62e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Mon, 4 Mar 2013 18:13:03 +0700
+Subject: [PATCH 06/18] openpgp-tool: Support deleting key in Gnuk.
+
+---
+ src/tools/openpgp-tool.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 143 insertions(+), 1 deletion(-)
+
+diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c
+index 0d360a3..239c86b 100644
+--- a/src/tools/openpgp-tool.c
++++ b/src/tools/openpgp-tool.c
+@@ -39,6 +39,7 @@
+ #define       OPT_PRETTY      257
+ #define       OPT_VERIFY      258
+ #define       OPT_PIN     259
++#define       OPT_DELKEY  260
+ /* define structures */
+ struct ef_name_map {
+@@ -77,6 +78,7 @@ static char *verifytype = NULL;
+ static int opt_pin = 0;
+ static char *pin = NULL;
+ static int opt_erase = 0;
++static int opt_delkey = 0;
+ static const char *app_name = "openpgp-tool";
+@@ -96,6 +98,7 @@ static const struct option options[] = {
+       { "erase",     no_argument,       NULL, 'E'        },
+       { "verify",    required_argument, NULL, OPT_VERIFY },
+       { "pin",       required_argument, NULL, OPT_PIN },
++      { "del-key",   required_argument, NULL, OPT_DELKEY },
+       { NULL, 0, NULL, 0 }
+ };
+@@ -114,7 +117,8 @@ static const char *option_help[] = {
+ /* V */       "Show version number",
+ /* E */       "Erase (reset) the card",
+       "Verify PIN (CHV1, CHV2, CHV3...)",
+-      "PIN string"
++      "PIN string",
++      "Delete key (1, 2, 3 or all)"
+ };
+ static const struct ef_name_map openpgp_data[] = {
+@@ -294,6 +298,14 @@ static int decode_options(int argc, char **argv)
+               case 'E':
+                       opt_erase++;
+                       break;
++              case OPT_DELKEY:
++                      opt_delkey++;
++                      if (strcmp(optarg, "all") != 0)   /* Arg string is not 'all' */
++                              key_id = optarg[0] - '0';
++                      else                              /* Arg string is 'all' */
++                              key_id = 'a';
++                      actions++;
++                      break;
+               default:
+                       util_print_usage_and_die(app_name, options, option_help, NULL);
+               }
+@@ -452,6 +464,133 @@ int do_verify(sc_card_t *card, u8 *type, u8* pin)
+       return r;
+ }
++/**
++ * Delete key, for Gnuk.
++ **/
++int delete_key_gnuk(sc_card_t *card, u8 key_id)
++{
++      sc_context_t *ctx = card->ctx;
++      int r = SC_SUCCESS;
++      u8 *data = NULL;
++
++      /* Delete fingerprint */
++      sc_log(ctx, "Delete fingerprints");
++      r |= sc_put_data(card, 0xC6 + key_id, NULL, 0);
++      /* Delete creation time */
++      sc_log(ctx, "Delete creation time");
++      r |= sc_put_data(card, 0xCD + key_id, NULL, 0);
++
++      /* Rewrite Extended Header List */
++      sc_log(ctx, "Rewrite Extended Header List");
++
++      if (key_id == 1)
++              data = "\x4D\x02\xB6";
++      else if (key_id == 2)
++              data = "\x4D\x02\xB8";
++      else if (key_id == 3)
++              data = "\x4D\x02\xA4";
++      else
++              return SC_ERROR_INVALID_ARGUMENTS;
++
++      r |= sc_put_data(card, 0x4D, data, strlen(data) + 1);
++      return r;
++}
++
++/**
++ * Delete key, for OpenPGP card.
++ * This function is not complete and is reserved for future version (> 2) of OpenPGP card.
++ **/
++int delete_key_openpgp(sc_card_t *card, u8 key_id)
++{
++      sc_context_t *ctx = card->ctx;
++      char *del_fingerprint = "00:DA:00:C6:14:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00";
++      char *del_creationtime = "00:DA:00:CD:04:00:00:00:00";
++      /* We need to replace the 4th byte later */
++      char *apdustring = NULL;
++      u8 buf[SC_MAX_APDU_BUFFER_SIZE];
++      u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
++      sc_apdu_t apdu;
++      size_t len0;
++      int i;
++      int r = SC_SUCCESS;
++
++      for (i = 0; i < 2; i++) {
++              if (i == 0)    /* Reset fingerprint */
++                      apdustring = del_fingerprint;
++              else           /* Reset creation time */
++                      apdustring = del_creationtime;
++              /* Convert the string to binary array */
++              len0 = sizeof(buf);
++              sc_hex_to_bin(apdustring, buf, &len0);
++
++              /* Replace DO tag, subject to key ID */
++              buf[3] = buf[3] + key_id;
++
++              /* Build APDU from binary array */
++              r = sc_bytes2apdu(card->ctx, buf, len0, &apdu);
++              if (r) {
++                      sc_log(ctx, "Failed to build APDU");
++                      LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
++              }
++              apdu.resp = rbuf;
++              apdu.resplen = sizeof(rbuf);
++
++              /* Send APDU to card */
++              r = sc_transmit_apdu(card, &apdu);
++              LOG_TEST_RET(ctx, r, "Transmiting APDU failed");
++      }
++      /* TODO: Rewrite Extended Header List.
++       * Not support by OpenGPG v2 yet */
++      LOG_FUNC_RETURN(ctx, r);
++}
++
++int delete_key(sc_card_t *card, u8 key_id)
++{
++      sc_context_t *ctx = card->ctx;
++      int r;
++
++      LOG_FUNC_CALLED(ctx);
++      /* Check key ID */
++      if (key_id < 1 || key_id > 3) {
++              sc_log(ctx, "Invalid key ID %d", key_id);
++              LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
++      }
++
++      if (card->type == SC_CARD_TYPE_OPENPGP_GNUK)
++              r = delete_key_gnuk(card, key_id);
++      else
++              r = delete_key_openpgp(card, key_id);
++
++      LOG_FUNC_RETURN(ctx, r);
++}
++
++int do_delete_key(sc_card_t *card, u8 key_id)
++{
++      sc_context_t *ctx = card->ctx;
++      int r = SC_SUCCESS;
++
++      /* Currently, only Gnuk supports deleting keys */
++      if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
++              printf("Only Gnuk supports deleting keys. General OpenPGP doesn't.");
++              return SC_ERROR_NOT_SUPPORTED;
++      }
++
++      if (key_id < 1 || (key_id > 3 && key_id != 'a')) {
++              printf("Error: Invalid key id %d", key_id);
++              return SC_ERROR_INVALID_ARGUMENTS;
++      }
++      if (key_id == 1 || key_id == 'a') {
++              r |= delete_key(card, 1);
++      }
++      if (key_id == 2 || key_id == 'a') {
++              r |= delete_key(card, 2);
++      }
++      if (key_id == 3 || key_id == 'a') {
++              r |= delete_key(card, 3);
++      }
++      return r;
++}
++
+ int do_erase(sc_card_t *card)
+ {
+       int r;
+@@ -539,6 +678,9 @@ int main(int argc, char **argv)
+               exit(EXIT_FAILURE);
+       }
++      if (opt_delkey)
++              exit_status != do_delete_key(card, key_id);
++
+       if (opt_erase)
+               exit_status != do_erase(card);
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0007-OpenPGP-Correct-building-Extended-Header-List-when-i.patch b/utils/opensc/patches/0007-OpenPGP-Correct-building-Extended-Header-List-when-i.patch
new file mode 100644 (file)
index 0000000..1d487af
--- /dev/null
@@ -0,0 +1,27 @@
+From b6bc7a497e1fe20104f923de1092a35d137ba553 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Mon, 4 Mar 2013 18:14:51 +0700
+Subject: [PATCH 07/18] OpenPGP: Correct building Extended Header List when
+ importing keys.
+
+---
+ src/libopensc/card-openpgp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 42a9684..47c1938 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -1978,7 +1978,7 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info
+       u8 *p = NULL;
+       u8 *components[] = {key_info->e, key_info->p, key_info->q, key_info->n};
+       size_t componentlens[] = {key_info->e_len, key_info->p_len, key_info->q_len, key_info->n_len};
+-      unsigned int componenttags[] = {0x91, 0x92, 0x93, 0x95};
++      unsigned int componenttags[] = {0x91, 0x92, 0x93, 0x97};
+       char *componentnames[] = {
+               "public exponent",
+               "prime p",
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0008-OpenPGP-Read-some-empty-DOs-from-Gnuk.patch b/utils/opensc/patches/0008-OpenPGP-Read-some-empty-DOs-from-Gnuk.patch
new file mode 100644 (file)
index 0000000..25a69d4
--- /dev/null
@@ -0,0 +1,58 @@
+From d1b8d3588336abac4876c1d537d8e8e5e578bc02 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Mon, 25 Mar 2013 11:58:38 +0700
+Subject: [PATCH 08/18] OpenPGP: Read some empty DOs from Gnuk.
+
+In Gnuk, some empty DOs are returned as not exist, instead of existing with empty value.
+So, we will consider them exist in driver.
+---
+ src/libopensc/card-openpgp.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 47c1938..9b08bbb 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -813,6 +813,23 @@ pgp_get_blob(sc_card_t *card, struct blob *blob, unsigned int id,
+               }
+       }
++      /* This part is for "NOT FOUND" cases */
++
++      /* Special case:
++       * Gnuk does not have default value for children of DO 65 (DOs 5B, 5F2D, 5F35)
++       * So, if these blob was not found, we create it. */
++      if (blob->id == 0x65 && (id == 0x5B || id == 0x5F2D || id == 0x5F35)) {
++              sc_log(card->ctx, "Create blob %X under %X", id, blob->id);
++              child = pgp_new_blob(card, blob, id, sc_file_new());
++              if (child) {
++                      pgp_set_blob(child, NULL, 0);
++                      *ret = child;
++                      return SC_SUCCESS;
++              }
++              else
++                      sc_log(card->ctx, "Not enough memory to create blob for DO %X");
++      }
++
+       return SC_ERROR_FILE_NOT_FOUND;
+ }
+@@ -1147,6 +1164,14 @@ pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
+       LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+       r = sc_check_sw(card, apdu.sw1, apdu.sw2);
++
++      /* For Gnuk card, if there is no certificate, it returns error instead of empty data.
++       * So, for this case, we ignore error and consider success */
++      if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND && card->type == SC_CARD_TYPE_OPENPGP_GNUK
++        && (tag == DO_CERT || tag == 0x0101 || tag == 0x0102 || tag == 0x0103 || tag == 0x0104)) {
++              r = SC_SUCCESS;
++              apdu.resplen = 0;
++      }
+       LOG_TEST_RET(card->ctx, r, "Card returned error");
+       LOG_FUNC_RETURN(card->ctx, apdu.resplen);
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0009-PKCS15-OpenPGP-Do-not-show-empty-DO-in-pkcs15-emu_in.patch b/utils/opensc/patches/0009-PKCS15-OpenPGP-Do-not-show-empty-DO-in-pkcs15-emu_in.patch
new file mode 100644 (file)
index 0000000..5abf6f8
--- /dev/null
@@ -0,0 +1,53 @@
+From 6a4457cde65ef44f05b0689415ae7165b06fb8bf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Wed, 27 Mar 2013 11:38:42 +0700
+Subject: [PATCH 09/18] PKCS15-OpenPGP: Do not show empty DO in pkcs15
+ emu_init.
+
+---
+ src/libopensc/pkcs15-openpgp.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c
+index 9f239ef..850dd74 100644
+--- a/src/libopensc/pkcs15-openpgp.c
++++ b/src/libopensc/pkcs15-openpgp.c
+@@ -385,16 +385,34 @@ sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *p15card)
+               sc_pkcs15_object_t dat_obj;
+               char name[8];
+               char path[9];
++              u8 content[254];
+               memset(&dat_info, 0, sizeof(dat_info));
+               memset(&dat_obj, 0, sizeof(dat_obj));
+               sprintf(name, "PrivDO%d", i);
+               sprintf(path, "3F00010%d", i);
++              /* Check if the DO can be read.
++               * We won't expose pkcs15 DATA object if DO is empty.
++               */
++              r = read_file(p15card->card, path, content, sizeof(content));
++              if (r <= 0 ) {
++                      sc_log(ctx, "Cannot read DO 010%d or there is no data in it", i);
++                      /* Skip */
++                      continue;
++              }
+               sc_format_path(path, &dat_info.path);
+               strlcpy(dat_obj.label, name, sizeof(dat_obj.label));
+               strlcpy(dat_info.app_label, name, sizeof(dat_info.app_label));
++              /* Add DATA object to slot protected by PIN2 (PW1 with Ref 0x82) */
++              dat_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE;
++              dat_obj.auth_id.len = 1;
++              if (i == 1 || i == 3)
++                      dat_obj.auth_id.value[0] = 2;
++              else
++                      dat_obj.auth_id.value[0] = 3;
++
+               sc_log(ctx, "Add %s data object", name);
+               r = sc_pkcs15emu_add_data_object(p15card, &dat_obj, &dat_info);
+       }
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0010-PKCS15-OpenPGP-Allow-to-store-data-to-pkcs15-data-ob.patch b/utils/opensc/patches/0010-PKCS15-OpenPGP-Allow-to-store-data-to-pkcs15-data-ob.patch
new file mode 100644 (file)
index 0000000..a3c7530
--- /dev/null
@@ -0,0 +1,91 @@
+From 88ded8fc5802c073caa71b649cee5a3116699b2a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Wed, 27 Mar 2013 11:39:33 +0700
+Subject: [PATCH 10/18] PKCS15-OpenPGP: Allow to store data to pkcs15 data
+ object.
+
+Only one DO is supported now.
+---
+ src/libopensc/pkcs15-openpgp.c  |  2 +-
+ src/pkcs15init/pkcs15-openpgp.c | 38 +++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 38 insertions(+), 2 deletions(-)
+
+diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c
+index 850dd74..b701041 100644
+--- a/src/libopensc/pkcs15-openpgp.c
++++ b/src/libopensc/pkcs15-openpgp.c
+@@ -397,7 +397,7 @@ sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *p15card)
+                */
+               r = read_file(p15card->card, path, content, sizeof(content));
+               if (r <= 0 ) {
+-                      sc_log(ctx, "Cannot read DO 010%d or there is no data in it", i);
++                      sc_log(ctx, "No data get from DO 010%d", i);
+                       /* Skip */
+                       continue;
+               }
+diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c
+index f3a4962..1455580 100755
+--- a/src/pkcs15init/pkcs15-openpgp.c
++++ b/src/pkcs15init/pkcs15-openpgp.c
+@@ -236,13 +236,16 @@ static int openpgp_emu_update_tokeninfo(sc_profile_t *profile, sc_pkcs15_card_t
+ }
+ static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
+-                              struct sc_pkcs15_object *obj,   struct sc_pkcs15_der *content,
++                              struct sc_pkcs15_object *obj, struct sc_pkcs15_der *content,
+                               struct sc_path *path)
+ {
+       sc_card_t *card = p15card->card;
++      sc_context_t *ctx = card->ctx;
+       sc_file_t *file;
+       sc_pkcs15_cert_info_t *cinfo;
+       sc_pkcs15_id_t *cid;
++      sc_pkcs15_data_info_t *dinfo;
++      u8 buf[254];
+       int r;
+       LOG_FUNC_CALLED(card->ctx);
+@@ -282,6 +285,39 @@ static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile
+                                            content->len, 0);
+               break;
++      case SC_PKCS15_TYPE_DATA_OBJECT:
++              dinfo = (sc_pkcs15_data_info_t *) obj->data;
++              /* dinfo->app_label contains filename */
++              sc_log(ctx, "===== App label %s", dinfo->app_label);
++              /* Currently, we only support DO 0101. The reason is that when initializing this
++               * pkcs15 emulation, PIN authentication is not applied and we can expose only this DO,
++               * which is "read always".
++               * If we support other DOs, they will not be exposed, and not helpful to user.
++               * I haven't found a way to refresh the list of exposed DOs after verifying PIN yet.
++               * http://sourceforge.net/mailarchive/message.php?msg_id=30646373
++               **/
++              sc_log(ctx, "About to write to DO 0101");
++              sc_format_path("0101", path);
++              r = sc_select_file(card, path, &file);
++              LOG_TEST_RET(card->ctx, r, "Cannot select private DO");
++              r = sc_read_binary(card, 0, buf, sizeof(buf), 0);
++              if (r < 0) {
++                      sc_log(ctx, "Cannot read DO 0101");
++                      break;
++              }
++              if (r > 0) {
++                      sc_log(ctx, "DO 0101 is full.");
++                      r = SC_ERROR_TOO_MANY_OBJECTS;
++                      break;
++              }
++              r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
++              if (r >= 0 && content->len) {
++                      r = sc_update_binary(p15card->card, 0,
++                                           (const unsigned char *) content->value,
++                                           content->len, 0);
++              }
++              break;
++
+       default:
+               r = SC_ERROR_NOT_IMPLEMENTED;
+       }
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0011-OpenPGP-Provide-enough-buffer-to-read-pubkey-from-Gn.patch b/utils/opensc/patches/0011-OpenPGP-Provide-enough-buffer-to-read-pubkey-from-Gn.patch
new file mode 100644 (file)
index 0000000..8fc3464
--- /dev/null
@@ -0,0 +1,87 @@
+From 7231ee09bb628f0401939778decce818ef6e3665 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Fri, 5 Apr 2013 17:18:50 +0700
+Subject: [PATCH 11/18] OpenPGP: Provide enough buffer to read pubkey from
+ Gnuk.
+
+---
+ src/libopensc/card-openpgp.c | 28 +++++++++++++++++++++++-----
+ 1 file changed, 23 insertions(+), 5 deletions(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 9b08bbb..8a1a270 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -263,7 +263,12 @@ static struct do_info             pgp2_objects[] = {      /* OpenPGP card spec 2.0 */
+ /* The DO holding X.509 certificate is constructed but does not contain child DO.
+  * We should notice this when building fake file system later. */
+-#define DO_CERT               0x7f21
++#define DO_CERT                  0x7f21
++/* Maximum length for response buffer when reading pubkey. This value is calculated with
++ * 4096-bit key length */
++#define MAXLEN_RESP_PUBKEY       527
++/* Gnuk only support 1 key length (2048 bit) */
++#define MAXLEN_RESP_PUBKEY_GNUK  271
+ #define DRVDATA(card)        ((struct pgp_priv_data *) ((card)->drv_data))
+ struct pgp_priv_data {
+@@ -729,6 +734,14 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
+               u8      buffer[2048];
+               size_t  buf_len = (card->caps & SC_CARD_CAP_APDU_EXT)
+                                 ? sizeof(buffer) : 256;
++
++              /* Buffer length for Gnuk pubkey */
++              if (card->type == SC_CARD_TYPE_OPENPGP_GNUK &&
++                  (blob->id == 0xa400 || blob->id == 0xb600 || blob->id == 0xb800
++                   || blob->id == 0xa401 || blob->id == 0xb601 || blob->id == 0xb801)) {
++                      buf_len = MAXLEN_RESP_PUBKEY_GNUK;
++              }
++
+               int     r = blob->info->get_fn(card, blob->id, buffer, buf_len);
+               if (r < 0) {    /* an error occurred */
+@@ -1830,6 +1843,7 @@ static int pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in
+       u8 apdu_case;
+       u8 *apdu_data;
+       size_t apdu_le;
++      size_t resplen = 0;
+       int r = SC_SUCCESS;
+       LOG_FUNC_CALLED(card->ctx);
+@@ -1868,23 +1882,27 @@ static int pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in
+               apdu_case = SC_APDU_CASE_4_EXT;
+       }
+       else {
+-              apdu_le = 256;
+               apdu_case = SC_APDU_CASE_4_SHORT;
++              apdu_le = 256;
++              resplen = MAXLEN_RESP_PUBKEY;
++      }
++      if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
++              resplen = MAXLEN_RESP_PUBKEY_GNUK;
+       }
+       /* Prepare APDU */
+-      sc_format_apdu(card, &apdu, apdu_case, 0x47, 0x80,  0);
++      sc_format_apdu(card, &apdu, apdu_case, 0x47, 0x80, 0);
+       apdu.data = apdu_data;
+       apdu.datalen = 2;  /* Data = B600 */
+       apdu.lc = 2;
+       apdu.le = apdu_le;
+       /* Buffer to receive response */
+-      apdu.resp = calloc(apdu.le, 1);
++      apdu.resplen = (resplen > 0) ? resplen : apdu_le;
++      apdu.resp = calloc(apdu.resplen, 1);
+       if (apdu.resp == NULL) {
+               LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
+       }
+-      apdu.resplen = apdu.le;
+       /* Send */
+       sc_log(card->ctx, "Waiting for the card to generate key...");
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0012-OpenPGP-Support-write-certificate-for-Gnuk.patch b/utils/opensc/patches/0012-OpenPGP-Support-write-certificate-for-Gnuk.patch
new file mode 100644 (file)
index 0000000..0d54d96
--- /dev/null
@@ -0,0 +1,220 @@
+From d8f63eb6fcc1441c12a44850da2fa22a6fe81634 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Thu, 11 Apr 2013 11:47:51 +0700
+Subject: [PATCH 12/18] OpenPGP: Support write certificate for Gnuk.
+
+---
+ src/libopensc/card-openpgp.c | 158 +++++++++++++++++++++++++++++++++----------
+ 1 file changed, 123 insertions(+), 35 deletions(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 8a1a270..d9db948 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -725,6 +725,8 @@ pgp_iterate_blobs(struct blob *blob, int level, void (*func)())
+ static int
+ pgp_read_blob(sc_card_t *card, struct blob *blob)
+ {
++      struct pgp_priv_data *priv = DRVDATA (card);
++
+       if (blob->data != NULL)
+               return SC_SUCCESS;
+       if (blob->info == NULL)
+@@ -735,6 +737,11 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
+               size_t  buf_len = (card->caps & SC_CARD_CAP_APDU_EXT)
+                                 ? sizeof(buffer) : 256;
++              /* Buffer length for certificate */
++              if (blob->id == DO_CERT && priv->max_cert_size > 0) {
++                      buf_len = MIN(priv->max_cert_size, sizeof(buffer));
++              }
++
+               /* Buffer length for Gnuk pubkey */
+               if (card->type == SC_CARD_TYPE_OPENPGP_GNUK &&
+                   (blob->id == 0xa400 || blob->id == 0xb600 || blob->id == 0xb800
+@@ -1190,49 +1197,75 @@ pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
+       LOG_FUNC_RETURN(card->ctx, apdu.resplen);
+ }
+-/* ABI: PUT DATA */
+-static int
+-pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
++
++/* Internal: Write certificate for Gnuk */
++static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
+ {
++      sc_context_t *ctx = card->ctx;
++      size_t i = 0;
+       sc_apdu_t apdu;
++      u8 *part;
++      size_t plen;
++      int r = SC_SUCCESS;
++
++      LOG_FUNC_CALLED(ctx);
++
++      /* If null data is passed, delete certificate */
++      if (buf == NULL || length == 0) {
++              sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xD6, 0x85, 0);
++              r = sc_transmit_apdu(card, &apdu);
++              LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
++              /* Check response */
++              r = sc_check_sw(card, apdu.sw1, apdu.sw2);
++              LOG_FUNC_RETURN(card->ctx, length);
++      }
++
++      /* Ref: gnuk_put_binary_libusb.py and gnuk_token.py in Gnuk source tree */
++      /* Split data to segments of 256 bytes. Send each segment via command chaining,
++       * with particular P1 byte for each segment */
++      while (i*256 < length) {
++              part = (u8 *)buf + i*256;
++              plen = MIN(length - i*256, 256);
++
++              sc_log(card->ctx, "Write part %d from offset 0x%X, len %d", i+1, part, plen);
++
++              if (i == 0) {
++                      sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, 0x85, 0);
++              }
++              else {
++                      sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, i, 0);
++              }
++              apdu.flags |= SC_APDU_FLAGS_CHAINING;
++              apdu.data = part;
++              apdu.datalen = apdu.lc = plen;
++
++              r = sc_transmit_apdu(card, &apdu);
++              LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
++              /* Check response */
++              r = sc_check_sw(card, apdu.sw1, apdu.sw2);
++              LOG_TEST_RET(card->ctx, r, "UPDATE BINARY returned error");
++
++              /* To next part */
++              i++;
++      }
++      LOG_FUNC_RETURN(card->ctx, length);
++}
++
++
++/* Internal: Use PUT DATA command to write */
++static int
++pgp_put_data_plain(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
++{
+       struct pgp_priv_data *priv = DRVDATA(card);
+-      struct blob *affected_blob = NULL;
+-      struct do_info *dinfo = NULL;
++      sc_context_t *ctx = card->ctx;
++      sc_apdu_t apdu;
+       u8 ins = 0xDA;
+       u8 p1 = tag >> 8;
+       u8 p2 = tag & 0xFF;
+       u8 apdu_case = SC_APDU_CASE_3;
+       int r;
+-      LOG_FUNC_CALLED(card->ctx);
+-
+-      /* Check if the tag is writable */
+-      affected_blob = pgp_find_blob(card, tag);
+-
+-      /* Non-readable DOs have no represented blob, we have to check from pgp_get_info_by_tag */
+-      if (affected_blob == NULL)
+-              dinfo = pgp_get_info_by_tag(card, tag);
+-      else
+-              dinfo = affected_blob->info;
+-
+-      if (dinfo == NULL) {
+-              sc_log(card->ctx, "The DO %04X does not exist.", tag);
+-              LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+-      }
+-      else if ((dinfo->access & WRITE_MASK) == WRITE_NEVER) {
+-              sc_log(card->ctx, "DO %04X is not writable.", tag);
+-              LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
+-      }
+-
+-      /* Check data size.
+-       * We won't check other DOs than 7F21 (certificate), because their capacity
+-       * is hard-codded and may change in various version of the card. If we check here,
+-       * the driver may be sticked to a limit version number of card.
+-       * 7F21 size is soft-coded, so we can check it. */
+-      if (tag == DO_CERT && buf_len > priv->max_cert_size) {
+-              sc_log(card->ctx, "Data size %ld exceeds DO size limit %ld.", buf_len, priv->max_cert_size);
+-              LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
+-      }
++      LOG_FUNC_CALLED(ctx);
+       /* Extended Header list (004D DO) needs a variant of PUT DATA command */
+       if (tag == 0x004D) {
+@@ -1258,15 +1291,70 @@ pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
+               apdu.lc = buf_len;
+       }
+       else {
++              /* This case is to empty DO */
+               sc_format_apdu(card, &apdu, SC_APDU_CASE_1, ins, p1, p2);
+       }
+       /* Send APDU to card */
+       r = sc_transmit_apdu(card, &apdu);
+-      LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
++      LOG_TEST_RET(ctx, r, "APDU transmit failed");
+       /* Check response */
+       r = sc_check_sw(card, apdu.sw1, apdu.sw2);
++      if (r < 0)
++              LOG_FUNC_RETURN(ctx, r);
++
++      LOG_FUNC_RETURN(ctx, buf_len);
++}
++
++/* ABI: PUT DATA */
++static int
++pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
++{
++      struct pgp_priv_data *priv = DRVDATA(card);
++      struct blob *affected_blob = NULL;
++      struct do_info *dinfo = NULL;
++      int r;
++
++      LOG_FUNC_CALLED(card->ctx);
++
++      /* Check if the tag is writable */
++      if (priv->current->id != tag)
++              affected_blob = pgp_find_blob(card, tag);
++
++      /* Non-readable DOs have no represented blob, we have to check from pgp_get_info_by_tag */
++      if (affected_blob == NULL)
++              dinfo = pgp_get_info_by_tag(card, tag);
++      else
++              dinfo = affected_blob->info;
++
++      if (dinfo == NULL) {
++              sc_log(card->ctx, "The DO %04X does not exist.", tag);
++              LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
++      }
++      else if ((dinfo->access & WRITE_MASK) == WRITE_NEVER) {
++              sc_log(card->ctx, "DO %04X is not writable.", tag);
++              LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
++      }
++
++      /* Check data size.
++       * We won't check other DOs than 7F21 (certificate), because their capacity
++       * is hard-codded and may change in various version of the card. If we check here,
++       * the driver may be sticked to a limit version number of card.
++       * 7F21 size is soft-coded, so we can check it. */
++      if (tag == DO_CERT && buf_len > priv->max_cert_size) {
++              sc_log(card->ctx, "Data size %ld exceeds DO size limit %ld.", buf_len, priv->max_cert_size);
++              LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
++      }
++
++      if (tag == DO_CERT && card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
++              /* Gnuk need a special way to write certificate. */
++              r = gnuk_write_certificate(card, buf, buf_len);
++      }
++      else {
++              r = pgp_put_data_plain(card, tag, buf, buf_len);
++      }
++
+       /* Instruct more in case of error */
+       if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
+               sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Please verify PIN first.");
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0013-pkcs15-openpgp-Change-to-sc_put_data-instead-of-sc_u.patch b/utils/opensc/patches/0013-pkcs15-openpgp-Change-to-sc_put_data-instead-of-sc_u.patch
new file mode 100644 (file)
index 0000000..67d79dd
--- /dev/null
@@ -0,0 +1,31 @@
+From e5c94d3f1f7e6a96a98815d6e51190498c357fb6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Wed, 10 Apr 2013 18:35:58 +0700
+Subject: [PATCH 13/18] pkcs15-openpgp: Change to sc_put_data instead of
+ sc_update_binary when writing certificate.
+
+---
+ src/pkcs15init/pkcs15-openpgp.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c
+index 1455580..be1291e 100755
+--- a/src/pkcs15init/pkcs15-openpgp.c
++++ b/src/pkcs15init/pkcs15-openpgp.c
+@@ -279,10 +279,9 @@ static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile
+               r = sc_select_file(card, path, &file);
+               LOG_TEST_RET(card->ctx, r, "Cannot select cert file");
+               r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
++              sc_log(card->ctx, "Data to write is %d long", content->len);
+               if (r >= 0 && content->len)
+-                      r = sc_update_binary(p15card->card, 0,
+-                                           (const unsigned char *) content->value,
+-                                           content->len, 0);
++                      r = sc_put_data(p15card->card, 0x7F21, (const unsigned char *) content->value, content->len);
+               break;
+       case SC_PKCS15_TYPE_DATA_OBJECT:
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0014-OpenPGP-Overcome-the-restriction-of-even-data-length.patch b/utils/opensc/patches/0014-OpenPGP-Overcome-the-restriction-of-even-data-length.patch
new file mode 100644 (file)
index 0000000..cf1a07c
--- /dev/null
@@ -0,0 +1,53 @@
+From df8a78e3c8c9d9d591c0d3fa31db7e010eb2c8c2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Thu, 11 Apr 2013 16:18:31 +0700
+Subject: [PATCH 14/18] OpenPGP: Overcome the restriction of even data length
+ of Gnuk.
+
+When write certificate with odd length to Gnuk, we add zero padding to make it even.
+---
+ src/libopensc/card-openpgp.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index d9db948..a666163 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -1206,6 +1206,10 @@ static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
+       sc_apdu_t apdu;
+       u8 *part;
+       size_t plen;
++      /* Two round_ variables below are to build APDU data
++       * with even length for Gnuk */
++      u8 roundbuf[256];
++      size_t roundlen = 0;
+       int r = SC_SUCCESS;
+       LOG_FUNC_CALLED(ctx);
+@@ -1236,8 +1240,20 @@ static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
+                       sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, i, 0);
+               }
+               apdu.flags |= SC_APDU_FLAGS_CHAINING;
+-              apdu.data = part;
+-              apdu.datalen = apdu.lc = plen;
++
++              /* If the last part has odd length, we add zero padding to make it even.
++               * Gnuk does not allow data with odd length */
++              if (plen < 256 && (plen % 2) != 0) {
++                      roundlen = plen + 1;
++                      memset(roundbuf, 0, roundlen);
++                      memcpy(roundbuf, part, plen);
++                      apdu.data = roundbuf;
++                      apdu.datalen = apdu.lc = roundlen;
++              }
++              else {
++                      apdu.data = part;
++                      apdu.datalen = apdu.lc = plen;
++              }
+               r = sc_transmit_apdu(card, &apdu);
+               LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0015-OpenPGP-Delete-key-as-file-for-Gnuk.patch b/utils/opensc/patches/0015-OpenPGP-Delete-key-as-file-for-Gnuk.patch
new file mode 100644 (file)
index 0000000..cc88a12
--- /dev/null
@@ -0,0 +1,92 @@
+From 693b3ac5a53e89a0cdeab0f728d24a6e16864f5c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Fri, 12 Apr 2013 15:33:31 +0700
+Subject: [PATCH 15/18] OpenPGP: Delete key as file, for Gnuk.
+
+---
+ src/libopensc/card-openpgp.c | 51 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 50 insertions(+), 1 deletion(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index a666163..19d3b04 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -2437,6 +2437,44 @@ static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
+       LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+ }
++
++/* Internal: Delete key */
++static int
++gnuk_delete_key(sc_card_t *card, u8 key_id)
++{
++      sc_context_t *ctx = card->ctx;
++      int r = SC_SUCCESS;
++      u8 *data = NULL;
++
++      LOG_FUNC_CALLED(ctx);
++
++      /* Delete fingerprint */
++      sc_log(ctx, "Delete fingerprints");
++      r = pgp_put_data(card, 0xC6 + key_id, NULL, 0);
++      LOG_TEST_RET(ctx, r, "Failed to delete fingerprints");
++      /* Delete creation time */
++      sc_log(ctx, "Delete creation time");
++      r = pgp_put_data(card, 0xCD + key_id, NULL, 0);
++      LOG_TEST_RET(ctx, r, "Failed to delete creation time");
++
++      /* Rewrite Extended Header List */
++      sc_log(ctx, "Rewrite Extended Header List");
++
++      if (key_id == 1)
++              data = "\x4D\x02\xB6";
++      else if (key_id == 2)
++              data = "\x4D\x02\xB8";
++      else if (key_id == 3)
++              data = "\x4D\x02\xA4";
++      else
++              LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
++
++      r = pgp_put_data(card, 0x4D, data, strlen(data) + 1);
++
++      LOG_FUNC_RETURN(ctx, r);
++}
++
++
+ /* ABI: DELETE FILE */
+ static int
+ pgp_delete_file(sc_card_t *card, const sc_path_t *path)
+@@ -2444,6 +2482,7 @@ pgp_delete_file(sc_card_t *card, const sc_path_t *path)
+       struct pgp_priv_data *priv = DRVDATA(card);
+       struct blob *blob;
+       sc_file_t *file;
++      u8 key_id;
+       int r;
+       LOG_FUNC_CALLED(card->ctx);
+@@ -2459,10 +2498,20 @@ pgp_delete_file(sc_card_t *card, const sc_path_t *path)
+       if (blob == priv->mf)
+               LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+-      if (file->id == 0xB601 || file->id == 0xB801 || file->id == 0xA401) {
++      if (card->type != SC_CARD_TYPE_OPENPGP_GNUK &&
++          (file->id == 0xB601 || file->id == 0xB801 || file->id == 0xA401)) {
+               /* These tags are just symbolic. We don't really delete it. */
+               r = SC_SUCCESS;
+       }
++      else if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && file->id == 0xB601) {
++              r = gnuk_delete_key(card, 1);
++      }
++      else if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && file->id == 0xB801) {
++              r = gnuk_delete_key(card, 2);
++      }
++      else if (card->type == SC_CARD_TYPE_OPENPGP_GNUK && file->id == 0xA401) {
++              r = gnuk_delete_key(card, 3);
++      }
+       else {
+               /* call pgp_put_data() with zero-sized NULL-buffer to zap the DO contents */
+               r = pgp_put_data(card, file->id, NULL, 0);
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0016-OpenPGP-Correct-parameter-checking.patch b/utils/opensc/patches/0016-OpenPGP-Correct-parameter-checking.patch
new file mode 100644 (file)
index 0000000..c49de13
--- /dev/null
@@ -0,0 +1,47 @@
+From f96f7536a8c2efd0ba41fd94fe3334e5fa556854 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Tue, 16 Apr 2013 10:19:34 +0700
+Subject: [PATCH 16/18] OpenPGP: Correct parameter checking.
+
+---
+ src/libopensc/card-openpgp.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 19d3b04..196c094 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -1221,6 +1221,8 @@ static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
+               LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+               /* Check response */
+               r = sc_check_sw(card, apdu.sw1, apdu.sw2);
++              if (r < 0)
++                      LOG_FUNC_RETURN(card->ctx, r);
+               LOG_FUNC_RETURN(card->ctx, length);
+       }
+@@ -2448,6 +2450,11 @@ gnuk_delete_key(sc_card_t *card, u8 key_id)
+       LOG_FUNC_CALLED(ctx);
++      if (key_id < 1 || key_id > 3) {
++              sc_log(ctx, "Key ID %d is invalid. Should be 1, 2 or 3.", key_id);
++              LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
++      }
++
+       /* Delete fingerprint */
+       sc_log(ctx, "Delete fingerprints");
+       r = pgp_put_data(card, 0xC6 + key_id, NULL, 0);
+@@ -2466,8 +2473,6 @@ gnuk_delete_key(sc_card_t *card, u8 key_id)
+               data = "\x4D\x02\xB8";
+       else if (key_id == 3)
+               data = "\x4D\x02\xA4";
+-      else
+-              LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+       r = pgp_put_data(card, 0x4D, data, strlen(data) + 1);
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0017-OpenPGP-Make-code-neater.patch b/utils/opensc/patches/0017-OpenPGP-Make-code-neater.patch
new file mode 100644 (file)
index 0000000..50501e0
--- /dev/null
@@ -0,0 +1,39 @@
+From 8a69525a60391b46db4994033527d219d2adaa4e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Tue, 16 Apr 2013 16:02:17 +0700
+Subject: [PATCH 17/18] OpenPGP: Make code neater
+
+---
+ src/libopensc/card-openpgp.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index 196c094..c4ef3b6 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -1220,10 +1220,7 @@ static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
+               r = sc_transmit_apdu(card, &apdu);
+               LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+               /* Check response */
+-              r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+-              if (r < 0)
+-                      LOG_FUNC_RETURN(card->ctx, r);
+-              LOG_FUNC_RETURN(card->ctx, length);
++              LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Certificate writing failed");
+       }
+       /* Ref: gnuk_put_binary_libusb.py and gnuk_token.py in Gnuk source tree */
+@@ -1260,8 +1257,7 @@ static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
+               r = sc_transmit_apdu(card, &apdu);
+               LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+               /* Check response */
+-              r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+-              LOG_TEST_RET(card->ctx, r, "UPDATE BINARY returned error");
++              LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "UPDATE BINARY returned error");
+               /* To next part */
+               i++;
+-- 
+1.9.3
+
diff --git a/utils/opensc/patches/0018-Move-declaration-to-top-of-block.patch b/utils/opensc/patches/0018-Move-declaration-to-top-of-block.patch
new file mode 100644 (file)
index 0000000..b05cc59
--- /dev/null
@@ -0,0 +1,34 @@
+From a099f951d085d3abfefeead14a4af06913cb67d2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
+Date: Wed, 8 May 2013 16:51:21 +0700
+Subject: [PATCH 18/18] Move declaration to top of block.
+
+---
+ src/libopensc/card-openpgp.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
+index c4ef3b6..7f2006e 100644
+--- a/src/libopensc/card-openpgp.c
++++ b/src/libopensc/card-openpgp.c
+@@ -736,6 +736,7 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
+               u8      buffer[2048];
+               size_t  buf_len = (card->caps & SC_CARD_CAP_APDU_EXT)
+                                 ? sizeof(buffer) : 256;
++              int r = SC_SUCCESS;
+               /* Buffer length for certificate */
+               if (blob->id == DO_CERT && priv->max_cert_size > 0) {
+@@ -749,7 +750,7 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
+                       buf_len = MAXLEN_RESP_PUBKEY_GNUK;
+               }
+-              int     r = blob->info->get_fn(card, blob->id, buffer, buf_len);
++              r = blob->info->get_fn(card, blob->id, buffer, buf_len);
+               if (r < 0) {    /* an error occurred */
+                       blob->status = r;
+-- 
+1.9.3
+