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