* decrypt.c (prepare_decryption): Hack to detected already
[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               log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
331               if (algoid && !strcmp (algoid, "1.2.840.113549.3.2"))
332                 log_info (_("(this is the RC2 algorithm)\n"));
333               gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
334                              gnupg_error_token (rc), algoid, NULL);
335               rc = GNUPG_Unsupported_Algorithm;
336               goto leave;
337             }
338           dfparm.algo = algo;
339           dfparm.mode = mode;
340           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
341           if (dfparm.blklen > sizeof (dfparm.helpblock))
342             return GNUPG_Bug;
343
344           rc = ksba_cms_get_content_enc_iv (cms,
345                                             dfparm.iv,
346                                             sizeof (dfparm.iv),
347                                             &dfparm.ivlen);
348           if (rc)
349             {
350               log_error ("error getting IV: %s\n", ksba_strerror (err));
351               rc = map_ksba_err (err);
352               goto leave;
353             }
354           
355           for (recp=0; !any_key; recp++)
356             {
357               char *issuer;
358               KsbaSexp serial;
359               KsbaSexp enc_val;
360               char *hexkeygrip = NULL;
361
362               err = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
363               if (err == -1 && recp)
364                 break; /* no more recipients */
365               if (err)
366                 log_error ("recp %d - error getting info: %s\n",
367                            recp, ksba_strerror (err));
368               else
369                 {
370                   KsbaCert cert = NULL;
371
372                   log_debug ("recp %d - issuer: `%s'\n",
373                              recp, issuer? issuer:"[NONE]");
374                   log_debug ("recp %d - serial: ", recp);
375                   gpgsm_dump_serial (serial);
376                   log_printf ("\n");
377
378                   keydb_search_reset (kh);
379                   rc = keydb_search_issuer_sn (kh, issuer, serial);
380                   if (rc)
381                     {
382                       log_error ("failed to find the certificate: %s\n",
383                                  gnupg_strerror(rc));
384                       goto oops;
385                     }
386
387                   rc = keydb_get_cert (kh, &cert);
388                   if (rc)
389                     {
390                       log_error ("failed to get cert: %s\n", gnupg_strerror (rc));
391                       goto oops;     
392                     }
393                   /* Just in case there is a problem with the own
394                      certificate we print this message - should never
395                      happen of course */
396                   rc = gpgsm_cert_use_decrypt_p (cert);
397                   if (rc)
398                     {
399                       gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
400                                      gnupg_error_token (rc), NULL);
401                       rc = 0;
402                     }
403
404                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
405
406                 oops:
407                   xfree (issuer);
408                   xfree (serial);
409                   ksba_cert_release (cert);
410                 }
411
412               if (!hexkeygrip)
413                 ;
414               else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
415                 log_error ("recp %d - error getting encrypted session key\n",
416                            recp);
417               else
418                 {
419                   rc = prepare_decryption (hexkeygrip, enc_val, &dfparm);
420                   xfree (enc_val);
421                   if (rc)
422                     {
423                       log_debug ("decrypting session key failed: %s\n",
424                                  gnupg_strerror (rc));
425                     }
426                   else
427                     { /* setup the bulk decrypter */
428                       any_key = 1;
429                       ksba_writer_set_filter (writer,
430                                               decrypt_filter,
431                                               &dfparm);
432                     }
433                 }
434             }
435           if (!any_key)
436             {
437               rc = GNUPG_No_Secret_Key;
438               goto leave;
439             }
440         }
441       else if (stopreason == KSBA_SR_END_DATA)
442         {
443           ksba_writer_set_filter (writer, NULL, NULL);
444           if (dfparm.any_data)
445             { /* write the last block with padding removed */
446               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
447               if (!npadding || npadding > dfparm.blklen)
448                 {
449                   log_error ("invalid padding with value %d\n", npadding);
450                   rc = seterr (Invalid_Data);
451                   goto leave;
452                 }
453               rc = ksba_writer_write (writer,
454                                       dfparm.lastblock, 
455                                       dfparm.blklen - npadding);
456               if (rc)
457                 {
458                   rc = map_ksba_err (rc);
459                   goto leave;
460                 }
461               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
462                 {
463                   if (dfparm.lastblock[i] != npadding)
464                     {
465                       log_error ("inconsistent padding\n");
466                       rc = seterr (Invalid_Data);
467                       goto leave;
468                     }
469                 }
470             }
471         }
472
473     }
474   while (stopreason != KSBA_SR_READY);   
475
476   rc = gpgsm_finish_writer (b64writer);
477   if (rc) 
478     {
479       log_error ("write failed: %s\n", gnupg_strerror (rc));
480       goto leave;
481     }
482   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
483
484
485  leave:
486   if (rc)
487     gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
488   ksba_cms_release (cms);
489   gpgsm_destroy_reader (b64reader);
490   gpgsm_destroy_writer (b64writer);
491   keydb_release (kh); 
492   if (in_fp)
493     fclose (in_fp);
494   if (dfparm.hd)
495     gcry_cipher_close (dfparm.hd); 
496   return rc;
497 }
498
499