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