Preparing the 2.0.3 release
[gnupg.git] / sm / decrypt.c
1 /* decrypt.c - Decrypt a message
2  *      Copyright (C) 2001, 2003 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h> 
28 #include <time.h>
29 #include <assert.h>
30
31 #include "gpgsm.h"
32 #include <gcrypt.h>
33 #include <ksba.h>
34
35 #include "keydb.h"
36 #include "i18n.h"
37
38 struct decrypt_filter_parm_s {
39   int algo;
40   int mode;
41   int blklen;
42   gcry_cipher_hd_t hd;
43   char iv[16];
44   size_t ivlen;
45   int any_data;  /* dod we push anything through the filter at all? */
46   unsigned char lastblock[16];  /* to strip the padding we have to
47                                    keep this one */
48   char helpblock[16];  /* needed because there is no block buffering in
49                           libgcrypt (yet) */
50   int  helpblocklen;
51 };
52
53
54
55 /* Decrypt the session key and fill in the parm structure.  The
56    algo and the IV is expected to be already in PARM. */
57 static int 
58 prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
59                     ksba_const_sexp_t enc_val,
60                     struct decrypt_filter_parm_s *parm)
61 {
62   char *seskey = NULL;
63   size_t n, seskeylen;
64   int rc;
65
66   rc = gpgsm_agent_pkdecrypt (ctrl, hexkeygrip, desc, enc_val,
67                               &seskey, &seskeylen);
68   if (rc)
69     {
70       log_error ("error decrypting session key: %s\n", gpg_strerror (rc));
71       goto leave;
72     }
73
74   if (DBG_CRYPTO)
75     log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
76
77   n=0;
78   if (seskeylen == 24)
79     {
80       /* Smells like a 3-des key.  This might happen because a SC has
81          already done the unpacking. */
82     }
83   else
84     {
85       if (n + 7 > seskeylen )
86         {
87           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
88           goto leave; 
89         }
90       
91       /* FIXME: Actually the leading zero is required but due to the way
92          we encode the output in libgcrypt as an MPI we are not able to
93          encode that leading zero.  However, when using a Smartcard we are
94          doing it the right way and therefore we have to skip the zero.  This
95          should be fixed in gpg-agent of course. */
96       if (!seskey[n])
97         n++;
98       
99       if (seskey[n] != 2 )  /* Wrong block type version. */
100         { 
101           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
102           goto leave; 
103         }
104       
105       for (n++; n < seskeylen && seskey[n]; n++) /* Skip the random bytes. */
106         ;
107       n++; /* and the zero byte */
108       if (n >= seskeylen )
109         { 
110           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
111           goto leave; 
112         }
113     }
114
115   if (DBG_CRYPTO)
116     log_printhex ("session key:", seskey+n, seskeylen-n);
117
118   rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0);
119   if (rc)
120     {
121       log_error ("error creating decryptor: %s\n", gpg_strerror (rc));
122       goto leave;
123     }
124                         
125   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
126   if (gpg_err_code (rc) == GPG_ERR_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", gpg_strerror(rc) );
135       goto leave;
136     }
137
138   gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
139
140  leave:
141   xfree (seskey);
142   return rc;
143 }
144
145
146 /* This function is called by the KSBA writer just before the actual
147    write is done.  The function must take INLEN bytes from INBUF,
148    decrypt it and store it inoutbuf which has a maximum size of
149    maxoutlen.  The valid bytes in outbuf should be return in outlen.
150    Due to different buffer sizes or different length of input and
151    output, it may happen that fewer bytes are processed or fewer bytes
152    are written. */
153 static gpg_error_t
154 decrypt_filter (void *arg,
155                 const void *inbuf, size_t inlen, size_t *inused,
156                 void *outbuf, size_t maxoutlen, size_t *outlen)
157 {
158   struct decrypt_filter_parm_s *parm = arg;
159   int blklen = parm->blklen;
160   size_t orig_inlen = inlen;
161
162   /* fixme: Should we issue an error when we have not seen one full block? */
163   if (!inlen)
164     return gpg_error (GPG_ERR_BUG);
165
166   if (maxoutlen < 2*parm->blklen)
167     return gpg_error (GPG_ERR_BUG);
168   /* Make some space because we will later need an extra block at the end.  */
169   maxoutlen -= blklen;
170
171   if (parm->helpblocklen)
172     {
173       int i, j;
174
175       for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
176         parm->helpblock[i] = ((const char*)inbuf)[j];
177       inlen -= j;
178       if (blklen > maxoutlen)
179         return gpg_error (GPG_ERR_BUG);
180       if (i < blklen)
181         {
182           parm->helpblocklen = i;
183           *outlen = 0;
184         }
185       else
186         {
187           parm->helpblocklen = 0;
188           if (parm->any_data)
189             {
190               memcpy (outbuf, parm->lastblock, blklen);
191               *outlen =blklen;
192             }
193           else
194             *outlen = 0;
195           gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
196                                parm->helpblock, blklen);
197           parm->any_data = 1;
198         }
199       *inused = orig_inlen - inlen;
200       return 0;
201     }
202
203
204   if (inlen > maxoutlen)
205     inlen = maxoutlen;
206   if (inlen % blklen)
207     { /* store the remainder away */
208       parm->helpblocklen = inlen%blklen;
209       inlen = inlen/blklen*blklen;
210       memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
211     }
212
213   *inused = inlen + parm->helpblocklen;
214   if (inlen)
215     {
216       assert (inlen >= blklen);
217       if (parm->any_data)
218         {
219           gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
220                                inbuf, inlen);
221           memcpy (outbuf, parm->lastblock, blklen);
222           memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
223           *outlen = inlen;
224         }
225       else
226         {
227           gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
228           memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
229           *outlen = inlen - blklen;
230           parm->any_data = 1;
231         }
232     }
233   else
234     *outlen = 0;
235   return 0;
236 }
237
238
239 \f
240 /* Perform a decrypt operation.  */
241 int
242 gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
243 {
244   int rc;
245   Base64Context b64reader = NULL;
246   Base64Context b64writer = NULL;
247   ksba_reader_t reader;
248   ksba_writer_t writer;
249   ksba_cms_t cms = NULL;
250   ksba_stop_reason_t stopreason;
251   KEYDB_HANDLE kh;
252   int recp;
253   FILE *in_fp = NULL;
254   struct decrypt_filter_parm_s dfparm;
255
256   memset (&dfparm, 0, sizeof dfparm);
257
258   kh = keydb_new (0);
259   if (!kh)
260     {
261       log_error (_("failed to allocated keyDB handle\n"));
262       rc = gpg_error (GPG_ERR_GENERAL);
263       goto leave;
264     }
265
266
267   in_fp = fdopen ( dup (in_fd), "rb");
268   if (!in_fp)
269     {
270       rc = gpg_error (gpg_err_code_from_errno (errno));
271       log_error ("fdopen() failed: %s\n", strerror (errno));
272       goto leave;
273     }
274
275   rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, 0, &reader);
276   if (rc)
277     {
278       log_error ("can't create reader: %s\n", gpg_strerror (rc));
279       goto leave;
280     }
281
282   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
283   if (rc)
284     {
285       log_error ("can't create writer: %s\n", gpg_strerror (rc));
286       goto leave;
287     }
288
289   rc = ksba_cms_new (&cms);
290   if (rc)
291     goto leave;
292
293   rc = ksba_cms_set_reader_writer (cms, reader, writer);
294   if (rc)
295     {
296       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
297                  gpg_strerror (rc));
298       goto leave;
299     }
300
301   /* Parser loop. */
302   do 
303     {
304       rc = ksba_cms_parse (cms, &stopreason);
305       if (rc)
306         {
307           log_debug ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
308           goto leave;
309         }
310
311       if (stopreason == KSBA_SR_BEGIN_DATA
312           || stopreason == KSBA_SR_DETACHED_DATA)
313         {
314           int algo, mode;
315           const char *algoid;
316           int any_key = 0;
317           
318           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
319           algo = gcry_cipher_map_name (algoid);
320           mode = gcry_cipher_mode_from_oid (algoid);
321           if (!algo || !mode)
322             {
323               rc = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
324               log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
325               if (algoid && !strcmp (algoid, "1.2.840.113549.3.2"))
326                 log_info (_("(this is the RC2 algorithm)\n"));
327               else if (!algoid)
328                 log_info (_("(this does not seem to be an encrypted"
329                             " message)\n"));
330               {
331                 char numbuf[50];
332                 sprintf (numbuf, "%d", rc);
333                 gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
334                                numbuf, algoid?algoid:"?", NULL);
335               }
336
337               /* If it seems that this is not an encrypted message we
338                  return a more sensible error code. */
339               if (!algoid)
340                 rc = gpg_error (GPG_ERR_NO_DATA);
341
342               goto leave;
343             }
344           dfparm.algo = algo;
345           dfparm.mode = mode;
346           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
347           if (dfparm.blklen > sizeof (dfparm.helpblock))
348             return gpg_error (GPG_ERR_BUG);
349
350           rc = ksba_cms_get_content_enc_iv (cms,
351                                             dfparm.iv,
352                                             sizeof (dfparm.iv),
353                                             &dfparm.ivlen);
354           if (rc)
355             {
356               log_error ("error getting IV: %s\n", gpg_strerror (rc));
357               goto leave;
358             }
359           
360           for (recp=0; !any_key; recp++)
361             {
362               char *issuer;
363               ksba_sexp_t serial;
364               ksba_sexp_t enc_val;
365               char *hexkeygrip = NULL;
366               char *desc = NULL;
367
368               rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
369               if (rc == -1 && recp)
370                 break; /* no more recipients */
371               if (rc)
372                 log_error ("recp %d - error getting info: %s\n",
373                            recp, gpg_strerror (rc));
374               else
375                 {
376                   ksba_cert_t cert = NULL;
377
378                   log_debug ("recp %d - issuer: `%s'\n",
379                              recp, issuer? issuer:"[NONE]");
380                   log_debug ("recp %d - serial: ", recp);
381                   gpgsm_dump_serial (serial);
382                   log_printf ("\n");
383
384                   keydb_search_reset (kh);
385                   rc = keydb_search_issuer_sn (kh, issuer, serial);
386                   if (rc)
387                     {
388                       log_error ("failed to find the certificate: %s\n",
389                                  gpg_strerror(rc));
390                       goto oops;
391                     }
392
393                   rc = keydb_get_cert (kh, &cert);
394                   if (rc)
395                     {
396                       log_error ("failed to get cert: %s\n", gpg_strerror (rc));
397                       goto oops;     
398                     }
399                   /* Just in case there is a problem with the own
400                      certificate we print this message - should never
401                      happen of course */
402                   rc = gpgsm_cert_use_decrypt_p (cert);
403                   if (rc)
404                     {
405                       char numbuf[50];
406                       sprintf (numbuf, "%d", rc);
407                       gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
408                                      numbuf, NULL);
409                       rc = 0;
410                     }
411
412                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
413                   desc = gpgsm_format_keydesc (cert);
414
415                 oops:
416                   xfree (issuer);
417                   xfree (serial);
418                   ksba_cert_release (cert);
419                 }
420
421               if (!hexkeygrip)
422                 ;
423               else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
424                 log_error ("recp %d - error getting encrypted session key\n",
425                            recp);
426               else
427                 {
428                   rc = prepare_decryption (ctrl,
429                                            hexkeygrip, desc, enc_val, &dfparm);
430                   xfree (enc_val);
431                   if (rc)
432                     {
433                       log_info ("decrypting session key failed: %s\n",
434                                 gpg_strerror (rc));
435                     }
436                   else
437                     { /* setup the bulk decrypter */
438                       any_key = 1;
439                       ksba_writer_set_filter (writer,
440                                               decrypt_filter,
441                                               &dfparm);
442                     }
443                 }
444               xfree (hexkeygrip);
445               xfree (desc);
446             }
447           if (!any_key)
448             {
449               rc = gpg_error (GPG_ERR_NO_SECKEY);
450               goto leave;
451             }
452         }
453       else if (stopreason == KSBA_SR_END_DATA)
454         {
455           ksba_writer_set_filter (writer, NULL, NULL);
456           if (dfparm.any_data)
457             { /* write the last block with padding removed */
458               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
459               if (!npadding || npadding > dfparm.blklen)
460                 {
461                   log_error ("invalid padding with value %d\n", npadding);
462                   rc = gpg_error (GPG_ERR_INV_DATA);
463                   goto leave;
464                 }
465               rc = ksba_writer_write (writer,
466                                       dfparm.lastblock, 
467                                       dfparm.blklen - npadding);
468               if (rc)
469                   goto leave;
470
471               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
472                 {
473                   if (dfparm.lastblock[i] != npadding)
474                     {
475                       log_error ("inconsistent padding\n");
476                       rc = gpg_error (GPG_ERR_INV_DATA);
477                       goto leave;
478                     }
479                 }
480             }
481         }
482
483     }
484   while (stopreason != KSBA_SR_READY);   
485
486   rc = gpgsm_finish_writer (b64writer);
487   if (rc) 
488     {
489       log_error ("write failed: %s\n", gpg_strerror (rc));
490       goto leave;
491     }
492   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
493
494
495  leave:
496   if (rc)
497     {
498       gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
499       log_error ("message decryption failed: %s <%s>\n",
500                  gpg_strerror (rc), gpg_strsource (rc));
501     }
502   ksba_cms_release (cms);
503   gpgsm_destroy_reader (b64reader);
504   gpgsm_destroy_writer (b64writer);
505   keydb_release (kh); 
506   if (in_fp)
507     fclose (in_fp);
508   if (dfparm.hd)
509     gcry_cipher_close (dfparm.hd); 
510   return rc;
511 }
512
513