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