mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +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>
|
||||
|
||||
* scdaemon.h (out_of_core): Removed. Replaced callers by standard
|
||||
|
@ -34,12 +34,12 @@ scdaemon_SOURCES = \
|
||||
scdaemon.c scdaemon.h \
|
||||
command.c card.c \
|
||||
card-common.h \
|
||||
card-p15.c card-dinsig.c \
|
||||
card-p15.c \
|
||||
apdu.c apdu.h \
|
||||
ccid-driver.c ccid-driver.h \
|
||||
iso7816.c iso7816.h \
|
||||
tlv.c tlv.h \
|
||||
app.c app-common.h $(card_apps)
|
||||
app.c app-common.h app-help.c $(card_apps)
|
||||
|
||||
|
||||
scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
|
||||
@ -53,12 +53,12 @@ sc_investigate_SOURCES = \
|
||||
iso7816.c iso7816.h \
|
||||
tlv.c tlv.h \
|
||||
atr.c atr.h \
|
||||
app.c app-common.h $(card_apps)
|
||||
app.c app-common.h app-help.c $(card_apps)
|
||||
|
||||
sc_investigate_LDADD = \
|
||||
../jnlib/libjnlib.a ../common/libcommon.a \
|
||||
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) @INTLLIBS@ \
|
||||
-lgpg-error -ldl
|
||||
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBUSB_LIBS) \
|
||||
@INTLLIBS@ -lgpg-error -ldl
|
||||
|
||||
|
||||
sc_copykeys_SOURCES = \
|
||||
@ -68,10 +68,10 @@ sc_copykeys_SOURCES = \
|
||||
iso7816.c iso7816.h \
|
||||
tlv.c tlv.h \
|
||||
atr.c atr.h \
|
||||
app.c app-common.h $(card_apps)
|
||||
app.c app-common.h app-help.c $(card_apps)
|
||||
|
||||
sc_copykeys_LDADD = \
|
||||
../jnlib/libjnlib.a ../common/libcommon.a \
|
||||
../common/libsimple-pwquery.a \
|
||||
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) \
|
||||
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBUSB_LIBS) \
|
||||
-lgpg-error @INTLLIBS@ -ldl
|
||||
|
@ -21,6 +21,8 @@
|
||||
#ifndef GNUPG_SCD_APP_COMMON_H
|
||||
#define GNUPG_SCD_APP_COMMON_H
|
||||
|
||||
#include <ksba.h>
|
||||
|
||||
struct app_ctx_s {
|
||||
int initialized; /* The application has been initialied and the
|
||||
function pointers may be used. Note that for
|
||||
@ -80,6 +82,11 @@ struct app_ctx_s {
|
||||
int app_select_openpgp (app_t app);
|
||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||
#else
|
||||
/*-- app-help.c --*/
|
||||
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
|
||||
size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
||||
|
||||
|
||||
/*-- app.c --*/
|
||||
app_t select_application (ctrl_t ctrl, int slot, const char *name);
|
||||
void release_application (app_t app);
|
||||
|
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.
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -65,9 +65,6 @@
|
||||
The letters in brackets indicate optional or mandatory files: The
|
||||
first for card terminals under full control and the second for
|
||||
"business" card terminals.
|
||||
|
||||
FIXME: Needs a lot more explanation.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@ -85,18 +82,318 @@
|
||||
|
||||
#include "iso7816.h"
|
||||
#include "app-common.h"
|
||||
|
||||
#include "tlv.h"
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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
|
||||
must be used before any other DINSIG application functions. */
|
||||
@ -113,17 +410,18 @@ app_select_dinsig (APP app)
|
||||
app->apptype = "DINSIG";
|
||||
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
app->fnc.getattr = NULL;
|
||||
app->fnc.setattr = NULL;
|
||||
app->fnc.genkey = NULL;
|
||||
app->fnc.sign = NULL;
|
||||
app->fnc.sign = do_sign;
|
||||
app->fnc.auth = NULL;
|
||||
app->fnc.decipher = NULL;
|
||||
app->fnc.change_pin = NULL;
|
||||
app->fnc.check_pin = NULL;
|
||||
|
||||
app->force_chv1 = 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
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
|
||||
its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
|
||||
static gpg_error_t
|
||||
@ -191,8 +129,10 @@ do_learn_status (APP app, CTRL ctrl)
|
||||
{
|
||||
if (filelist[i].certtype)
|
||||
{
|
||||
size_t len = get_length_of_cert (app->slot, filelist[i].fid);
|
||||
size_t len;
|
||||
|
||||
len = app_help_read_length_of_cert (app->slot,
|
||||
filelist[i].fid, NULL);
|
||||
if (len)
|
||||
{
|
||||
/* FIXME: We should store the length in the application's
|
||||
|
@ -1201,7 +1201,7 @@ app_select_openpgp (APP app)
|
||||
|
||||
/* The OpenPGP card returns the serial number as part of the
|
||||
AID; because we prefer to use OpenPGP serial numbers, we
|
||||
repalce a possibly already set one from a EF.GDO with this
|
||||
replace a possibly already set one from a EF.GDO with this
|
||||
one. Note, that for current OpenPGP cards, no EF.GDO exists
|
||||
and thus it won't matter at all. */
|
||||
rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
|
||||
|
@ -325,8 +325,6 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
|
||||
}
|
||||
if (card->p15card)
|
||||
card_p15_bind (card);
|
||||
else
|
||||
card_dinsig_bind (card);
|
||||
card->fnc.initialized = 1;
|
||||
}
|
||||
|
||||
|
@ -488,6 +488,8 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
|
||||
int sw;
|
||||
unsigned char *buffer;
|
||||
size_t bufferlen;
|
||||
int read_all = !nmax;
|
||||
size_t n;
|
||||
|
||||
if (!result || !resultlen)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
@ -496,18 +498,22 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
|
||||
|
||||
/* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
|
||||
we check for this limit. */
|
||||
if (offset > 32767 || nmax > 254)
|
||||
if (offset > 32767)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
do
|
||||
{
|
||||
buffer = NULL;
|
||||
bufferlen = 0;
|
||||
/* Fixme: Either the ccid driver of the TCOS cards have problems
|
||||
/* Fixme: Either the ccid driver or the TCOS cards have problems
|
||||
with an Le of 0. */
|
||||
if (read_all || nmax > 254)
|
||||
n = 254;
|
||||
else
|
||||
n = nmax;
|
||||
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
|
||||
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
|
||||
nmax? nmax : 254, &buffer, &bufferlen);
|
||||
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
|
||||
n, &buffer, &bufferlen);
|
||||
|
||||
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
|
||||
{
|
||||
@ -545,8 +551,12 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
|
||||
if (offset > 32767)
|
||||
break; /* We simply truncate the result for too large
|
||||
files. */
|
||||
if (nmax > bufferlen)
|
||||
nmax -= bufferlen;
|
||||
else
|
||||
nmax = 0;
|
||||
}
|
||||
while (!nmax && sw != SW_EOF_REACHED);
|
||||
while ((read_all && sw != SW_EOF_REACHED) || (!read_all && nmax));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
|
||||
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
|
||||
{ oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
|
||||
{ octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ct-API driver")},
|
||||
{ opcscDriver, "pcsc-driver", 2, N_("NAME|use NAME as PC/SC driver")},
|
||||
{ octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")},
|
||||
{ opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")},
|
||||
{ oDisableCCID, "disable-ccid", 0,
|
||||
#ifdef HAVE_LIBUSB
|
||||
N_("do not use the internal CCID driver")
|
||||
@ -126,6 +126,9 @@ static ARGPARSE_OPTS opts[] = {
|
||||
};
|
||||
|
||||
|
||||
#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
|
||||
|
||||
|
||||
static volatile int caught_fatal_sig = 0;
|
||||
|
||||
/* It is possible that we are currently running under setuid permissions */
|
||||
@ -302,6 +305,7 @@ main (int argc, char **argv )
|
||||
char *logfile = NULL;
|
||||
int debug_wait = 0;
|
||||
int gpgconf_list = 0;
|
||||
const char *config_filename = NULL;
|
||||
|
||||
set_strusage (my_strusage);
|
||||
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
|
||||
@ -334,7 +338,7 @@ main (int argc, char **argv )
|
||||
may_coredump = disable_core_dumps ();
|
||||
|
||||
/* Set default options. */
|
||||
opt.pcsc_driver = "libpcsclite.so";
|
||||
opt.pcsc_driver = DEFAULT_PCSC_DRIVER;
|
||||
|
||||
|
||||
shell = getenv ("SHELL");
|
||||
@ -466,7 +470,8 @@ main (int argc, char **argv )
|
||||
{
|
||||
fclose( configfp );
|
||||
configfp = NULL;
|
||||
xfree(configname);
|
||||
/* Keep a copy of the config name for use by --gpgconf-list. */
|
||||
config_filename = configname;
|
||||
configname = NULL;
|
||||
goto next_pass;
|
||||
}
|
||||
@ -507,19 +512,49 @@ main (int argc, char **argv )
|
||||
|
||||
if (gpgconf_list)
|
||||
{ /* List options and default values in the GPG Conf format. */
|
||||
char *filename;
|
||||
|
||||
filename = make_filename (opt.homedir, "scdaemon.conf", NULL);
|
||||
printf ("gpgconf-scdaemon.conf:\"%s\n", filename);
|
||||
xfree (filename);
|
||||
|
||||
printf ("verbose:\n"
|
||||
"quiet:\n"
|
||||
"debug-level:none\n"
|
||||
"log-file:\n"
|
||||
"force:\n"
|
||||
"faked-system-time:\n"
|
||||
"no-greeting:\n");
|
||||
/* The following list is taken from gnupg/tools/gpgconf-comp.c. */
|
||||
/* Option flags. YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
|
||||
FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE. */
|
||||
#define GC_OPT_FLAG_NONE 0UL
|
||||
/* The RUNTIME flag for an option indicates that the option can be
|
||||
changed at runtime. */
|
||||
#define GC_OPT_FLAG_RUNTIME (1UL << 3)
|
||||
/* The DEFAULT flag for an option indicates that the option has a
|
||||
default value. */
|
||||
#define GC_OPT_FLAG_DEFAULT (1UL << 4)
|
||||
/* The DEF_DESC flag for an option indicates that the option has a
|
||||
default, which is described by the value of the default field. */
|
||||
#define GC_OPT_FLAG_DEF_DESC (1UL << 5)
|
||||
/* The NO_ARG_DESC flag for an option indicates that the argument has
|
||||
a default, which is described by the value of the ARGDEF field. */
|
||||
#define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6)
|
||||
|
||||
printf ("gpgconf-scdaemon.conf:%lu:\"%s\"\n",
|
||||
GC_OPT_FLAG_DEFAULT,
|
||||
config_filename?config_filename:"/dev/null");
|
||||
|
||||
printf ("verbose:%lu:\n"
|
||||
"quiet:%lu:\n"
|
||||
"debug-level:%lu:\"none\":\n"
|
||||
"log-file:%lu:\n",
|
||||
GC_OPT_FLAG_NONE,
|
||||
GC_OPT_FLAG_NONE,
|
||||
GC_OPT_FLAG_DEFAULT,
|
||||
GC_OPT_FLAG_NONE );
|
||||
|
||||
printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE );
|
||||
printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE );
|
||||
printf ("pcsc-driver:%lu:\"%s\":\n",
|
||||
GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
|
||||
#ifdef HAVE_LIBUSB
|
||||
printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
|
||||
#endif
|
||||
#ifdef HAVE_LIBUSB
|
||||
printf ("disable-opensc:%lu:\n", GC_OPT_FLAG_NONE );
|
||||
#endif
|
||||
printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE );
|
||||
|
||||
|
||||
scd_exit (0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user