common: New function percent_data_escape.
[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 <https://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 #include "../common/host2net.h"
35
36
37 /* Return the fingerprint of the certificate (we can't put this into
38    libksba because we need libgcrypt support).  The caller must
39    provide an array of sufficient length or NULL so that the function
40    allocates the array.  If r_len is not NULL, the length of the
41    digest is returned; well, this can also be done by using
42    gcry_md_get_algo_dlen().  If algo is 0, a SHA-1 will be used.
43
44    If there is a problem , the function does never return NULL but a
45    digest of all 0xff.
46  */
47 unsigned char *
48 gpgsm_get_fingerprint (ksba_cert_t cert, int algo,
49                        unsigned char *array, int *r_len)
50 {
51   gcry_md_hd_t md;
52   int rc, len;
53
54   if (!algo)
55     algo = GCRY_MD_SHA1;
56
57   len = gcry_md_get_algo_dlen (algo);
58   assert (len);
59   if (!array)
60     array = xmalloc (len);
61
62   if (r_len)
63     *r_len = len;
64
65   /* Fist check whether we have cached the fingerprint.  */
66   if (algo == GCRY_MD_SHA1)
67     {
68       size_t buflen;
69
70       assert (len >= 20);
71       if (!ksba_cert_get_user_data (cert, "sha1-fingerprint",
72                                     array, len, &buflen)
73           && buflen == 20)
74         return array;
75     }
76
77   /* No, need to compute it.  */
78   rc = gcry_md_open (&md, algo, 0);
79   if (rc)
80     {
81       log_error ("md_open failed: %s\n", gpg_strerror (rc));
82       memset (array, 0xff, len); /* better return an invalid fpr than NULL */
83       return array;
84     }
85
86   rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
87   if (rc)
88     {
89       log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
90       gcry_md_close (md);
91       memset (array, 0xff, len); /* better return an invalid fpr than NULL */
92       return array;
93     }
94   gcry_md_final (md);
95   memcpy (array, gcry_md_read(md, algo), len );
96   gcry_md_close (md);
97
98   /* Cache an SHA-1 fingerprint.  */
99   if ( algo == GCRY_MD_SHA1 )
100     ksba_cert_set_user_data (cert, "sha1-fingerprint", array, 20);
101
102   return array;
103 }
104
105
106 /* Return an allocated buffer with the formatted fingerprint */
107 char *
108 gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo)
109 {
110   unsigned char digest[MAX_DIGEST_LEN];
111   char *buf;
112   int len;
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   bin2hexcolon (digest, len, buf);
122   return buf;
123 }
124
125 /* Return an allocated buffer with the formatted fingerprint as one
126    large hexnumber */
127 char *
128 gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo)
129 {
130   unsigned char digest[MAX_DIGEST_LEN];
131   char *buf;
132   int len;
133
134   if (!algo)
135     algo = GCRY_MD_SHA1;
136
137   len = gcry_md_get_algo_dlen (algo);
138   assert (len <= MAX_DIGEST_LEN );
139   gpgsm_get_fingerprint (cert, algo, digest, NULL);
140   buf = xmalloc (len*2+1);
141   bin2hex (digest, len, buf);
142   return buf;
143 }
144
145 /* Return a certificate ID.  These are the last 4 bytes of the SHA-1
146    fingerprint.  If R_HIGH is not NULL the next 4 bytes are stored
147    there. */
148 unsigned long
149 gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned long *r_high)
150 {
151   unsigned char digest[20];
152
153   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
154   if (r_high)
155     *r_high = buf32_to_ulong (digest+12);
156   return buf32_to_ulong (digest + 16);
157 }
158
159 \f
160 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
161    key parameters expressed as an canoncial encoded S-Exp.  ARRAY must
162    be 20 bytes long.  Returns ARRAY or a newly allocated buffer if ARRAY was
163    given as NULL.  May return NULL on error.  */
164 unsigned char *
165 gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
166 {
167   gcry_sexp_t s_pkey;
168   int rc;
169   ksba_sexp_t p;
170   size_t n;
171
172   p = ksba_cert_get_public_key (cert);
173   if (!p)
174     return NULL; /* oops */
175
176   if (DBG_X509)
177     log_debug ("get_keygrip for public key\n");
178   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
179   if (!n)
180     {
181       log_error ("libksba did not return a proper S-Exp\n");
182       return NULL;
183     }
184   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
185   xfree (p);
186   if (rc)
187     {
188       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
189       return NULL;
190     }
191   array = gcry_pk_get_keygrip (s_pkey, array);
192   gcry_sexp_release (s_pkey);
193   if (!array)
194     {
195       log_error ("can't calculate keygrip\n");
196       return NULL;
197     }
198   if (DBG_X509)
199     log_printhex (array, 20, "keygrip=");
200
201   return array;
202 }
203
204 /* Return an allocated buffer with the keygrip of CERT encoded as a
205    hexstring.  NULL is returned in case of error.  */
206 char *
207 gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
208 {
209   unsigned char grip[20];
210   char *buf;
211
212   if (!gpgsm_get_keygrip (cert, grip))
213     return NULL;
214   buf = xtrymalloc (20*2+1);
215   if (buf)
216     bin2hex (grip, 20, buf);
217   return buf;
218 }
219
220
221 /* Return the PK algorithm used by CERT as well as the length in bits
222    of the public key at NBITS. */
223 int
224 gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
225 {
226   gcry_sexp_t s_pkey;
227   int rc;
228   ksba_sexp_t p;
229   size_t n;
230   gcry_sexp_t l1, l2;
231   const char *name;
232   char namebuf[128];
233
234   if (nbits)
235     *nbits = 0;
236
237   p = ksba_cert_get_public_key (cert);
238   if (!p)
239     return 0;
240   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
241   if (!n)
242     {
243       xfree (p);
244       return 0;
245     }
246   rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
247   xfree (p);
248   if (rc)
249     return 0;
250
251   if (nbits)
252     *nbits = gcry_pk_get_nbits (s_pkey);
253
254   /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
255   l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
256   if (!l1)
257     {
258       gcry_sexp_release (s_pkey);
259       return 0;
260     }
261   l2 = gcry_sexp_cadr (l1);
262   gcry_sexp_release (l1);
263   l1 = l2;
264   name = gcry_sexp_nth_data (l1, 0, &n);
265   if (name)
266     {
267       if (n > sizeof namebuf -1)
268         n = sizeof namebuf -1;
269       memcpy (namebuf, name, n);
270       namebuf[n] = 0;
271     }
272   else
273     *namebuf = 0;
274   gcry_sexp_release (l1);
275   gcry_sexp_release (s_pkey);
276   return gcry_pk_map_name (namebuf);
277 }
278
279
280 /* If KEY is an RSA key, return its modulus.  For non-RSA keys or on
281  * error return NULL.  */
282 gcry_mpi_t
283 gpgsm_get_rsa_modulus (ksba_cert_t cert)
284 {
285   gpg_error_t err;
286   gcry_sexp_t key;
287   gcry_sexp_t list = NULL;
288   gcry_sexp_t l2 = NULL;
289   char *name = NULL;
290   gcry_mpi_t modulus = NULL;
291
292   {
293     ksba_sexp_t ckey;
294     size_t n;
295
296     ckey = ksba_cert_get_public_key (cert);
297     if (!ckey)
298       return NULL;
299     n = gcry_sexp_canon_len (ckey, 0, NULL, NULL);
300     if (!n)
301       {
302         xfree (ckey);
303         return NULL;
304       }
305     err = gcry_sexp_sscan (&key, NULL, (char *)ckey, n);
306     xfree (ckey);
307     if (err)
308       return NULL;
309   }
310
311   list = gcry_sexp_find_token (key, "public-key", 0);
312   if (!list)
313     list = gcry_sexp_find_token (key, "private-key", 0);
314   if (!list)
315     list = gcry_sexp_find_token (key, "protected-private-key", 0);
316   if (!list)
317     list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
318
319   gcry_sexp_release (key);
320   if (!list)
321     return NULL;  /* No suitable key.  */
322
323   l2 = gcry_sexp_cadr (list);
324   gcry_sexp_release (list);
325   list = l2;
326   l2 = NULL;
327
328   name = gcry_sexp_nth_string (list, 0);
329   if (!name)
330     ;
331   else if (gcry_pk_map_name (name) == GCRY_PK_RSA)
332     {
333       l2 = gcry_sexp_find_token (list, "n", 1);
334       if (l2)
335         modulus = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
336     }
337
338   gcry_free (name);
339   gcry_sexp_release (l2);
340   gcry_sexp_release (list);
341   return modulus;
342 }
343
344
345 \f
346 /* For certain purposes we need a certificate id which has an upper
347    limit of the size.  We use the hash of the issuer name and the
348    serial number for this.  In most cases the serial number is not
349    that large and the resulting string can be passed on an assuan
350    command line.  Everything is hexencoded with the serialnumber
351    delimited from the hash by a dot.
352
353    The caller must free the string.
354 */
355 char *
356 gpgsm_get_certid (ksba_cert_t cert)
357 {
358   ksba_sexp_t serial;
359   char *p;
360   char *endp;
361   unsigned char hash[20];
362   unsigned long n;
363   char *certid;
364   int i;
365
366   p = ksba_cert_get_issuer (cert, 0);
367   if (!p)
368     return NULL; /* Ooops: No issuer */
369   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
370   xfree (p);
371
372   serial = ksba_cert_get_serial (cert);
373   if (!serial)
374     return NULL; /* oops: no serial number */
375   p = (char *)serial;
376   if (*p != '(')
377     {
378       log_error ("Ooops: invalid serial number\n");
379       xfree (serial);
380       return NULL;
381     }
382   p++;
383   n = strtoul (p, &endp, 10);
384   p = endp;
385   if (*p != ':')
386     {
387       log_error ("Ooops: invalid serial number (no colon)\n");
388       xfree (serial);
389       return NULL;
390     }
391   p++;
392
393   certid = xtrymalloc ( 40 + 1 + n*2 + 1);
394   if (!certid)
395     {
396       xfree (serial);
397       return NULL; /* out of core */
398     }
399
400   for (i=0, endp = certid; i < 20; i++, endp += 2 )
401     sprintf (endp, "%02X", hash[i]);
402   *endp++ = '.';
403   for (i=0; i < n; i++, endp += 2)
404     sprintf (endp, "%02X", ((unsigned char*)p)[i]);
405   *endp = 0;
406
407   xfree (serial);
408   return certid;
409 }