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