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