2d5448e668c21e33fda9b0acc58e60d07baee27e
[gnupg.git] / sm / certcheck.c
1 /* certcheck.c - check one certificate
2  *      Copyright (C) 2001 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 <gcrypt.h>
31 #include <ksba.h>
32
33 #include "gpgsm.h"
34 #include "keydb.h"
35 #include "i18n.h"
36
37
38 static int
39 do_encode_md (GCRY_MD_HD md, int algo,  unsigned int nbits,
40               GCRY_MPI *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 GPGSM_Internal_Error;
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 GPGSM_Internal_Error;
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 GPGSM_Out_Of_Core;
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, &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 md;
108   int rc, algo;
109   GCRY_MPI frame;
110   char *p;
111   GCRY_SEXP s_sig, s_hash, s_pkey;
112
113   algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
114   if (!algo)
115     {
116       log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
117       return GPGSM_General_Error;
118     }
119   md = gcry_md_open (algo, 0);
120   if (!md)
121     {
122       log_error ("md_open failed: %s\n", gcry_strerror (-1));
123       return GPGSM_General_Error;
124     }
125
126   rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
127   if (rc)
128     {
129       log_error ("ksba_cert_hash failed: %s\n", ksba_strerror (rc));
130       gcry_md_close (md);
131       return map_ksba_err (rc);
132     }
133   gcry_md_final (md);
134
135   p = ksba_cert_get_sig_val (cert); /* fixme: check p*/
136   if (DBG_X509)
137     log_debug ("signature: %s\n", p);
138
139   rc = gcry_sexp_sscan ( &s_sig, NULL, p, strlen(p));
140   if (rc)
141     {
142       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
143       return map_gcry_err (rc);
144     }
145
146   p = ksba_cert_get_public_key (issuer_cert);
147   if (DBG_X509)
148     log_debug ("issuer public key: %s\n", p);
149
150   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, strlen(p));
151   if (rc)
152     {
153       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
154       return map_gcry_err (rc);
155     }
156
157   rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
158   if (rc)
159     {
160       /* fixme: clean up some things */
161       return rc;
162     }
163   /* put hash into the S-Exp s_hash */
164   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
165     BUG ();
166
167   
168   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
169   if (DBG_CRYPTO)
170       log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc));
171   return map_gcry_err (rc);
172 }
173
174
175
176 int
177 gpgsm_check_cms_signature (KsbaCert cert, const char *sigval,
178                            GCRY_MD_HD md, int algo)
179 {
180   int rc;
181   char *p;
182   GCRY_MPI frame;
183   GCRY_SEXP s_sig, s_hash, s_pkey;
184
185   rc = gcry_sexp_sscan (&s_sig, NULL, sigval, strlen(sigval));
186   if (rc)
187     {
188       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
189       return map_gcry_err (rc);
190     }
191
192   if (getenv ("GPGSM_FAKE_KEY"))
193     {
194       const char n[] = "#8732A669BB7C5057AD070EFA54E035C86DF474F7A7EBE2435"
195         "3DADEB86FFE74C32AEEF9E5C6BD7584CB572520167B3E8C89A1FA75C74FF9E938"
196         "2710F3B270B638EB96E7486491D81C53CA8A50B4E840B1C7458A4A1E52EC18D681"
197         "8A2805C9165827F77EF90D55014E4B2AF9386AE8F6462F46A547CB593ABD509311"
198         "4D3D16375F#";
199       const char e[] = "#11#";
200       char *tmp;
201
202       log_debug ("Using HARDWIRED public key\n");
203       asprintf (&tmp, "(public-key(rsa(n %s)(e %s)))", n, e);
204       /* asprintf does not use our allocation fucntions, so we can't
205          use our free */
206       p = xstrdup (tmp);
207       free (tmp);
208     }
209   else
210     {
211       p = ksba_cert_get_public_key (cert);
212     }
213
214   if (DBG_X509)
215     log_debug ("public key: %s\n", p);
216   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, strlen(p));
217   if (rc)
218     {
219       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
220       return map_gcry_err (rc);
221     }
222
223
224   rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
225   if (rc)
226     {
227       /* fixme: clean up some things */
228       return rc;
229     }
230   /* put hash into the S-Exp s_hash */
231   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
232     BUG ();
233
234   
235   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
236   if (DBG_CRYPTO)
237       log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc));
238   return map_gcry_err (rc);
239 }
240
241
242
243 int
244 gpgsm_create_cms_signature (KsbaCert cert, GCRY_MD_HD md, int mdalgo,
245                             char **r_sigval)
246 {
247   /* our sample key */
248   const char n[] = "#8732A669BB7C5057AD070EFA54E035C86DF474F7A7EBE2435"
249     "3DADEB86FFE74C32AEEF9E5C6BD7584CB572520167B3E8C89A1FA75C74FF9E938"
250     "2710F3B270B638EB96E7486491D81C53CA8A50B4E840B1C7458A4A1E52EC18D681"
251     "8A2805C9165827F77EF90D55014E4B2AF9386AE8F6462F46A547CB593ABD509311"
252     "4D3D16375F#";
253   const char e[] = "#11#";
254   const char d[] = "#07F3EBABDDDA22D7FB1E8869140D30571586D9B4370DE02213F"
255     "DD0DDAC3C24FC6BEFF0950BB0CAAD755F7AA788DA12BCF90987341AC8781CC7115"
256     "B59A115B05D9D99B3D7AF77854DC2EE6A36154512CC0EAD832601038A88E837112"
257     "AB2A39FD9FBE05E30D6FFA6F43D71C59F423CA43BC91C254A8C89673AB61F326B0"
258     "762FBC9#";
259   const char p[] = "#B2ABAD4328E66303E206C53CFBED17F18F712B1C47C966EE13DD"
260     "AA9AD3616A610ADF513F8376FA48BAE12FED64CECC1E73091A77B45119AF0FC1286A"
261     "85BD9BBD#";
262   const char q[] = "#C1B648B294BB9AEE7FEEB77C4F64E9333E4EA9A7C54D521356FB"
263     "BBB7558A0E7D6331EC7B42E3F0CD7BBBA9B7A013422F615F10DCC1E8462828BF8FC7"
264     "39C5E34B#";
265   const char  u[] = "#A9B5EFF9C80A4A356B9A95EB63E381B262071E5CE9C1F32FF03"
266     "83AD8289BED8BC690555E54411FA2FDB9B49638A21B2046C325F5633B4B1ECABEBFD"
267     "1B3519072#";
268
269   GCRY_SEXP s_skey, s_hash, s_sig;
270   GCRY_MPI frame;
271   int rc;
272   char *buf;
273   size_t len;
274
275   /* create a secret key as an sexp */
276   log_debug ("Using HARDWIRED secret key\n");
277   asprintf (&buf, "(private-key(oid.1.2.840.113549.1.1.1"
278            "(n %s)(e %s)(d %s)(p %s)(q %s)(u %s)))",
279            n, e, d, p, q, u);
280   /* asprintf does not use our allocation fucntions, so we can't
281      use our free */
282   rc = gcry_sexp_sscan (&s_skey, NULL, buf, strlen(buf));
283   free (buf);
284   if (rc)
285     {
286       log_error ("failed to build S-Exp: %s\n", gcry_strerror (rc));
287       return map_gcry_err (rc);
288     }
289   
290   /* put the hash into a sexp */
291   rc = do_encode_md (md, mdalgo, gcry_pk_get_nbits (s_skey), &frame);
292   if (rc)
293     {
294       /* fixme: clean up some things */
295       return rc;
296     }
297   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
298     BUG ();
299
300
301   /* sign */
302   rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
303   if (rc)
304     {
305       log_error ("signing failed: %s\n", gcry_strerror (rc));
306       return map_gcry_err (rc);
307     }
308
309   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
310   assert (len);
311   buf = xmalloc (len);
312   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
313   assert (len);
314
315   *r_sigval = buf;
316   return 0;
317 }
318
319