fc628a6f1b5af0ae642cb90a18c5c2cc3fd1f434
[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 #include "keydb.h"
35 #include "i18n.h"
36
37 struct reader_cb_parm_s {
38   FILE *fp;
39   unsigned char line[1024];
40   int linelen;
41   int readpos;
42   int have_lf;
43   unsigned long line_counter;
44
45   int identified;
46   int is_pem;
47   int stop_seen;
48
49   struct {
50     int idx;
51     unsigned char val;
52     int stop_seen;
53   } base64;
54
55
56 };
57
58 /*  static unsigned char bintoasc[] =  */
59 /*  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */
60 /*  "abcdefghijklmnopqrstuvwxyz" */
61 /*  "0123456789+/"; */
62
63 static unsigned char asctobin[256] = {
64   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
65   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
66   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
67   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 
68   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 
69   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
70   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 
71   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 
72   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 
73   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
74   0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
75   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
76   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
77   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
78   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
79   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
80   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
81   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
82   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
83   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
84   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
85   0xff, 0xff, 0xff, 0xff
86 };
87
88
89
90 static int
91 reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
92 {
93   struct reader_cb_parm_s *parm = cb_value;
94   size_t n;
95   int c, c2;
96
97   *nread = 0;
98   if (!buffer)
99     return -1; /* not supported */
100
101  next:
102   if (!parm->linelen)
103     {
104       /* read an entire line or up to the size of the buffer */
105       parm->line_counter++;
106       parm->have_lf = 0;
107       for (n=0; n < DIM(parm->line);)
108         {
109           c = getc (parm->fp);
110           if (c == EOF)
111             {
112               if (ferror (parm->fp))
113                 return -1;
114               break; 
115             }
116           parm->line[n++] = c;
117           if (c == '\n')
118             {
119               parm->have_lf = 1;
120               /* FIXME: we need to skip overlong lines while detecting
121                  the dashed lines */
122               break;
123             }
124         }
125       parm->linelen = n;
126       if (!n)
127         return -1; /* eof */
128       parm->readpos = 0;
129     }
130
131   if (!parm->identified)
132     {
133       if (parm->line_counter == 1 && !parm->have_lf)
134         {
135           /* first line too long - assume DER encoding */
136           parm->is_pem = 0;
137         }
138       else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
139         {
140           /* the very first bytes does pretty much look like a SEQUENCE tag*/
141           parm->is_pem = 0;
142         }
143       else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11)
144                 && strncmp (parm->line+11, "PGP ", 4) )
145         {
146           /* Fixme: we must only compare if the line really starts at
147              the beginning */
148           parm->is_pem = 1;
149           parm->linelen = parm->readpos = 0;
150         }
151       else
152         {
153           parm->linelen = parm->readpos = 0;
154           goto next;
155         }
156       parm->identified = 1;
157       parm->base64.stop_seen = 0;
158       parm->base64.idx = 0;
159     }
160   
161
162   n = 0;
163   if (parm->is_pem)
164     {  
165       if (parm->have_lf && !strncmp (parm->line, "-----END ", 9))
166         { 
167           parm->identified = 0;
168           parm->linelen = parm->readpos = 0;
169           /* let us return 0 */
170         }
171       else if (parm->stop_seen)
172         { /* skip the rest of the line */
173           parm->linelen = parm->readpos = 0;
174         }
175       else
176         {
177           int idx = parm->base64.idx;
178           unsigned char val = parm->base64.val;
179
180           while (n < count && parm->readpos < parm->linelen )
181             {
182               c = parm->line[parm->readpos++];
183               if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
184                 continue;
185               if (c == '=')
186                 { /* pad character: stop */
187                   if (idx == 1)
188                     buffer[n++] = val; 
189                   parm->stop_seen = 1;
190                   break;
191                 }
192               if( (c = asctobin[(c2=c)]) == 255 ) 
193                 {
194                   log_error (_("invalid radix64 character %02x skipped\n"),
195                              c2);
196                   continue;
197                 }
198               switch (idx) 
199                 {
200                 case 0: 
201                   val = c << 2;
202                   break;
203                 case 1: 
204                   val |= (c>>4)&3;
205                   buffer[n++] = val;
206                   val = (c<<4)&0xf0;
207                   break;
208                 case 2: 
209                   val |= (c>>2)&15;
210                   buffer[n++] = val;
211                   val = (c<<6)&0xc0;
212                   break;
213                 case 3: 
214                   val |= c&0x3f;
215                   buffer[n++] = val;
216                   break;
217                 }
218               idx = (idx+1) % 4;
219             }
220           if (parm->readpos == parm->linelen)
221             parm->linelen = parm->readpos = 0;
222
223           parm->base64.idx = idx;
224           parm->base64.val = val;
225         }
226     }
227   else
228     { /* DER encoded */
229       while (n < count && parm->readpos < parm->linelen)
230           buffer[n++] = parm->line[parm->readpos++];
231       if (parm->readpos == parm->linelen)
232         parm->linelen = parm->readpos = 0;
233     }
234
235   *nread = n;
236   return 0;
237 }
238
239
240 static void
241 store_cert (KsbaCert cert)
242 {
243   KEYDB_HANDLE kh;
244   int rc;
245
246   kh = keydb_new (0);
247   if (!kh)
248     {
249       log_error (_("failed to allocated keyDB handle\n"));
250       return;
251     }
252   rc = keydb_locate_writable (kh, 0);
253   if (rc)
254       log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
255
256   rc = keydb_insert_cert (kh, cert);
257   if (rc)
258     {
259       log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
260     }
261   keydb_release (kh);               
262 }
263
264
265
266 \f
267 int
268 gpgsm_import (CTRL ctrl, int in_fd)
269 {
270   int rc;
271   KsbaReader reader = NULL;
272   KsbaCert cert = NULL;
273   struct reader_cb_parm_s rparm;
274
275   memset (&rparm, 0, sizeof rparm);
276
277   rparm.fp = fdopen ( dup (in_fd), "rb");
278   if (!rparm.fp)
279     {
280       log_error ("fdopen() failed: %s\n", strerror (errno));
281       rc = seterr (IO_Error);
282       goto leave;
283     }
284
285   /* setup a skaba reader which uses a callback function so that we can 
286      strip off a base64 encoding when necessary */
287   reader = ksba_reader_new ();
288   if (!reader)
289     {
290       rc = seterr (Out_Of_Core);
291       goto leave;
292     }
293
294   rc = ksba_reader_set_cb (reader, reader_cb, &rparm );
295   if (rc)
296     {
297       ksba_reader_release (reader);
298       rc = map_ksba_err (rc);
299       goto leave;
300     }
301
302   cert = ksba_cert_new ();
303   if (!cert)
304     {
305       rc = seterr (Out_Of_Core);
306       goto leave;
307     }
308
309   rc = ksba_cert_read_der (cert, reader);
310   if (rc)
311     {
312       rc = map_ksba_err (rc);
313       goto leave;
314     }
315
316   if ( !gpgsm_validate_path (cert) )
317     store_cert (cert);
318
319  leave:
320   ksba_cert_release (cert);
321   ksba_reader_release (reader);
322   if (rparm.fp)
323     fclose (rparm.fp);
324   return rc;
325 }
326
327