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 <https://www.gnu.org/licenses/>.
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.
44 If there is a problem , the function does never return NULL but a
48 gpgsm_get_fingerprint (ksba_cert_t cert, int algo,
49 unsigned char *array, int *r_len)
57 len = gcry_md_get_algo_dlen (algo);
60 array = xmalloc (len);
65 /* Fist check whether we have cached the fingerprint. */
66 if (algo == GCRY_MD_SHA1)
71 if (!ksba_cert_get_user_data (cert, "sha1-fingerprint",
77 /* No, need to compute it. */
78 rc = gcry_md_open (&md, algo, 0);
81 log_error ("md_open failed: %s\n", gpg_strerror (rc));
82 memset (array, 0xff, len); /* better return an invalid fpr than NULL */
86 rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
89 log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
91 memset (array, 0xff, len); /* better return an invalid fpr than NULL */
95 memcpy (array, gcry_md_read(md, algo), len );
98 /* Cache an SHA-1 fingerprint. */
99 if ( algo == GCRY_MD_SHA1 )
100 ksba_cert_set_user_data (cert, "sha1-fingerprint", array, 20);
106 /* Return an allocated buffer with the formatted fingerprint */
108 gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo)
110 unsigned char digest[MAX_DIGEST_LEN];
117 len = gcry_md_get_algo_dlen (algo);
118 assert (len <= MAX_DIGEST_LEN );
119 gpgsm_get_fingerprint (cert, algo, digest, NULL);
120 buf = xmalloc (len*3+1);
121 bin2hexcolon (digest, len, buf);
125 /* Return an allocated buffer with the formatted fingerprint as one
128 gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo)
130 unsigned char digest[MAX_DIGEST_LEN];
137 len = gcry_md_get_algo_dlen (algo);
138 assert (len <= MAX_DIGEST_LEN );
139 gpgsm_get_fingerprint (cert, algo, digest, NULL);
140 buf = xmalloc (len*2+1);
141 bin2hex (digest, len, buf);
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
149 gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned long *r_high)
151 unsigned char digest[20];
153 gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
155 *r_high = buf32_to_ulong (digest+12);
156 return buf32_to_ulong (digest + 16);
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. */
165 gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
172 p = ksba_cert_get_public_key (cert);
174 return NULL; /* oops */
177 log_debug ("get_keygrip for public key\n");
178 n = gcry_sexp_canon_len (p, 0, NULL, NULL);
181 log_error ("libksba did not return a proper S-Exp\n");
184 rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
188 log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
191 array = gcry_pk_get_keygrip (s_pkey, array);
192 gcry_sexp_release (s_pkey);
195 log_error ("can't calculate keygrip\n");
199 log_printhex ("keygrip=", array, 20);
204 /* Return an allocated buffer with the keygrip of CERT encoded as a
205 hexstring. NULL is returned in case of error. */
207 gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
209 unsigned char grip[20];
212 if (!gpgsm_get_keygrip (cert, grip))
214 buf = xtrymalloc (20*2+1);
216 bin2hex (grip, 20, buf);
221 /* Return the PK algorithm used by CERT as well as the length in bits
222 of the public key at NBITS. */
224 gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
237 p = ksba_cert_get_public_key (cert);
240 n = gcry_sexp_canon_len (p, 0, NULL, NULL);
246 rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
252 *nbits = gcry_pk_get_nbits (s_pkey);
254 /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
255 l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
258 gcry_sexp_release (s_pkey);
261 l2 = gcry_sexp_cadr (l1);
262 gcry_sexp_release (l1);
264 name = gcry_sexp_nth_data (l1, 0, &n);
267 if (n > sizeof namebuf -1)
268 n = sizeof namebuf -1;
269 memcpy (namebuf, name, n);
274 gcry_sexp_release (l1);
275 gcry_sexp_release (s_pkey);
276 return gcry_pk_map_name (namebuf);
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.
289 The caller must free the string.
292 gpgsm_get_certid (ksba_cert_t cert)
297 unsigned char hash[20];
302 p = ksba_cert_get_issuer (cert, 0);
304 return NULL; /* Ooops: No issuer */
305 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
308 serial = ksba_cert_get_serial (cert);
310 return NULL; /* oops: no serial number */
314 log_error ("Ooops: invalid serial number\n");
319 n = strtoul (p, &endp, 10);
323 log_error ("Ooops: invalid serial number (no colon)\n");
329 certid = xtrymalloc ( 40 + 1 + n*2 + 1);
333 return NULL; /* out of core */
336 for (i=0, endp = certid; i < 20; i++, endp += 2 )
337 sprintf (endp, "%02X", hash[i]);
339 for (i=0; i < n; i++, endp += 2)
340 sprintf (endp, "%02X", ((unsigned char*)p)[i]);