aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2015-07-09 03:44:11 +0000
committerNIIBE Yutaka <[email protected]>2015-07-09 03:51:03 +0000
commit67b2dc7636e47baefd5aafe0eb45b4730f974481 (patch)
tree033ee903ddd037709f562b1d16979ab2445da4c4
parentg10: Use canonical name for curve. (diff)
downloadgnupg-67b2dc7636e47baefd5aafe0eb45b4730f974481.tar.gz
gnupg-67b2dc7636e47baefd5aafe0eb45b4730f974481.zip
scd: Remove unused files.
* scd/Makefile.am (sc_copykeys_*): Remove. * scd/sc-copykeys.c: Remove. * scd/pcsc-wrapper.c: Remove. * scd/{card-common.h,card-dinsig.c,card-p15.c,card.c}: Remove. -- sc-copykeys doesn't work any more because it's based on old API. pcsc-wrapper has gone because of nPth which is compatible to pthreads. The card* files are old files, now we have app*.
Diffstat (limited to '')
-rw-r--r--scd/Makefile.am19
-rw-r--r--scd/card-common.h72
-rw-r--r--scd/card-dinsig.c257
-rw-r--r--scd/card-p15.c494
-rw-r--r--scd/card.c568
-rw-r--r--scd/pcsc-wrapper.c911
-rw-r--r--scd/sc-copykeys.c715
7 files changed, 0 insertions, 3036 deletions
diff --git a/scd/Makefile.am b/scd/Makefile.am
index 6212e6150..80e4c0f97 100644
--- a/scd/Makefile.am
+++ b/scd/Makefile.am
@@ -49,22 +49,3 @@ scdaemon_LDADD = $(libcommonpth) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
$(LIBUSB_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(DL_LIBS) $(NETLIBS) $(LIBICONV) $(resource_objs)
-
-# Removed for now: We need to decide whether it makes sense to
-# continue it at all, given that gpg has now all required
-# functionality.
-#sc_copykeys_SOURCES = \
-# sc-copykeys.c scdaemon.h \
-# apdu.c apdu.h \
-# ccid-driver.c ccid-driver.h \
-# iso7816.c iso7816.h \
-# atr.c atr.h \
-# app.c app-common.h app-help.c $(card_apps)
-#
-#sc_copykeys_LDADD = \
-# ../common/libcommon.a \
-# ../common/libsimple-pwquery.a \
-# $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
-# $(LIBUSB_LIBS) \
-# -lgpg-error @LIBINTL@ @DL_LIBS@
-#
diff --git a/scd/card-common.h b/scd/card-common.h
deleted file mode 100644
index 640cec776..000000000
--- a/scd/card-common.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* card-common.h - Common declarations for all card types
- * Copyright (C) 2001, 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CARD_COMMON_H
-#define CARD_COMMON_H
-
-/* Declaration of private data structure used by card-p15.c */
-struct p15private_s;
-
-
-struct card_ctx_s {
- int reader; /* used reader */
- struct sc_context *ctx;
- struct sc_card *scard;
- struct sc_pkcs15_card *p15card; /* only if there is a pkcs15 application */
- struct p15private_s *p15priv; /* private data used by card-p15.c */
-
- struct {
- int initialized; /* the card has been initialied and the function
- pointers may be used. However for
- unsupported operations the particular
- function pointer is set to NULL */
-
- int (*enum_keypairs) (CARD card, int idx,
- unsigned char *keygrip, char **keyid);
- int (*enum_certs) (CARD card, int idx, char **certid, int *certtype);
- int (*read_cert) (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert);
- int (*sign) (CARD card,
- 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 );
- int (*decipher) (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen);
- } fnc;
-
-};
-
-/*-- card.c --*/
-gpg_error_t map_sc_err (int rc);
-int card_help_get_keygrip (ksba_cert_t cert, unsigned char *array);
-
-/*-- card-15.c --*/
-void p15_release_private_data (CARD card);
-
-/* constructors */
-void card_p15_bind (CARD card);
-void card_dinsig_bind (CARD card);
-
-
-#endif /*CARD_COMMON_H*/
diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c
deleted file mode 100644
index 5be006179..000000000
--- a/scd/card-dinsig.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-/* 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 "scdaemon.h"
-#include <ksba.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;
- ksba_cert_t 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;
-
- rc = ksba_cert_new (&cert);
- if (rc)
- {
- xfree (buf);
- return rc;
- }
-
- rc = ksba_cert_init_from_mem (cert, buf, buflen);
- xfree (buf);
- if (rc)
- {
- log_error ("failed to parse the certificate at idx %d: %s\n",
- idx, gpg_strerror (rc));
- ksba_cert_release (cert);
- return rc;
- }
- 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 gpg_error (gpg_err_code_from_errno (errno));
- 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 = gpg_error (gpg_err_code_from_errno (errno));
- 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*/
diff --git a/scd/card-p15.c b/scd/card-p15.c
deleted file mode 100644
index 4af447278..000000000
--- a/scd/card-p15.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/* card-p15.c - PKCS-15 based card access
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#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 "scdaemon.h"
-#include <ksba.h>
-#include "card-common.h"
-
-
-struct p15private_s {
- int n_prkey_rsa_objs;
- struct sc_pkcs15_object *prkey_rsa_objs[32];
- int n_cert_objs;
- struct sc_pkcs15_object *cert_objs[32];
-};
-
-
-/* Allocate private data. */
-static int
-init_private_data (CARD card)
-{
- struct p15private_s *priv;
- int rc;
-
- if (card->p15priv)
- return 0; /* already done. */
-
- priv = xtrycalloc (1, sizeof *priv);
- if (!priv)
- return gpg_error (gpg_err_code_from_errno (errno));
-
- /* OpenSC (0.7.0) is a bit strange in that the get_objects functions
- tries to be a bit too clever and implicitly does an enumeration
- which eventually leads to the fact that every call to this
- fucntion returns one more macthing object. The old code in
- p15_enum_keypairs assume that it would alwyas return the same
- numer of objects and used this to figure out what the last object
- enumerated is. We now do an enum_objects just once and keep it
- in the private data. */
- rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_PRKEY_RSA,
- priv->prkey_rsa_objs,
- DIM (priv->prkey_rsa_objs));
- if (rc < 0)
- {
- log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
- xfree (priv);
- return gpg_error (GPG_ERR_CARD);
- }
- priv->n_prkey_rsa_objs = rc;
-
- /* Read all certificate objects. */
- rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_CERT_X509,
- priv->cert_objs,
- DIM (priv->cert_objs));
- if (rc < 0)
- {
- log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
- xfree (priv);
- return gpg_error (GPG_ERR_CARD);
- }
- priv->n_cert_objs = rc;
-
- card->p15priv = priv;
- return 0;
-}
-
-
-/* Release private data used in this module. */
-void
-p15_release_private_data (CARD card)
-{
- if (!card->p15priv)
- return;
- xfree (card->p15priv);
- card->p15priv = NULL;
-}
-
-
-
-/* See card.c for interface description */
-static int
-p15_enum_keypairs (CARD card, int idx,
- unsigned char *keygrip, char **keyid)
-{
- int rc;
- struct p15private_s *priv;
- struct sc_pkcs15_object *tmpobj;
- int nobjs;
- struct sc_pkcs15_prkey_info *pinfo;
- struct sc_pkcs15_cert_info *certinfo;
- struct sc_pkcs15_cert *certder;
- ksba_cert_t cert;
-
- rc = init_private_data (card);
- if (rc)
- return rc;
- priv = card->p15priv;
- nobjs = priv->n_prkey_rsa_objs;
- rc = 0;
- if (idx >= nobjs)
- return -1;
- pinfo = priv->prkey_rsa_objs[idx]->data;
-
- /* now we need to read the certificate so that we can calculate the
- keygrip */
- rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &tmpobj);
- if (rc)
- {
- log_info ("certificate for private key %d not found: %s\n",
- idx, sc_strerror (rc));
- /* note, that we return the ID anyway */
- rc = gpg_error (GPG_ERR_MISSING_CERT);
- goto return_keyid;
- }
- certinfo = tmpobj->data;
- rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
- if (rc)
- {
- log_info ("failed to read certificate for private key %d: %s\n",
- idx, sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
-
- rc = ksba_cert_new (&cert);
- if (rc)
- {
- sc_pkcs15_free_certificate (certder);
- return rc;
- }
- rc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
- sc_pkcs15_free_certificate (certder);
- if (rc)
- {
- log_error ("failed to parse the certificate for private key %d: %s\n",
- idx, gpg_strerror (rc));
- ksba_cert_release (cert);
- return rc;
- }
- if (card_help_get_keygrip (cert, keygrip))
- {
- log_error ("failed to calculate the keygrip of private key %d\n", idx);
- ksba_cert_release (cert);
- return gpg_error (GPG_ERR_CARD);
- }
- ksba_cert_release (cert);
-
- rc = 0;
- return_keyid:
- if (keyid)
- {
- char *p;
-
- *keyid = p = xtrymalloc (9+pinfo->id.len*2+1);
- if (!*keyid)
- return gpg_error (gpg_err_code_from_errno (errno));
- p = stpcpy (p, "P15-5015.");
- bin2hex (pinfo->id.value, pinfo->id.len, p);
- }
-
- return rc;
-}
-
-/* See card.c for interface description */
-static int
-p15_enum_certs (CARD card, int idx, char **certid, int *type)
-{
- int rc;
- struct p15private_s *priv;
- struct sc_pkcs15_object *obj;
- struct sc_pkcs15_cert_info *cinfo;
- int nobjs;
-
- rc = init_private_data (card);
- if (rc)
- return rc;
- priv = card->p15priv;
- nobjs = priv->n_cert_objs;
- rc = 0;
- if (idx >= nobjs)
- return -1;
- obj = priv->cert_objs[idx];
- cinfo = obj->data;
-
- if (certid)
- {
- char *p;
- int i;
-
- *certid = p = xtrymalloc (9+cinfo->id.len*2+1);
- if (!*certid)
- return gpg_error (gpg_err_code_from_errno (errno));
- p = stpcpy (p, "P15-5015.");
- bin2hex (cinfo->id.value, cinfo->id.len, p);
- }
- if (type)
- {
- if (!obj->df)
- *type = 0; /* unknown */
- else if (obj->df->type == SC_PKCS15_CDF)
- *type = 100;
- else if (obj->df->type == SC_PKCS15_CDF_TRUSTED)
- *type = 101;
- else if (obj->df->type == SC_PKCS15_CDF_USEFUL)
- *type = 102;
- else
- *type = 0; /* error -> unknown */
- }
-
- return rc;
-}
-
-
-
-static int
-idstr_to_id (const char *idstr, struct sc_pkcs15_id *id)
-{
- const char *s;
- int n;
-
- /* For now we only support the standard DF */
- if (strncmp (idstr, "P15-5015.", 9) )
- return gpg_error (GPG_ERR_INV_ID);
- for (s=idstr+9, n=0; hexdigitp (s); s++, n++)
- ;
- if (*s || (n&1))
- return gpg_error (GPG_ERR_INV_ID); /*invalid or odd number of digits*/
- n /= 2;
- if (!n || n > SC_PKCS15_MAX_ID_SIZE)
- return gpg_error (GPG_ERR_INV_ID); /* empty or too large */
- for (s=idstr+9, n=0; *s; s += 2, n++)
- id->value[n] = xtoi_2 (s);
- id->len = n;
- return 0;
-}
-
-
-/* See card.c for interface description */
-static int
-p15_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert)
-{
- struct sc_pkcs15_object *tmpobj;
- struct sc_pkcs15_id certid;
- struct sc_pkcs15_cert_info *certinfo;
- struct sc_pkcs15_cert *certder;
- int rc;
-
- if (!card || !certidstr || !cert || !ncert)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->p15card)
- return gpg_error (GPG_ERR_NO_PKCS15_APP);
-
- rc = idstr_to_id (certidstr, &certid);
- if (rc)
- return rc;
-
- rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &tmpobj);
- if (rc)
- {
- log_info ("certificate '%s' not found: %s\n",
- certidstr, sc_strerror (rc));
- return -1;
- }
- certinfo = tmpobj->data;
- rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
- if (rc)
- {
- log_info ("failed to read certificate '%s': %s\n",
- certidstr, sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
-
- *cert = xtrymalloc (certder->data_len);
- if (!*cert)
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- sc_pkcs15_free_certificate (certder);
- return tmperr;
- }
- memcpy (*cert, certder->data, certder->data_len);
- *ncert = certder->data_len;
- sc_pkcs15_free_certificate (certder);
- return 0;
-}
-
-
-
-
-
-static int
-p15_prepare_key (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg, struct sc_pkcs15_object **r_keyobj)
-{
- struct sc_pkcs15_id keyid;
- struct sc_pkcs15_pin_info *pin;
- struct sc_pkcs15_object *keyobj, *pinobj;
- char *pinvalue;
- int rc;
-
- rc = idstr_to_id (keyidstr, &keyid);
- if (rc)
- return rc;
-
- rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &keyobj);
- if (rc < 0)
- {
- log_error ("private key not found: %s\n", sc_strerror(rc));
- return gpg_error (GPG_ERR_NO_SECKEY);
- }
-
- rc = sc_pkcs15_find_pin_by_auth_id (card->p15card,
- &keyobj->auth_id, &pinobj);
- if (rc)
- {
- log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_BAD_PIN_METHOD);
- }
- pin = pinobj->data;
-
- /* Fixme: pack this into a verification loop */
- /* Fixme: we might want to pass pin->min_length and
- pin->stored_length */
- rc = pincb (pincb_arg, pinobj->label, &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- rc = sc_pkcs15_verify_pin (card->p15card, pin,
- pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_info ("PIN verification failed: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- /* fixme: check wheter we need to release KEYOBJ in case of an error */
- *r_keyobj = keyobj;
- return 0;
-}
-
-
-/* See card.c for interface description */
-static int
-p15_sign (CARD card, 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 )
-{
- unsigned int cryptflags;
- struct sc_pkcs15_object *keyobj;
- int rc;
- unsigned char *outbuf = NULL;
- size_t outbuflen;
-
- if (hashalgo != GCRY_MD_SHA1)
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-
- rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
- if (rc)
- return rc;
-
- cryptflags = SC_ALGORITHM_RSA_PAD_PKCS1;
-
- outbuflen = 1024;
- outbuf = xtrymalloc (outbuflen);
- if (!outbuf)
- return gpg_error (gpg_err_code_from_errno (errno));
-
- rc = sc_pkcs15_compute_signature (card->p15card, keyobj,
- cryptflags,
- indata, indatalen,
- outbuf, outbuflen );
- if (rc < 0)
- {
- log_error ("failed to create signature: %s\n", sc_strerror (rc));
- rc = gpg_error (GPG_ERR_CARD);
- }
- else
- {
- *outdatalen = rc;
- *outdata = outbuf;
- outbuf = NULL;
- rc = 0;
- }
-
- xfree (outbuf);
- return rc;
-}
-
-
-/* See card.c for description */
-static int
-p15_decipher (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- struct sc_pkcs15_object *keyobj;
- int rc;
- unsigned char *outbuf = NULL;
- size_t outbuflen;
-
- rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
- if (rc)
- return rc;
-
- if (card && card->scard && card->scard->driver
- && !strcasecmp (card->scard->driver->short_name, "tcos"))
- {
- /* very ugly hack to force the use of a local key. We need this
- until we have fixed the initialization code for TCOS cards */
- struct sc_pkcs15_prkey_info *prkey = keyobj->data;
- if ( !(prkey->key_reference & 0x80))
- {
- prkey->key_reference |= 0x80;
- log_debug ("using TCOS hack to force the use of local keys\n");
- }
- if (*keyidstr && keyidstr[strlen(keyidstr)-1] == '6')
- {
- prkey->key_reference |= 1;
- log_debug ("warning: using even more TCOS hacks\n");
- }
- }
-
- outbuflen = indatalen < 256? 256 : indatalen;
- outbuf = xtrymalloc (outbuflen);
- if (!outbuf)
- return gpg_error (gpg_err_code_from_errno (errno));
-
- rc = sc_pkcs15_decipher (card->p15card, keyobj,
- 0,
- indata, indatalen,
- outbuf, outbuflen);
- if (rc < 0)
- {
- log_error ("failed to decipher the data: %s\n", sc_strerror (rc));
- rc = gpg_error (GPG_ERR_CARD);
- }
- else
- {
- *outdatalen = rc;
- *outdata = outbuf;
- outbuf = NULL;
- rc = 0;
- }
-
- xfree (outbuf);
- return rc;
-}
-
-
-
-/* Bind our operations to the card */
-void
-card_p15_bind (CARD card)
-{
- card->fnc.enum_keypairs = p15_enum_keypairs;
- card->fnc.enum_certs = p15_enum_certs;
- card->fnc.read_cert = p15_read_cert;
- card->fnc.sign = p15_sign;
- card->fnc.decipher = p15_decipher;
-}
-#endif /*HAVE_OPENSC*/
diff --git a/scd/card.c b/scd/card.c
deleted file mode 100644
index a582c500f..000000000
--- a/scd/card.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/* card.c - SCdaemon card 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#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>
-#endif
-
-#include "scdaemon.h"
-#include <ksba.h>
-
-#include "card-common.h"
-
-/* Map the SC error codes to the GNUPG ones */
-gpg_error_t
-map_sc_err (int rc)
-{
- gpg_err_code_t e;
-
- switch (rc)
- {
- case 0: e = 0; break;
-#ifdef HAVE_OPENSC
- case SC_ERROR_NOT_SUPPORTED: e = GPG_ERR_NOT_SUPPORTED; break;
- case SC_ERROR_PKCS15_APP_NOT_FOUND: e = GPG_ERR_NO_PKCS15_APP; break;
- case SC_ERROR_OUT_OF_MEMORY: e = GPG_ERR_ENOMEM; break;
- case SC_ERROR_CARD_NOT_PRESENT: e = GPG_ERR_CARD_NOT_PRESENT; break;
- case SC_ERROR_CARD_REMOVED: e = GPG_ERR_CARD_REMOVED; break;
- case SC_ERROR_INVALID_CARD: e = GPG_ERR_INV_CARD; break;
-#endif
- default: e = GPG_ERR_CARD; break;
- }
- /* It does not make much sense to further distingusih the error
- source between OpenSC and SCD. Thus we use SCD as source
- here. */
- return gpg_err_make (GPG_ERR_SOURCE_SCD, e);
-}
-
-/* Get the keygrip from CERT, return 0 on success */
-int
-card_help_get_keygrip (ksba_cert_t cert, unsigned char *array)
-{
- gcry_sexp_t s_pkey;
- int rc;
- ksba_sexp_t p;
- size_t n;
-
- p = ksba_cert_get_public_key (cert);
- if (!p)
- return -1; /* oops */
- n = gcry_sexp_canon_len (p, 0, NULL, NULL);
- if (!n)
- return -1; /* libksba did not return a proper S-expression */
- rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
- xfree (p);
- if (rc)
- return -1; /* can't parse that S-expression */
- array = gcry_pk_get_keygrip (s_pkey, array);
- gcry_sexp_release (s_pkey);
- if (!array)
- return -1; /* failed to calculate the keygrip */
- return 0;
-}
-
-
-
-
-
-
-
-/* Create a new context for the card and figures out some basic
- information of the card. Detects whether a PKCS_15 application is
- stored.
-
- Common errors: GPG_ERR_CARD_NOT_PRESENT */
-int
-card_open (CARD *rcard)
-{
-#ifdef HAVE_OPENSC
- CARD card;
- int rc;
-
- if (opt.disable_opensc)
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-
- card = xtrycalloc (1, sizeof *card);
- if (!card)
- return gpg_error (gpg_err_code_from_errno (errno));
- card->reader = 0;
-
- rc = sc_establish_context (&card->ctx, "scdaemon");
- if (rc)
- {
- log_error ("failed to establish SC context: %s\n", sc_strerror (rc));
- rc = map_sc_err (rc);
- goto leave;
- }
- if (card->reader >= card->ctx->reader_count)
- {
- log_error ("no card reader available\n");
- rc = gpg_error (GPG_ERR_CARD);
- goto leave;
- }
- card->ctx->error_file = log_get_stream ();
- card->ctx->debug = opt.debug_sc;
- card->ctx->debug_file = log_get_stream ();
-
- if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1)
- {
- rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
- goto leave;
- }
-
- rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard);
- if (rc)
- {
- log_error ("failed to connect card in reader %d: %s\n",
- card->reader, sc_strerror (rc));
- rc = map_sc_err (rc);
- goto leave;
- }
- if (opt.verbose)
- log_info ("connected to card in reader %d using driver '%s'\n",
- card->reader, card->scard->driver->name);
-
- rc = sc_lock (card->scard);
- if (rc)
- {
- log_error ("can't lock card in reader %d: %s\n",
- card->reader, sc_strerror (rc));
- rc = map_sc_err (rc);
- goto leave;
- }
-
-
- leave:
- if (rc)
- card_close (card);
- else
- *rcard = card;
-
- return rc;
-#else
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-#endif
-}
-
-
-/* Close a card and release all resources */
-void
-card_close (CARD card)
-{
- if (card)
- {
-#ifdef HAVE_OPENSC
- if (card->p15card)
- {
- sc_pkcs15_unbind (card->p15card);
- card->p15card = NULL;
- }
- if (card->p15priv)
- p15_release_private_data (card);
- if (card->scard)
- {
- sc_unlock (card->scard);
- sc_disconnect_card (card->scard, 0);
- card->scard = NULL;
- }
- if (card->ctx)
- {
- sc_release_context (card->ctx);
- card->ctx = NULL;
- }
-#endif
- xfree (card);
- }
-}
-
-/* Locate a simple TLV encoded data object in BUFFER of LENGTH and
- return a pointer to value as well as its length in NBYTES. Return
- NULL if it was not found. Note, that the function does not check
- whether the value fits into the provided buffer. */
-#ifdef HAVE_OPENSC
-static const char *
-find_simple_tlv (const unsigned char *buffer, size_t length,
- int tag, size_t *nbytes)
-{
- const char *s = buffer;
- size_t n = length;
- size_t len;
-
- for (;;)
- {
- buffer = s;
- if (n < 2)
- return NULL; /* buffer too short for tag and length. */
- len = s[1];
- s += 2; n -= 2;
- if (len == 255)
- {
- if (n < 2)
- return NULL; /* we expected 2 more bytes with the length. */
- len = (s[0] << 8) | s[1];
- s += 2; n -= 2;
- }
- if (*buffer == tag)
- {
- *nbytes = len;
- return s;
- }
- if (len > n)
- return NULL; /* buffer too short to skip to the next tag. */
- s += len; n -= len;
- }
-}
-#endif /*HAVE_OPENSC*/
-
-/* Find the ICC Serial Number within the provided BUFFER of LENGTH
- (which should contain the GDO file) and return it as a hex encoded
- string and allocated string in SERIAL. Return an error code when
- the ICCSN was not found. */
-#ifdef HAVE_OPENSC
-static int
-find_iccsn (const unsigned char *buffer, size_t length, char **serial)
-{
- size_t n;
- const unsigned char *s;
- char *p;
-
- s = find_simple_tlv (buffer, length, 0x5A, &n);
- if (!s)
- return gpg_error (GPG_ERR_CARD);
- length -= s - buffer;
- if (n > length)
- {
- /* Oops, it does not fit into the buffer. This is an invalid
- encoding (or the buffer is too short. However, I have some
- test cards with such an invalid encoding and therefore I use
- this ugly workaround to return something I can further
- experiment with. */
- if (n == 0x0D && length+1 == n)
- {
- log_debug ("enabling BMI testcard workaround\n");
- n--;
- }
- else
- return gpg_error (GPG_ERR_CARD); /* Bad encoding; does
- not fit into buffer. */
- }
- if (!n)
- return gpg_error (GPG_ERR_CARD); /* Well, that is too short. */
-
- *serial = p = xtrymalloc (2*n+1);
- if (!*serial)
- return gpg_error (gpg_err_code_from_errno (errno));
- for (; n; n--, p += 2, s++)
- sprintf (p, "%02X", *s);
- *p = 0;
- return 0;
-}
-#endif /*HAVE_OPENSC*/
-
-/* Retrieve the serial number and the time of the last update of the
- card. The serial number is returned as a malloced string (hex
- encoded) in SERIAL and the time of update is returned in STAMP.
- If no update time is available the returned value is 0. The serial
- is mandatory for a PKCS_15 application and an error will be
- returned if this value is not availbale. For non-PKCS-15 cards a
- serial number is constructed by other means. Caller must free
- SERIAL unless the function returns an error. */
-int
-card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
-{
-#ifdef HAVE_OPENSC
- int rc;
- struct sc_path path;
- struct sc_file *file;
- unsigned char buf[256];
- int buflen;
-#endif
-
- if (!card || !serial || !stamp)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- *serial = NULL;
- *stamp = 0; /* not available */
-
-#ifdef HAVE_OPENSC
- if (!card->fnc.initialized)
- {
- card->fnc.initialized = 1;
- /* The first use of this card tries to figure out the type of the card
- and sets up the function pointers. */
- rc = sc_pkcs15_bind (card->scard, &card->p15card);
- if (rc)
- {
- if (rc != SC_ERROR_PKCS15_APP_NOT_FOUND)
- log_error ("binding of existing PKCS-15 failed in reader %d: %s\n",
- card->reader, sc_strerror (rc));
- card->p15card = NULL;
- rc = 0;
- }
- if (card->p15card)
- card_p15_bind (card);
- card->fnc.initialized = 1;
- }
-
-
- /* We should lookup the iso 7812-1 and 8583-3 - argh ISO
- practice is suppressing innovation - IETF rules! So we
- always get the serialnumber from the 2F02 GDO file. */
- /* FIXME: in case we can't parse the 2F02 EF and we have a P15 card,
- we should get the serial number from the respective P15 file */
- sc_format_path ("3F002F02", &path);
- rc = sc_select_file (card->scard, &path, &file);
- if (rc)
- {
- log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
- if (file->type != SC_FILE_TYPE_WORKING_EF
- || file->ef_structure != SC_FILE_EF_TRANSPARENT)
- {
- log_error ("wrong type or structure of GDO file\n");
- sc_file_free (file);
- return gpg_error (GPG_ERR_CARD);
- }
-
- if (!file->size || file->size >= DIM(buf) )
- { /* FIXME: Use a real parser */
- log_error ("unsupported size of GDO file (%d)\n", file->size);
- sc_file_free (file);
- return gpg_error (GPG_ERR_CARD);
- }
- buflen = file->size;
-
- rc = sc_read_binary (card->scard, 0, buf, buflen, 0);
- sc_file_free (file);
- if (rc < 0)
- {
- log_error ("error reading GDO file: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
- if (rc != buflen)
- {
- log_error ("short read on GDO file\n");
- return gpg_error (GPG_ERR_CARD);
- }
-
- rc = find_iccsn (buf, buflen, serial);
- if (gpg_err_code (rc) == GPG_ERR_CARD)
- log_error ("invalid structure of GDO file\n");
- if (!rc && card->p15card && !strcmp (*serial, "D27600000000000000000000"))
- { /* This is a German card with a silly serial number. Try to get
- the serial number from the EF(TokenInfo). We indicate such a
- serial number by the using the prefix: "FF0100". */
- const char *efser = card->p15card->serial_number;
- char *p;
-
- if (!efser)
- efser = "";
-
- xfree (*serial);
- *serial = NULL;
- p = xtrymalloc (strlen (efser) + 7);
- if (!p)
- rc = gpg_error (gpg_err_code_from_errno (errno));
- else
- {
- strcpy (p, "FF0100");
- strcpy (p+6, efser);
- *serial = p;
- }
- }
- else if (!rc && **serial == 'F' && (*serial)[1] == 'F')
- { /* The serial number starts with our special prefix. This
- requires that we put our default prefix "FF0000" in front. */
- char *p = xtrymalloc (strlen (*serial) + 7);
- if (!p)
- {
- xfree (*serial);
- *serial = NULL;
- rc = gpg_error (gpg_err_code_from_errno (errno));
- }
- else
- {
- strcpy (p, "FF0000");
- strcpy (p+6, *serial);
- xfree (*serial);
- *serial = p;
- }
- }
- return rc;
-#else
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-#endif
-}
-
-
-/* Enumerate all keypairs on the card and return the Keygrip as well
- as the internal identification of the key. KEYGRIP must be a
- caller provided buffer with a size of 20 bytes which will receive
- the KEYGRIP of the keypair. If KEYID is not NULL, it returns the
- ID field of the key in allocated memory; this is a string without
- spaces. The function returns -1 when all keys have been
- enumerated. Note that the error GPG_ERR_MISSING_CERTIFICATE may be
- returned if there is just the private key but no public key (ie.e a
- certificate) available. Applications might want to continue
- enumerating after this error.*/
-int
-card_enum_keypairs (CARD card, int idx,
- unsigned char *keygrip,
- char **keyid)
-{
- int rc;
-
- if (keyid)
- *keyid = NULL;
-
- if (!card || !keygrip)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (idx < 0)
- return gpg_error (GPG_ERR_INV_INDEX);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.enum_keypairs)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.enum_keypairs (card, idx, keygrip, keyid);
- if (opt.verbose)
- log_info ("card operation enum_keypairs result: %s\n",
- gpg_strerror (rc));
- return rc;
-}
-
-
-/* Enumerate all trusted certificates available on the card, return
- their ID in CERT and the type in CERTTYPE. Types of certificates
- are:
- 0 := Unknown
- 100 := Regular X.509 cert
- 101 := Trusted X.509 cert
- 102 := Useful X.509 cert
- 110 := Root CA cert (DINSIG)
- */
-int
-card_enum_certs (CARD card, int idx, char **certid, int *certtype)
-{
- int rc;
-
- if (certid)
- *certid = NULL;
-
- if (!card)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (idx < 0)
- return gpg_error (GPG_ERR_INV_INDEX);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.enum_certs)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.enum_certs (card, idx, certid, certtype);
- if (opt.verbose)
- log_info ("card operation enum_certs result: %s\n",
- gpg_strerror (rc));
- return rc;
-}
-
-
-
-/* Read the certificate identified by CERTIDSTR which is the
- hexadecimal encoded ID of the certificate, prefixed with the string
- "3F005015.". The certificate is return in DER encoded form in CERT
- and NCERT. */
-int
-card_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert)
-{
- int rc;
-
- if (!card || !certidstr || !cert || !ncert)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.read_cert)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.read_cert (card, certidstr, cert, ncert);
- if (opt.verbose)
- log_info ("card operation read_cert result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* 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; it
- should return the PIN in an allocated buffer and put it into PIN. */
-int
-card_sign (CARD card, 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 )
-{
- int rc;
-
- if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.sign)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.sign (card, keyidstr, hashalgo,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("card operation sign result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* 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; it
- should return the PIN in an allocated buffer and put it into PIN. */
-int
-card_decipher (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
-
- if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.decipher)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.decipher (card, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("card operation decipher result: %s\n", gpg_strerror (rc));
- return rc;
-}
diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c
deleted file mode 100644
index 843603a24..000000000
--- a/scd/pcsc-wrapper.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/* pcsc-wrapper.c - Wrapper for accessing the PC/SC service
- * Copyright (C) 2003, 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- This wrapper is required to handle problems with the libpscslite
- library. That library assumes that pthreads are used and fails
- badly if one tries to use it with a process using Pth. Note that
- the wrapper is not required if nPth is used.
-
- The operation model is pretty simple: It reads requests from stdin
- and returns the answer on stdout. There is no direct mapping to the
- pcsc interface but to a higher level one which resembles the code
- used in scdaemon (apdu.c) when not using Pth or while running under
- Windows.
-
- The interface is binary consisting of a command tag and the length
- of the parameter list. The calling process needs to pass the
- version number of the interface on the command line to make sure
- that both agree on the same interface. For each port a separate
- instance of this process needs to be started.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <dlfcn.h>
-
-
-#define PGM "pcsc-wrapper"
-
-/* Allow for a standalone build. */
-#ifdef VERSION
-#define MYVERSION_LINE PGM " ("GNUPG_NAME") " VERSION
-#define BUGREPORT_LINE "\nReport bugs to <[email protected]>.\n"
-#else
-#define MYVERSION_LINE PGM
-#define BUGREPORT_LINE ""
-#endif
-
-#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
-
-
-static int verbose;
-
-#if defined(__APPLE__) || defined(_WIN32) || defined(__CYGWIN__)
-typedef unsigned int pcsc_dword_t;
-#else
-typedef unsigned long pcsc_dword_t;
-#endif
-
-
-/* PC/SC constants and function pointer. */
-#define PCSC_SCOPE_USER 0
-#define PCSC_SCOPE_TERMINAL 1
-#define PCSC_SCOPE_SYSTEM 2
-#define PCSC_SCOPE_GLOBAL 3
-
-#define PCSC_PROTOCOL_T0 1
-#define PCSC_PROTOCOL_T1 2
-#define PCSC_PROTOCOL_RAW 4
-
-#define PCSC_SHARE_EXCLUSIVE 1
-#define PCSC_SHARE_SHARED 2
-#define PCSC_SHARE_DIRECT 3
-
-#define PCSC_LEAVE_CARD 0
-#define PCSC_RESET_CARD 1
-#define PCSC_UNPOWER_CARD 2
-#define PCSC_EJECT_CARD 3
-
-#define PCSC_UNKNOWN 0x0001
-#define PCSC_ABSENT 0x0002 /* Card is absent. */
-#define PCSC_PRESENT 0x0004 /* Card is present. */
-#define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */
-#define PCSC_POWERED 0x0010 /* Card is powered. */
-#define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */
-#define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */
-
-#define PCSC_STATE_UNAWARE 0x0000 /* Want status. */
-#define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */
-#define PCSC_STATE_CHANGED 0x0002 /* State has changed. */
-#define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */
-#define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */
-#define PCSC_STATE_EMPTY 0x0010 /* Card removed. */
-#define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */
-#define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */
-#define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */
-#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
-#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
-
-struct pcsc_io_request_s {
- unsigned long protocol;
- unsigned long pci_len;
-};
-
-typedef struct pcsc_io_request_s *pcsc_io_request_t;
-
-#ifdef __APPLE__
-#pragma pack(1)
-#endif
-
-struct pcsc_readerstate_s
-{
- const char *reader;
- void *user_data;
- pcsc_dword_t current_state;
- pcsc_dword_t event_state;
- pcsc_dword_t atrlen;
- unsigned char atr[33];
-};
-
-#ifdef __APPLE__
-#pragma pack()
-#endif
-
-typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
-
-
-static int driver_is_open; /* True if the PC/SC driver has been
- initialzied and is ready for
- operations. The following variables
- are then valid. */
-static long pcsc_context; /* The current PC/CS context. */
-static char *current_rdrname;
-static long pcsc_card;
-static pcsc_dword_t pcsc_protocol;
-static unsigned char current_atr[33];
-static size_t current_atrlen;
-
-long (* pcsc_establish_context) (pcsc_dword_t scope,
- const void *reserved1,
- const void *reserved2,
- long *r_context);
-long (* pcsc_release_context) (long context);
-long (* pcsc_list_readers) (long context,
- const char *groups,
- char *readers, pcsc_dword_t *readerslen);
-long (* pcsc_get_status_change) (long context,
- pcsc_dword_t timeout,
- pcsc_readerstate_t readerstates,
- pcsc_dword_t nreaderstates);
-long (* pcsc_connect) (long context,
- const char *reader,
- pcsc_dword_t share_mode,
- pcsc_dword_t preferred_protocols,
- long *r_card,
- pcsc_dword_t *r_active_protocol);
-long (* pcsc_reconnect) (long card,
- pcsc_dword_t share_mode,
- pcsc_dword_t preferred_protocols,
- pcsc_dword_t initialization,
- pcsc_dword_t *r_active_protocol);
-long (* pcsc_disconnect) (long card,
- pcsc_dword_t disposition);
-long (* pcsc_status) (long card,
- char *reader, pcsc_dword_t *readerlen,
- pcsc_dword_t *r_state,
- pcsc_dword_t *r_protocol,
- unsigned char *atr, pcsc_dword_t *atrlen);
-long (* pcsc_begin_transaction) (long card);
-long (* pcsc_end_transaction) (long card,
- pcsc_dword_t disposition);
-long (* pcsc_transmit) (long card,
- const pcsc_io_request_t send_pci,
- const unsigned char *send_buffer,
- pcsc_dword_t send_len,
- pcsc_io_request_t recv_pci,
- unsigned char *recv_buffer,
- pcsc_dword_t *recv_len);
-long (* pcsc_set_timeout) (long context,
- pcsc_dword_t timeout);
-long (* pcsc_control) (long card,
- pcsc_dword_t control_code,
- const void *send_buffer,
- pcsc_dword_t send_len,
- void *recv_buffer,
- pcsc_dword_t recv_len,
- pcsc_dword_t *bytes_returned);
-
-
-
-static void
-bad_request (const char *type)
-{
- fprintf (stderr, PGM ": bad '%s' request\n", type);
- exit (1);
-}
-
-static void
-request_failed (int err)
-{
- if (!err)
- err = -1;
-
- putchar (0x81); /* Simple error/success response. */
-
- putchar (0);
- putchar (0);
- putchar (0);
- putchar (4);
-
- putchar ((err >> 24) & 0xff);
- putchar ((err >> 16) & 0xff);
- putchar ((err >> 8) & 0xff);
- putchar ((err ) & 0xff);
-
- fflush (stdout);
-}
-
-
-static void
-request_succeeded (const void *buffer, size_t buflen)
-{
- size_t len;
-
- putchar (0x81); /* Simple error/success response. */
-
- len = 4 + buflen;
- putchar ((len >> 24) & 0xff);
- putchar ((len >> 16) & 0xff);
- putchar ((len >> 8) & 0xff);
- putchar ((len ) & 0xff);
-
- /* Error code. */
- putchar (0);
- putchar (0);
- putchar (0);
- putchar (0);
-
- /* Optional reponse string. */
- if (buffer)
- fwrite (buffer, buflen, 1, stdout);
-
- fflush (stdout);
-}
-
-
-
-static unsigned long
-read_32 (FILE *fp)
-{
- int c1, c2, c3, c4;
-
- c1 = getc (fp);
- c2 = getc (fp);
- c3 = getc (fp);
- c4 = getc (fp);
- if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
- {
- fprintf (stderr, PGM ": premature EOF while parsing request\n");
- exit (1);
- }
- return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
-}
-
-
-
-static const char *
-pcsc_error_string (long err)
-{
- const char *s;
-
- if (!err)
- return "okay";
- if ((err & 0x80100000) != 0x80100000)
- return "invalid PC/SC error code";
- err &= 0xffff;
- switch (err)
- {
- case 0x0002: s = "cancelled"; break;
- case 0x000e: s = "can't dispose"; break;
- case 0x0008: s = "insufficient buffer"; break;
- case 0x0015: s = "invalid ATR"; break;
- case 0x0003: s = "invalid handle"; break;
- case 0x0004: s = "invalid parameter"; break;
- case 0x0005: s = "invalid target"; break;
- case 0x0011: s = "invalid value"; break;
- case 0x0006: s = "no memory"; break;
- case 0x0013: s = "comm error"; break;
- case 0x0001: s = "internal error"; break;
- case 0x0014: s = "unknown error"; break;
- case 0x0007: s = "waited too long"; break;
- case 0x0009: s = "unknown reader"; break;
- case 0x000a: s = "timeout"; break;
- case 0x000b: s = "sharing violation"; break;
- case 0x000c: s = "no smartcard"; break;
- case 0x000d: s = "unknown card"; break;
- case 0x000f: s = "proto mismatch"; break;
- case 0x0010: s = "not ready"; break;
- case 0x0012: s = "system cancelled"; break;
- case 0x0016: s = "not transacted"; break;
- case 0x0017: s = "reader unavailable"; break;
- case 0x0065: s = "unsupported card"; break;
- case 0x0066: s = "unresponsive card"; break;
- case 0x0067: s = "unpowered card"; break;
- case 0x0068: s = "reset card"; break;
- case 0x0069: s = "removed card"; break;
- case 0x006a: s = "inserted card"; break;
- case 0x001f: s = "unsupported feature"; break;
- case 0x0019: s = "PCI too small"; break;
- case 0x001a: s = "reader unsupported"; break;
- case 0x001b: s = "duplicate reader"; break;
- case 0x001c: s = "card unsupported"; break;
- case 0x001d: s = "no service"; break;
- case 0x001e: s = "service stopped"; break;
- default: s = "unknown PC/SC error code"; break;
- }
- return s;
-}
-
-static void
-load_pcsc_driver (const char *libname)
-{
- void *handle;
-
- handle = dlopen (libname, RTLD_LAZY);
- if (!handle)
- {
- fprintf (stderr, PGM ": failed to open driver '%s': %s",
- libname, dlerror ());
- exit (1);
- }
-
- pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
- pcsc_release_context = dlsym (handle, "SCardReleaseContext");
- pcsc_list_readers = dlsym (handle, "SCardListReaders");
- pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
- pcsc_connect = dlsym (handle, "SCardConnect");
- pcsc_reconnect = dlsym (handle, "SCardReconnect");
- pcsc_disconnect = dlsym (handle, "SCardDisconnect");
- pcsc_status = dlsym (handle, "SCardStatus");
- pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
- pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
- pcsc_transmit = dlsym (handle, "SCardTransmit");
- pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
- pcsc_control = dlsym (handle, "SCardControl");
-
- if (!pcsc_establish_context
- || !pcsc_release_context
- || !pcsc_list_readers
- || !pcsc_get_status_change
- || !pcsc_connect
- || !pcsc_reconnect
- || !pcsc_disconnect
- || !pcsc_status
- || !pcsc_begin_transaction
- || !pcsc_end_transaction
- || !pcsc_transmit
- || !pcsc_control
- /* || !pcsc_set_timeout */)
- {
- /* Note that set_timeout is currently not used and also not
- available under Windows. */
- fprintf (stderr,
- "apdu_open_reader: invalid PC/SC driver "
- "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
- !!pcsc_establish_context,
- !!pcsc_release_context,
- !!pcsc_list_readers,
- !!pcsc_get_status_change,
- !!pcsc_connect,
- !!pcsc_reconnect,
- !!pcsc_disconnect,
- !!pcsc_status,
- !!pcsc_begin_transaction,
- !!pcsc_end_transaction,
- !!pcsc_transmit,
- !!pcsc_set_timeout,
- !!pcsc_control );
- dlclose (handle);
- exit (1);
- }
-}
-
-
-
-
-/* Handle a open request. The argument is expected to be a string
- with the port identification. ARGBUF is always guaranteed to be
- terminted by a 0 which is not counted in ARGLEN. We may modifiy
- ARGBUF. */
-static void
-handle_open (unsigned char *argbuf, size_t arglen)
-{
- long err;
- const char * portstr;
- char *list = NULL;
- pcsc_dword_t nreader, atrlen;
- char *p;
- pcsc_dword_t card_state, card_protocol;
- unsigned char atr[33];
-
- /* Make sure there is only the port string */
- if (arglen != strlen ((char*)argbuf))
- bad_request ("OPEN");
- portstr = (char*)argbuf;
-
- if (driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has already been opened\n");
- request_failed (-1);
- return;
- }
-
- err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
-
- err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
- if (!err)
- {
- list = malloc (nreader+1); /* Better add 1 for safety reasons. */
- if (!list)
- {
- fprintf (stderr, PGM": error allocating memory for reader list\n");
- exit (1);
- }
- err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
- }
- if (err)
- {
- fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- free (list);
- request_failed (err);
- return;
- }
-
- p = list;
- while (nreader)
- {
- if (!*p && !p[1])
- break;
- fprintf (stderr, PGM": detected reader '%s'\n", p);
- if (nreader < (strlen (p)+1))
- {
- fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
- break;
- }
- nreader -= strlen (p)+1;
- p += strlen (p) + 1;
- }
-
- current_rdrname = malloc (strlen (portstr && *portstr? portstr:list)+1);
- if (!current_rdrname)
- {
- fprintf (stderr, PGM": error allocating memory for reader name\n");
- exit (1);
- }
- strcpy (current_rdrname, portstr && *portstr? portstr:list);
- free (list);
-
- err = pcsc_connect (pcsc_context,
- current_rdrname,
- PCSC_SHARE_EXCLUSIVE,
- PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
- &pcsc_card,
- &pcsc_protocol);
- if (err == 0x8010000c) /* No smartcard. */
- {
- pcsc_card = 0;
- }
- else if (err)
- {
- fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- free (current_rdrname);
- current_rdrname = NULL;
- pcsc_card = 0;
- pcsc_protocol = 0;
- request_failed (err);
- return;
- }
-
- current_atrlen = 0;
- if (!err)
- {
- char reader[250];
- pcsc_dword_t readerlen;
-
- atrlen = 33;
- readerlen = sizeof reader -1;
- err = pcsc_status (pcsc_card,
- reader, &readerlen,
- &card_state, &card_protocol,
- atr, &atrlen);
- if (err)
- fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- else
- {
- if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
- {
- fprintf (stderr, PGM": ATR returned by pcsc_status"
- " is too large\n");
- exit (4);
- }
- memcpy (current_atr, atr, atrlen);
- current_atrlen = atrlen;
- }
- }
-
- driver_is_open = 1;
- request_succeeded (current_atr, current_atrlen);
-}
-
-
-
-/* Handle a close request. We expect no arguments. We may modifiy
- ARGBUF. */
-static void
-handle_close (unsigned char *argbuf, size_t arglen)
-{
- (void)argbuf;
- (void)arglen;
-
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- return;
- }
-
- free (current_rdrname);
- current_rdrname = NULL;
- pcsc_release_context (pcsc_context);
- pcsc_card = 0;
- pcsc_protocol = 0;
-
- request_succeeded (NULL, 0);
-}
-
-
-
-/* Handle a status request. We expect no arguments. We may modifiy
- ARGBUF. */
-static void
-handle_status (unsigned char *argbuf, size_t arglen)
-{
- long err;
- struct pcsc_readerstate_s rdrstates[1];
- int status;
- unsigned char buf[20];
-
- (void)argbuf;
- (void)arglen;
-
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- return;
- }
-
- memset (rdrstates, 0, sizeof *rdrstates);
- rdrstates[0].reader = current_rdrname;
- rdrstates[0].current_state = PCSC_STATE_UNAWARE;
- err = pcsc_get_status_change (pcsc_context,
- 0,
- rdrstates, 1);
- if (err == 0x8010000a) /* Timeout. */
- err = 0;
- if (err)
- {
- fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
-
- status = 0;
- if ( !(rdrstates[0].event_state & PCSC_STATE_UNKNOWN) )
- {
- if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
- {
- status |= 2;
- if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
- status |= 4;
- }
- /* We indicate a useful card if it is not in use by another
- application. This is because we only use exclusive access
- mode. */
- if ( (status & 6) == 6
- && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
- status |= 1;
- }
-
- /* First word is identical to the one used by apdu.c. */
- buf[0] = 0;
- buf[1] = 0;
- buf[2] = 0;
- buf[3] = status;
- /* The second word is the native PCSC state. */
- buf[4] = (rdrstates[0].event_state >> 24);
- buf[5] = (rdrstates[0].event_state >> 16);
- buf[6] = (rdrstates[0].event_state >> 8);
- buf[7] = (rdrstates[0].event_state >> 0);
- /* The third word is the protocol. */
- buf[8] = (pcsc_protocol >> 24);
- buf[9] = (pcsc_protocol >> 16);
- buf[10] = (pcsc_protocol >> 8);
- buf[11] = (pcsc_protocol);
-
- request_succeeded (buf, 8);
-}
-
-
-/* Handle a reset request. We expect no arguments. We may modifiy
- ARGBUF. */
-static void
-handle_reset (unsigned char *argbuf, size_t arglen)
-{
- long err;
- char reader[250];
- pcsc_dword_t nreader, atrlen;
- pcsc_dword_t card_state, card_protocol;
-
- (void)argbuf;
- (void)arglen;
-
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- return;
- }
-
- if (pcsc_card)
- {
- err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
- if (err == 0x80100003) /* Invalid handle. (already disconnected) */
- err = 0;
- if (err)
- {
- fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
- pcsc_card = 0;
- }
-
- err = pcsc_connect (pcsc_context,
- current_rdrname,
- PCSC_SHARE_EXCLUSIVE,
- PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
- &pcsc_card,
- &pcsc_protocol);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_card = 0;
- request_failed (err);
- return;
- }
-
-
- atrlen = 33;
- nreader = sizeof reader - 1;
- err = pcsc_status (pcsc_card,
- reader, &nreader,
- &card_state, &card_protocol,
- current_atr, &atrlen);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- current_atrlen = 0;
- request_failed (err);
- return;
- }
-
- request_succeeded (current_atr, current_atrlen);
-}
-
-
-
-/* Handle a transmit request. The argument is expected to be a buffer
- with the APDU. We may modifiy ARGBUF. */
-static void
-handle_transmit (unsigned char *argbuf, size_t arglen)
-{
- long err;
- struct pcsc_io_request_s send_pci;
- pcsc_dword_t recv_len;
- unsigned char buffer[4096];
-
- /* The apdu should at least be one byte. */
- if (!arglen)
- bad_request ("TRANSMIT");
-
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- return;
- }
- if ((pcsc_protocol & PCSC_PROTOCOL_T1))
- send_pci.protocol = PCSC_PROTOCOL_T1;
- else
- send_pci.protocol = PCSC_PROTOCOL_T0;
- send_pci.pci_len = sizeof send_pci;
- recv_len = sizeof (buffer);
- err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
- NULL, buffer, &recv_len);
- if (err)
- {
- if (verbose)
- fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
- request_succeeded (buffer, recv_len);
-}
-
-
-/* Handle a control request. The argument is expected to be a buffer
- which contains CONTROL_CODE (4-byte) and INPUT_BYTES.
- */
-static void
-handle_control (unsigned char *argbuf, size_t arglen)
-{
- long err;
- pcsc_dword_t ioctl_code;
- pcsc_dword_t recv_len = 1024;
- unsigned char buffer[1024];
-
- if (arglen < 4)
- bad_request ("CONTROL");
-
- ioctl_code = (argbuf[0] << 24) | (argbuf[1] << 16) | (argbuf[2] << 8) | argbuf[3];
- argbuf += 4;
- arglen -= 4;
-
- recv_len = sizeof (buffer);
- err = pcsc_control (pcsc_card, ioctl_code, argbuf, arglen,
- buffer, recv_len, &recv_len);
- if (err)
- {
- if (verbose)
- fprintf (stderr, PGM": pcsc_control failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
- request_succeeded (buffer, recv_len);
-}
-
-
-static void
-print_version (int with_help)
-{
- fputs (MYVERSION_LINE "\n"
- "Copyright (C) 2004 Free Software Foundation, Inc.\n"
- "This program comes with ABSOLUTELY NO WARRANTY.\n"
- "This is free software, and you are welcome to redistribute it\n"
- "under certain conditions. See the file COPYING for details.\n",
- stdout);
-
- if (with_help)
- fputs ("\n"
- "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
- "Helper to connect scdaemon to the PC/SC library\n"
- "\n"
- " --verbose enable extra informational output\n"
- " --version print version of the program and exit\n"
- " --help display this help and exit\n"
- BUGREPORT_LINE, stdout );
-
- exit (0);
-}
-
-
-int
-main (int argc, char **argv)
-{
- int last_argc = -1;
- int api_number = 0;
- int c;
-
- if (argc)
- {
- argc--; argv++;
- }
- while (argc && last_argc != argc )
- {
- last_argc = argc;
- if (!strcmp (*argv, "--"))
- {
- argc--; argv++;
- break;
- }
- else if (!strcmp (*argv, "--version"))
- print_version (0);
- else if (!strcmp (*argv, "--help"))
- print_version (1);
- else if (!strcmp (*argv, "--verbose"))
- {
- verbose = 1;
- argc--; argv++;
- }
- }
- if (argc != 1 && argc != 2)
- {
- fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
- exit (1);
- }
-
- api_number = atoi (*argv);
- argv++; argc--;
- if (api_number != 1)
- {
- fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
- exit (1);
- }
-
- load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
-
- while ((c = getc (stdin)) != EOF)
- {
- size_t arglen;
- unsigned char argbuffer[2048];
-
- arglen = read_32 (stdin);
- if (arglen >= sizeof argbuffer - 1)
- {
- fprintf (stderr, PGM ": request too long\n");
- exit (1);
- }
- if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
- {
- fprintf (stderr, PGM ": error reading request: %s\n",
- strerror (errno));
- exit (1);
- }
- argbuffer[arglen] = 0;
- switch (c)
- {
- case 1:
- handle_open (argbuffer, arglen);
- break;
-
- case 2:
- handle_close (argbuffer, arglen);
- exit (0);
- break;
-
- case 3:
- handle_transmit (argbuffer, arglen);
- break;
-
- case 4:
- handle_status (argbuffer, arglen);
- break;
-
- case 5:
- handle_reset (argbuffer, arglen);
- break;
-
- case 6:
- handle_control (argbuffer, arglen);
- break;
-
- default:
- fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
- exit (1);
- }
- }
- return 0;
-}
-
-
-
-/*
-Local Variables:
-compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
-End:
-*/
diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c
deleted file mode 100644
index eb246c492..000000000
--- a/scd/sc-copykeys.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/* sc-copykeys.c - A tool to store keys on a smartcard.
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "scdaemon.h"
-#include <gcrypt.h>
-
-#include "../common/ttyio.h"
-#include "../common/simple-pwquery.h"
-#include "iso7816.h"
-#include "apdu.h" /* for open_reader */
-#include "atr.h"
-#include "app-common.h"
-
-#define _(a) (a)
-
-
-enum cmd_and_opt_values
-{ oVerbose = 'v',
- oReaderPort = 500,
- octapiDriver,
- oDebug,
- oDebugAll,
-
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, "@Options:\n " },
-
- { oVerbose, "verbose", 0, "verbose" },
- { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
- { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
- { oDebug, "debug" ,4|16, "set debugging flags"},
- { oDebugAll, "debug-all" ,0, "enable full debugging"},
- {0}
-};
-
-
-static void copykeys (APP app, const char *fname);
-
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "sc-copykeys (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
-
- case 1:
- case 40: p = _("Usage: sc-copykeys [options] (-h for help)\n");
- break;
- case 41: p = _("Syntax: sc-copykeys [options] "
- "file-with-key\n"
- "Copy keys to a smartcards\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int slot, rc;
- const char *reader_port = NULL;
- struct app_ctx_s appbuf;
-
- memset (&appbuf, 0, sizeof appbuf);
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- log_set_prefix ("sc-copykeys", 1);
-
- /* check that the libraries are suitable. Do it here because
- the option parsing may need services of the library */
- if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
- {
- log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
- NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
- }
-
- setup_libgcrypt_logging ();
- gcry_control (GCRYCTL_DISABLE_SECMEM, 0); /* FIXME - we want to use it */
- /* FIXME? gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);*/
-
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1; /* do not remove the args */
- while (arg_parse (&pargs, opts) )
- {
- switch (pargs.r_opt)
- {
- case oVerbose: opt.verbose++; break;
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
- case oReaderPort: reader_port = pargs.r.ret_str; break;
- case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
- default : pargs.err = 2; break;
- }
- }
- if (log_get_errorcount(0))
- exit(2);
-
- if (argc != 1)
- usage (1);
-
- slot = apdu_open_reader (reader_port);
- if (slot == -1)
- exit (1);
- if (apdu_connect (slot))
- exit (1);
-
- /* FIXME: Use select_application. */
- appbuf.slot = slot;
- rc = app_select_openpgp (&appbuf);
- if (rc)
- {
- log_error ("selecting openpgp failed: %s\n", gpg_strerror (rc));
- exit (1);
- }
- appbuf.initialized = 1;
- log_info ("openpgp application selected\n");
-
- copykeys (&appbuf, *argv);
-
-
- return 0;
-}
-
-
-
-void
-send_status_info (CTRL ctrl, const char *keyword, ...)
-{
- /* DUMMY */
-}
-
-
-
-static char *
-read_file (const char *fname, size_t *r_length)
-{
- FILE *fp;
- struct stat st;
- char *buf;
- size_t buflen;
-
- fp = fname? fopen (fname, "rb") : stdin;
- if (!fp)
- {
- log_error ("can't open '%s': %s\n",
- fname? fname: "[stdin]", strerror (errno));
- return NULL;
- }
-
- if (fstat (fileno(fp), &st))
- {
- log_error ("can't stat '%s': %s\n",
- fname? fname: "[stdin]", strerror (errno));
- if (fname)
- fclose (fp);
- return NULL;
- }
-
- buflen = st.st_size;
- buf = xmalloc (buflen+1);
- if (fread (buf, buflen, 1, fp) != 1)
- {
- log_error ("error reading '%s': %s\n",
- fname? fname: "[stdin]", strerror (errno));
- if (fname)
- fclose (fp);
- xfree (buf);
- return NULL;
- }
- if (fname)
- fclose (fp);
-
- *r_length = buflen;
- return buf;
-}
-
-
-static gcry_sexp_t
-read_key (const char *fname)
-{
- char *buf;
- size_t buflen;
- gcry_sexp_t private;
- int rc;
-
- buf = read_file (fname, &buflen);
- if (!buf)
- return NULL;
-
- rc = gcry_sexp_new (&private, buf, buflen, 1);
- if (rc)
- {
- log_error ("gcry_sexp_new failed: %s\n", gpg_strerror (rc));
- return NULL;
- }
- xfree (buf);
-
- return private;
-}
-
-
-
-static gcry_mpi_t *
-sexp_to_kparms (gcry_sexp_t sexp, unsigned long *created)
-{
- gcry_sexp_t list, l2;
- const char *name;
- const char *s;
- size_t n;
- int i, idx;
- const char *elems;
- gcry_mpi_t *array;
-
- *created = 0;
- list = gcry_sexp_find_token (sexp, "private-key", 0 );
- if(!list)
- return NULL;
-
- /* quick hack to get the creation time. */
- l2 = gcry_sexp_find_token (list, "created", 0);
- if (l2 && (name = gcry_sexp_nth_data (l2, 1, &n)))
- {
- char *tmp = xmalloc (n+1);
- memcpy (tmp, name, n);
- tmp[n] = 0;
- *created = strtoul (tmp, NULL, 10);
- xfree (tmp);
- }
- gcry_sexp_release (l2);
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- name = gcry_sexp_nth_data (list, 0, &n);
- if(!name || n != 3 || memcmp (name, "rsa", 3))
- {
- gcry_sexp_release (list);
- return NULL;
- }
-
- /* Parameter names used with RSA. */
- elems = "nedpqu";
- array = xcalloc (strlen(elems) + 1, sizeof *array);
- for (idx=0, s=elems; *s; s++, idx++ )
- {
- l2 = gcry_sexp_find_token (list, s, 1);
- if (!l2)
- {
- for (i=0; i<idx; i++)
- gcry_mpi_release (array[i]);
- xfree (array);
- gcry_sexp_release (list);
- return NULL; /* required parameter not found */
- }
- array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (l2);
- if (!array[idx])
- {
- for (i=0; i<idx; i++)
- gcry_mpi_release (array[i]);
- xfree (array);
- gcry_sexp_release (list);
- return NULL; /* required parameter is invalid */
- }
- }
-
- gcry_sexp_release (list);
- return array;
-}
-
-
-/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */
-static int
-fpr_is_zero (const char *fpr)
-{
- int i;
-
- for (i=0; i < 20 && !fpr[i]; i++)
- ;
- return (i == 20);
-}
-
-
-static void
-show_sha1_fpr (const unsigned char *fpr)
-{
- int i;
-
- if (fpr)
- {
- for (i=0; i < 20 ; i+=2, fpr += 2 )
- {
- if (i == 10 )
- tty_printf (" ");
- tty_printf (" %02X%02X", *fpr, fpr[1]);
- }
- }
- else
- tty_printf (" [none]");
- tty_printf ("\n");
-}
-
-/* Query the card, show a list of already stored keys and ask the user
- where to store the key. Returns the key number or 0 for cancel
- operation. */
-static int
-query_card (APP app)
-{
- int keyno = 0;
- char *serialno, *disp_name, *pubkey_url;
- unsigned char *fpr1, *fpr2, *fpr3;
-
-
- if (app_openpgp_cardinfo (app,
- &serialno,
- &disp_name,
- &pubkey_url,
- &fpr1, &fpr2, &fpr3))
- return 0;
-
-
- for (;;)
- {
- char *answer;
-
- tty_printf ("\n");
-
- tty_printf ("Serial number ....: %s\n",
- serialno? serialno : "[none]");
- tty_printf ("Name of cardholder: %s\n",
- disp_name && *disp_name? disp_name : "[not set]");
- tty_printf ("URL of public key : %s\n",
- pubkey_url && *pubkey_url? pubkey_url : "[not set]");
- tty_printf ("Signature key ....:");
- show_sha1_fpr (fpr1);
- tty_printf ("Encryption key....:");
- show_sha1_fpr (fpr2);
- tty_printf ("Authentication key:");
- show_sha1_fpr (fpr3);
-
- tty_printf ("\n"
- "1 - store as signature key and reset usage counter\n"
- "2 - store as encryption key\n"
- "3 - store as authentication key\n"
- "Q - quit\n"
- "\n");
-
- answer = tty_get("Your selection? ");
- tty_kill_prompt();
- if (strlen (answer) != 1)
- ;
- else if ( *answer == '1' )
- {
- if ( (fpr1 && !fpr_is_zero (fpr1)) )
- {
- tty_printf ("\n");
- log_error ("WARNING: signature key does already exists!\n");
- tty_printf ("\n");
- if ( tty_get_answer_is_yes ("Replace existing key? ") )
- {
- keyno = 1;
- break;
- }
- }
- else
- {
- keyno = 1;
- break;
- }
- }
- else if ( *answer == '2' )
- {
- if ( (fpr2 && !fpr_is_zero (fpr2)) )
- {
- tty_printf ("\n");
- log_error ("WARNING: encryption key does already exists!\n");
- tty_printf ("\n");
- if ( tty_get_answer_is_yes ("Replace existing key? ") )
- {
- keyno = 2;
- break;
- }
- }
- else
- {
- keyno = 2;
- break;
- }
- }
- else if ( *answer == '3' )
- {
- if ( (fpr3 && !fpr_is_zero (fpr3)) )
- {
- tty_printf ("\n");
- log_error ("WARNING: authentication key does already exists!\n");
- tty_printf ("\n");
- if ( tty_get_answer_is_yes ("Replace existing key? ") )
- {
- keyno = 3;
- break;
- }
- }
- else
- {
- keyno = 3;
- break;
- }
- }
- else if ( *answer == 'q' || *answer == 'Q')
- {
- keyno = 0;
- break;
- }
- }
-
- xfree (serialno);
- xfree (disp_name);
- xfree (pubkey_url);
- xfree (fpr1);
- xfree (fpr2);
- xfree (fpr3);
-
- return keyno;
-}
-
-
-/* Callback function to ask for a PIN. */
-static gpg_error_t
-pincb (void *arg, const char *prompt, char **pinvalue)
-{
- char *pin = xstrdup ("12345678");
-
-/* pin = simple_pwquery (NULL, NULL, prompt, */
-/* "We need the admin's PIN to store the key on the card", */
-/* 0, NULL); */
-/* if (!pin) */
-/* return gpg_error (GPG_ERR_CANCELED); */
-
-
-
- *pinvalue = pin;
- return 0;
-}
-
-
-/* This function expects a file (or NULL for stdin) with the secret
- and public key parameters. This file should consist of an
- S-expression as used by gpg-agent. Only the unprotected format is
- supported. Example:
-
- (private-key
- (rsa
- (n #00e0ce9..[some bytes not shown]..51#)
- (e #010001#)
- (d #046129F..[some bytes not shown]..81#)
- (p #00e861b..[some bytes not shown]..f1#)
- (q #00f7a7c..[some bytes not shown]..61#)
- (u #304559a..[some bytes not shown]..9b#))
- (uri http://foo.bar x-foo:whatever_you_want))
-
-*/
-static void
-copykeys (APP app, const char *fname)
-{
- int rc;
- gcry_sexp_t private;
- gcry_mpi_t *mpis, rsa_n, rsa_e, rsa_p, rsa_q;
- unsigned int nbits;
- size_t n;
- unsigned char *template, *tp;
- unsigned char m[128], e[4];
- size_t mlen, elen;
- unsigned long creation_date;
- time_t created_at;
- int keyno;
-
- if (!strcmp (fname, "-"))
- fname = NULL;
-
- private = read_key (fname);
- if (!private)
- exit (1);
-
- mpis = sexp_to_kparms (private, &creation_date);
- if (!creation_date)
- {
- log_info ("no creation date found - assuming current date\n");
- created_at = time (NULL);
- }
- else
- created_at = creation_date;
- gcry_sexp_release (private);
- if (!mpis)
- {
- log_error ("invalid structure of key file or not RSA\n");
- exit (1);
- }
- /* MPIS is now an array with the key parameters as defined by OpenPGP. */
- rsa_n = mpis[0];
- rsa_e = mpis[1];
- gcry_mpi_release (mpis[2]);
- rsa_p = mpis[3];
- rsa_q = mpis[4];
- gcry_mpi_release (mpis[5]);
- xfree (mpis);
-
- nbits = gcry_mpi_get_nbits (rsa_e);
- if (nbits < 2 || nbits > 32)
- {
- log_error ("public exponent too large (more than 32 bits)\n");
- goto failure;
- }
- nbits = gcry_mpi_get_nbits (rsa_p);
- if (nbits != 512)
- {
- log_error ("length of first RSA prime is not 512\n");
- goto failure;
- }
- nbits = gcry_mpi_get_nbits (rsa_q);
- if (nbits != 512)
- {
- log_error ("length of second RSA prime is not 512\n");
- goto failure;
- }
-
- nbits = gcry_mpi_get_nbits (rsa_n);
- if (nbits != 1024)
- {
- log_error ("length of RSA modulus is not 1024\n");
- goto failure;
- }
-
- keyno = query_card (app);
- if (!keyno)
- goto failure;
-
- /* Build the private key template as described in section 4.3.3.6 of
- the specs.
- 0xC0 <length> public exponent
- 0xC1 <length> prime p
- 0xC2 <length> prime q */
- template = tp = xmalloc (1+2 + 1+1+4 + 1+1+64 + 1+1+64);
- *tp++ = 0xC0;
- *tp++ = 4;
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, tp, 4, &n, rsa_e);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n <= 4);
- memcpy (e, tp, n);
- elen = n;
- if (n != 4)
- {
- memmove (tp+4-n, tp, 4-n);
- memset (tp, 0, 4-n);
- }
- tp += 4;
-
- *tp++ = 0xC1;
- *tp++ = 64;
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, tp, 64, &n, rsa_p);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n == 64);
- tp += 64;
-
- *tp++ = 0xC2;
- *tp++ = 64;
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, tp, 64, &n, rsa_q);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n == 64);
- tp += 64;
- assert (tp - template == 138);
-
- /* (we need the modulus to calculate the fingerprint) */
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, m, 128, &n, rsa_n);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n == 128);
- mlen = 128;
-
-
- rc = app_openpgp_storekey (app, keyno,
- template, tp - template,
- created_at,
- m, mlen,
- e, elen,
- pincb, NULL);
-
- if (rc)
- {
- log_error ("error storing key: %s\n", gpg_strerror (rc));
- goto failure;
- }
- log_info ("key successfully stored\n");
- {
- unsigned char *mm, *ee;
- size_t mmlen, eelen;
- int i;
-
- rc = app_openpgp_readkey (app, keyno, &mm, &mmlen, &ee, &eelen);
- if (rc)
- {
- log_error ("error reading key back: %s\n", gpg_strerror (rc));
- goto failure;
- }
-
- /* Strip leading zeroes. */
- for (i=0; i < mmlen && !mm[i]; i++)
- ;
- mmlen -= i;
- memmove (mm, mm+i, mmlen);
- for (i=0; i < eelen && !ee[i]; i++)
- ;
- eelen -= i;
- memmove (ee, ee+i, eelen);
-
- if (eelen != elen || mmlen != mlen)
- {
- log_error ("key parameter length mismatch (n=%u/%u, e=%u/%u)\n",
- (unsigned int)mlen, (unsigned int)mmlen,
- (unsigned int)elen, (unsigned int)eelen);
- xfree (mm);
- xfree (ee);
- goto failure;
- }
-
- if (memcmp (m, mm, mlen))
- {
- log_error ("key parameter n mismatch\n");
- log_printhex ("original n: ", m, mlen);
- log_printhex (" copied n: ", mm, mlen);
- xfree (mm);
- xfree (ee);
- goto failure;
- }
- if (memcmp (e, ee, elen))
- {
- log_error ("key parameter e mismatch\n");
- log_printhex ("original e: ", e, elen);
- log_printhex (" copied e: ", ee, elen);
- xfree (mm);
- xfree (ee);
- goto failure;
- }
- xfree (mm);
- xfree (ee);
- }
-
-
- gcry_mpi_release (rsa_e);
- gcry_mpi_release (rsa_p);
- gcry_mpi_release (rsa_q);
- gcry_mpi_release (rsa_n);
- return;
-
- failure:
- gcry_mpi_release (rsa_e);
- gcry_mpi_release (rsa_p);
- gcry_mpi_release (rsa_q);
- gcry_mpi_release (rsa_n);
- exit (1);
-}