* command.c (scd_update_reader_status_file): Write status files.
[gnupg.git] / scd / app-help.c
1 /* app-help.c - Application helper functions
2  *      Copyright (C) 2004 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
27 #include "scdaemon.h"
28 #include "app-common.h"
29 #include "iso7816.h"
30 #include "tlv.h"
31
32 /* Return the KEYGRIP for the certificate CERT as an hex encoded
33    string in the user provided buffer HEXKEYGRIP which must be of at
34    least 41 bytes. */
35 gpg_error_t
36 app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
37 {
38   gpg_error_t err;
39   gcry_sexp_t s_pkey;
40   ksba_sexp_t p;
41   size_t n;
42   unsigned char array[20];
43   int i;
44
45   p = ksba_cert_get_public_key (cert);
46   if (!p)
47     return gpg_error (GPG_ERR_BUG);
48   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
49   if (!n)
50     return gpg_error (GPG_ERR_INV_SEXP);
51   err = gcry_sexp_sscan (&s_pkey, NULL, p, n);
52   xfree (p);
53   if (err)
54     return err; /* Can't parse that S-expression. */
55   if (!gcry_pk_get_keygrip (s_pkey, array))
56     {
57       gcry_sexp_release (s_pkey);
58       return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/
59     }
60   gcry_sexp_release (s_pkey);
61
62   for (i=0; i < 20; i++)
63     sprintf (hexkeygrip+i*2, "%02X", array[i]);
64
65   return 0;
66 }
67
68
69
70 /* Given the SLOT and the File ID FID, return the length of the
71    certificate contained in that file. Returns 0 if the file does not
72    exists or does not contain a certificate.  If R_CERTOFF is not
73    NULL, the length the header will be stored at this address; thus to
74    parse the X.509 certificate a read should start at that offset.
75
76    On success the file is still selected.
77 */
78 size_t
79 app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff)
80 {
81   gpg_error_t err;
82   unsigned char *buffer;
83   const unsigned char *p;
84   size_t buflen, n;
85   int class, tag, constructed, ndef;
86   size_t resultlen, objlen, hdrlen;
87
88   err = iso7816_select_file (slot, fid, 0, NULL, NULL);
89   if (err)
90     {
91       log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
92       return 0;
93     }
94
95   err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen);
96   if (err)
97     {
98       log_info ("error reading certificate from FID 0x%04X: %s\n",
99                  fid, gpg_strerror (err));
100       return 0;
101     }
102   
103   if (!buflen || *buffer == 0xff)
104     {
105       log_info ("no certificate contained in FID 0x%04X\n", fid);
106       xfree (buffer);
107       return 0;
108     }
109
110   p = buffer;
111   n = buflen;
112   err = parse_ber_header (&p, &n, &class, &tag, &constructed,
113                           &ndef, &objlen, &hdrlen);
114   if (err)
115     {
116       log_info ("error parsing certificate in FID 0x%04X: %s\n",
117                 fid, gpg_strerror (err));
118       xfree (buffer);
119       return 0;
120     }
121
122   /* All certificates should commence with a SEQUENCE except for the
123      special ROOT CA which are enclosed in a SET. */
124   if ( !(class == CLASS_UNIVERSAL &&  constructed
125          && (tag == TAG_SEQUENCE || tag == TAG_SET)))
126     {
127       log_info ("contents of FID 0x%04X does not look like a certificate\n",
128                 fid);
129       return 0;
130     }
131
132   resultlen = objlen + hdrlen;
133   if (r_certoff)
134     {
135       /* The callers want the offset to the actual certificate. */
136       *r_certoff = hdrlen;
137
138       err = parse_ber_header (&p, &n, &class, &tag, &constructed,
139                               &ndef, &objlen, &hdrlen);
140       if (err)
141         return 0;
142
143       if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
144         {
145           /* The certificate seems to be contained in a
146              userCertificate container.  Assume the following sequence
147              is the certificate. */
148           *r_certoff += hdrlen + objlen;
149           if (*r_certoff > resultlen)
150             {
151               *r_certoff = 0;
152               return 0; /* That should never happen. */
153             }
154         }
155       else
156         *r_certoff = 0;
157     }
158
159   return resultlen;
160 }
161
162