gcc-4 defaults forced me to edit many many files to get rid of the
[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       return gpg_error (GPG_ERR_GENERAL);
172     }
173   rc = gcry_md_open (&md, algo, 0);
174   if (rc)
175     {
176       log_error ("md_open failed: %s\n", gpg_strerror (rc));
177       return rc;
178     }
179   if (DBG_HASHING)
180     gcry_md_start_debug (md, "hash.cert");
181
182   rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
183   if (rc)
184     {
185       log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc));
186       gcry_md_close (md);
187       return rc;
188     }
189   gcry_md_final (md);
190
191   p = ksba_cert_get_sig_val (cert);
192   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
193   if (!n)
194     {
195       log_error ("libksba did not return a proper S-Exp\n");
196       gcry_md_close (md);
197       ksba_free (p);
198       return gpg_error (GPG_ERR_BUG);
199     }
200   if (DBG_CRYPTO)
201     {
202       int j;
203       log_debug ("signature value:");
204       for (j=0; j < n; j++)
205         log_printf (" %02X", p[j]);
206       log_printf ("\n");
207     }
208
209   rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n);
210   ksba_free (p);
211   if (rc)
212     {
213       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
214       gcry_md_close (md);
215       return rc;
216     }
217
218   p = ksba_cert_get_public_key (issuer_cert);
219   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
220   if (!n)
221     {
222       log_error ("libksba did not return a proper S-Exp\n");
223       gcry_md_close (md);
224       ksba_free (p);
225       gcry_sexp_release (s_sig);
226       return gpg_error (GPG_ERR_BUG);
227     }
228   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
229   ksba_free (p);
230   if (rc)
231     {
232       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
233       gcry_md_close (md);
234       gcry_sexp_release (s_sig);
235       return rc;
236     }
237
238   rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
239                      gcry_pk_get_nbits (s_pkey), &frame);
240   if (rc)
241     {
242       gcry_md_close (md);
243       gcry_sexp_release (s_sig);
244       gcry_sexp_release (s_pkey);
245       return rc;
246     }
247
248   /* put hash into the S-Exp s_hash */
249   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
250     BUG ();
251   gcry_mpi_release (frame);
252
253   
254   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
255   if (DBG_X509)
256       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
257   gcry_md_close (md);
258   gcry_sexp_release (s_sig);
259   gcry_sexp_release (s_hash);
260   gcry_sexp_release (s_pkey);
261   return rc;
262 }
263
264
265
266 int
267 gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
268                            gcry_md_hd_t md, int algo)
269 {
270   int rc;
271   ksba_sexp_t p;
272   gcry_mpi_t frame;
273   gcry_sexp_t s_sig, s_hash, s_pkey;
274   size_t n;
275
276   n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
277   if (!n)
278     {
279       log_error ("libksba did not return a proper S-Exp\n");
280       return gpg_error (GPG_ERR_BUG);
281     }
282   rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n);
283   if (rc)
284     {
285       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
286       return rc;
287     }
288
289   p = ksba_cert_get_public_key (cert);
290   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
291   if (!n)
292     {
293       log_error ("libksba did not return a proper S-Exp\n");
294       ksba_free (p);
295       gcry_sexp_release (s_sig);
296       return gpg_error (GPG_ERR_BUG);
297     }
298   if (DBG_CRYPTO)
299     log_printhex ("public key: ", p, n);
300
301   rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
302   ksba_free (p);
303   if (rc)
304     {
305       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
306       gcry_sexp_release (s_sig);
307       return rc;
308     }
309
310
311   rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
312                      gcry_pk_get_nbits (s_pkey), &frame);
313   if (rc)
314     {
315       gcry_sexp_release (s_sig);
316       gcry_sexp_release (s_pkey);
317       return rc;
318     }
319   /* put hash into the S-Exp s_hash */
320   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
321     BUG ();
322   gcry_mpi_release (frame);
323   
324   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
325   if (DBG_X509)
326       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
327   gcry_sexp_release (s_sig);
328   gcry_sexp_release (s_hash);
329   gcry_sexp_release (s_pkey);
330   return rc;
331 }
332
333
334
335 int
336 gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert,
337                             gcry_md_hd_t md, int mdalgo,
338                             unsigned char **r_sigval)
339 {
340   int rc;
341   char *grip, *desc;
342   size_t siglen;
343
344   grip = gpgsm_get_keygrip_hexstring (cert);
345   if (!grip)
346     return gpg_error (GPG_ERR_BAD_CERT);
347
348   desc = gpgsm_format_keydesc (cert);
349
350   rc = gpgsm_agent_pksign (ctrl, grip, desc, gcry_md_read(md, mdalgo), 
351                            gcry_md_get_algo_dlen (mdalgo), mdalgo,
352                            r_sigval, &siglen);
353   xfree (desc);
354   xfree (grip);
355   return rc;
356 }
357
358
359