Updated FSF's address.
[gnupg.git] / sm / certcheck.c
1 /* certcheck.c - check one certificate
2  *      Copyright (C) 2001, 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h> 
28 #include <time.h>
29 #include <assert.h>
30
31 #include "gpgsm.h"
32 #include <gcrypt.h>
33 #include <ksba.h>
34
35 #include "keydb.h"
36 #include "i18n.h"
37
38
39 static int
40 do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits,
41               gcry_mpi_t *r_val)
42 {
43   int n;
44   size_t nframe;
45   unsigned char *frame;
46
47   if (pkalgo == GCRY_PK_DSA)
48     {
49       nframe = gcry_md_get_algo_dlen (algo);
50       if (nframe != 20)
51         {
52           log_error (_("DSA requires the use of a 160 bit hash algorithm\n"));
53           return gpg_error (GPG_ERR_INTERNAL);
54         }
55       frame = xtrymalloc (nframe);
56       if (!frame)
57         return OUT_OF_CORE (errno);
58       memcpy (frame, gcry_md_read (md, algo), nframe);
59       n = nframe;
60     }
61   else
62     {
63       int i;
64       unsigned char asn[100];
65       size_t asnlen;
66       size_t len;
67
68       nframe = (nbits+7) / 8;
69
70       asnlen = DIM(asn);
71       if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
72         {
73           log_error ("no object identifier for algo %d\n", algo);
74           return gpg_error (GPG_ERR_INTERNAL);
75         }
76       
77       len = gcry_md_get_algo_dlen (algo);
78       
79       if ( len + asnlen + 4  > nframe )
80         {
81           log_error ("can't encode a %d bit MD into a %d bits frame\n",
82                      (int)(len*8), (int)nbits);
83           return gpg_error (GPG_ERR_INTERNAL);
84         }
85       
86       /* We encode the MD in this way:
87        *
88        *           0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
89        *
90        * PAD consists of FF bytes.
91        */
92       frame = xtrymalloc (nframe);
93       if (!frame)
94         return OUT_OF_CORE (errno);
95       n = 0;
96       frame[n++] = 0;
97       frame[n++] = 1; /* block type */
98       i = nframe - len - asnlen -3 ;
99       assert ( i > 1 );
100       memset ( frame+n, 0xff, i ); n += i;
101       frame[n++] = 0;
102       memcpy ( frame+n, asn, asnlen ); n += asnlen;
103       memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len;
104       assert ( n == nframe );
105     }
106   if (DBG_CRYPTO)
107     {
108       int j;
109       log_debug ("encoded hash:");
110       for (j=0; j < nframe; j++)
111         log_printf (" %02X", frame[j]);
112       log_printf ("\n");
113     }
114       
115   gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe);
116   xfree (frame);
117   return 0;
118 }
119
120 /* Return the public key algorithm id from the S-expression PKEY.
121    FIXME: libgcrypt should provide such a function.  Note that this
122    implementation uses the names as used by libksba.  */
123 static int
124 pk_algo_from_sexp (gcry_sexp_t pkey)
125 {
126   gcry_sexp_t l1, l2;
127   const char *name;
128   size_t n;
129   int algo;
130
131   l1 = gcry_sexp_find_token (pkey, "public-key", 0);
132   if (!l1)
133     return 0; /* Not found.  */
134   l2 = gcry_sexp_cadr (l1);
135   gcry_sexp_release (l1);
136
137   name = gcry_sexp_nth_data (l2, 0, &n);
138   if (!name)
139     algo = 0; /* Not found. */
140   else if (n==3 && !memcmp (name, "rsa", 3))
141     algo = GCRY_PK_RSA;
142   else if (n==3 && !memcmp (name, "dsa", 3))
143     algo = GCRY_PK_DSA;
144   else if (n==13 && !memcmp (name, "ambiguous-rsa", 13))
145     algo = GCRY_PK_RSA;
146   else
147     algo = 0;
148   gcry_sexp_release (l2);
149   return algo;
150 }
151
152
153 /*
154   Check the signature on CERT using the ISSUER-CERT.  This function
155   does only test the cryptographic signature and nothing else.  It is
156   assumed that the ISSUER_CERT is valid. */
157 int
158 gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
159 {
160   const char *algoid;
161   gcry_md_hd_t md;
162   int rc, algo;
163   gcry_mpi_t frame;
164   ksba_sexp_t p;
165   size_t n;
166   gcry_sexp_t s_sig, s_hash, s_pkey;
167
168   algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
169   if (!algo)
170     {
171       log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
172       if (algoid
173           && (  !strcmp (algoid, "1.2.840.113549.1.1.2")
174                 ||!strcmp (algoid, "1.2.840.113549.2.2")))
175         log_info (_("(this is the MD2 algorithm)\n"));
176       return gpg_error (GPG_ERR_GENERAL);
177     }
178   rc = gcry_md_open (&md, algo, 0);
179   if (rc)
180     {
181       log_error ("md_open failed: %s\n", gpg_strerror (rc));
182       return rc;
183     }
184   if (DBG_HASHING)
185     gcry_md_start_debug (md, "hash.cert");
186
187   rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
188   if (rc)
189     {
190       log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
191       gcry_md_close (md);
192       return rc;
193     }
194   gcry_md_final (md);
195
196   p = ksba_cert_get_sig_val (cert);
197   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
198   if (!n)
199     {
200       log_error ("libksba did not return a proper S-Exp\n");
201       gcry_md_close (md);
202       ksba_free (p);
203       return gpg_error (GPG_ERR_BUG);
204     }
205   if (DBG_CRYPTO)
206     {
207       int j;
208       log_debug ("signature value:");
209       for (j=0; j < n; j++)
210         log_printf (" %02X", p[j]);
211       log_printf ("\n");
212     }
213
214   rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n);
215   ksba_free (p);
216   if (rc)
217     {
218       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
219       gcry_md_close (md);
220       return rc;
221     }
222
223   p = ksba_cert_get_public_key (issuer_cert);
224   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
225   if (!n)
226     {
227       log_error ("libksba did not return a proper S-Exp\n");
228       gcry_md_close (md);
229       ksba_free (p);
230       gcry_sexp_release (s_sig);
231       return gpg_error (GPG_ERR_BUG);
232     }
233   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
234   ksba_free (p);
235   if (rc)
236     {
237       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
238       gcry_md_close (md);
239       gcry_sexp_release (s_sig);
240       return rc;
241     }
242
243   rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
244                      gcry_pk_get_nbits (s_pkey), &frame);
245   if (rc)
246     {
247       gcry_md_close (md);
248       gcry_sexp_release (s_sig);
249       gcry_sexp_release (s_pkey);
250       return rc;
251     }
252
253   /* put hash into the S-Exp s_hash */
254   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
255     BUG ();
256   gcry_mpi_release (frame);
257
258   
259   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
260   if (DBG_X509)
261       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
262   gcry_md_close (md);
263   gcry_sexp_release (s_sig);
264   gcry_sexp_release (s_hash);
265   gcry_sexp_release (s_pkey);
266   return rc;
267 }
268
269
270
271 int
272 gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
273                            gcry_md_hd_t md, int algo)
274 {
275   int rc;
276   ksba_sexp_t p;
277   gcry_mpi_t frame;
278   gcry_sexp_t s_sig, s_hash, s_pkey;
279   size_t n;
280
281   n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
282   if (!n)
283     {
284       log_error ("libksba did not return a proper S-Exp\n");
285       return gpg_error (GPG_ERR_BUG);
286     }
287   rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n);
288   if (rc)
289     {
290       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
291       return rc;
292     }
293
294   p = ksba_cert_get_public_key (cert);
295   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
296   if (!n)
297     {
298       log_error ("libksba did not return a proper S-Exp\n");
299       ksba_free (p);
300       gcry_sexp_release (s_sig);
301       return gpg_error (GPG_ERR_BUG);
302     }
303   if (DBG_CRYPTO)
304     log_printhex ("public key: ", p, n);
305
306   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
307   ksba_free (p);
308   if (rc)
309     {
310       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
311       gcry_sexp_release (s_sig);
312       return rc;
313     }
314
315
316   rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
317                      gcry_pk_get_nbits (s_pkey), &frame);
318   if (rc)
319     {
320       gcry_sexp_release (s_sig);
321       gcry_sexp_release (s_pkey);
322       return rc;
323     }
324   /* put hash into the S-Exp s_hash */
325   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
326     BUG ();
327   gcry_mpi_release (frame);
328   
329   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
330   if (DBG_X509)
331       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
332   gcry_sexp_release (s_sig);
333   gcry_sexp_release (s_hash);
334   gcry_sexp_release (s_pkey);
335   return rc;
336 }
337
338
339
340 int
341 gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert,
342                             gcry_md_hd_t md, int mdalgo,
343                             unsigned char **r_sigval)
344 {
345   int rc;
346   char *grip, *desc;
347   size_t siglen;
348
349   grip = gpgsm_get_keygrip_hexstring (cert);
350   if (!grip)
351     return gpg_error (GPG_ERR_BAD_CERT);
352
353   desc = gpgsm_format_keydesc (cert);
354
355   rc = gpgsm_agent_pksign (ctrl, grip, desc, gcry_md_read(md, mdalgo), 
356                            gcry_md_get_algo_dlen (mdalgo), mdalgo,
357                            r_sigval, &siglen);
358   xfree (desc);
359   xfree (grip);
360   return rc;
361 }
362
363
364