Fix error detection
[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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h> 
26 #include <time.h>
27 #include <assert.h>
28
29
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 /* Return the fingerprint of the certificate (we can't put this into
35    libksba because we need libgcrypt support).  The caller must
36    provide an array of sufficient length or NULL so that the function
37    allocates the array.  If r_len is not NULL, the length of the
38    digest is returned; well, this can also be done by using
39    gcry_md_get_algo_dlen().  If algo is 0, a SHA-1 will be used.
40    
41    If there is a problem , the function does never return NULL but a
42    digest of all 0xff.
43  */
44 unsigned char *
45 gpgsm_get_fingerprint (ksba_cert_t cert, int algo,
46                        unsigned 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   /* Fist check whether we have cached the fingerprint.  */
63   if (algo == GCRY_MD_SHA1)
64     {
65       size_t buflen;
66
67       assert (len >= 20);
68       if (!ksba_cert_get_user_data (cert, "sha1-fingerprint", 
69                                     array, len, &buflen)
70           && buflen == 20)
71         return array;
72     }
73
74   /* No, need to compute it.  */
75   rc = gcry_md_open (&md, algo, 0);
76   if (rc)
77     {
78       log_error ("md_open failed: %s\n", gpg_strerror (rc));
79       memset (array, 0xff, len); /* better return an invalid fpr than NULL */
80       return array;
81     }
82
83   rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
84   if (rc)
85     {
86       log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
87       gcry_md_close (md);
88       memset (array, 0xff, len); /* better return an invalid fpr than NULL */
89       return array;
90     }
91   gcry_md_final (md);
92   memcpy (array, gcry_md_read(md, algo), len );
93   gcry_md_close (md);
94
95   /* Cache an SHA-1 fingerprint.  */
96   if ( algo == GCRY_MD_SHA1 )
97     ksba_cert_set_user_data (cert, "sha1-fingerprint", array, 20);
98
99   return array;
100 }
101
102
103 /* Return an allocated buffer with the formatted fingerprint */
104 char *
105 gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo)
106 {
107   unsigned char digest[MAX_DIGEST_LEN];
108   char *buf;
109   int len;
110
111   if (!algo)
112     algo = GCRY_MD_SHA1;
113
114   len = gcry_md_get_algo_dlen (algo);
115   assert (len <= MAX_DIGEST_LEN );
116   gpgsm_get_fingerprint (cert, algo, digest, NULL);
117   buf = xmalloc (len*3+1);
118   bin2hexcolon (digest, len, buf);
119   return buf;
120 }
121
122 /* Return an allocated buffer with the formatted fingerprint as one
123    large hexnumber */
124 char *
125 gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo)
126 {
127   unsigned char digest[MAX_DIGEST_LEN];
128   char *buf;
129   int len;
130
131   if (!algo)
132     algo = GCRY_MD_SHA1;
133
134   len = gcry_md_get_algo_dlen (algo);
135   assert (len <= MAX_DIGEST_LEN );
136   gpgsm_get_fingerprint (cert, algo, digest, NULL);
137   buf = xmalloc (len*2+1);
138   bin2hex (digest, len, buf);
139   return buf;
140 }
141
142 /* Return a certificate ID.  These are the last 4 bytes of the SHA-1
143    fingerprint. */
144 unsigned long
145 gpgsm_get_short_fingerprint (ksba_cert_t cert)
146 {
147   unsigned char digest[20];
148
149   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
150   return ((digest[16]<<24)|(digest[17]<<16)|(digest[18]<< 8)|digest[19]);
151 }
152
153 \f
154 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
155    key parameters expressed as an canoncial encoded S-Exp.  ARRAY must
156    be 20 bytes long.  Returns ARRAY or a newly allocated buffer if ARRAY was
157    given as NULL.  May return NULL on error.  */
158 unsigned char *
159 gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
160 {
161   gcry_sexp_t s_pkey;
162   int rc;
163   ksba_sexp_t p;
164   size_t n;
165   
166   p = ksba_cert_get_public_key (cert);
167   if (!p)
168     return NULL; /* oops */
169
170   if (DBG_X509)
171     log_debug ("get_keygrip for public key\n");
172   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
173   if (!n)
174     {
175       log_error ("libksba did not return a proper S-Exp\n");
176       return NULL;
177     }
178   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
179   xfree (p);
180   if (rc)
181     {
182       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
183       return NULL;
184     }
185   array = gcry_pk_get_keygrip (s_pkey, array);
186   gcry_sexp_release (s_pkey);
187   if (!array)
188     {
189       rc = gpg_error (GPG_ERR_GENERAL);
190       log_error ("can't calculate keygrip\n");
191       return NULL;
192     }
193   if (DBG_X509)
194     log_printhex ("keygrip=", array, 20);
195
196   return array;
197 }
198
199 /* Return an allocated buffer with the keygrip of CERT in from of an
200    hexstring.  NULL is returned in case of error */
201 char *
202 gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
203 {
204   unsigned char grip[20];
205   char *buf;
206
207   if (!gpgsm_get_keygrip (cert, grip))
208     return NULL;
209   buf = xtrymalloc (20*2+1);
210   if (buf)
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