1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-11-10 21:38:50 +01:00

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*.
This commit is contained in:
NIIBE Yutaka 2015-07-09 12:44:11 +09:00
parent 5b46726931
commit 67b2dc7636
7 changed files with 0 additions and 3036 deletions

View File

@ -49,22 +49,3 @@ scdaemon_LDADD = $(libcommonpth) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
$(LIBUSB_LIBS) $(GPG_ERROR_LIBS) \ $(LIBUSB_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(DL_LIBS) $(NETLIBS) $(LIBICONV) $(resource_objs) $(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@
#

View File

@ -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*/

View File

@ -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*/

View File

@ -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*/

View File

@ -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;
}

View File

@ -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 <bug-gnupg@gnu.org>.\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:
*/

View File

@ -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);
}