1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00
gnupg/scd/card-dinsig.c
Werner Koch b008274afd Nuked almost all trailing white space.
We better do this once and for all instead of cluttering all future
commits with diffs of trailing white spaces.  In the majority of cases
blank or single lines are affected and thus this change won't disturb
a git blame too much.  For future commits the pre-commit scripts
checks that this won't happen again.
2011-02-04 12:57:53 +01:00

258 lines
7.7 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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