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 : log_error ("can't calculate keygrip\n");
196 0 : return NULL;
197 : }
198 0 : if (DBG_X509)
199 0 : log_printhex ("keygrip=", array, 20);
200 :
201 0 : 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 0 : gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
208 : {
209 : unsigned char grip[20];
210 : char *buf;
211 :
212 0 : if (!gpgsm_get_keygrip (cert, grip))
213 0 : return NULL;
214 0 : buf = xtrymalloc (20*2+1);
215 0 : if (buf)
216 0 : bin2hex (grip, 20, buf);
217 0 : 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 0 : 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 0 : if (nbits)
235 0 : *nbits = 0;
236 :
237 0 : p = ksba_cert_get_public_key (cert);
238 0 : if (!p)
239 0 : return 0;
240 0 : n = gcry_sexp_canon_len (p, 0, NULL, NULL);
241 0 : if (!n)
242 : {
243 0 : xfree (p);
244 0 : return 0;
245 : }
246 0 : rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
247 0 : xfree (p);
248 0 : if (rc)
249 0 : return 0;
250 :
251 0 : if (nbits)
252 0 : *nbits = gcry_pk_get_nbits (s_pkey);
253 :
254 : /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
255 0 : l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
256 0 : if (!l1)
257 : {
258 0 : gcry_sexp_release (s_pkey);
259 0 : return 0;
260 : }
261 0 : l2 = gcry_sexp_cadr (l1);
262 0 : gcry_sexp_release (l1);
263 0 : l1 = l2;
264 0 : name = gcry_sexp_nth_data (l1, 0, &n);
265 0 : if (name)
266 : {
267 0 : if (n > sizeof namebuf -1)
268 0 : n = sizeof namebuf -1;
269 0 : memcpy (namebuf, name, n);
270 0 : namebuf[n] = 0;
271 : }
272 : else
273 0 : *namebuf = 0;
274 0 : gcry_sexp_release (l1);
275 0 : gcry_sexp_release (s_pkey);
276 0 : return gcry_pk_map_name (namebuf);
277 : }
278 :
279 :
280 :
281 :
282 : /* For certain purposes we need a certificate id which has an upper
283 : limit of the size. We use the hash of the issuer name and the
284 : serial number for this. In most cases the serial number is not
285 : that large and the resulting string can be passed on an assuan
286 : command line. Everything is hexencoded with the serialnumber
287 : delimited from the hash by a dot.
288 :
289 : The caller must free the string.
290 : */
291 : char *
292 0 : gpgsm_get_certid (ksba_cert_t cert)
293 : {
294 : ksba_sexp_t serial;
295 : char *p;
296 : char *endp;
297 : unsigned char hash[20];
298 : unsigned long n;
299 : char *certid;
300 : int i;
301 :
302 0 : p = ksba_cert_get_issuer (cert, 0);
303 0 : if (!p)
304 0 : return NULL; /* Ooops: No issuer */
305 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
306 0 : xfree (p);
307 :
308 0 : serial = ksba_cert_get_serial (cert);
309 0 : if (!serial)
310 0 : return NULL; /* oops: no serial number */
311 0 : p = (char *)serial;
312 0 : if (*p != '(')
313 : {
314 0 : log_error ("Ooops: invalid serial number\n");
315 0 : xfree (serial);
316 0 : return NULL;
317 : }
318 0 : p++;
319 0 : n = strtoul (p, &endp, 10);
320 0 : p = endp;
321 0 : if (*p != ':')
322 : {
323 0 : log_error ("Ooops: invalid serial number (no colon)\n");
324 0 : xfree (serial);
325 0 : return NULL;
326 : }
327 0 : p++;
328 :
329 0 : certid = xtrymalloc ( 40 + 1 + n*2 + 1);
330 0 : if (!certid)
331 : {
332 0 : xfree (serial);
333 0 : return NULL; /* out of core */
334 : }
335 :
336 0 : for (i=0, endp = certid; i < 20; i++, endp += 2 )
337 0 : sprintf (endp, "%02X", hash[i]);
338 0 : *endp++ = '.';
339 0 : for (i=0; i < n; i++, endp += 2)
340 0 : sprintf (endp, "%02X", ((unsigned char*)p)[i]);
341 0 : *endp = 0;
342 :
343 0 : xfree (serial);
344 0 : return certid;
345 : }
|