summaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2004-12-02 08:48:09 +0100
committerWerner Koch <wk@gnupg.org>2004-12-02 08:48:09 +0100
commit4a73d94757f61e4aa2d1841535409622c2c473e3 (patch)
tree3848fcc2f05e79f26e776f6e4dfa133aeff8d04e /scd
parent2004-11-30 Timo Schulz <ts@g10code.com> (diff)
downloadgnupg2-4a73d94757f61e4aa2d1841535409622c2c473e3.tar.xz
gnupg2-4a73d94757f61e4aa2d1841535409622c2c473e3.zip
First take on a W32 port
Diffstat (limited to 'scd')
-rw-r--r--scd/app-p15.c691
1 files changed, 691 insertions, 0 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c
new file mode 100644
index 000000000..af2eed465
--- /dev/null
+++ b/scd/app-p15.c
@@ -0,0 +1,691 @@
+/* app-p15.c - The pkcs#15 card application.
+ * 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 <assert.h>
+#include <time.h>
+
+#include "scdaemon.h"
+
+#include "iso7816.h"
+#include "app-common.h"
+#include "tlv.h"
+
+
+/* Context local to this application. */
+struct app_local_s
+{
+ unsigned short home_df; /* The home DF. Note, that we don't yet
+ support a multilevel hierachy. Thus we
+ assume this is directly below the MF. */
+ struct
+ {
+ unsigned short private_keys;
+ unsigned short public_keys;
+ unsigned short trusted_public_keys;
+ unsigned short secret_keys;
+ unsigned short certificates;
+ unsigned short trusted_certificates;
+ unsigned short useful_certificates;
+ unsigned short data_objects;
+ unsigned short auth_objects;
+ } odf;
+
+
+};
+
+
+
+
+/* Do a select and a read for the file with EFID. EFID is a
+ desctription of the EF to be used with error messages. On success
+ BUFFER and BUFLEN contain the entire content of the EF. The caller
+ must free BUFFER but only on success. */
+static gpg_error_t
+select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
+ unsigned char **buffer, size_t *buflen)
+{
+ gpg_error_t err;
+
+ err = iso7816_select_file (slot, efid, 0, NULL, NULL);
+ if (err)
+ {
+ log_error ("error selecting %s (0x%04X): %s\n",
+ efid_desc, efid, gpg_strerror (err));
+ return err;
+ }
+ err = iso7816_read_binary (slot, 0, 0, buffer, buflen);
+ if (err)
+ {
+ log_error ("error reading %s (0x%04X): %s\n",
+ efid_desc, efid, gpg_strerror (err));
+ return err;
+ }
+ return 0;
+}
+
+
+
+
+/* Read and parse the Object Directory File and store away the
+ pointers.
+
+ Example of such a file:
+
+ A0 06 30 04 04 02 60 34 = Private Keys
+ A4 06 30 04 04 02 60 35 = Certificates
+ A5 06 30 04 04 02 60 36 = TrustedCertificates
+ A7 06 30 04 04 02 60 37 = DataObjects
+ A8 06 30 04 04 02 60 38 = AuthObjects
+
+ These are all PathOrObjects using the path CHOICE. The paths are
+ octet strings of length 2. Using this Path CHOICE is recommended,
+ so we only implement that for now.
+*/
+static gpg_error_t
+read_ef_odf (app_t app)
+{
+ gpg_error_t err;
+ unsigned char *buffer, *p;
+ size_t buflen;
+ unsigned short value;
+
+ err = select_and_read_binary (app->slot, 0x5031, "ODF", &buffer, &buflen);
+ if (err)
+ return err;
+
+ if (len < 8)
+ {
+ log_error ("error: ODF too short\n");
+ xfree (buffer);
+ return gpg_error (GPG_ERR_INV_OBJ);
+ }
+ for (p=buffer; buflen >= 8; p += 8, buflen -= 8)
+ {
+ if ( (p[0] & 0xf0) != 0xA0
+ || memcmp (p+1, "\x06\x30\x04\x04\x02", 5) )
+ {
+ log_error ("ODF format is not supported by us\n");
+ xfree (buffer);
+ return gpg_error (GPG_ERR_INV_OBJ);
+ }
+ switch ((p[0] & 0x0f))
+ {
+ case 0: value = app->app_local->odf.private_keys; break;
+ case 1: value = app->app_local->odf.public_keys; break;
+ case 2: value = app->app_local->odf.trusted_public_keys; break;
+ case 3: value = app->app_local->odf.secret_keys; break;
+ case 4: value = app->app_local->odf.certificates; break;
+ case 5: value = app->app_local->odf.trusted_certificates; break;
+ case 6: value = app->app_local->odf.useful_certificates; break;
+ case 7: value = app->app_local->odf.data_objects; break;
+ case 8: value = app->app_local->odf.auth_objects; break;
+ default: value = 0; break;
+ }
+ if (value)
+ {
+ log_error ("duplicate object type %d in ODF ignored\n",(p[0)&0x0f));
+ continue;
+ }
+ value = ((p[6] << 8) | p[7]);
+ switch ((p[0] & 0x0f))
+ {
+ case 0: app->app_local->odf.private_keys = value; break;
+ case 1: app->app_local->odf.public_keys = value; break;
+ case 2: app->app_local->odf.trusted_public_keys = value; break;
+ case 3: app->app_local->odf.secret_keys = value; break;
+ case 4: app->app_local->odf.certificates = value; break;
+ case 5: app->app_local->odf.trusted_certificates = value; break;
+ case 6: app->app_local->odf.useful_certificates = value; break;
+ case 7: app->app_local->odf.data_objects = value; break;
+ case 8: app->app_local->odf.auth_objects = value; break;
+ default:
+ log_error ("unknown object type %d in ODF ignored\n", (p[0)&0x0f));
+ }
+ }
+
+ if (buflen)
+ log_info ("warning: %u bytes of garbage detected at end of ODF\n", buflen);
+
+ xfree (buffer);
+ return 0;
+}
+
+
+
+/* Read and parse the Private Key Directory Files. */
+/*
+ 6034 (privatekeys)
+
+30 33 30 11 0C 08 53 4B 2E 43 48 2E 44 53 03 02 030...SK.CH.DS..
+06 80 04 01 07 30 0C 04 01 01 03 03 06 00 40 02 .....0........@.
+02 00 50 A1 10 30 0E 30 08 04 06 3F 00 40 16 00 ..P..0.0...?.@..
+50 02 02 04 00 30 33 30 11 0C 08 53 4B 2E 43 48 P....030...SK.CH
+2E 4B 45 03 02 06 80 04 01 0A 30 0C 04 01 0C 03 .KE.......0.....
+03 06 44 00 02 02 00 52 A1 10 30 0E 30 08 04 06 ..D....R..0.0...
+3F 00 40 16 00 52 02 02 04 00 30 34 30 12 0C 09 ?.@..R....040...
+53 4B 2E 43 48 2E 41 55 54 03 02 06 80 04 01 0A SK.CH.AUT.......
+30 0C 04 01 0D 03 03 06 20 00 02 02 00 51 A1 10 0....... ....Q..
+30 0E 30 08 04 06 3F 00 40 16 00 51 02 02 04 00 0.0...?.@..Q....
+30 37 30 15 0C 0C 53 4B 2E 43 48 2E 44 53 2D 53 070...SK.CH.DS-S
+50 58 03 02 06 80 04 01 0A 30 0C 04 01 02 03 03 PX.......0......
+06 20 00 02 02 00 53 A1 10 30 0E 30 08 04 06 3F . ....S..0.0...?
+00 40 16 00 53 02 02 04 00 00 00 00 00 00 00 00 .@..S...........
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+*/
+static gpg_error_t
+read_ef_prkdf (app_t app)
+{
+
+
+}
+
+/* Read and parse the Public Key Directory Files. */
+static gpg_error_t
+read_ef_pukdf (app_t app)
+{
+
+
+}
+
+
+/* Read and parse the Certificate Directory Files. */
+/*
+
+6035 (certificates)
+
+30 2A 30 15 0C 0C 43 5F 58 35 30 39 2E 43 48 2E 0*0...C_X509.CH.
+44 53 03 02 06 40 04 01 0A 30 03 04 01 01 A1 0C DS...@...0......
+30 0A 30 08 04 06 3F 00 40 16 C0 00 30 2A 30 15 0.0...?.@...0*0.
+0C 0C 43 5F 58 35 30 39 2E 43 48 2E 4B 45 03 02 ..C_X509.CH.KE..
+06 40 04 01 0A 30 03 04 01 0C A1 0C 30 0A 30 08 .@...0......0.0.
+04 06 3F 00 40 16 C2 00 30 2B 30 16 0C 0D 43 5F ..?.@...0+0...C_
+58 35 30 39 2E 43 48 2E 41 55 54 03 02 06 40 04 X509.CH.AUT...@.
+01 0A 30 03 04 01 0D A1 0C 30 0A 30 08 04 06 3F ..0......0.0...?
+00 40 16 C5 00 30 2E 30 19 0C 10 43 5F 58 35 30 .@...0.0...C_X50
+39 2E 43 48 2E 44 53 2D 53 50 58 03 02 06 40 04 9.CH.DS-SPX...@.
+01 0A 30 03 04 01 02 A1 0C 30 0A 30 08 04 06 3F ..0......0.0...?
+00 40 16 C1 20 00 00 00 00 00 00 00 00 00 00 00 .@.. ...........
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ 0 42: SEQUENCE {
+ 2 21: SEQUENCE { -- commonObjectAttributes
+ 4 12: UTF8String 'C_X509.CH.DS'
+ 18 2: BIT STRING 6 unused bits
+ : '10'B (bit 1)
+ 22 1: OCTET STRING 0A
+ : }
+ 25 3: SEQUENCE { -- commonCertificateAttributes
+ 27 1: OCTET STRING 01
+ : }
+ 30 12: [1] { -- certAttributes
+ 32 10: SEQUENCE {
+ 34 8: SEQUENCE {
+ 36 6: OCTET STRING 3F 00 40 16 C0 00
+ : }
+ : }
+ : }
+ : }
+
+
+
+6036 (trustedcertificates)
+
+30 35 30 06 03 02 00 00 04 00 30 16 04 14 2D 36 050.......0...-6
+33 39 33 33 39 34 30 33 39 37 37 36 34 30 31 32 3933940397764012
+31 36 A1 13 30 11 30 0F 04 06 3F 00 40 16 C7 08 16..0.0...?.@...
+02 01 00 80 02 02 29 30 35 30 06 03 02 00 00 04 ......)050......
+00 30 16 04 14 2D 34 30 31 39 30 35 32 37 32 36 .0...-4019052726
+38 30 31 36 39 33 34 39 32 A1 13 30 11 30 0F 04 801693492..0.0..
+06 3F 00 40 16 C7 0E 02 01 00 80 02 04 12 30 34 .?.@..........04
+30 06 03 02 00 00 04 00 30 15 04 13 37 39 36 33 0.......0...7963
+32 38 33 36 35 30 37 36 36 34 38 32 39 36 30 A1 283650766482960.
+13 30 11 30 0F 04 06 3F 00 40 16 C0 08 02 01 00 .0.0...?.@......
+80 02 04 11 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ 0 53: SEQUENCE {
+ 2 6: SEQUENCE {
+ 4 2: BIT STRING
+ : '00000000'B
+ : Error: Spurious zero bits in bitstring.
+ 8 0: OCTET STRING
+ : Error: Object has zero length.
+ : }
+ 10 22: SEQUENCE {
+ 12 20: OCTET STRING '-6393394039776401216'
+ : }
+ 34 19: [1] {
+ 36 17: SEQUENCE {
+ 38 15: SEQUENCE {
+ 40 6: OCTET STRING 3F 00 40 16 C7 08
+ 48 1: INTEGER 0 -- index
+ 51 2: [0] 02 29 -- length
+ : }
+ : }
+ : }
+ : }
+
+
+*/
+static gpg_error_t
+read_ef_cdf (app_t app)
+{
+ gpg_error_t err;
+ unsigned char *buffer = NULL;
+ size_t buflen;
+ unsigned short value;
+ unsigned short fid;
+ const unsigned char *p;
+ size_t n, objlen, hdrlen;
+ int class, tag, constructed, ndef;
+
+ fid = app->app_local->odf.certificates;
+ if (!fid)
+ return 0; /* No certificates. */
+
+ err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen);
+ if (err)
+ return err;
+
+ p = buffer;
+ n = buflen;
+
+ /* Loop over the records. We stop as soon as we detect a new record
+ starting with 0x00 or 0xff as these values are commonly used to pad
+ the the read datablocks and are no valid ASN.1 encoding. */
+ while (n && *p && *p == 0xff)
+ {
+ const unsigned char *pp;
+ size_t nn;
+
+ err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && (objlen > n || tag != TAG_SEQUENCE))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ {
+ log_error ("error parsing CDF record: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ pp = p;
+ nn = objlen;
+ p += objlen;
+ n -= objlen;
+
+ /* Skip the commonObjectAttributes. */
+ err = parse_ber_header (&pp, &nn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && (objlen > nn || tag != TAG_SEQUENCE))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ {
+ log_error ("error parsing CDF record: %s - skipped\n",
+ gpg_strerror (err));
+ continue;
+ }
+ pp += objlen;
+ nn -= objlen;
+
+ /* Skip the commonCertificateAttributes. */
+ err = parse_ber_header (&pp, &nn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && (objlen > nn || tag != TAG_SEQUENCE))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ {
+ log_error ("error parsing CDF record: %s - skipped\n",
+ gpg_strerror (err));
+ continue;
+ }
+ pp += objlen;
+ nn -= objlen;
+
+ /* FIXME: Check that this is a reference to a certificate. */
+
+
+ }
+
+
+ leave:
+ xfree (buffer);
+ return err;
+}
+
+/* Read and parse Authentication Object Directory Files. */
+static gpg_error_t
+read_ef_aodf (app_t app)
+{
+
+}
+
+
+/* 6037 (dataobjects)
+
+30 1E 30 0B 0C 06 45 46 2E 47 44 4F 04 01 0A 30 0.0...EF.GDO...0
+02 0C 00 A1 0B 30 09 04 04 3F 00 2F 02 80 01 0E .....0...?./....
+30 30 30 18 0C 0F 64 69 73 70 6C 61 79 20 6D 65 000...display me
+73 73 61 67 65 03 02 06 C0 04 01 0A 30 05 0C 03 ssage.......0...
+42 53 53 A1 0D 30 0B 04 06 3F 00 40 16 D0 00 80 BSS..0...?.@....
+01 20 30 2B 30 0C 0C 03 53 53 4F 03 02 06 C0 04 . 0+0...SSO.....
+01 0A 30 0B 0C 09 53 61 66 65 47 75 61 72 64 A1 ..0...SafeGuard.
+0E 30 0C 04 06 3F 00 0F FF 30 02 80 02 03 00 30 .0...?...0.....0
+30 30 11 0C 08 53 47 41 53 64 61 74 61 03 02 06 00...SGASdata...
+C0 04 01 0A 30 0B 0C 09 53 61 66 65 47 75 61 72 ....0...SafeGuar
+64 A1 0E 30 0C 04 06 3F 00 0F FF 40 01 80 02 00 d..0...?...@....
+80 30 30 30 11 0C 08 55 73 65 72 64 61 74 61 03 .000...Userdata.
+02 06 40 04 01 0A 30 0B 0C 09 53 61 66 65 47 75 ..@...0...SafeGu
+61 72 64 A1 0E 30 0C 04 06 3F 00 0F FF 30 01 80 ard..0...?...0..
+02 01 00 30 2C 30 13 0C 0A 62 61 73 69 63 20 64 ...0,0...basic d
+61 74 61 03 02 06 C0 04 01 0A 30 05 0C 03 49 44 ata.......0...ID
+44 A1 0E 30 0C 04 06 3F 00 40 17 D0 01 80 02 02 D..0...?.@......
+00 30 2F 30 16 0C 0D 65 78 74 65 6E 64 65 64 20 .0/0...extended
+64 61 74 61 03 02 06 C0 04 01 0A 30 05 0C 03 49 data.......0...I
+44 44 A1 0E 30 0C 04 06 3F 00 40 17 D0 02 80 02 DD..0...?.@.....
+08 00 30 34 30 1B 0C 12 73 70 65 63 69 61 6C 20 ..040...special
+70 72 69 76 69 6C 65 67 65 73 03 02 06 C0 04 01 privileges......
+0A 30 05 0C 03 49 44 44 A1 0E 30 0C 04 06 3F 00 .0...IDD..0...?.
+40 17 D0 03 80 02 04 00 @.......
+
+ 0 30: SEQUENCE {
+ 2 11: SEQUENCE {
+ 4 6: UTF8String 'EF.GDO'
+ 12 1: OCTET STRING 0A
+ : }
+ 15 2: SEQUENCE {
+ 17 0: UTF8String
+ : Error: Object has zero length.
+ : }
+ 19 11: [1] {
+ 21 9: SEQUENCE {
+ 23 4: OCTET STRING 3F 00 2F 02
+ 29 1: [0] 0E
+ : }
+ : }
+ : }
+
+
+
+6038 (authobjects)
+
+30 2A 30 0B 0C 05 62 61 73 69 63 03 02 00 C0 30 0*0...basic....0
+03 04 01 0A A1 16 30 14 03 03 00 0C 10 0A 01 01 ......0.........
+02 01 06 02 01 06 02 01 08 80 01 01 30 51 30 19 ............0Q0.
+0C 13 73 70 65 63 69 66 69 63 20 50 49 4E 20 66 ..specific PIN f
+6F 72 20 44 53 03 02 00 C0 30 03 04 01 07 A1 2F or DS....0...../
+30 2D 03 03 00 4C 10 0A 01 01 02 01 06 02 01 06 0-...L..........
+02 01 08 80 01 02 18 0F 32 30 30 32 30 34 31 39 ........20020419
+31 32 31 33 34 31 5A 30 06 04 04 3F 00 40 16 121341Z0...?.@.
+
+ 0 42: SEQUENCE {
+ 2 11: SEQUENCE {
+ 4 5: UTF8String 'basic'
+ 11 2: BIT STRING
+ : '00000011'B
+ : Error: Spurious zero bits in bitstring.
+ : }
+ 15 3: SEQUENCE {
+ 17 1: OCTET STRING 0A
+ : }
+ 20 22: [1] {
+ 22 20: SEQUENCE {
+ 24 3: BIT STRING
+ : '0000100000110000'B
+ : Error: Spurious zero bits in bitstring.
+ 29 1: ENUMERATED 1
+ 32 1: INTEGER 6
+ 35 1: INTEGER 6
+ 38 1: INTEGER 8
+ 41 1: [0] 01
+ : }
+ : }
+ : }
+
+
+
+*/
+
+
+/* Read and parse the EF(TokenInfo).
+
+TokenInfo ::= SEQUENCE {
+ version INTEGER {v1(0)} (v1,...),
+ serialNumber OCTET STRING,
+ manufacturerID Label OPTIONAL,
+ label [0] Label OPTIONAL,
+ tokenflags TokenFlags,
+ seInfo SEQUENCE OF SecurityEnvironmentInfo OPTIONAL,
+ recordInfo [1] RecordInfo OPTIONAL,
+ supportedAlgorithms [2] SEQUENCE OF AlgorithmInfo OPTIONAL,
+ ...,
+ issuerId [3] Label OPTIONAL,
+ holderId [4] Label OPTIONAL,
+ lastUpdate [5] LastUpdate OPTIONAL,
+ preferredLanguage PrintableString OPTIONAL -- In accordance with
+ -- IETF RFC 1766
+} (CONSTRAINED BY { -- Each AlgorithmInfo.reference value must be unique --})
+
+TokenFlags ::= BIT STRING {
+ readonly (0),
+ loginRequired (1),
+ prnGeneration (2),
+ eidCompliant (3)
+}
+
+
+ 5032:
+
+30 31 02 01 00 04 04 05 45 36 9F 0C 0C 44 2D 54 01......E6...D-T
+72 75 73 74 20 47 6D 62 48 80 14 4F 66 66 69 63 rust GmbH..Offic
+65 20 69 64 65 6E 74 69 74 79 20 63 61 72 64 03 e identity card.
+02 00 40 20 63 61 72 64 03 02 00 40 00 00 00 00 ..@ card...@....
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ 0 49: SEQUENCE {
+ 2 1: INTEGER 0
+ 5 4: OCTET STRING 05 45 36 9F
+ 11 12: UTF8String 'D-Trust GmbH'
+ 25 20: [0] 'Office identity card'
+ 47 2: BIT STRING
+ : '00000010'B (bit 1)
+ : Error: Spurious zero bits in bitstring.
+ : }
+
+
+
+
+ */
+static gpg_error_t
+read_ef_tokeninfo (app_t app)
+{
+ unsigned short efid = 0x5032;
+
+}
+
+
+/* Get all the basic information from the pkcs#15 card, check the
+ structure and init our context. This is used once at application
+ initialization. */
+static gpg_error_t
+read_p15_info (app_t app)
+{
+ gpg_error_t err;
+
+ err = read_ed_odf (app);
+ if (err)
+ return err;
+
+}
+
+
+static int
+do_learn_status (APP app, CTRL ctrl)
+{
+ gpg_error_t err;
+ char ct_buf[100], id_buf[100];
+ int i;
+
+ /* Output information about all useful objects. */
+ for (i=0; objlist[i].fid; i++)
+ {
+ if (filelist[i].certtype)
+ {
+ 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
+ context so that a following readcert does only need to
+ read that many bytes. */
+ sprintf (ct_buf, "%d", filelist[i].certtype);
+ sprintf (id_buf, "P15-DF01.%04X", filelist[i].fid);
+ send_status_info (ctrl, "CERTINFO",
+ ct_buf, strlen (ct_buf),
+ id_buf, strlen (id_buf),
+ NULL, (size_t)0);
+ }
+ }
+ else if (filelist[i].iskeypair)
+ {
+ char gripstr[40+1];
+
+ err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
+ if (err)
+ log_error ("can't get keygrip from FID 0x%04X: %s\n",
+ filelist[i].fid, gpg_strerror (err));
+ else
+ {
+ sprintf (id_buf, "P15-DF01.%04X", filelist[i].fid);
+ send_status_info (ctrl, "KEYPAIRINFO",
+ gripstr, 40,
+ id_buf, strlen (id_buf),
+ NULL, (size_t)0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+/* Release all resources. */
+static void
+do_deinit (app_t app)
+{
+ if (app && app->app_local)
+ {
+ xfree (app->app_local);
+ app->app_local = NULL;
+ }
+}
+
+
+/* Select the PKCS#15 application on the card in SLOT. */
+int
+app_select_p15 (APP app)
+{
+ static char const aid[] = { 0xA0, 0, 0, 0, 0x63,
+ 0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
+ int slot = app->slot;
+ int rc;
+
+ rc = iso7816_select_application (slot, aid, sizeof aid);
+ if (!rc)
+ {
+ app->apptype = "P15";
+
+ app->app_local = xtrycalloc (1, sizeof *app->app_local);
+ if (!app->app_local)
+ {
+ rc = gpg_error_from_errno (errno);
+ goto leave;
+ }
+
+ /* Read basic information and check whether this is a real
+ card. */
+ rc = read_p15_info (app);
+
+ /* Special serial number munging. We need to do one case here
+ because we need to access the EF(TokenInfo). */
+ if (app->serialnolen == 12
+ && !memcmp (app->serial, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12))
+ {
+ /* 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
+ rc = app_munge_serialno (app);
+
+ app->fnc.deinit = do_deinit;
+ 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 = do_decipher;
+ app->fnc.change_pin = NULL;
+ app->fnc.check_pin = NULL;
+
+ leave:
+ if (rc)
+ {
+ xfree (app->app_local);
+ app->app_local = NULL;
+ }
+
+ }
+
+ return rc;
+}
+
+