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