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