summaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2004-03-16 19:59:21 +0100
committerWerner Koch <wk@gnupg.org>2004-03-16 19:59:21 +0100
commite209ea3c39e7110d94e4420513f397d8656a75b7 (patch)
tree6ce23948ac5b3c3c1c0bb0205fc953fe7a24f13e /scd
parent(main): Implemented --gpgconf-list. (diff)
downloadgnupg2-e209ea3c39e7110d94e4420513f397d8656a75b7.tar.xz
gnupg2-e209ea3c39e7110d94e4420513f397d8656a75b7.zip
* 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.
Diffstat (limited to 'scd')
-rw-r--r--scd/ChangeLog14
-rw-r--r--scd/Makefile.am14
-rw-r--r--scd/app-common.h7
-rw-r--r--scd/app-dinsig.c314
-rw-r--r--scd/app-help.c157
-rw-r--r--scd/app-nks.c66
-rw-r--r--scd/app-openpgp.c2
-rw-r--r--scd/card.c2
-rw-r--r--scd/iso7816.c20
-rw-r--r--scd/scdaemon.c67
10 files changed, 561 insertions, 102 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog
index a9296cbbb..679f867fe 100644
--- a/scd/ChangeLog
+++ b/scd/ChangeLog
@@ -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
diff --git a/scd/Makefile.am b/scd/Makefile.am
index 89ebf4e05..da59a1997 100644
--- a/scd/Makefile.am
+++ b/scd/Makefile.am
@@ -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
diff --git a/scd/app-common.h b/scd/app-common.h
index cda17700f..c16a15719 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -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);
diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c
index 4b5b517eb..38fbc79ee 100644
--- a/scd/app-dinsig.c
+++ b/scd/app-dinsig.c
@@ -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.
-
*/
@@ -85,17 +82,317 @@
#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
index 000000000..c6695635f
--- /dev/null
+++ b/scd/app-help.c
@@ -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;
+}
+
+
diff --git a/scd/app-nks.c b/scd/app-nks.c
index a4b6e3a15..e69b59879 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -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
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 7782b8e1c..af5f5a27f 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -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);
diff --git a/scd/card.c b/scd/card.c
index 8366dcb1c..9ec2a52c5 100644
--- a/scd/card.c
+++ b/scd/card.c
@@ -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;
}
diff --git a/scd/iso7816.c b/scd/iso7816.c
index d7d3c126b..24361d148 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -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;
}
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 5665237ca..93746ec35 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -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);
}