agent/
[gnupg.git] / sm / fingerprint.c
blob4704f59724c7c4458227ee73b0c7c9d938e32a7a
1 /* fingerprint.c - Get the fingerprint
2 * Copyright (C) 2001 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
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>
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
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.
41 If there is a problem , the function does never return NULL but a
42 digest of all 0xff.
44 unsigned char *
45 gpgsm_get_fingerprint (ksba_cert_t cert, int algo,
46 unsigned char *array, int *r_len)
48 gcry_md_hd_t md;
49 int rc, len;
51 if (!algo)
52 algo = GCRY_MD_SHA1;
54 len = gcry_md_get_algo_dlen (algo);
55 assert (len);
56 if (!array)
57 array = xmalloc (len);
59 if (r_len)
60 *r_len = len;
62 /* Fist check whether we have cached the fingerprint. */
63 if (algo == GCRY_MD_SHA1)
65 size_t buflen;
67 assert (len >= 20);
68 if (!ksba_cert_get_user_data (cert, "sha1-fingerprint",
69 array, len, &buflen)
70 && buflen == 20)
71 return array;
74 /* No, need to compute it. */
75 rc = gcry_md_open (&md, algo, 0);
76 if (rc)
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;
83 rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
84 if (rc)
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;
91 gcry_md_final (md);
92 memcpy (array, gcry_md_read(md, algo), len );
93 gcry_md_close (md);
95 /* Cache an SHA-1 fingerprint. */
96 if ( algo == GCRY_MD_SHA1 )
97 ksba_cert_set_user_data (cert, "sha1-fingerprint", array, 20);
99 return array;
103 /* Return an allocated buffer with the formatted fingerprint */
104 char *
105 gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo)
107 unsigned char digest[MAX_DIGEST_LEN];
108 char *buf;
109 int len;
111 if (!algo)
112 algo = GCRY_MD_SHA1;
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;
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)
127 unsigned char digest[MAX_DIGEST_LEN];
128 char *buf;
129 int len;
131 if (!algo)
132 algo = GCRY_MD_SHA1;
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;
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)
148 unsigned char digest[20];
150 gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
151 if (r_high)
152 *r_high = ((digest[12]<<24)|(digest[13]<<16)|(digest[14]<< 8)|digest[15]);
153 return ((digest[16]<<24)|(digest[17]<<16)|(digest[18]<< 8)|digest[19]);
157 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
158 key parameters expressed as an canoncial encoded S-Exp. ARRAY must
159 be 20 bytes long. Returns ARRAY or a newly allocated buffer if ARRAY was
160 given as NULL. May return NULL on error. */
161 unsigned char *
162 gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
164 gcry_sexp_t s_pkey;
165 int rc;
166 ksba_sexp_t p;
167 size_t n;
169 p = ksba_cert_get_public_key (cert);
170 if (!p)
171 return NULL; /* oops */
173 if (DBG_X509)
174 log_debug ("get_keygrip for public key\n");
175 n = gcry_sexp_canon_len (p, 0, NULL, NULL);
176 if (!n)
178 log_error ("libksba did not return a proper S-Exp\n");
179 return NULL;
181 rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
182 xfree (p);
183 if (rc)
185 log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
186 return NULL;
188 array = gcry_pk_get_keygrip (s_pkey, array);
189 gcry_sexp_release (s_pkey);
190 if (!array)
192 rc = gpg_error (GPG_ERR_GENERAL);
193 log_error ("can't calculate keygrip\n");
194 return NULL;
196 if (DBG_X509)
197 log_printhex ("keygrip=", array, 20);
199 return array;
202 /* Return an allocated buffer with the keygrip of CERT encoded as a
203 hexstring. NULL is returned in case of error. */
204 char *
205 gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
207 unsigned char grip[20];
208 char *buf;
210 if (!gpgsm_get_keygrip (cert, grip))
211 return NULL;
212 buf = xtrymalloc (20*2+1);
213 if (buf)
214 bin2hex (grip, 20, buf);
215 return buf;
219 /* Return the PK algorithm used by CERT as well as the length in bits
220 of the public key at NBITS. */
222 gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
224 gcry_sexp_t s_pkey;
225 int rc;
226 ksba_sexp_t p;
227 size_t n;
228 gcry_sexp_t l1, l2;
229 const char *name;
230 char namebuf[128];
232 if (nbits)
233 *nbits = 0;
235 p = ksba_cert_get_public_key (cert);
236 if (!p)
237 return 0;
238 n = gcry_sexp_canon_len (p, 0, NULL, NULL);
239 if (!n)
241 xfree (p);
242 return 0;
244 rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
245 xfree (p);
246 if (rc)
247 return 0;
249 if (nbits)
250 *nbits = gcry_pk_get_nbits (s_pkey);
252 /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
253 l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
254 if (!l1)
256 gcry_sexp_release (s_pkey);
257 return 0;
259 l2 = gcry_sexp_cadr (l1);
260 gcry_sexp_release (l1);
261 l1 = l2;
262 name = gcry_sexp_nth_data (l1, 0, &n);
263 if (name)
265 if (n > sizeof namebuf -1)
266 n = sizeof namebuf -1;
267 memcpy (namebuf, name, n);
268 namebuf[n] = 0;
270 else
271 *namebuf = 0;
272 gcry_sexp_release (l1);
273 gcry_sexp_release (s_pkey);
274 return gcry_pk_map_name (namebuf);
280 /* For certain purposes we need a certificate id which has an upper
281 limit of the size. We use the hash of the issuer name and the
282 serial number for this. In most cases the serial number is not
283 that large and the resulting string can be passed on an assuan
284 command line. Everything is hexencoded with the serialnumber
285 delimited from the hash by a dot.
287 The caller must free the string.
289 char *
290 gpgsm_get_certid (ksba_cert_t cert)
292 ksba_sexp_t serial;
293 char *p;
294 char *endp;
295 unsigned char hash[20];
296 unsigned long n;
297 char *certid;
298 int i;
300 p = ksba_cert_get_issuer (cert, 0);
301 if (!p)
302 return NULL; /* Ooops: No issuer */
303 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
304 xfree (p);
306 serial = ksba_cert_get_serial (cert);
307 if (!serial)
308 return NULL; /* oops: no serial number */
309 p = (char *)serial;
310 if (*p != '(')
312 log_error ("Ooops: invalid serial number\n");
313 xfree (serial);
314 return NULL;
316 p++;
317 n = strtoul (p, &endp, 10);
318 p = endp;
319 if (*p != ':')
321 log_error ("Ooops: invalid serial number (no colon)\n");
322 xfree (serial);
323 return NULL;
325 p++;
327 certid = xtrymalloc ( 40 + 1 + n*2 + 1);
328 if (!certid)
330 xfree (serial);
331 return NULL; /* out of core */
334 for (i=0, endp = certid; i < 20; i++, endp += 2 )
335 sprintf (endp, "%02X", hash[i]);
336 *endp++ = '.';
337 for (i=0; i < n; i++, endp += 2)
338 sprintf (endp, "%02X", ((unsigned char*)p)[i]);
339 *endp = 0;
341 xfree (serial);
342 return certid;