summaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorRepo Admin <nobody@gnupg.org>2003-06-05 09:14:21 +0200
committerRepo Admin <nobody@gnupg.org>2003-06-05 09:14:21 +0200
commit7250331472efe70fac928fa06e51c7c80f2b715c (patch)
treed6ec62958ba3971115da3b81c8e1ad0f6d822fe0 /scd
parentMake use of libgpg-error (diff)
downloadgnupg2-7250331472efe70fac928fa06e51c7c80f2b715c.tar.xz
gnupg2-7250331472efe70fac928fa06e51c7c80f2b715c.zip
This commit was manufactured by cvs2svn to create branch
'GNUPG-1-9-BRANCH'.
Diffstat (limited to 'scd')
-rw-r--r--scd/atr.c287
-rw-r--r--scd/atr.h28
-rw-r--r--scd/card-dinsig.c260
3 files changed, 575 insertions, 0 deletions
diff --git a/scd/atr.c b/scd/atr.c
new file mode 100644
index 000000000..4e15aad50
--- /dev/null
+++ b/scd/atr.c
@@ -0,0 +1,287 @@
+/* atr.c - ISO 7816 ATR fucntions
+ * Copyright (C) 2003 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 <dlfcn.h>
+#include <assert.h>
+
+#include "scdaemon.h"
+#include "apdu.h"
+#include "atr.h"
+
+static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
+ -1, 512, 768, 1024, 1536, 2048, -1, -1 };
+static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
+ 0, -1, -2, -4, -8, -16, -32, -64};
+
+
+/* Dump the ATR of the card at SLOT in a human readable format to
+ stream FP. */
+int
+atr_dump (int slot, FILE *fp)
+{
+ unsigned char *atrbuffer, *atr;
+ size_t atrlen;
+ int have_ta, have_tb, have_tc, have_td;
+ int n_historical;
+ int idx, val;
+ unsigned char chksum;
+
+ atr = atrbuffer = apdu_get_atr (slot, &atrlen);
+ if (!atr)
+ return gpg_error (GPG_ERR_GENERAL);
+
+ fprintf (fp, "Info on ATR of length %u at slot %d\n",
+ (unsigned int)atrlen, slot);
+ if (!atrlen)
+ {
+ fprintf (fp, "error: empty ATR\n");
+ goto bailout;
+ }
+
+
+ if (*atr == 0x3b)
+ fputs ("direct convention\n", fp);
+ else if (*atr == 0x3f)
+ fputs ("inverse convention\n", fp);
+ else
+ fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+
+ chksum = *atr;
+ for (idx=1; idx < atrlen-1; idx++)
+ chksum ^= atr[idx];
+
+ have_ta = !!(*atr & 0x10);
+ have_tb = !!(*atr & 0x20);
+ have_tc = !!(*atr & 0x40);
+ have_td = !!(*atr & 0x80);
+ n_historical = (*atr & 0x0f);
+ fprintf (fp, "%d historical characters indicated\n", n_historical);
+
+ if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
+ fputs ("error: ATR shorter than indicated by format character\n", fp);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+
+ if (have_ta)
+ {
+ fputs ("TA1: F=", fp);
+ val = fi_table[(*atr >> 4) & 0x0f];
+ if (!val)
+ fputs ("internal clock", fp);
+ else if (val == -1)
+ fputs ("RFU", fp);
+ else
+ fprintf (fp, "%d", val);
+ fputs (" D=", fp);
+ val = di_table[*atr & 0x0f];
+ if (!val)
+ fputs ("[impossible value]\n", fp);
+ else if (val == -1)
+ fputs ("RFU\n", fp);
+ else if (val < 0 )
+ fprintf (fp, "1/%d\n", val);
+ else
+ fprintf (fp, "%d\n", val);
+
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_tb)
+ {
+ fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
+ (*atr & 0x80)? " [high bit not cleared]":"");
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_tc)
+ {
+ if (*atr == 255)
+ fputs ("TC1: guard time shortened to 1 etu\n", fp);
+ else
+ fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
+
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_td)
+ {
+ have_ta = !!(*atr & 0x10);
+ have_tb = !!(*atr & 0x20);
+ have_tc = !!(*atr & 0x40);
+ have_td = !!(*atr & 0x80);
+ fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
+
+ if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
+ fputs ("error: ATR shorter than indicated by format character\n", fp);
+
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+ else
+ have_ta = have_tb = have_tc = have_td = 0;
+
+ if (have_ta)
+ {
+ fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
+ (*atr & 0x80)? "no-":"",
+ (*atr & 0x10)? "im": "ex",
+ (*atr & 0x0f));
+ if ((*atr & 0x60))
+ fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_tb)
+ {
+ fprintf (fp, "TB2: PI2=%d\n", *atr);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_tc)
+ {
+ fprintf (fp, "TC2: PWI=%d\n", *atr);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_td)
+ {
+ have_ta = !!(*atr & 0x10);
+ have_tb = !!(*atr & 0x20);
+ have_tc = !!(*atr & 0x40);
+ have_td = !!(*atr & 0x80);
+ fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
+
+ if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
+ fputs ("error: ATR shorter than indicated by format character\n", fp);
+
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+ else
+ have_ta = have_tb = have_tc = have_td = 0;
+
+ for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
+ {
+ if (have_ta)
+ {
+ fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_tb)
+ {
+ fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
+ idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_tc)
+ {
+ fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+
+ if (have_td)
+ {
+ have_ta = !!(*atr & 0x10);
+ have_tb = !!(*atr & 0x20);
+ have_tc = !!(*atr & 0x40);
+ have_td = !!(*atr & 0x80);
+ fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
+
+ if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
+ fputs ("error: ATR shorter than indicated by format character\n",
+ fp);
+
+ if (!--atrlen)
+ goto bailout;
+ atr++;
+ }
+ else
+ have_ta = have_tb = have_tc = have_td = 0;
+ }
+
+ if (n_historical + 1 > atrlen)
+ fputs ("error: ATR shorter than required for historical bytes "
+ "and checksum\n", fp);
+
+ if (n_historical)
+ {
+ fputs ("Historical:", fp);
+ for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
+ fprintf (fp, " %02X", *atr);
+ putchar ('\n');
+ }
+
+ if (!atrlen)
+ fputs ("error: checksum missing\n", fp);
+ else if (*atr == chksum)
+ fprintf (fp, "TCK: %02X (good)\n", *atr);
+ else
+ fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
+
+ atrlen--;
+ if (atrlen)
+ fprintf (fp, "error: %u bytes garbage at end of ATR\n",
+ (unsigned int)atrlen );
+
+ bailout:
+ xfree (atrbuffer);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
diff --git a/scd/atr.h b/scd/atr.h
new file mode 100644
index 000000000..5fdd57457
--- /dev/null
+++ b/scd/atr.h
@@ -0,0 +1,28 @@
+/* atr.h - ISO 7816 ATR functions
+ * Copyright (C) 2003 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
+ */
+
+#ifndef ATR_H
+#define ATR_H
+
+int atr_dump (int slot, FILE *fp);
+
+
+
+#endif /*ATR_H*/
diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c
new file mode 100644
index 000000000..391a51da8
--- /dev/null
+++ b/scd/card-dinsig.c
@@ -0,0 +1,260 @@
+/* card-dinsig.c - German signature law (DINSIG) functions
+ * Copyright (C) 2002 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
+ */
+
+/* The German signature law and its bylaw (SigG and SigV) is currently
+ used with an interface specification described in DIN V 66291-1.
+ The AID to be used is: 'D27600006601'.
+
+ The file IDs for certificates utilize the generic format:
+ Cxyz
+ C being the hex digit 'C' (12).
+ x being the service indicator:
+ '0' := SigG conform digital signature.
+ '1' := entity authentication.
+ '2' := key encipherment.
+ '3' := data encipherment.
+ '4' := key agreement.
+ other values are reserved for future use.
+ y being the security environment number using '0' for cards
+ not supporting a SE number.
+ z being the certificate type:
+ '0' := C.CH (base certificate of ard holder) or C.ICC.
+ '1' .. '7' := C.CH (business or professional certificate
+ of card holder.
+ '8' .. 'D' := C.CA (certificate of a CA issue by the Root-CA).
+ 'E' := C.RCA (self certified certificate of the Root-CA).
+ 'F' := reserved.
+
+ The file IDs used by default are:
+ '1F00' EF.SSD (security service descriptor). [o,o]
+ '2F02' EF.GDO (global data objects) [m,m]
+ 'A000' EF.PROT (signature log). Cyclic file with 20 records of 53 byte.
+ Read and update after user authentication. [o,o]
+ 'B000' EF.PK.RCA.DS (public keys of Root-CA). Size is 512b or size
+ of keys. [m (unless a 'C00E' is present),m]
+ 'B001' EF.PK.CA.DS (public keys of CAs). Size is 512b or size
+ of keys. [o,o]
+ 'C00n' EF.C.CH.DS (digital signature certificate of card holder)
+ with n := 0 .. 7. Size is 2k or size of cert. Read and
+ update allowed after user authentication. [m,m]
+ 'C00m' EF.C.CA.DS (digital signature certificate of CA)
+ with m := 8 .. E. Size is 1k or size of cert. Read always
+ allowed, update after uder authentication. [o,o]
+ 'C100' EF.C.ICC.AUT (AUT certificate of ICC) [o,m]
+ 'C108' EF.C.CA.AUT (AUT certificate of CA) [o,m]
+ 'D000' EF.DM (display message) [-,m]
+
+ 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 <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef HAVE_OPENSC
+#include <opensc/pkcs15.h>
+#include <ksba.h>
+
+#include "scdaemon.h"
+#include "card-common.h"
+
+static int dinsig_read_cert (CARD card, const char *certidstr,
+ unsigned char **cert, size_t *ncert);
+
+
+
+/* See card.c for interface description. Frankly we don't do any real
+ enumeration but just check whether the well know files are
+ available. */
+static int
+dinsig_enum_keypairs (CARD card, int idx,
+ unsigned char *keygrip, char **keyid)
+{
+ int rc;
+ unsigned char *buf;
+ size_t buflen;
+ KsbaError krc;
+ KsbaCert cert;
+
+ /* fixme: We should locate the application via the EF(DIR) and not
+ assume a Netkey card */
+ if (!idx)
+ rc = dinsig_read_cert (card, "DINSIG-DF01.C000", &buf, &buflen);
+ else if (idx == 1)
+ rc = dinsig_read_cert (card, "DINSIG-DF01.C200", &buf, &buflen);
+ else
+ rc = -1;
+ if (rc)
+ return rc;
+
+ cert = ksba_cert_new ();
+ if (!cert)
+ {
+ gpg_error_t tmperr = out_of_core ();
+ xfree (buf);
+ return tmperr;
+ }
+
+ krc = ksba_cert_init_from_mem (cert, buf, buflen);
+ xfree (buf);
+ if (krc)
+ {
+ log_error ("failed to parse the certificate at idx %d: %s\n",
+ idx, ksba_strerror (krc));
+ ksba_cert_release (cert);
+ return gpg_error (GPG_ERR_CARD);
+ }
+ if (card_help_get_keygrip (cert, keygrip))
+ {
+ log_error ("failed to calculate the keygrip at index %d\n", idx);
+ ksba_cert_release (cert);
+ return gpg_error (GPG_ERR_CARD);
+ }
+ ksba_cert_release (cert);
+
+ /* return the iD */
+ if (keyid)
+ {
+ *keyid = xtrymalloc (17);
+ if (!*keyid)
+ return out_of_core ();
+ if (!idx)
+ strcpy (*keyid, "DINSIG-DF01.C000");
+ else
+ strcpy (*keyid, "DINSIG-DF01.C200");
+ }
+
+ return 0;
+}
+
+
+
+/* See card.c for interface description */
+static int
+dinsig_read_cert (CARD card, const char *certidstr,
+ unsigned char **cert, size_t *ncert)
+{
+ int rc;
+ struct sc_path path;
+ struct sc_file *file;
+ unsigned char *buf;
+ int buflen;
+
+ if (!strcmp (certidstr, "DINSIG-DF01.C000"))
+ sc_format_path ("3F00DF01C000", &path);
+ else if (!strcmp (certidstr, "DINSIG-DF01.C200"))
+ sc_format_path ("3F00DF01C200", &path);
+ else
+ return gpg_error (GPG_ERR_INV_ID);
+
+ rc = sc_select_file (card->scard, &path, &file);
+ if (rc)
+ {
+ log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
+ return map_sc_err (rc);
+ }
+ if (file->type != SC_FILE_TYPE_WORKING_EF
+ || file->ef_structure != SC_FILE_EF_TRANSPARENT)
+ {
+ log_error ("wrong type or structure of certificate EF\n");
+ sc_file_free (file);
+ return gpg_error (GPG_ERR_CARD);
+ }
+ if (file->size < 20) /* check against a somewhat arbitrary length */
+ {
+ log_error ("certificate EF too short\n");
+ sc_file_free (file);
+ return gpg_error (GPG_ERR_CARD);
+ }
+ buf = xtrymalloc (file->size);
+ if (!buf)
+ {
+ gpg_error_t tmperr = out_of_core ();
+ sc_file_free (file);
+ return tmperr;
+ }
+
+ rc = sc_read_binary (card->scard, 0, buf, file->size, 0);
+ if (rc >= 0 && rc != file->size)
+ {
+ log_error ("short read on certificate EF\n");
+ sc_file_free (file);
+ xfree (buf);
+ return gpg_error (GPG_ERR_CARD);
+ }
+ sc_file_free (file);
+ if (rc < 0)
+ {
+ log_error ("error reading certificate EF: %s\n", sc_strerror (rc));
+ xfree (buf);
+ return map_sc_err (rc);
+ }
+ buflen = rc;
+
+ /* The object is not a plain certificate but wrapped into id-at
+ userCertificate - fixme: we should check the specs and decided
+ whether libksba should support it */
+ if (buflen > 9 && buf[0] == 0x30 && buf[4] == 6 && buf[5] == 3
+ && buf[6] == 0x55 && buf[7] == 4 && buf[8] == 0x24)
+ {
+ /* We have to strip the padding. Although this is a good idea
+ anyway, we have to do it due to a KSBA problem; KSBA does not
+ work correct when the buffer is larger than the ASN.1
+ structure and the certificates here are padded with FF. So
+ as a workaround we look at the outer structure to get the
+ size of the entire thing and adjust the buflen. We can only
+ do this when there is a 2 byte length field */
+ size_t seqlen;
+ if (buf[1] == 0x82)
+ {
+ seqlen = ((buf[2] << 8) | buf[3]) + 4;
+ if (seqlen < buflen)
+ buflen = seqlen;
+ }
+ memmove (buf, buf+9, buflen-9);
+ buflen -= 9;
+ }
+
+ *cert = buf;
+ *ncert = buflen;
+ return 0;
+}
+
+
+
+
+/* Bind our operations to the card */
+void
+card_dinsig_bind (CARD card)
+{
+ card->fnc.enum_keypairs = dinsig_enum_keypairs;
+ card->fnc.read_cert = dinsig_read_cert;
+
+}
+#endif /*HAVE_OPENSC*/