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