~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to sm/fingerprint.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <errno.h>
 
26
#include <unistd.h> 
 
27
#include <time.h>
 
28
#include <assert.h>
 
29
 
 
30
 
 
31
#include "gpgsm.h"
 
32
#include <gcrypt.h>
 
33
#include <ksba.h>
 
34
 
 
35
/* Return the fingerprint of the certificate (we can't put this into
 
36
   libksba because we need libgcrypt support).  The caller must
 
37
   provide an array of sufficient length or NULL so that the function
 
38
   allocates the array.  If r_len is not NULL, the length of the
 
39
   digest is returned; well, this can also be done by using
 
40
   gcry_md_get_algo_dlen().  If algo is 0, a SHA-1 will be used.
 
41
   
 
42
   If there is a problem , the function does never return NULL but a
 
43
   digest of all 0xff.
 
44
 */
 
45
char *
 
46
gpgsm_get_fingerprint (ksba_cert_t cert, int algo, 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
  rc = gcry_md_open (&md, algo, 0);
 
63
  if (rc)
 
64
    {
 
65
      log_error ("md_open failed: %s\n", gpg_strerror (rc));
 
66
      memset (array, 0xff, len); /* better return an invalid fpr than NULL */
 
67
      return array;
 
68
    }
 
69
 
 
70
  rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
 
71
  if (rc)
 
72
    {
 
73
      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
 
74
      gcry_md_close (md);
 
75
      memset (array, 0xff, len); /* better return an invalid fpr than NULL */
 
76
      return array;
 
77
    }
 
78
  gcry_md_final (md);
 
79
  memcpy (array, gcry_md_read(md, algo), len );
 
80
  return array;
 
81
}
 
82
 
 
83
 
 
84
/* Return an allocated buffer with the formatted fingerprint */
 
85
char *
 
86
gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo)
 
87
{
 
88
  unsigned char digest[MAX_DIGEST_LEN];
 
89
  char *buf;
 
90
  int len, i;
 
91
 
 
92
  if (!algo)
 
93
    algo = GCRY_MD_SHA1;
 
94
 
 
95
  len = gcry_md_get_algo_dlen (algo);
 
96
  assert (len <= MAX_DIGEST_LEN );
 
97
  gpgsm_get_fingerprint (cert, algo, digest, NULL);
 
98
  buf = xmalloc (len*3+1);
 
99
  *buf = 0;
 
100
  for (i=0; i < len; i++ )
 
101
    sprintf (buf+strlen(buf), i? ":%02X":"%02X", digest[i]);
 
102
  return buf;
 
103
}
 
104
 
 
105
/* Return an allocated buffer with the formatted fingerprint as one
 
106
   large hexnumber */
 
107
char *
 
108
gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo)
 
109
{
 
110
  unsigned char digest[MAX_DIGEST_LEN];
 
111
  char *buf;
 
112
  int len, i;
 
113
 
 
114
  if (!algo)
 
115
    algo = GCRY_MD_SHA1;
 
116
 
 
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
  *buf = 0;
 
122
  for (i=0; i < len; i++ )
 
123
    sprintf (buf+strlen(buf), "%02X", digest[i]);
 
124
  return buf;
 
125
}
 
126
 
 
127
/* Return a certificate ID.  These are the last 4 bytes of the SHA-1
 
128
   fingerprint. */
 
129
unsigned long
 
130
gpgsm_get_short_fingerprint (ksba_cert_t cert)
 
131
{
 
132
  unsigned char digest[20];
 
133
 
 
134
  gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
 
135
  return ((digest[16]<<24)|(digest[17]<<16)|(digest[18]<< 8)|digest[19]);
 
136
}
 
137
 
 
138
 
 
139
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
 
140
   key parameters expressed as an canoncial encoded S-Exp.  array must
 
141
   be 20 bytes long. returns the array or a newly allocated one if the
 
142
   passed one was NULL */
 
143
char *
 
144
gpgsm_get_keygrip (ksba_cert_t cert, char *array)
 
145
{
 
146
  gcry_sexp_t s_pkey;
 
147
  int rc;
 
148
  ksba_sexp_t p;
 
149
  size_t n;
 
150
  
 
151
  p = ksba_cert_get_public_key (cert);
 
152
  if (!p)
 
153
    return NULL; /* oops */
 
154
 
 
155
  if (DBG_X509)
 
156
    log_debug ("get_keygrip for public key\n");
 
157
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
 
158
  if (!n)
 
159
    {
 
160
      log_error ("libksba did not return a proper S-Exp\n");
 
161
      return NULL;
 
162
    }
 
163
  rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
 
164
  xfree (p);
 
165
  if (rc)
 
166
    {
 
167
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
 
168
      return NULL;
 
169
    }
 
170
  array = gcry_pk_get_keygrip (s_pkey, array);
 
171
  gcry_sexp_release (s_pkey);
 
172
  if (!array)
 
173
    {
 
174
      rc = gpg_error (GPG_ERR_GENERAL);
 
175
      log_error ("can't calculate keygrip\n");
 
176
      return NULL;
 
177
    }
 
178
  if (DBG_X509)
 
179
    log_printhex ("keygrip=", array, 20);
 
180
 
 
181
  return array;
 
182
}
 
183
 
 
184
/* Return an allocated buffer with the keygrip of CERT in from of an
 
185
   hexstring.  NULL is returned in case of error */
 
186
char *
 
187
gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
 
188
{
 
189
  unsigned char grip[20];
 
190
  char *buf, *p;
 
191
  int i;
 
192
 
 
193
  gpgsm_get_keygrip (cert, grip);
 
194
  buf = p = xmalloc (20*2+1);
 
195
  for (i=0; i < 20; i++, p += 2 )
 
196
    sprintf (p, "%02X", grip[i]);
 
197
  return buf;
 
198
}
 
199
 
 
200
 
 
201
/* Return the PK algorithm used by CERT as well as the length in bits
 
202
   of the public key at NBITS. */
 
203
int
 
204
gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
 
205
{
 
206
  gcry_sexp_t s_pkey;
 
207
  int rc;
 
208
  ksba_sexp_t p;
 
209
  size_t n;
 
210
  gcry_sexp_t l1, l2;
 
211
  const char *name;
 
212
  char namebuf[128];
 
213
 
 
214
  if (nbits)
 
215
    *nbits = 0;
 
216
 
 
217
  p = ksba_cert_get_public_key (cert);
 
218
  if (!p)
 
219
    return 0; 
 
220
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
 
221
  if (!n)
 
222
    {
 
223
      xfree (p);
 
224
      return 0;
 
225
    }
 
226
  rc = gcry_sexp_sscan (&s_pkey, NULL, p, n);
 
227
  xfree (p);
 
228
  if (rc)
 
229
    return 0;
 
230
 
 
231
  if (nbits)
 
232
    *nbits = gcry_pk_get_nbits (s_pkey);
 
233
 
 
234
  /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */
 
235
  l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
 
236
  if (!l1)
 
237
    {
 
238
      gcry_sexp_release (s_pkey);
 
239
      return 0;
 
240
    }
 
241
  l2 = gcry_sexp_cadr (l1);
 
242
  gcry_sexp_release (l1);
 
243
  l1 = l2;
 
244
  name = gcry_sexp_nth_data (l1, 0, &n);
 
245
  if (name)
 
246
    {
 
247
      if (n > sizeof namebuf -1)
 
248
        n = sizeof namebuf -1;
 
249
      memcpy (namebuf, name, n);
 
250
      namebuf[n] = 0;
 
251
    }
 
252
  else
 
253
    *namebuf = 0;
 
254
  gcry_sexp_release (l1);
 
255
  gcry_sexp_release (s_pkey);
 
256
  return gcry_pk_map_name (namebuf);
 
257
}
 
258
 
 
259
 
 
260
 
 
261
 
 
262
/* For certain purposes we need a certificate id which has an upper
 
263
   limit of the size.  We use the hash of the issuer name and the
 
264
   serial number for this.  In most cases the serial number is not
 
265
   that large and the resulting string can be passed on an assuan
 
266
   command line.  Everything is hexencoded with the serialnumber
 
267
   delimited from the hash by a dot. 
 
268
 
 
269
   The caller must free the string.
 
270
*/
 
271
char *
 
272
gpgsm_get_certid (ksba_cert_t cert)
 
273
{
 
274
  ksba_sexp_t serial;
 
275
  unsigned char *p;
 
276
  char *endp;
 
277
  unsigned char hash[20];
 
278
  unsigned long n;
 
279
  char *certid;
 
280
  int i;
 
281
  
 
282
  p = ksba_cert_get_issuer (cert, 0);
 
283
  if (!p)
 
284
    return NULL; /* Ooops: No issuer */
 
285
  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
 
286
  xfree (p);
 
287
 
 
288
  serial = ksba_cert_get_serial (cert);
 
289
  if (!serial)
 
290
    return NULL; /* oops: no serial number */
 
291
  p = serial;
 
292
  if (*p != '(')
 
293
    {
 
294
      log_error ("Ooops: invalid serial number\n");
 
295
      xfree (serial);
 
296
      return NULL;
 
297
    }
 
298
  p++;
 
299
  n = strtoul (p, &endp, 10);
 
300
  p = endp;
 
301
  if (*p != ':')
 
302
    {
 
303
      log_error ("Ooops: invalid serial number (no colon)\n");
 
304
      xfree (serial);
 
305
      return NULL;
 
306
    }
 
307
  p++;
 
308
 
 
309
  certid = xtrymalloc ( 40 + 1 + n*2 + 1);
 
310
  if (!certid)
 
311
    {
 
312
      xfree (serial);
 
313
      return NULL; /* out of core */
 
314
    }
 
315
 
 
316
  for (i=0, endp = certid; i < 20; i++, endp += 2 )
 
317
    sprintf (endp, "%02X", hash[i]);
 
318
  *endp++ = '.';
 
319
  for (i=0; i < n; i++, endp += 2)
 
320
    sprintf (endp, "%02X", p[i]);
 
321
  *endp = 0;
 
322
 
 
323
  xfree (serial);
 
324
  return certid;
 
325
}
 
326
 
 
327
 
 
328
 
 
329
 
 
330
 
 
331