Changed the way i18n files are located under Windows. The setting of the
[gnupg.git] / sm / fingerprint.c
1 /* fingerprint.c - Get the fingerprint
2  *      Copyright (C) 2001 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 <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h> 
26 #include <time.h>
27 #include <assert.h>
28
29
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 /* Return the fingerprint of the certificate (we can't put this into
35    libksba because we need libgcrypt support).  The caller must
36    provide an array of sufficient length or NULL so that the function
37    allocates the array.  If r_len is not NULL, the length of the
38    digest is returned; well, this can also be done by using
39    gcry_md_get_algo_dlen().  If algo is 0, a SHA-1 will be used.
40    
41    If there is a problem , the function does never return NULL but a
42    digest of all 0xff.
43  */
44 unsigned char *
45 gpgsm_get_fingerprint (ksba_cert_t cert, int algo,
46                        unsigned char *array, int *r_len)
47 {
48   gcry_md_hd_t md;
49   int rc, len;
50   
51   if (!algo)
52     algo = GCRY_MD_SHA1;
53
54   len = gcry_md_get_algo_dlen (algo);
55   assert (len);
56   if (!array)
57     array = xmalloc (len);
58
59   if (r_len)
60     *r_len = len;
61
62   /* Fist check whether we have cached the fingerprint.  */
63   if (algo == GCRY_MD_SHA1)
64     {
65       size_t buflen;
66
67       assert (len >= 20);
68       if (!ksba_cert_get_user_data (cert, "sha1-fingerprint", 
69                                     array, len, &buflen)
70           && buflen == 20)
71         return array;
72     }
73
74   /* No, need to compute it.  */
75   rc = gcry_md_open (&md, algo, 0);
76   if (rc)
77     {
78       log_error ("md_open failed: %s\n", gpg_strerror (rc));
79       memset (array, 0xff, len); /* better return an invalid fpr than NULL */
80       return array;
81     }
82
83   rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
84   if (rc)
85     {
86       log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
87       gcry_md_close (md);
88       memset (array, 0xff, len); /* better return an invalid fpr than NULL */
89       return array;
90     }
91   gcry_md_final (md);
92   memcpy (array, gcry_md_read(md, algo), len );
93   gcry_md_close (md);
94
95   /* Cache an SHA-1 fingerprint.  */
96   if ( algo == GCRY_MD_SHA1 )
97     ksba_cert_set_user_data (cert, "sha1-fingerprint", array, 20);
98
99   return array;
100 }
101
102
103 /* Return an allocated buffer with the formatted fingerprint */
104 char *
105 gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo)
106 {
107   unsigned char digest[MAX_DIGEST_LEN];
108   char *buf;
109   int len;
110
111   if (!algo)
112     algo = GCRY_MD_SHA1;
113
114   len = gcry_md_get_algo_dlen (algo);
115   assert (len <= MAX_DIGEST_LEN );
116   gpgsm_get_fingerprint (cert, algo, digest, NULL);
117   buf = xmalloc (len*3+1);
118   bin2hexcolon (digest, len, buf);
119   return buf;
120 }
121
122 /* Return an allocated buffer with the formatted fingerprint as one
123    large hexnumber */
124 char *
125 gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo)
126 {
127   unsigned char digest[MAX_DIGEST_LEN];
128   char *buf;
129   int len;
130
131   if (!algo)
132     algo = GCRY_MD_SHA1;
133
134   len = gcry_md_get_algo_dlen (algo);
135   assert (len <= MAX_DIGEST_LEN );
136   gpgsm_get_fingerprint (cert, algo, digest, NULL);
137   buf = xmalloc (len*2+1);
138   bin2hex (digest, len, buf);
139   return buf;
140 }
141
142 /* Return a certificate ID.  These are the last 4 bytes of the SHA-1
143    fingerprint. */
144 unsigned long
145 gpgsm_get_short_fingerprint (ksba_cert_t cert)
146 {
147   unsigned char digest[20];
148
149   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
150   return ((digest[16]<<24)|(digest[17]<<16)|(digest[18]<< 8)|digest[19]);
151 }
152
153 \f
154 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
155    key parameters expressed as an canoncial encoded S-Exp.  array must
156    be 20 bytes long. returns the array or a newly allocated one if the
157    passed one was NULL */
158 unsigned char *
159 gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
160 {
161   gcry_sexp_t s_pkey;
162   int rc;
163   ksba_sexp_t p;
164   size_t n;
165   
166   p = ksba_cert_get_public_key (cert);
167   if (!p)
168     return NULL; /* oops */
169
170   if (DBG_X509)
171     log_debug ("get_keygrip for public key\n");
172   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
173   if (!n)
174     {
175       log_error ("libksba did not return a proper S-Exp\n");
176       return NULL;
177     }
178   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
179   xfree (p);
180   if (rc)
181     {
182       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
183       return NULL;
184     }
185   array = gcry_pk_get_keygrip (s_pkey, array);
186   gcry_sexp_release (s_pkey);
187   if (!array)
188     {
189       rc = gpg_error (GPG_ERR_GENERAL);
190       log_error ("can't calculate keygrip\n");
191       return NULL;
192     }
193   if (DBG_X509)
194     log_printhex ("keygrip=", array, 20);
195
196   return array;
197 }
198
199 /* Return an allocated buffer with the keygrip of CERT in from of an
200    hexstring.  NULL is returned in case of error */
201 char *
202 gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
203 {
204   unsigned char grip[20];
205   char *buf;
206
207   gpgsm_get_keygrip (cert, grip);
208   buf = xmalloc (20*2+1);
209   bin2hex (grip, 20, buf);
210   return buf;
211 }
212
213
214 /* Return the PK algorithm used by CERT as well as the length in bits
215    of the public key at NBITS. */
216 int
217 gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
218 {
219   gcry_sexp_t s_pkey;
220   int rc;
221   ksba_sexp_t p;
222   size_t n;
223   gcry_sexp_t l1, l2;
224   const char *name;
225   char namebuf[128];
226
227   if (nbits)
228     *nbits = 0;
229
230   p = ksba_cert_get_public_key (cert);
231   if (!p)
232     return 0; 
233   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
234   if (!n)
235     {
236       xfree (p);
237       return 0;
238     }
239   rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
240   xfree (p);
241   if (rc)
242     return 0;
243
244   if (nbits)
245     *nbits = gcry_pk_get_nbits (s_pkey);
246
247   /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
248   l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
249   if (!l1)
250     {
251       gcry_sexp_release (s_pkey);
252       return 0;
253     }
254   l2 = gcry_sexp_cadr (l1);
255   gcry_sexp_release (l1);
256   l1 = l2;
257   name = gcry_sexp_nth_data (l1, 0, &n);
258   if (name)
259     {
260       if (n > sizeof namebuf -1)
261         n = sizeof namebuf -1;
262       memcpy (namebuf, name, n);
263       namebuf[n] = 0;
264     }
265   else
266     *namebuf = 0;
267   gcry_sexp_release (l1);
268   gcry_sexp_release (s_pkey);
269   return gcry_pk_map_name (namebuf);
270 }
271
272
273
274 \f
275 /* For certain purposes we need a certificate id which has an upper
276    limit of the size.  We use the hash of the issuer name and the
277    serial number for this.  In most cases the serial number is not
278    that large and the resulting string can be passed on an assuan
279    command line.  Everything is hexencoded with the serialnumber
280    delimited from the hash by a dot. 
281
282    The caller must free the string.
283 */
284 char *
285 gpgsm_get_certid (ksba_cert_t cert)
286 {
287   ksba_sexp_t serial;
288   char *p;
289   char *endp;
290   unsigned char hash[20];
291   unsigned long n;
292   char *certid;
293   int i;
294   
295   p = ksba_cert_get_issuer (cert, 0);
296   if (!p)
297     return NULL; /* Ooops: No issuer */
298   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
299   xfree (p);
300
301   serial = ksba_cert_get_serial (cert);
302   if (!serial)
303     return NULL; /* oops: no serial number */
304   p = (char *)serial;
305   if (*p != '(')
306     {
307       log_error ("Ooops: invalid serial number\n");
308       xfree (serial);
309       return NULL;
310     }
311   p++;
312   n = strtoul (p, &endp, 10);
313   p = endp;
314   if (*p != ':')
315     {
316       log_error ("Ooops: invalid serial number (no colon)\n");
317       xfree (serial);
318       return NULL;
319     }
320   p++;
321
322   certid = xtrymalloc ( 40 + 1 + n*2 + 1);
323   if (!certid)
324     {
325       xfree (serial);
326       return NULL; /* out of core */
327     }
328
329   for (i=0, endp = certid; i < 20; i++, endp += 2 )
330     sprintf (endp, "%02X", hash[i]);
331   *endp++ = '.';
332   for (i=0; i < n; i++, endp += 2)
333     sprintf (endp, "%02X", ((unsigned char*)p)[i]);
334   *endp = 0;
335
336   xfree (serial);
337   return certid;
338 }
339
340
341
342