we are now able to check self-signed certificates
[gnupg.git] / sm / import.c
1 /* import.c - Import certificates
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
35 struct reader_cb_parm_s {
36   FILE *fp;
37 };
38
39
40 static int
41 reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
42 {
43   struct reader_cb_parm_s *parm = cb_value;
44   size_t n;
45   int c = 0;
46
47   *nread = 0;
48   if (!buffer)
49     return -1; /* not supported */
50
51   for (n=0; n < count; n++)
52     {
53       c = getc (parm->fp);
54       if (c == EOF)
55         {
56           if ( ferror (parm->fp) )
57             return -1;
58           if (n)
59             break; /* return what we have before an EOF */
60           return -1;
61         }
62       *(byte *)buffer++ = c;
63     }
64
65   *nread = n;
66   return 0;
67 }
68
69
70 static void
71 print_integer (unsigned char *p)
72 {
73   unsigned long len;
74
75   if (!p)
76     fputs ("none", stdout);
77   else
78     {
79       len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
80       for (p+=4; len; len--, p++)
81         printf ("%02X", *p);
82     }
83 }
84
85 static void
86 print_time (time_t t)
87 {
88
89   if (!t)
90     fputs ("none", stdout);
91   else if ( t == (time_t)(-1) )
92     fputs ("error", stdout);
93   else
94     {
95       struct tm *tp;
96
97       tp = gmtime (&t);
98       printf ("%04d-%02d-%02d %02d:%02d:%02d",
99               1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
100               tp->tm_hour, tp->tm_min, tp->tm_sec);
101       assert (!tp->tm_isdst);
102     }
103 }
104
105 static void
106 print_dn (char *p)
107 {
108
109   if (!p)
110     fputs ("error", stdout);
111   else
112     printf ("`%s'", p);
113 }
114
115 static void 
116 print_cert (KsbaCert cert)
117 {
118   unsigned char *p;
119   char *dn;
120   time_t t;
121     
122   p = ksba_cert_get_serial (cert);
123   fputs ("serial: ", stdout);
124   print_integer (p);
125   ksba_free (p);
126   putchar ('\n');
127
128   t = ksba_cert_get_validity (cert, 0);
129   fputs ("notBefore: ", stdout);
130   print_time (t);
131   putchar ('\n');
132   t = ksba_cert_get_validity (cert, 1);
133   fputs ("notAfter: ", stdout);
134   print_time (t);
135   putchar ('\n');
136     
137   dn = ksba_cert_get_issuer (cert);
138   fputs ("issuer: ", stdout);
139   print_dn (dn);
140   ksba_free (dn);
141   putchar ('\n');
142     
143   dn = ksba_cert_get_subject (cert);
144   fputs ("subject: ", stdout);
145   print_dn (dn);
146   ksba_free (dn);
147   putchar ('\n');
148
149   printf ("hash algo: %d\n", ksba_cert_get_digest_algo (cert));
150 }
151
152
153
154 static MPI
155 do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
156               const byte *asn, size_t asnlen)
157 {
158     int nframe = (nbits+7) / 8;
159     byte *frame;
160     int i,n;
161     MPI a;
162
163     if( len + asnlen + 4  > nframe )
164         log_bug("can't encode a %d bit MD into a %d bits frame\n",
165                     (int)(len*8), (int)nbits);
166
167     /* We encode the MD in this way:
168      *
169      *     0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
170      *
171      * PAD consists of FF bytes.
172      */
173     frame = xmalloc (nframe);
174     n = 0;
175     frame[n++] = 0;
176     frame[n++] = 1; /* block type */
177     i = nframe - len - asnlen -3 ;
178     assert( i > 1 );
179     memset( frame+n, 0xff, i ); n += i;
180     frame[n++] = 0;
181     memcpy( frame+n, asn, asnlen ); n += asnlen;
182     memcpy( frame+n, gcry_md_read(md, algo), len ); n += len;
183     assert( n == nframe );
184     gcry_mpi_scan ( &a, GCRYMPI_FMT_USG, frame, &nframe);
185     xfree(frame);
186     return a;
187 }
188
189
190
191
192 static void
193 check_selfsigned_cert (KsbaCert cert)
194 {
195   /* OID for MD5 as defined in PKCS#1 (rfc2313) */
196   static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 (md5) */
197   { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48,
198     0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
199   };
200
201   GCRY_MD_HD md;
202   int rc, algo;
203   GCRY_MPI frame;
204   char *p;
205   GCRY_SEXP s_sig, s_hash, s_pkey;
206
207   algo = ksba_cert_get_digest_algo (cert);
208   md = gcry_md_open (algo, 0);
209   if (!md)
210     {
211       log_error ("md_open failed: %s\n", gcry_strerror (-1));
212       return;
213     }
214
215   gcry_md_start_debug (md, "cert");
216   rc = ksba_cert_hash (cert, gcry_md_write, md);
217   if (rc)
218     {
219       log_error ("ksba_cert_hash failed: %s\n", ksba_strerror (rc));
220       gcry_md_close (md);
221       return;
222     }
223   gcry_md_final (md);
224
225   p = ksba_cert_get_sig_val (cert);
226   printf ("signature: %s\n", p);
227
228   rc = gcry_sexp_sscan ( &s_sig, NULL, p, strlen(p));
229   if (rc)
230     {
231       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
232       return;
233     }
234   /*gcry_sexp_dump (s_sig);*/
235
236
237   /* FIXME: need to map the algo to the ASN OID - we assume a fixed
238      one for now */
239   frame = do_encode_md (md, algo, 16, 2048, asn, DIM(asn));
240
241   /* put hash into the S-Exp s_hash */
242   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
243     BUG ();
244   /*fputs ("hash:\n", stderr); gcry_sexp_dump (s_hash);*/
245   _gcry_log_mpidump ("hash", frame);
246
247   p = ksba_cert_get_public_key (cert);
248   printf ("public key: %s\n", p);
249
250   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, strlen(p));
251   if (rc)
252     {
253       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
254       return;
255     }
256   /*gcry_sexp_dump (s_pkey);*/
257   
258   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
259   log_error ("gcry_pk_verify: %s\n", gcry_strerror (rc));
260
261 }
262
263
264 \f
265 int
266 gpgsm_import (int in_fd)
267 {
268   int rc;
269   KsbaReader reader = NULL;
270   KsbaCert cert = NULL;
271   struct reader_cb_parm_s rparm;
272
273   memset (&rparm, 0, sizeof rparm);
274
275   rparm.fp = fdopen ( dup (in_fd), "rb");
276   if (!rparm.fp)
277     {
278       log_error ("fdopen() failed: %s\n", strerror (errno));
279       rc = seterr (IO_Error);
280       goto leave;
281     }
282
283   /* setup a skaba reader which uses a callback function so that we can 
284      strip off a base64 encoding when necessary */
285   reader = ksba_reader_new ();
286   if (!reader)
287     {
288       rc = seterr (Out_Of_Core);
289       goto leave;
290     }
291
292   rc = ksba_reader_set_cb (reader, reader_cb, &rparm );
293   if (rc)
294     {
295       ksba_reader_release (reader);
296       rc = map_ksba_err (rc);
297       goto leave;
298     }
299
300   cert = ksba_cert_new ();
301   if (!cert)
302     {
303       rc = seterr (Out_Of_Core);
304       goto leave;
305     }
306
307   rc = ksba_cert_read_der (cert, reader);
308   if (rc)
309     {
310       rc = map_ksba_err (rc);
311       goto leave;
312     }
313
314   print_cert (cert);
315   check_selfsigned_cert (cert);
316
317
318  leave:
319   ksba_cert_release (cert);
320   ksba_reader_release (reader);
321   if (rparm.fp)
322     fclose (rparm.fp);
323   return rc;
324 }
325