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