Line data Source code
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 : #include "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 9 : 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 9 : if (!algo)
55 3 : algo = GCRY_MD_SHA1;
56 :
57 9 : len = gcry_md_get_algo_dlen (algo);
58 9 : assert (len);
59 9 : if (!array)
60 0 : array = xmalloc (len);
61 :
62 9 : if (r_len)
63 0 : *r_len = len;
64 :
65 : /* Fist check whether we have cached the fingerprint. */
66 9 : if (algo == GCRY_MD_SHA1)
67 : {
68 : size_t buflen;
69 :
70 9 : assert (len >= 20);
71 9 : if (!ksba_cert_get_user_data (cert, "sha1-fingerprint",
72 : array, len, &buflen)
73 6 : && buflen == 20)
74 6 : return array;
75 : }
76 :
77 : /* No, need to compute it. */
78 3 : rc = gcry_md_open (&md, algo, 0);
79 3 : if (rc)
80 : {
81 0 : log_error ("md_open failed: %s\n", gpg_strerror (rc));
82 0 : memset (array, 0xff, len); /* better return an invalid fpr than NULL */
83 0 : return array;
84 : }
85 :
86 3 : rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
87 3 : if (rc)
88 : {
89 0 : log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
90 0 : gcry_md_close (md);
91 0 : memset (array, 0xff, len); /* better return an invalid fpr than NULL */
92 0 : return array;
93 : }
94 3 : gcry_md_final (md);
95 3 : memcpy (array, gcry_md_read(md, algo), len );
96 3 : gcry_md_close (md);
97 :
98 : /* Cache an SHA-1 fingerprint. */
99 3 : if ( algo == GCRY_MD_SHA1 )
100 3 : ksba_cert_set_user_data (cert, "sha1-fingerprint", array, 20);
101 :
102 3 : return array;
103 : }
104 :
105 :
106 : /* Return an allocated buffer with the formatted fingerprint */
107 : char *
108 0 : 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 0 : if (!algo)
115 0 : algo = GCRY_MD_SHA1;
116 :
117 0 : len = gcry_md_get_algo_dlen (algo);
118 0 : assert (len <= MAX_DIGEST_LEN );
119 0 : gpgsm_get_fingerprint (cert, algo, digest, NULL);
120 0 : buf = xmalloc (len*3+1);
121 0 : bin2hexcolon (digest, len, buf);
122 0 : return buf;
123 : }
124 :
125 : /* Return an allocated buffer with the formatted fingerprint as one
126 : large hexnumber */
127 : char *
128 3 : 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 3 : if (!algo)
135 0 : algo = GCRY_MD_SHA1;
136 :
137 3 : len = gcry_md_get_algo_dlen (algo);
138 3 : assert (len <= MAX_DIGEST_LEN );
139 3 : gpgsm_get_fingerprint (cert, algo, digest, NULL);
140 3 : buf = xmalloc (len*2+1);
141 3 : bin2hex (digest, len, buf);
142 3 : 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 0 : gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned long *r_high)
150 : {
151 : unsigned char digest[20];
152 :
153 0 : gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
154 0 : if (r_high)
155 0 : *r_high = buf32_to_ulong (digest+12);
156 0 : return buf32_to_ulong (digest + 16);
157 : }
158 :
159 :
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 0 : 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 0 : p = ksba_cert_get_public_key (cert);
173 0 : if (!p)
174 0 : return NULL; /* oops */
175 :
176 0 : if (DBG_X509)
177 0 : log_debug ("get_keygrip for public key\n");
178 0 : n = gcry_sexp_canon_len (p, 0, NULL, NULL);
179 0 : if (!n)
180 : {
181 0 : log_error ("libksba did not return a proper S-Exp\n");
182 0 : return NULL;
183 : }
184 0 : rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
185 0 : xfree (p);
186 0 : if (rc)
187 : {
188 0 : log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
189 0 : return NULL;
190 : }
191 0 : array = gcry_pk_get_keygrip (s_pkey, array);
192 0 : gcry_sexp_release (s_pkey);
193 0 : if (!array)
194 : {
195 0 : rc = gpg_error (GPG_ERR_GENERAL);
196 0 : log_error ("can't calculate keygrip\n");
197 0 : return NULL;
198 : }
199 0 : if (DBG_X509)
200 0 : log_printhex ("keygrip=", array, 20);
201 :
202 0 : return array;
203 : }
204 :
205 : /* Return an allocated buffer with the keygrip of CERT encoded as a
206 : hexstring. NULL is returned in case of error. */
207 : char *
208 0 : gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
209 : {
210 : unsigned char grip[20];
211 : char *buf;
212 :
213 0 : if (!gpgsm_get_keygrip (cert, grip))
214 0 : return NULL;
215 0 : buf = xtrymalloc (20*2+1);
216 0 : if (buf)
217 0 : bin2hex (grip, 20, buf);
218 0 : return buf;
219 : }
220 :
221 :
222 : /* Return the PK algorithm used by CERT as well as the length in bits
223 : of the public key at NBITS. */
224 : int
225 0 : gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
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 *name;
233 : char namebuf[128];
234 :
235 0 : if (nbits)
236 0 : *nbits = 0;
237 :
238 0 : p = ksba_cert_get_public_key (cert);
239 0 : if (!p)
240 0 : return 0;
241 0 : n = gcry_sexp_canon_len (p, 0, NULL, NULL);
242 0 : if (!n)
243 : {
244 0 : xfree (p);
245 0 : return 0;
246 : }
247 0 : rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
248 0 : xfree (p);
249 0 : if (rc)
250 0 : return 0;
251 :
252 0 : if (nbits)
253 0 : *nbits = gcry_pk_get_nbits (s_pkey);
254 :
255 : /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
256 0 : l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
257 0 : if (!l1)
258 : {
259 0 : gcry_sexp_release (s_pkey);
260 0 : return 0;
261 : }
262 0 : l2 = gcry_sexp_cadr (l1);
263 0 : gcry_sexp_release (l1);
264 0 : l1 = l2;
265 0 : name = gcry_sexp_nth_data (l1, 0, &n);
266 0 : if (name)
267 : {
268 0 : if (n > sizeof namebuf -1)
269 0 : n = sizeof namebuf -1;
270 0 : memcpy (namebuf, name, n);
271 0 : namebuf[n] = 0;
272 : }
273 : else
274 0 : *namebuf = 0;
275 0 : gcry_sexp_release (l1);
276 0 : gcry_sexp_release (s_pkey);
277 0 : return gcry_pk_map_name (namebuf);
278 : }
279 :
280 :
281 :
282 :
283 : /* For certain purposes we need a certificate id which has an upper
284 : limit of the size. We use the hash of the issuer name and the
285 : serial number for this. In most cases the serial number is not
286 : that large and the resulting string can be passed on an assuan
287 : command line. Everything is hexencoded with the serialnumber
288 : delimited from the hash by a dot.
289 :
290 : The caller must free the string.
291 : */
292 : char *
293 0 : gpgsm_get_certid (ksba_cert_t cert)
294 : {
295 : ksba_sexp_t serial;
296 : char *p;
297 : char *endp;
298 : unsigned char hash[20];
299 : unsigned long n;
300 : char *certid;
301 : int i;
302 :
303 0 : p = ksba_cert_get_issuer (cert, 0);
304 0 : if (!p)
305 0 : return NULL; /* Ooops: No issuer */
306 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
307 0 : xfree (p);
308 :
309 0 : serial = ksba_cert_get_serial (cert);
310 0 : if (!serial)
311 0 : return NULL; /* oops: no serial number */
312 0 : p = (char *)serial;
313 0 : if (*p != '(')
314 : {
315 0 : log_error ("Ooops: invalid serial number\n");
316 0 : xfree (serial);
317 0 : return NULL;
318 : }
319 0 : p++;
320 0 : n = strtoul (p, &endp, 10);
321 0 : p = endp;
322 0 : if (*p != ':')
323 : {
324 0 : log_error ("Ooops: invalid serial number (no colon)\n");
325 0 : xfree (serial);
326 0 : return NULL;
327 : }
328 0 : p++;
329 :
330 0 : certid = xtrymalloc ( 40 + 1 + n*2 + 1);
331 0 : if (!certid)
332 : {
333 0 : xfree (serial);
334 0 : return NULL; /* out of core */
335 : }
336 :
337 0 : for (i=0, endp = certid; i < 20; i++, endp += 2 )
338 0 : sprintf (endp, "%02X", hash[i]);
339 0 : *endp++ = '.';
340 0 : for (i=0; i < n; i++, endp += 2)
341 0 : sprintf (endp, "%02X", ((unsigned char*)p)[i]);
342 0 : *endp = 0;
343 :
344 0 : xfree (serial);
345 0 : return certid;
346 : }
|