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