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