35509c67ed7dc473e75fb7948a1ab878efadf957
[gnupg.git] / sm / certcheck.c
1 /* certcheck.c - check one certificate
2  *      Copyright (C) 2001, 2003 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,  unsigned int nbits,
40               gcry_mpi_t *r_val)
41 {
42   int nframe = (nbits+7) / 8;
43   byte *frame;
44   int i, n;
45   byte asn[100];
46   size_t asnlen;
47   size_t len;
48
49   asnlen = DIM(asn);
50   if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
51     {
52       log_error ("No object identifier for algo %d\n", algo);
53       return gpg_error (GPG_ERR_INTERNAL);
54     }
55
56   len = gcry_md_get_algo_dlen (algo);
57   
58   if ( len + asnlen + 4  > nframe )
59     {
60       log_error ("can't encode a %d bit MD into a %d bits frame\n",
61                  (int)(len*8), (int)nbits);
62       return gpg_error (GPG_ERR_INTERNAL);
63     }
64   
65   /* We encode the MD in this way:
66    *
67    *       0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
68    *
69    * PAD consists of FF bytes.
70    */
71   frame = xtrymalloc (nframe);
72   if (!frame)
73     return OUT_OF_CORE (errno);
74   n = 0;
75   frame[n++] = 0;
76   frame[n++] = 1; /* block type */
77   i = nframe - len - asnlen -3 ;
78   assert ( i > 1 );
79   memset ( frame+n, 0xff, i ); n += i;
80   frame[n++] = 0;
81   memcpy ( frame+n, asn, asnlen ); n += asnlen;
82   memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len;
83   assert ( n == nframe );
84   if (DBG_X509)
85     {
86       int j;
87       log_debug ("encoded hash:");
88       for (j=0; j < nframe; j++)
89         log_printf (" %02X", frame[j]);
90       log_printf ("\n");
91     }
92       
93   gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe);
94   xfree (frame);
95   return 0;
96 }
97
98
99 /*
100   Check the signature on CERT using the ISSUER-CERT.  This function
101   does only test the cryptographic signature and nothing else.  It is
102   assumed that the ISSUER_CERT is valid. */
103 int
104 gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert)
105 {
106   const char *algoid;
107   gcry_md_hd_t md;
108   int rc, algo;
109   gcry_mpi_t frame;
110   KsbaSexp p;
111   size_t n;
112   gcry_sexp_t s_sig, s_hash, s_pkey;
113
114   algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
115   if (!algo)
116     {
117       log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
118       return gpg_error (GPG_ERR_GENERAL);
119     }
120   rc = gcry_md_open (&md, algo, 0);
121   if (rc)
122     {
123       log_error ("md_open failed: %s\n", gpg_strerror (rc));
124       return rc;
125     }
126   if (DBG_HASHING)
127     gcry_md_start_debug (md, "hash.cert");
128
129   rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
130   if (rc)
131     {
132       log_error ("ksba_cert_hash failed: %s\n", ksba_strerror (rc));
133       gcry_md_close (md);
134       return map_ksba_err (rc);
135     }
136   gcry_md_final (md);
137
138   p = ksba_cert_get_sig_val (cert);
139   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
140   if (!n)
141     {
142       log_error ("libksba did not return a proper S-Exp\n");
143       gcry_md_close (md);
144       ksba_free (p);
145       return gpg_error (GPG_ERR_BUG);
146     }
147   if (DBG_X509)
148     {
149       int j;
150       log_debug ("signature value:");
151       for (j=0; j < n; j++)
152         log_printf (" %02X", p[j]);
153       log_printf ("\n");
154     }
155
156   rc = gcry_sexp_sscan ( &s_sig, NULL, p, n);
157   ksba_free (p);
158   if (rc)
159     {
160       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
161       gcry_md_close (md);
162       return rc;
163     }
164
165   p = ksba_cert_get_public_key (issuer_cert);
166   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
167   if (!n)
168     {
169       log_error ("libksba did not return a proper S-Exp\n");
170       gcry_md_close (md);
171       ksba_free (p);
172       gcry_sexp_release (s_sig);
173       return gpg_error (GPG_ERR_BUG);
174     }
175   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
176   ksba_free (p);
177   if (rc)
178     {
179       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
180       gcry_md_close (md);
181       gcry_sexp_release (s_sig);
182       return rc;
183     }
184
185   rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
186   if (rc)
187     {
188       gcry_md_close (md);
189       gcry_sexp_release (s_sig);
190       gcry_sexp_release (s_pkey);
191       return rc;
192     }
193
194   /* put hash into the S-Exp s_hash */
195   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
196     BUG ();
197   gcry_mpi_release (frame);
198
199   
200   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
201   if (DBG_CRYPTO)
202       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
203   gcry_md_close (md);
204   gcry_sexp_release (s_sig);
205   gcry_sexp_release (s_hash);
206   gcry_sexp_release (s_pkey);
207   return rc;
208 }
209
210
211
212 int
213 gpgsm_check_cms_signature (KsbaCert cert, KsbaConstSexp sigval,
214                            gcry_md_hd_t md, int algo)
215 {
216   int rc;
217   KsbaSexp p;
218   gcry_mpi_t frame;
219   gcry_sexp_t s_sig, s_hash, s_pkey;
220   size_t n;
221
222   n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
223   if (!n)
224     {
225       log_error ("libksba did not return a proper S-Exp\n");
226       return gpg_error (GPG_ERR_BUG);
227     }
228   rc = gcry_sexp_sscan (&s_sig, NULL, sigval, n);
229   if (rc)
230     {
231       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
232       return rc;
233     }
234
235   p = ksba_cert_get_public_key (cert);
236   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
237   if (!n)
238     {
239       log_error ("libksba did not return a proper S-Exp\n");
240       ksba_free (p);
241       gcry_sexp_release (s_sig);
242       return gpg_error (GPG_ERR_BUG);
243     }
244   if (DBG_X509)
245     log_printhex ("public key: ", p, n);
246
247   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
248   ksba_free (p);
249   if (rc)
250     {
251       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
252       gcry_sexp_release (s_sig);
253       return rc;
254     }
255
256
257   rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
258   if (rc)
259     {
260       gcry_sexp_release (s_sig);
261       gcry_sexp_release (s_pkey);
262       return rc;
263     }
264   /* put hash into the S-Exp s_hash */
265   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
266     BUG ();
267   gcry_mpi_release (frame);
268   
269   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
270   if (DBG_CRYPTO)
271       log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
272   gcry_sexp_release (s_sig);
273   gcry_sexp_release (s_hash);
274   gcry_sexp_release (s_pkey);
275   return rc;
276 }
277
278
279
280 int
281 gpgsm_create_cms_signature (KsbaCert cert, gcry_md_hd_t md, int mdalgo,
282                             char **r_sigval)
283 {
284   int rc;
285   char *grip;
286   size_t siglen;
287
288   grip = gpgsm_get_keygrip_hexstring (cert);
289   if (!grip)
290     return gpg_error (GPG_ERR_BAD_CERT);
291
292   rc = gpgsm_agent_pksign (grip, gcry_md_read(md, mdalgo), 
293                            gcry_md_get_algo_dlen (mdalgo), mdalgo,
294                            r_sigval, &siglen);
295   xfree (grip);
296   return rc;
297 }
298
299
300