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