* app-dinsig.c: Implemented. Based on app-nks.c and card-dinsig.c
authorWerner Koch <wk@gnupg.org>
Tue, 16 Mar 2004 18:59:21 +0000 (18:59 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 16 Mar 2004 18:59:21 +0000 (18:59 +0000)
* app-nks.c (get_length_of_cert): Removed.
* app-help.c: New.
(app_help_read_length_of_cert): New.  Code taken from above.  New
optional arg R_CERTOFF.

* card-dinsig.c: Removed.
* card.c (card_get_serial_and_stamp): Do not bind to the old and
never finsiged card-dinsig.c.

* iso7816.c (iso7816_read_binary): Allow for an NMAX > 254.

scd/ChangeLog
scd/Makefile.am
scd/app-common.h
scd/app-dinsig.c
scd/app-help.c [new file with mode: 0644]
scd/app-nks.c
scd/app-openpgp.c
scd/card.c
scd/iso7816.c
scd/scdaemon.c

index a9296cb..679f867 100644 (file)
@@ -1,3 +1,17 @@
+2004-03-16  Werner Koch  <wk@gnupg.org>
+
+       * app-dinsig.c: Implemented. Based on app-nks.c and card-dinsig.c
+       * app-nks.c (get_length_of_cert): Removed.
+       * app-help.c: New.
+       (app_help_read_length_of_cert): New.  Code taken from above.  New
+       optional arg R_CERTOFF.
+
+       * card-dinsig.c: Removed.
+       * card.c (card_get_serial_and_stamp): Do not bind to the old and
+       never finsiged card-dinsig.c.
+
+       * iso7816.c (iso7816_read_binary): Allow for an NMAX > 254.
+
 2004-03-11  Werner Koch  <wk@gnupg.org>
 
        * scdaemon.h (out_of_core): Removed.  Replaced callers by standard
index 89ebf4e..da59a19 100644 (file)
@@ -34,12 +34,12 @@ scdaemon_SOURCES = \
        scdaemon.c scdaemon.h \
        command.c card.c \
        card-common.h \
-       card-p15.c card-dinsig.c \
+       card-p15.c  \
        apdu.c apdu.h \
        ccid-driver.c ccid-driver.h \
        iso7816.c iso7816.h \
        tlv.c tlv.h \
-       app.c app-common.h $(card_apps)
+       app.c app-common.h app-help.c $(card_apps)
 
 
 scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
@@ -53,12 +53,12 @@ sc_investigate_SOURCES = \
        iso7816.c iso7816.h \
        tlv.c tlv.h \
        atr.c atr.h \
-       app.c app-common.h $(card_apps) 
+       app.c app-common.h app-help.c $(card_apps) 
 
 sc_investigate_LDADD = \
        ../jnlib/libjnlib.a ../common/libcommon.a \
-       $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) @INTLLIBS@ \
-        -lgpg-error -ldl
+       $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBUSB_LIBS) \
+         @INTLLIBS@  -lgpg-error -ldl
 
 
 sc_copykeys_SOURCES = \
@@ -68,10 +68,10 @@ sc_copykeys_SOURCES = \
        iso7816.c iso7816.h \
        tlv.c tlv.h \
        atr.c atr.h \
-       app.c app-common.h $(card_apps)
+       app.c app-common.h app-help.c $(card_apps)
 
 sc_copykeys_LDADD = \
        ../jnlib/libjnlib.a ../common/libcommon.a \
        ../common/libsimple-pwquery.a \
-       $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) \
+       $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBUSB_LIBS) \
         -lgpg-error @INTLLIBS@ -ldl
index cda1770..c16a157 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef GNUPG_SCD_APP_COMMON_H
 #define GNUPG_SCD_APP_COMMON_H
 
+#include <ksba.h>
+
 struct app_ctx_s {
   int initialized;  /* The application has been initialied and the
                        function pointers may be used.  Note that for
@@ -80,6 +82,11 @@ struct app_ctx_s {
 int app_select_openpgp (app_t app);
 int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
 #else
+/*-- app-help.c --*/
+gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
+size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
+
+
 /*-- app.c --*/
 app_t select_application (ctrl_t ctrl, int slot, const char *name);
 void release_application (app_t app);
index 4b5b517..38fbc79 100644 (file)
@@ -1,5 +1,5 @@
 /* app-dinsig.c - The DINSIG (DIN V 66291-1) card application.
- *     Copyright (C) 2004 Free Software Foundation, Inc.
+ *     Copyright (C) 2002, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -65,9 +65,6 @@
    The letters in brackets indicate optional or mandatory files: The
    first for card terminals under full control and the second for
    "business" card terminals.
-
-   FIXME: Needs a lot more explanation.
-
 */
 
 
 
 #include "iso7816.h"
 #include "app-common.h"
+#include "tlv.h"
+
+
+static int
+do_learn_status (app_t app, ctrl_t ctrl)
+{
+  gpg_error_t err;
+  char ct_buf[100], id_buf[100];
+  char hexkeygrip[41];
+  size_t len, certoff;
+  unsigned char *der;
+  size_t derlen;
+  ksba_cert_t cert;
+  int fid;
+
+  /* Return the certificate of the card holder. */
+  fid = 0xC000;
+  len = app_help_read_length_of_cert (app->slot, fid, &certoff); 
+  if (!len)
+    return 0; /* Card has not been personalized. */
+
+  sprintf (ct_buf, "%d", 101);
+  sprintf (id_buf, "DINSIG.%04X", fid);
+  send_status_info (ctrl, "CERTINFO",
+                    ct_buf, strlen (ct_buf), 
+                    id_buf, strlen (id_buf), 
+                    NULL, (size_t)0);
+
+  /* Now we need to read the certificate, so that we can get the
+     public key out of it.  */
+  err = iso7816_read_binary (app->slot, certoff, len-certoff, &der, &derlen);
+  if (err)
+    {
+      log_info ("error reading entire certificate from FID 0x%04X: %s\n",
+                fid, gpg_strerror (err));
+      return 0;
+    }
+
+  err = ksba_cert_new (&cert);
+  if (err)
+    {
+      xfree (der);
+      return err;
+    }
+  err = ksba_cert_init_from_mem (cert, der, derlen); 
+  xfree (der); der = NULL;
+  if (err)
+    {
+      log_error ("failed to parse the certificate at FID 0x%04X: %s\n",
+                 fid, gpg_strerror (err));
+      ksba_cert_release (cert);
+      return err;
+    }
+  err = app_help_get_keygrip_string (cert, hexkeygrip);
+  if (err)
+    {
+      log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid);
+      ksba_cert_release (cert);
+      return gpg_error (GPG_ERR_CARD);
+    }      
+  ksba_cert_release (cert);
+
+  sprintf (id_buf, "DINSIG.%04X", fid);
+  send_status_info (ctrl, "KEYPAIRINFO",
+                    hexkeygrip, 40, 
+                    id_buf, strlen (id_buf), 
+                    NULL, (size_t)0);
+  return 0;
+}
+
+
 
 
+/* Read the certificate with id CERTID (as returned by learn_status in
+   the CERTINFO status lines) and return it in the freshly allocated
+   buffer put into CERT and the length of the certificate put into
+   CERTLEN. 
 
+   FIXME: This needs some cleanups and caching with do_learn_status.
+*/
 static int
-do_learn_status (APP app, CTRL ctrl)
+do_readcert (app_t app, const char *certid,
+             unsigned char **cert, size_t *certlen)
 {
+  int fid;
+  gpg_error_t err;
+  unsigned char *buffer;
+  const unsigned char *p;
+  size_t buflen, n;
+  int class, tag, constructed, ndef;
+  size_t totobjlen, objlen, hdrlen;
+  int rootca = 0;
+
+  *cert = NULL;
+  *certlen = 0;
+  if (strncmp (certid, "DINSIG.", 7) ) 
+    return gpg_error (GPG_ERR_INV_ID);
+  certid += 7;
+  if (!hexdigitp (certid) || !hexdigitp (certid+1)
+      || !hexdigitp (certid+2) || !hexdigitp (certid+3) 
+      || certid[4])
+    return gpg_error (GPG_ERR_INV_ID);
+  fid = xtoi_4 (certid);
+  if (fid != 0xC000 )
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  /* Read the entire file.  fixme: This could be optimized by first
+     reading the header to figure out how long the certificate
+     actually is. */
+  err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
+  if (err)
+    {
+      log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
+      return err;
+    }
+
+  err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
+  if (err)
+    {
+      log_error ("error reading certificate from FID 0x%04X: %s\n",
+                 fid, gpg_strerror (err));
+      return err;
+    }
+  
+  if (!buflen || *buffer == 0xff)
+    {
+      log_info ("no certificate contained in FID 0x%04X\n", fid);
+      err = gpg_error (GPG_ERR_NOT_FOUND);
+      goto leave;
+    }
+
+  /* Now figure something out about the object. */
+  p = buffer;
+  n = buflen;
+  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                          &ndef, &objlen, &hdrlen);
+  if (err)
+    goto leave;
+  if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
+    ;
+  else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
+    rootca = 1;
+  else
+    return gpg_error (GPG_ERR_INV_OBJ);
+  totobjlen = objlen + hdrlen;
+  assert (totobjlen <= buflen);
+
+  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                          &ndef, &objlen, &hdrlen);
+  if (err)
+    goto leave;
+  
+  if (rootca)
+    ;
+  else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
+    {
+      const unsigned char *save_p;
+  
+      /* The certificate seems to be contained in a userCertificate
+         container.  Skip this and assume the following sequence is
+         the certificate. */
+      if (n < objlen)
+        {
+          err = gpg_error (GPG_ERR_INV_OBJ);
+          goto leave;
+        }
+      p += objlen;
+      n -= objlen;
+      save_p = p;
+      err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (err) 
+        goto leave;
+      if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) )
+        return gpg_error (GPG_ERR_INV_OBJ);
+      totobjlen = objlen + hdrlen;
+      assert (save_p + totobjlen <= buffer + buflen);
+      memmove (buffer, save_p, totobjlen);
+    }
+  
+  *cert = buffer;
+  buffer = NULL;
+  *certlen = totobjlen;
+
+ leave:
+  xfree (buffer);
+  return err;
+}
+
+
+/* Verify the PIN if required.  */
+static int
+verify_pin (app_t app,
+            int (pincb)(void*, const char *, char **),
+            void *pincb_arg)
+{
+  if (!app->did_chv1 || app->force_chv1 ) 
+    {
+      char *pinvalue;
+      int rc;
+
+      rc = pincb (pincb_arg, "PIN", &pinvalue); 
+      if (rc)
+        {
+          log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
+          return rc;
+        }
+
+      /* We require the PIN to be at least 6 and at max 8 bytes.
+         According to the specs, this should all be ASCII but we don't
+         check this. */
+      if (strlen (pinvalue) < 6)
+        {
+          log_error ("PIN is too short; minimum length is 6\n");
+          xfree (pinvalue);
+          return gpg_error (GPG_ERR_BAD_PIN);
+        }
+      else if (strlen (pinvalue) > 8)
+        {
+          log_error ("PIN is too large; maximum length is 8\n");
+          xfree (pinvalue);
+          return gpg_error (GPG_ERR_BAD_PIN);
+        }
+
+      rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
+      if (rc)
+        {
+          log_error ("verify PIN failed\n");
+          xfree (pinvalue);
+          return rc;
+        }
+      app->did_chv1 = 1;
+      xfree (pinvalue);
+    }
+
   return 0;
 }
 
 
 
+/* Create the signature and return the allocated result in OUTDATA.
+   If a PIN is required the PINCB will be used to ask for the PIN;
+   that callback should return the PIN in an allocated buffer and
+   store that in the 3rd argument.  */
+static int 
+do_sign (app_t app, const char *keyidstr, int hashalgo,
+         int (pincb)(void*, const char *, char **),
+           void *pincb_arg,
+           const void *indata, size_t indatalen,
+           unsigned char **outdata, size_t *outdatalen )
+{
+  static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
+    { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
+      0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
+  static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
+    { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
+      0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
+  int rc;
+  int fid;
+  unsigned char data[35];   /* Must be large enough for a SHA-1 digest
+                               + the largest OID _prefix above. */
+
+  if (!keyidstr || !*keyidstr)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (indatalen != 20 && indatalen != 16 && indatalen != 35)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* Check that the provided ID is vaid.  This is not really needed
+     but we do it to to enforce correct usage by the caller. */
+  if (strncmp (keyidstr, "DINSIG.", 7) ) 
+    return gpg_error (GPG_ERR_INV_ID);
+  keyidstr += 7;
+  if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
+      || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3) 
+      || keyidstr[4])
+    return gpg_error (GPG_ERR_INV_ID);
+  fid = xtoi_4 (keyidstr);
+  if (fid != 0xC000)
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  /* Prepare the DER object from INDATA. */
+  if (indatalen == 35)
+    {
+      /* Alright, the caller was so kind to send us an already
+         prepared DER object.  Check that it is what we want and that
+         it matches the hash algorithm. */
+      if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
+        ;
+      else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
+        ;
+      else 
+        return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+      memcpy (data, indata, indatalen);
+    }
+  else
+    {
+      if (hashalgo == GCRY_MD_SHA1)
+        memcpy (data, sha1_prefix, 15);
+      else if (hashalgo == GCRY_MD_RMD160)
+        memcpy (data, rmd160_prefix, 15);
+      else 
+        return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+      memcpy (data+15, indata, indatalen);
+    }
+
+  rc = verify_pin (app, pincb, pincb_arg);
+  if (!rc)
+    rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
+  return rc;
+}
+
 
 
 /* Select the DINSIG application on the card in SLOT.  This function
@@ -113,17 +410,18 @@ app_select_dinsig (APP app)
       app->apptype = "DINSIG";
 
       app->fnc.learn_status = do_learn_status;
+      app->fnc.readcert = do_readcert;
       app->fnc.getattr = NULL;
       app->fnc.setattr = NULL;
       app->fnc.genkey = NULL;
-      app->fnc.sign = NULL;
+      app->fnc.sign = do_sign;
       app->fnc.auth = NULL;
       app->fnc.decipher = NULL;
       app->fnc.change_pin = NULL;
       app->fnc.check_pin = NULL;
+
+      app->force_chv1 = 1;
    }
 
   return rc;
 }
-
-
diff --git a/scd/app-help.c b/scd/app-help.c
new file mode 100644 (file)
index 0000000..c669563
--- /dev/null
@@ -0,0 +1,157 @@
+/* app-help.c - Application helper functions
+ *     Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "scdaemon.h"
+#include "app-common.h"
+#include "iso7816.h"
+#include "tlv.h"
+
+/* Return the KEYGRIP for the certificate CERT as an hex encoded
+   string in the user provided buffer HEXKEYGRIP which must be of at
+   least 41 bytes. */
+gpg_error_t
+app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_pkey;
+  ksba_sexp_t p;
+  size_t n;
+  unsigned char array[20];
+  int i;
+
+  p = ksba_cert_get_public_key (cert);
+  if (!p)
+    return gpg_error (GPG_ERR_BUG);
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  if (!n)
+    return gpg_error (GPG_ERR_INV_SEXP);
+  err = gcry_sexp_sscan (&s_pkey, NULL, p, n);
+  xfree (p);
+  if (err)
+    return err; /* Can't parse that S-expression. */
+  if (!gcry_pk_get_keygrip (s_pkey, array))
+    {
+      gcry_sexp_release (s_pkey);
+      return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/
+    }
+  gcry_sexp_release (s_pkey);
+
+  for (i=0; i < 20; i++)
+    sprintf (hexkeygrip+i*2, "%02X", array[i]);
+
+  return 0;
+}
+
+
+
+/* Given the SLOT and the File ID FID, return the length of the
+   certificate contained in that file. Returns 0 if the file does not
+   exists or does not contain a certificate.  If R_CERTOFF is not
+   NULL, the length the header will be stored at this address; thus to
+   parse the X.509 certificate a read should start at that offset.
+
+   On success the file is still selected.
+*/
+size_t
+app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff)
+{
+  gpg_error_t err;
+  unsigned char *buffer;
+  const unsigned char *p;
+  size_t buflen, n;
+  int class, tag, constructed, ndef;
+  size_t resultlen, objlen, hdrlen;
+
+  err = iso7816_select_file (slot, fid, 0, NULL, NULL);
+  if (err)
+    {
+      log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
+      return 0;
+    }
+
+  err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen);
+  if (err)
+    {
+      log_info ("error reading certificate from FID 0x%04X: %s\n",
+                 fid, gpg_strerror (err));
+      return 0;
+    }
+  
+  if (!buflen || *buffer == 0xff)
+    {
+      log_info ("no certificate contained in FID 0x%04X\n", fid);
+      xfree (buffer);
+      return 0;
+    }
+
+  p = buffer;
+  n = buflen;
+  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                          &ndef, &objlen, &hdrlen);
+  if (err)
+    {
+      log_info ("error parsing certificate in FID 0x%04X: %s\n",
+                fid, gpg_strerror (err));
+      xfree (buffer);
+      return 0;
+    }
+
+  /* All certificates should commence with a SEQUENCE except for the
+     special ROOT CA which are enclosed in a SET. */
+  if ( !(class == CLASS_UNIVERSAL &&  constructed
+         && (tag == TAG_SEQUENCE || tag == TAG_SET)))
+    {
+      log_info ("contents of FID 0x%04X does not look like a certificate\n",
+                fid);
+      return 0;
+    }
+
+  resultlen = objlen + hdrlen;
+  if (r_certoff)
+    {
+      /* The callers want the offset to the actual certificate. */
+      *r_certoff = hdrlen;
+
+      err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (err)
+        return 0;
+
+      if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
+        {
+          /* The certificate seems to be contained in a
+             userCertificate container.  Assume the following sequence
+             is the certificate. */
+          *r_certoff += hdrlen + objlen;
+          if (*r_certoff > resultlen)
+            return 0; /* That should never happen. */
+        }
+    }
+
+  return resultlen;
+}
+
+
index a4b6e3a..e69b598 100644 (file)
@@ -53,68 +53,6 @@ static struct {
 
 
 
-/* Given the slot and the File Id FID, return the length of the
-   certificate contained in that file. Returns 0 if the file does not
-   exists or does not contain a certificate. */
-static size_t
-get_length_of_cert (int slot, int fid)
-{
-  gpg_error_t err;
-  unsigned char *buffer;
-  const unsigned char *p;
-  size_t buflen, n;
-  int class, tag, constructed, ndef;
-  size_t objlen, hdrlen;
-
-  err = iso7816_select_file (slot, fid, 0, NULL, NULL);
-  if (err)
-    {
-      log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
-      return 0;
-    }
-
-  err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen);
-  if (err)
-    {
-      log_info ("error reading certificate from FID 0x%04X: %s\n",
-                 fid, gpg_strerror (err));
-      return 0;
-    }
-  
-  if (!buflen || *buffer == 0xff)
-    {
-      log_info ("no certificate contained in FID 0x%04X\n", fid);
-      xfree (buffer);
-      return 0;
-    }
-
-  p = buffer;
-  n = buflen;
-  err = parse_ber_header (&p, &n, &class, &tag, &constructed,
-                          &ndef, &objlen, &hdrlen);
-  if (err)
-    {
-      log_info ("error parsing certificate in FID 0x%04X: %s\n",
-                fid, gpg_strerror (err));
-      xfree (buffer);
-      return 0;
-    }
-
-  /* All certificates should commence with a SEQUENCE expect fro the
-     special ROOT CA which are enclosed in a SET. */
-  if ( !(class == CLASS_UNIVERSAL &&  constructed
-         && (tag == TAG_SEQUENCE || tag == TAG_SET)))
-    {
-      log_info ("contents of FID 0x%04X does not look like a certificate\n",
-                fid);
-      return 0;
-    }
-  return objlen + hdrlen;
-}
-
-
-
 /* Read the file with FID, assume it contains a public key and return
    its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
 static gpg_error_t
@@ -191,8 +129,10 @@ do_learn_status (APP app, CTRL ctrl)
     {
       if (filelist[i].certtype)
         {
-          size_t len = get_length_of_cert (app->slot, filelist[i].fid);
+          size_t len;
 
+          len = app_help_read_length_of_cert (app->slot,
+                                              filelist[i].fid, NULL);
           if (len)
             {
               /* FIXME: We should store the length in the application's
index 7782b8e..af5f5a2 100644 (file)
@@ -1201,7 +1201,7 @@ app_select_openpgp (APP app)
 
       /* The OpenPGP card returns the serial number as part of the
          AID; because we prefer to use OpenPGP serial numbers, we
-         repalce a possibly already set one from a EF.GDO with this
+         replace a possibly already set one from a EF.GDO with this
          one.  Note, that for current OpenPGP cards, no EF.GDO exists
          and thus it won't matter at all. */
       rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
index 8366dcb..9ec2a52 100644 (file)
@@ -325,8 +325,6 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
         }
       if (card->p15card)
         card_p15_bind (card);
-      else
-        card_dinsig_bind (card);
       card->fnc.initialized = 1;
     }
       
index d7d3c12..24361d1 100644 (file)
@@ -488,6 +488,8 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
   int sw;
   unsigned char *buffer;
   size_t bufferlen;
+  int read_all = !nmax;
+  size_t n;
 
   if (!result || !resultlen)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -496,18 +498,22 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
 
   /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
      we check for this limit. */
-  if (offset > 32767 || nmax > 254)
+  if (offset > 32767)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   do
     {
       buffer = NULL;
       bufferlen = 0;
-      /* Fixme: Either the ccid driver of the TCOS cards have problems
+      /* Fixme: Either the ccid driver or the TCOS cards have problems
          with an Le of 0. */
+      if (read_all || nmax > 254)
+        n = 254;
+      else
+        n = nmax;
       sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
-                      ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
-                      nmax? nmax : 254, &buffer, &bufferlen);
+                         ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
+                         n, &buffer, &bufferlen);
 
       if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
         {
@@ -545,8 +551,12 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
       if (offset > 32767)
         break; /* We simply truncate the result for too large
                   files. */
+      if (nmax > bufferlen)
+        nmax -= bufferlen;
+      else
+        nmax = 0;
     }
-  while (!nmax && sw != SW_EOF_REACHED);
+  while ((read_all && sw != SW_EOF_REACHED) || (!read_all && nmax));
   
   return 0;
 }
index 5665237..93746ec 100644 (file)
@@ -103,8 +103,8 @@ static ARGPARSE_OPTS opts[] = {
   { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
   { oLogFile,  "log-file"   ,2, N_("use a log file for the server")},
   { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
-  { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ct-API driver")},
-  { opcscDriver, "pcsc-driver", 2, N_("NAME|use NAME as PC/SC driver")},
+  { octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")},
+  { opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")},
   { oDisableCCID, "disable-ccid", 0,
 #ifdef HAVE_LIBUSB
                                     N_("do not use the internal CCID driver")
@@ -126,6 +126,9 @@ static ARGPARSE_OPTS opts[] = {
 };
 
 
+#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
+
+
 static volatile int caught_fatal_sig = 0;
 
 /* It is possible that we are currently running under setuid permissions */
@@ -302,6 +305,7 @@ main (int argc, char **argv )
   char *logfile = NULL;
   int debug_wait = 0;
   int gpgconf_list = 0;
+  const char *config_filename = NULL;
 
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
@@ -334,7 +338,7 @@ main (int argc, char **argv )
   may_coredump = disable_core_dumps ();
 
   /* Set default options. */
-  opt.pcsc_driver = "libpcsclite.so"
+  opt.pcsc_driver = DEFAULT_PCSC_DRIVER
 
 
   shell = getenv ("SHELL");
@@ -466,7 +470,8 @@ main (int argc, char **argv )
     {
       fclose( configfp );
       configfp = NULL;
-      xfree(configname);
+      /* Keep a copy of the config name for use by --gpgconf-list. */
+      config_filename = configname;
       configname = NULL;
       goto next_pass;
     }
@@ -507,19 +512,49 @@ main (int argc, char **argv )
   
   if (gpgconf_list)
     { /* List options and default values in the GPG Conf format.  */
-      char *filename;
 
-      filename = make_filename (opt.homedir, "scdaemon.conf", NULL);
-      printf ("gpgconf-scdaemon.conf:\"%s\n", filename);
-      xfree (filename);
-      
-      printf ("verbose:\n"
-              "quiet:\n"
-              "debug-level:none\n"
-              "log-file:\n"
-              "force:\n"
-              "faked-system-time:\n"
-              "no-greeting:\n");
+      /* The following list is taken from gnupg/tools/gpgconf-comp.c.  */
+      /* Option flags.  YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
+         FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE.  */
+#define GC_OPT_FLAG_NONE       0UL
+      /* The RUNTIME flag for an option indicates that the option can be
+         changed at runtime.  */
+#define GC_OPT_FLAG_RUNTIME    (1UL << 3)
+      /* The DEFAULT flag for an option indicates that the option has a
+         default value.  */
+#define GC_OPT_FLAG_DEFAULT    (1UL << 4)
+      /* The DEF_DESC flag for an option indicates that the option has a
+         default, which is described by the value of the default field.  */
+#define GC_OPT_FLAG_DEF_DESC   (1UL << 5)
+      /* The NO_ARG_DESC flag for an option indicates that the argument has
+         a default, which is described by the value of the ARGDEF field.  */
+#define GC_OPT_FLAG_NO_ARG_DESC        (1UL << 6)
+
+      printf ("gpgconf-scdaemon.conf:%lu:\"%s\"\n",
+              GC_OPT_FLAG_DEFAULT,
+              config_filename?config_filename:"/dev/null");
+        
+      printf ("verbose:%lu:\n"
+              "quiet:%lu:\n"
+              "debug-level:%lu:\"none\":\n"
+              "log-file:%lu:\n",
+              GC_OPT_FLAG_NONE,
+              GC_OPT_FLAG_NONE,
+              GC_OPT_FLAG_DEFAULT,
+              GC_OPT_FLAG_NONE );
+
+      printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE );
+      printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE );
+      printf ("pcsc-driver:%lu:\"%s\":\n",
+              GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
+#ifdef HAVE_LIBUSB
+      printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
+#endif
+#ifdef HAVE_LIBUSB
+      printf ("disable-opensc:%lu:\n", GC_OPT_FLAG_NONE );
+#endif
+      printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE );
+
 
       scd_exit (0);
     }