3e461fd99365fc17e97dff90f280072c832242c6
[gnupg.git] / scd / card-dinsig.c
1 /* card-dinsig.c - German signature law (DINSIG) functions
2  *      Copyright (C) 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include <opensc-pkcs15.h>
29 #include <ksba.h>
30
31 #include "scdaemon.h"
32 #include "card-common.h"
33
34 static int dinsig_read_cert (CARD card, const char *certidstr,
35                              unsigned char **cert, size_t *ncert);
36
37
38
39 /* See card.c for interface description.  Frankly we don't do any real
40    enumeration but just check whether the well know files are
41    available.
42  */
43 static int
44 dinsig_enum_keypairs (CARD card, int idx,
45                       unsigned char *keygrip, char **keyid)
46 {
47   int rc;
48   unsigned char *buf;
49   size_t buflen;
50   KsbaError krc;
51   KsbaCert cert;
52
53   /* fixme: We should locate the application via the EF(DIR) and not
54      assume a Netkey card */
55   if (!idx)
56     rc = dinsig_read_cert (card, "DINSIG-DF01.C000", &buf, &buflen);
57   else if (idx == 1)
58     rc = dinsig_read_cert (card, "DINSIG-DF01.C200", &buf, &buflen);
59   else
60     rc = -1;
61   if (rc)
62     return rc;
63
64   cert = ksba_cert_new ();
65   if (!cert)
66     {
67       xfree (buf);
68       return GNUPG_Out_Of_Core;
69     }
70
71   krc = ksba_cert_init_from_mem (cert, buf, buflen); 
72   xfree (buf);
73   if (krc)
74     {
75       log_error ("failed to parse the certificate at idx %d: %s\n",
76                  idx, ksba_strerror (krc));
77       ksba_cert_release (cert);
78       return GNUPG_Card_Error;
79     }
80   if (card_help_get_keygrip (cert, keygrip))
81     {
82       log_error ("failed to calculate the keygrip at index %d\n", idx);
83       ksba_cert_release (cert);
84       return GNUPG_Card_Error;
85     }      
86   ksba_cert_release (cert);
87
88   /* return the iD */
89   if (keyid)
90     {
91       *keyid = xtrymalloc (17);
92       if (!*keyid)
93         return GNUPG_Out_Of_Core;
94       if (!idx)
95         strcpy (*keyid, "DINSIG-DF01.C000");
96       else
97         strcpy (*keyid, "DINSIG-DF01.C200");
98     }
99   
100   return 0;
101 }
102
103
104 \f
105 /* See card.c for interface description */
106 static int
107 dinsig_read_cert (CARD card, const char *certidstr,
108                   unsigned char **cert, size_t *ncert)
109 {
110   int rc;
111   struct sc_path path;
112   struct sc_file *file;
113   unsigned char *buf;
114   int buflen;
115
116   if (!strcmp (certidstr, "DINSIG-DF01.C000"))
117     sc_format_path ("3F00DF01C000", &path);
118   else if (!strcmp (certidstr, "DINSIG-DF01.C200"))
119     sc_format_path ("3F00DF01C200", &path);
120   else
121     return GNUPG_Invalid_Id;
122
123   rc = sc_select_file (card->scard, &path, &file);
124   if (rc) 
125     {
126       log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
127       return map_sc_err (rc);
128     }
129   if (file->type != SC_FILE_TYPE_WORKING_EF
130       || file->ef_structure != SC_FILE_EF_TRANSPARENT)
131     {
132       log_error ("wrong type or structure of certificate EF\n");
133       sc_file_free (file);
134       return GNUPG_Card_Error;
135     }
136   if (file->size < 20) /* check against a somewhat arbitrary length */
137     { 
138       log_error ("certificate EF too short\n");
139       sc_file_free (file);
140       return GNUPG_Card_Error;
141     }
142   buf = xtrymalloc (file->size);
143   if (!buf)
144     {
145       sc_file_free (file);
146       return GNUPG_Out_Of_Core;
147     }
148       
149   rc = sc_read_binary (card->scard, 0, buf, file->size, 0);
150   if (rc >= 0 && rc != file->size)
151     {
152       log_error ("short read on certificate EF\n");
153       sc_file_free (file);
154       xfree (buf);
155       return GNUPG_Card_Error;
156     }
157   sc_file_free (file);
158   if (rc < 0) 
159     {
160       log_error ("error reading certificate EF: %s\n", sc_strerror (rc));
161       xfree (buf);
162       return map_sc_err (rc);
163     }
164   buflen = rc;
165
166   /* The object is not a plain certificate but wrapped into id-at
167      userCertificate - fixme: we should check the specs and decided
168      whether libksba should support it */
169   if (buflen > 9 && buf[0] == 0x30 && buf[4] == 6 && buf[5] == 3
170       && buf[6] == 0x55 && buf[7] == 4 && buf[8] == 0x24)
171     {
172       /* We have to strip the padding.  Although this is a good idea
173          anyway, we have to do it due to a KSBA problem; KSBA does not
174          work correct when the buffer is larger than the ASN.1
175          structure and the certificates here are padded with FF.  So
176          as a workaround we look at the outer structure to get the
177          size of the entire thing and adjust the buflen.  We can only
178          do this when there is a 2 byte length field */
179       size_t seqlen;
180       if (buf[1] == 0x82)
181         {
182           seqlen = ((buf[2] << 8) | buf[3]) + 4;
183           if (seqlen < buflen)
184             buflen = seqlen;
185         }
186       memmove (buf, buf+9, buflen-9);
187       buflen -= 9;
188     } 
189
190   *cert = buf;
191   *ncert = buflen;
192   return 0;
193 }
194
195
196
197
198 /* Bind our operations to the card */
199 void
200 card_dinsig_bind (CARD card)
201 {
202   card->fnc.enum_keypairs = dinsig_enum_keypairs;
203   card->fnc.read_cert     = dinsig_read_cert;
204
205 }