Print NO_SECKEY status line in gpgsm.
[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.  If R_HIGH is not NULL the next 4 bytes are stored
144    there. */
145 unsigned long
146 gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned long *r_high)
147 {
148   unsigned char digest[20];
149
150   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
151   if (r_high)
152     *r_high = ((digest[12]<<24)|(digest[13]<<16)|(digest[14]<< 8)|digest[15]);
153   return ((digest[16]<<24)|(digest[17]<<16)|(digest[18]<< 8)|digest[19]);
154 }
155
156 \f
157 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
158    key parameters expressed as an canoncial encoded S-Exp.  ARRAY must
159    be 20 bytes long.  Returns ARRAY or a newly allocated buffer if ARRAY was
160    given as NULL.  May return NULL on error.  */
161 unsigned char *
162 gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
163 {
164   gcry_sexp_t s_pkey;
165   int rc;
166   ksba_sexp_t p;
167   size_t n;
168   
169   p = ksba_cert_get_public_key (cert);
170   if (!p)
171     return NULL; /* oops */
172
173   if (DBG_X509)
174     log_debug ("get_keygrip for public key\n");
175   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
176   if (!n)
177     {
178       log_error ("libksba did not return a proper S-Exp\n");
179       return NULL;
180     }
181   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
182   xfree (p);
183   if (rc)
184     {
185       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
186       return NULL;
187     }
188   array = gcry_pk_get_keygrip (s_pkey, array);
189   gcry_sexp_release (s_pkey);
190   if (!array)
191     {
192       rc = gpg_error (GPG_ERR_GENERAL);
193       log_error ("can't calculate keygrip\n");
194       return NULL;
195     }
196   if (DBG_X509)
197     log_printhex ("keygrip=", array, 20);
198
199   return array;
200 }
201
202 /* Return an allocated buffer with the keygrip of CERT encoded as a
203    hexstring.  NULL is returned in case of error.  */
204 char *
205 gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
206 {
207   unsigned char grip[20];
208   char *buf;
209
210   if (!gpgsm_get_keygrip (cert, grip))
211     return NULL;
212   buf = xtrymalloc (20*2+1);
213   if (buf)
214     bin2hex (grip, 20, buf);
215   return buf;
216 }
217
218
219 /* Return the PK algorithm used by CERT as well as the length in bits
220    of the public key at NBITS. */
221 int
222 gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
223 {
224   gcry_sexp_t s_pkey;
225   int rc;
226   ksba_sexp_t p;
227   size_t n;
228   gcry_sexp_t l1, l2;
229   const char *name;
230   char namebuf[128];
231
232   if (nbits)
233     *nbits = 0;
234
235   p = ksba_cert_get_public_key (cert);
236   if (!p)
237     return 0; 
238   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
239   if (!n)
240     {
241       xfree (p);
242       return 0;
243     }
244   rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
245   xfree (p);
246   if (rc)
247     return 0;
248
249   if (nbits)
250     *nbits = gcry_pk_get_nbits (s_pkey);
251
252   /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
253   l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
254   if (!l1)
255     {
256       gcry_sexp_release (s_pkey);
257       return 0;
258     }
259   l2 = gcry_sexp_cadr (l1);
260   gcry_sexp_release (l1);
261   l1 = l2;
262   name = gcry_sexp_nth_data (l1, 0, &n);
263   if (name)
264     {
265       if (n > sizeof namebuf -1)
266         n = sizeof namebuf -1;
267       memcpy (namebuf, name, n);
268       namebuf[n] = 0;
269     }
270   else
271     *namebuf = 0;
272   gcry_sexp_release (l1);
273   gcry_sexp_release (s_pkey);
274   return gcry_pk_map_name (namebuf);
275 }
276
277
278
279 \f
280 /* For certain purposes we need a certificate id which has an upper
281    limit of the size.  We use the hash of the issuer name and the
282    serial number for this.  In most cases the serial number is not
283    that large and the resulting string can be passed on an assuan
284    command line.  Everything is hexencoded with the serialnumber
285    delimited from the hash by a dot. 
286
287    The caller must free the string.
288 */
289 char *
290 gpgsm_get_certid (ksba_cert_t cert)
291 {
292   ksba_sexp_t serial;
293   char *p;
294   char *endp;
295   unsigned char hash[20];
296   unsigned long n;
297   char *certid;
298   int i;
299   
300   p = ksba_cert_get_issuer (cert, 0);
301   if (!p)
302     return NULL; /* Ooops: No issuer */
303   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
304   xfree (p);
305
306   serial = ksba_cert_get_serial (cert);
307   if (!serial)
308     return NULL; /* oops: no serial number */
309   p = (char *)serial;
310   if (*p != '(')
311     {
312       log_error ("Ooops: invalid serial number\n");
313       xfree (serial);
314       return NULL;
315     }
316   p++;
317   n = strtoul (p, &endp, 10);
318   p = endp;
319   if (*p != ':')
320     {
321       log_error ("Ooops: invalid serial number (no colon)\n");
322       xfree (serial);
323       return NULL;
324     }
325   p++;
326
327   certid = xtrymalloc ( 40 + 1 + n*2 + 1);
328   if (!certid)
329     {
330       xfree (serial);
331       return NULL; /* out of core */
332     }
333
334   for (i=0, endp = certid; i < 20; i++, endp += 2 )
335     sprintf (endp, "%02X", hash[i]);
336   *endp++ = '.';
337   for (i=0; i < n; i++, endp += 2)
338     sprintf (endp, "%02X", ((unsigned char*)p)[i]);
339   *endp = 0;
340
341   xfree (serial);
342   return certid;
343 }
344
345
346
347