aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-dinsig.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app-dinsig.c')
-rw-r--r--scd/app-dinsig.c427
1 files changed, 0 insertions, 427 deletions
diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c
deleted file mode 100644
index 38fbc79ee..000000000
--- a/scd/app-dinsig.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/* app-dinsig.c - The DINSIG (DIN V 66291-1) card application.
- * Copyright (C) 2002, 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
- */
-
-
-/* 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 card 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 user 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.
-*/
-
-
-
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <time.h>
-
-#include "scdaemon.h"
-
-#include "iso7816.h"
-#include "app-common.h"
-#include "tlv.h"
-
-
-static int
-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. */
-int
-app_select_dinsig (APP app)
-{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 };
- int slot = app->slot;
- int rc;
-
- rc = iso7816_select_application (slot, aid, sizeof aid);
- if (!rc)
- {
- 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 = 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;
-}