* gpgsm.c, gpgsm.h: Add local_user.
[gnupg.git] / sm / fingerprint.c
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 #include <gcrypt.h>
31 #include <ksba.h>
32
33 #include "gpgsm.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 return, 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 (KsbaCert cert, int algo, char *array, int *r_len)
47 {
48   GCRY_MD_HD 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   md = gcry_md_open (algo, 0);
63   if (!md)
64     {
65       log_error ("md_open failed: %s\n", gcry_strerror (-1));
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", ksba_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 (KsbaCert 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 fungerprint as one
106    large hexnumber */
107 char *
108 gpgsm_get_fingerprint_hexstring (KsbaCert 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 \f
128 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
129    key parameters expressed as an canoncial encoded S-Exp.  array must
130    be 20 bytes long. returns the array or a newly allocated one if the
131    passed one was NULL */
132 char *
133 gpgsm_get_keygrip (KsbaCert cert, char *array)
134 {
135   GCRY_SEXP s_pkey;
136   int rc;
137   KsbaSexp p;
138   size_t n;
139   
140   p = ksba_cert_get_public_key (cert);
141   if (!p)
142     return NULL; /* oops */
143
144   if (DBG_X509)
145     log_debug ("get_keygrip for public key: %s\n", p);
146   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
147   if (!n)
148     {
149       log_error ("libksba did not return a proper S-Exp\n");
150       return NULL;
151     }
152   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
153   xfree (p);
154   if (rc)
155     {
156       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
157       return NULL;
158     }
159   array = gcry_pk_get_keygrip (s_pkey, array);
160   gcry_sexp_release (s_pkey);
161   if (!array)
162     {
163       rc = seterr (General_Error);
164       log_error ("can't calculate keygrip\n");
165       return NULL;
166     }
167   if (DBG_X509)
168     log_printhex ("keygrip=", array, 20);
169
170   return array;
171 }
172
173 /* Return an allocated buffer with the keygrip of CERT in from of an
174    hexstring.  NULL is returned in case of error */
175 char *
176 gpgsm_get_keygrip_hexstring (KsbaCert cert)
177 {
178   unsigned char grip[20];
179   char *buf, *p;
180   int i;
181
182   gpgsm_get_keygrip (cert, grip);
183   buf = p = xmalloc (20*2+1);
184   for (i=0; i < 20; i++, p += 2 )
185     sprintf (p, "%02X", grip[i]);
186   return buf;
187 }
188
189
190 \f
191 /* For certain purposes we need a certificate id which has an upper
192    limit of the size.  We use the hash of the issuer name and the
193    serial number for this.  In most cases the serial number is not
194    that large and the resulting string can be passed on an assuan
195    command line.  Everything is hexencoded with the serialnumber
196    delimted from the has by a dot. 
197
198    The caller must free the string.
199 */
200 char *
201 gpgsm_get_certid (KsbaCert cert)
202 {
203   KsbaSexp serial;
204   unsigned char *p;
205   char *endp;
206   unsigned char hash[20];
207   unsigned long n;
208   char *certid;
209   int i;
210   
211   p = ksba_cert_get_issuer (cert, 0);
212   if (!p)
213     return NULL; /* Ooops: No issuer */
214   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
215   xfree (p);
216
217   serial = ksba_cert_get_serial (cert);
218   if (!serial)
219     return NULL; /* oops: no serial number */
220   p = serial;
221   if (*p != '(')
222     {
223       log_error ("Ooops: invalid serial number\n");
224       xfree (serial);
225       return NULL;
226     }
227   p++;
228   n = strtoul (p, &endp, 10);
229   p = endp;
230   if (*p != ':')
231     {
232       log_error ("Ooops: invalid serial number (no colon)\n");
233       xfree (serial);
234       return NULL;
235     }
236   p++;
237
238   certid = xtrymalloc ( 40 + 1 + n*2 + 1);
239   if (!certid)
240     {
241       xfree (serial);
242       return NULL; /* out of core */
243     }
244
245   for (i=0, endp = certid; i < 20; i++, endp += 2 )
246     sprintf (endp, "%02X", hash[i]);
247   *endp++ = '.';
248   for (i=0; i < n; i++, endp += 2)
249     sprintf (endp, "%02X", p[i]);
250   *endp = 0;
251
252   xfree (serial);
253   return certid;
254 }
255
256
257
258
259
260