* decrypt.c (gpgsm_decrypt): Bail out after an decryption error.
[gnupg.git] / sm / decrypt.c
1 /* decrypt.c - Decrypt a message
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 decrypt_filter_parm_s {
38   int algo;
39   int mode;
40   int blklen;
41   GCRY_CIPHER_HD hd;
42   char iv[16];
43   size_t ivlen;
44   int any_data;  /* dod we push anything through the filter at all? */
45   unsigned char lastblock[16];  /* to strip the padding we have to
46                                    keep this one */
47   char helpblock[16];  /* needed because there is no block buffering in
48                           libgcrypt (yet) */
49   int  helpblocklen;
50 };
51
52
53
54 /* decrypt the session key and fill in the parm structure.  The
55    algo and the IV is expected to be already in PARM. */
56 static int 
57 prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
58                     struct decrypt_filter_parm_s *parm)
59 {
60   char *seskey = NULL;
61   size_t n, seskeylen;
62   int rc;
63
64   rc = gpgsm_agent_pkdecrypt (hexkeygrip, enc_val,
65                               &seskey, &seskeylen);
66   if (rc)
67     {
68       log_error ("error decrypting session key: %s\n", gnupg_strerror (rc));
69       goto leave;
70     }
71
72   if (DBG_CRYPTO)
73     log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
74
75   n=0;
76   if (n + 7 > seskeylen )
77     {
78       rc = seterr (Invalid_Session_Key);
79       goto leave; 
80     }
81
82   if (seskey[n] != 2 )  /* wrong block type version */
83     { 
84       rc = seterr (Invalid_Session_Key);
85       goto leave; 
86     }
87
88   for (n++; n < seskeylen && seskey[n]; n++) /* skip the random bytes */
89     ;
90   n++; /* and the zero byte */
91   if (n >= seskeylen )
92     { 
93       rc = seterr (Invalid_Session_Key);
94       goto leave; 
95     }
96   
97   if (DBG_CRYPTO)
98     log_printhex ("session key:", seskey+n, seskeylen-n);
99
100   parm->hd = gcry_cipher_open (parm->algo, parm->mode, 0);
101   if (!parm->hd)
102     {
103       rc = gcry_errno ();
104       log_error ("error creating decryptor: %s\n", gcry_strerror (rc));
105       rc = map_gcry_err (rc);
106       goto leave;
107     }
108                         
109   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
110   if (rc == GCRYERR_WEAK_KEY)
111     {
112       log_info (_("WARNING: message was encrypted with "
113                   "a weak key in the symmetric cipher.\n"));
114       rc = 0;
115     }
116   if (rc)
117     {
118       log_error("key setup failed: %s\n", gcry_strerror(rc) );
119       rc = map_gcry_err (rc);
120       goto leave;
121     }
122
123   gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
124
125  leave:
126   xfree (seskey);
127   return rc;
128 }
129
130
131 /* This function is called by the KSBA writer just before the actual
132    write is done.  The function must take INLEN bytes from INBUF,
133    decrypt it and store it inoutbuf which has a maximum size of
134    maxoutlen.  The valid bytes in outbuf should be return in outlen.
135    Due to different buffer sizes or different length of input and
136    output, it may happen that fewer bytes are process or fewer bytes
137    are written. */
138 static KsbaError  
139 decrypt_filter (void *arg,
140                 const void *inbuf, size_t inlen, size_t *inused,
141                 void *outbuf, size_t maxoutlen, size_t *outlen)
142 {
143   struct decrypt_filter_parm_s *parm = arg;
144   int blklen = parm->blklen;
145   size_t orig_inlen = inlen;
146
147   /* fixme: Should we issue an error when we have not seen one full block? */
148   if (!inlen)
149     return KSBA_Bug;
150
151   if (maxoutlen < 2*parm->blklen)
152     return KSBA_Bug;
153   /* make some space becuase we will later need an extra block at the end */
154   maxoutlen -= blklen;
155
156   if (parm->helpblocklen)
157     {
158       int i, j;
159
160       for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
161         parm->helpblock[i] = ((const char*)inbuf)[j];
162       inlen -= j;
163       if (blklen > maxoutlen)
164         return KSBA_Bug;
165       if (i < blklen)
166         {
167           parm->helpblocklen = i;
168           *outlen = 0;
169         }
170       else
171         {
172           parm->helpblocklen = 0;
173           if (parm->any_data)
174             {
175               memcpy (outbuf, parm->lastblock, blklen);
176               *outlen =blklen;
177             }
178           else
179             *outlen = 0;
180           gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
181                                parm->helpblock, blklen);
182           parm->any_data = 1;
183         }
184       *inused = orig_inlen - inlen;
185       return 0;
186     }
187
188
189   if (inlen > maxoutlen)
190     inlen = maxoutlen;
191   if (inlen % blklen)
192     { /* store the remainder away */
193       parm->helpblocklen = inlen%blklen;
194       inlen = inlen/blklen*blklen;
195       memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
196     }
197
198   *inused = inlen + parm->helpblocklen;
199   if (inlen)
200     {
201       assert (inlen >= blklen);
202       if (parm->any_data)
203         {
204           gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
205                                inbuf, inlen);
206           memcpy (outbuf, parm->lastblock, blklen);
207           memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
208           *outlen = inlen;
209         }
210       else
211         {
212           gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
213           memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
214           *outlen = inlen - blklen;
215           parm->any_data = 1;
216         }
217     }
218   else
219     *outlen = 0;
220   return 0;
221 }
222
223
224 \f
225 /* Perform a decrypt operation.  */
226 int
227 gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
228 {
229   int rc;
230   KsbaError err;
231   Base64Context b64reader = NULL;
232   Base64Context b64writer = NULL;
233   KsbaReader reader;
234   KsbaWriter writer;
235   KsbaCMS cms = NULL;
236   KsbaStopReason stopreason;
237   KEYDB_HANDLE kh;
238   int recp;
239   FILE *in_fp = NULL;
240   struct decrypt_filter_parm_s dfparm;
241
242   memset (&dfparm, 0, sizeof dfparm);
243
244   kh = keydb_new (0);
245   if (!kh)
246     {
247       log_error (_("failed to allocated keyDB handle\n"));
248       rc = GNUPG_General_Error;
249       goto leave;
250     }
251
252
253   in_fp = fdopen ( dup (in_fd), "rb");
254   if (!in_fp)
255     {
256       log_error ("fdopen() failed: %s\n", strerror (errno));
257       rc = seterr (IO_Error);
258       goto leave;
259     }
260
261   rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, &reader);
262   if (rc)
263     {
264       log_error ("can't create reader: %s\n", gnupg_strerror (rc));
265       goto leave;
266     }
267
268   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
269   if (rc)
270     {
271       log_error ("can't create writer: %s\n", gnupg_strerror (rc));
272       goto leave;
273     }
274
275   cms = ksba_cms_new ();
276   if (!cms)
277     {
278       rc = seterr (Out_Of_Core);
279       goto leave;
280     }
281
282   err = ksba_cms_set_reader_writer (cms, reader, writer);
283   if (err)
284     {
285       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
286                  ksba_strerror (err));
287       rc = map_ksba_err (err);
288       goto leave;
289     }
290
291   /* parser loop */
292   do 
293     {
294       err = ksba_cms_parse (cms, &stopreason);
295       if (err)
296         {
297           log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
298           rc = map_ksba_err (err);
299           goto leave;
300         }
301
302       if (stopreason == KSBA_SR_BEGIN_DATA
303           || stopreason == KSBA_SR_DETACHED_DATA)
304         {
305           int algo, mode;
306           const char *algoid;
307           
308           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
309           algo = gcry_cipher_map_name (algoid);
310           mode = gcry_cipher_mode_from_oid (algoid);
311           if (!algo || !mode)
312             {
313               log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
314               rc = GNUPG_Unsupported_Algorithm;
315               goto leave;
316             }
317           dfparm.algo = algo;
318           dfparm.mode = mode;
319           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
320           if (dfparm.blklen > sizeof (dfparm.helpblock))
321             return GNUPG_Bug;
322
323           rc = ksba_cms_get_content_enc_iv (cms,
324                                             dfparm.iv,
325                                             sizeof (dfparm.iv),
326                                             &dfparm.ivlen);
327           if (rc)
328             {
329               log_error ("error getting IV: %s\n", ksba_strerror (err));
330               rc = map_ksba_err (err);
331               goto leave;
332             }
333           
334           for (recp=0; recp < 1; recp++)
335             {
336               char *issuer;
337               KsbaSexp serial;
338               KsbaSexp enc_val;
339               char *hexkeygrip = NULL;
340
341               err = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
342               if (err)
343                 log_error ("recp %d - error getting info: %s\n",
344                            recp, ksba_strerror (err));
345               else
346                 {
347                   KsbaCert cert = NULL;
348
349                   log_debug ("recp %d - issuer: `%s'\n",
350                              recp, issuer? issuer:"[NONE]");
351                   log_debug ("recp %d - serial: ", recp);
352                   gpgsm_dump_serial (serial);
353                   log_printf ("\n");
354
355                   keydb_search_reset (kh);
356                   rc = keydb_search_issuer_sn (kh, issuer, serial);
357                   if (rc)
358                     {
359                       log_debug ("failed to find the certificate: %s\n",
360                                  gnupg_strerror(rc));
361                       goto oops;
362                     }
363
364                   rc = keydb_get_cert (kh, &cert);
365                   if (rc)
366                     {
367                       log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
368                       goto oops;                    }
369
370                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
371
372                 oops:
373                   xfree (issuer);
374                   xfree (serial);
375                   ksba_cert_release (cert);
376                 }
377
378               enc_val = ksba_cms_get_enc_val (cms, recp);
379               if (!enc_val)
380                 log_error ("recp %d - error getting encrypted session key\n",
381                            recp);
382               else
383                 {
384                   rc = prepare_decryption (hexkeygrip, enc_val,
385                                            &dfparm);
386                   xfree (enc_val);
387                   if (rc)
388                     {
389                       /* fixme: as soon as we support multiple recipients, we 
390                          should just set a flag and try the next recipient */
391                       log_error ("decrypting session key failed: %s\n",
392                                  gnupg_strerror (rc));
393                       goto leave;
394                     }
395                   else
396                     { /* setup the bulk decrypter */
397                       ksba_writer_set_filter (writer,
398                                               decrypt_filter,
399                                               &dfparm);
400                     }
401                 }
402             }
403         }
404       else if (stopreason == KSBA_SR_END_DATA)
405         {
406           ksba_writer_set_filter (writer, NULL, NULL);
407           if (dfparm.any_data)
408             { /* write the last block with padding removed */
409               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
410               if (!npadding || npadding > dfparm.blklen)
411                 {
412                   log_error ("invalid padding with value %d\n", npadding);
413                   rc = seterr (Invalid_Data);
414                   goto leave;
415                 }
416               rc = ksba_writer_write (writer,
417                                       dfparm.lastblock, 
418                                       dfparm.blklen - npadding);
419               if (rc)
420                 {
421                   rc = map_ksba_err (rc);
422                   goto leave;
423                 }
424               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
425                 {
426                   if (dfparm.lastblock[i] != npadding)
427                     {
428                       log_error ("inconsistent padding\n");
429                       rc = seterr (Invalid_Data);
430                       goto leave;
431                     }
432                 }
433             }
434         }
435
436     }
437   while (stopreason != KSBA_SR_READY);   
438
439   rc = gpgsm_finish_writer (b64writer);
440   if (rc) 
441     {
442       log_error ("write failed: %s\n", gnupg_strerror (rc));
443       goto leave;
444     }
445   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
446
447
448  leave:
449   if (rc)
450     gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
451   ksba_cms_release (cms);
452   gpgsm_destroy_reader (b64reader);
453   gpgsm_destroy_writer (b64writer);
454   keydb_release (kh); 
455   if (in_fp)
456     fclose (in_fp);
457   if (dfparm.hd)
458     gcry_cipher_close (dfparm.hd); 
459   return rc;
460 }
461
462