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