po: Update Japanese Translation.
[gnupg.git] / scd / app-help.c
1 /* app-help.c - Application helper functions
2  * Copyright (C) 2004, 2009 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 3 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, see <https://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "scdaemon.h"
27 #include "app-common.h"
28 #include "iso7816.h"
29 #include "../common/tlv.h"
30
31
32 /* Count the number of bits, assuming that A represents an unsigned
33  * big integer of length LEN bytes.  If A is NULL a length of 0 is
34  * returned. */
35 unsigned int
36 app_help_count_bits (const unsigned char *a, size_t len)
37 {
38   unsigned int n = len * 8;
39   int i;
40
41   if (!a)
42     return 0;
43
44   for (; len && !*a; len--, a++, n -=8)
45     ;
46   if (len)
47     {
48       for (i=7; i && !(*a & (1<<i)); i--)
49         n--;
50     }
51   return n;
52 }
53
54
55 /* Return the KEYGRIP for the certificate CERT as an hex encoded
56    string in the user provided buffer HEXKEYGRIP which must be of at
57    least 41 bytes. */
58 gpg_error_t
59 app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
60 {
61   gpg_error_t err;
62   gcry_sexp_t s_pkey;
63   ksba_sexp_t p;
64   size_t n;
65   unsigned char array[20];
66
67   p = ksba_cert_get_public_key (cert);
68   if (!p)
69     return gpg_error (GPG_ERR_BUG);
70   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
71   if (!n)
72     return gpg_error (GPG_ERR_INV_SEXP);
73   err = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
74   xfree (p);
75   if (err)
76     return err; /* Can't parse that S-expression. */
77   if (!gcry_pk_get_keygrip (s_pkey, array))
78     {
79       gcry_sexp_release (s_pkey);
80       return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/
81     }
82   gcry_sexp_release (s_pkey);
83
84   bin2hex (array, 20, hexkeygrip);
85
86   return 0;
87 }
88
89
90 gpg_error_t
91 app_help_pubkey_from_cert (const void *cert, size_t certlen,
92                            unsigned char **r_pk, size_t *r_pklen)
93 {
94   gpg_error_t err;
95   ksba_cert_t kc;
96   unsigned char *pk;
97   size_t pklen;
98
99   *r_pk = NULL;
100   *r_pklen = 0;
101
102   err = ksba_cert_new (&kc);
103   if (err)
104     return err;
105
106   err = ksba_cert_init_from_mem (kc, cert, certlen);
107   if (err)
108     goto leave;
109
110   pk = ksba_cert_get_public_key (kc);
111   if (!pk)
112     {
113       err = gpg_error (GPG_ERR_NO_PUBKEY);
114       goto leave;
115     }
116   pklen = gcry_sexp_canon_len (pk, 0, NULL, &err);
117
118  leave:
119   if (!err)
120     {
121       *r_pk = pk;
122       *r_pklen = pklen;
123     }
124   else
125     ksba_free (pk);
126   ksba_cert_release (kc);
127   return err;
128 }
129
130 /* Given the SLOT and the File ID FID, return the length of the
131    certificate contained in that file. Returns 0 if the file does not
132    exists or does not contain a certificate.  If R_CERTOFF is not
133    NULL, the length the header will be stored at this address; thus to
134    parse the X.509 certificate a read should start at that offset.
135
136    On success the file is still selected.
137 */
138 size_t
139 app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff)
140 {
141   gpg_error_t err;
142   unsigned char *buffer;
143   const unsigned char *p;
144   size_t buflen, n;
145   int class, tag, constructed, ndef;
146   size_t resultlen, objlen, hdrlen;
147
148   err = iso7816_select_file (slot, fid, 0);
149   if (err)
150     {
151       log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
152       return 0;
153     }
154
155   err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen);
156   if (err)
157     {
158       log_info ("error reading certificate from FID 0x%04X: %s\n",
159                  fid, gpg_strerror (err));
160       return 0;
161     }
162
163   if (!buflen || *buffer == 0xff)
164     {
165       log_info ("no certificate contained in FID 0x%04X\n", fid);
166       xfree (buffer);
167       return 0;
168     }
169
170   p = buffer;
171   n = buflen;
172   err = parse_ber_header (&p, &n, &class, &tag, &constructed,
173                           &ndef, &objlen, &hdrlen);
174   if (err)
175     {
176       log_info ("error parsing certificate in FID 0x%04X: %s\n",
177                 fid, gpg_strerror (err));
178       xfree (buffer);
179       return 0;
180     }
181
182   /* All certificates should commence with a SEQUENCE except for the
183      special ROOT CA which are enclosed in a SET. */
184   if ( !(class == CLASS_UNIVERSAL &&  constructed
185          && (tag == TAG_SEQUENCE || tag == TAG_SET)))
186     {
187       log_info ("data at FID 0x%04X does not look like a certificate\n", fid);
188       return 0;
189     }
190
191   resultlen = objlen + hdrlen;
192   if (r_certoff)
193     {
194       /* The callers want the offset to the actual certificate. */
195       *r_certoff = hdrlen;
196
197       err = parse_ber_header (&p, &n, &class, &tag, &constructed,
198                               &ndef, &objlen, &hdrlen);
199       if (err)
200         return 0;
201
202       if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
203         {
204           /* The certificate seems to be contained in a
205              userCertificate container.  Assume the following sequence
206              is the certificate. */
207           *r_certoff += hdrlen + objlen;
208           if (*r_certoff > resultlen)
209             {
210               *r_certoff = 0;
211               return 0; /* That should never happen. */
212             }
213         }
214       else
215         *r_certoff = 0;
216     }
217
218   return resultlen;
219 }