* certcheck.c (gpgsm_create_cms_signature): Format a description
[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 (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 (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 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               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 gpg_error (GPG_ERR_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", gpg_strerror (rc));
351               goto leave;
352             }
353           
354           for (recp=0; !any_key; recp++)
355             {
356               char *issuer;
357               ksba_sexp_t serial;
358               ksba_sexp_t enc_val;
359               char *hexkeygrip = NULL;
360               char *desc = NULL;
361
362               rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
363               if (rc == -1 && recp)
364                 break; /* no more recipients */
365               if (rc)
366                 log_error ("recp %d - error getting info: %s\n",
367                            recp, gpg_strerror (rc));
368               else
369                 {
370                   ksba_cert_t 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                                  gpg_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", gpg_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                       char numbuf[50];
400                       sprintf (numbuf, "%d", rc);
401                       gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
402                                      numbuf, NULL);
403                       rc = 0;
404                     }
405
406                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
407                   desc = gpgsm_format_keydesc (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, desc, enc_val, &dfparm);
423                   xfree (enc_val);
424                   if (rc)
425                     {
426                       log_info ("decrypting session key failed: %s\n",
427                                 gpg_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               xfree (hexkeygrip);
438               xfree (desc);
439             }
440           if (!any_key)
441             {
442               rc = gpg_error (GPG_ERR_NO_SECKEY);
443               goto leave;
444             }
445         }
446       else if (stopreason == KSBA_SR_END_DATA)
447         {
448           ksba_writer_set_filter (writer, NULL, NULL);
449           if (dfparm.any_data)
450             { /* write the last block with padding removed */
451               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
452               if (!npadding || npadding > dfparm.blklen)
453                 {
454                   log_error ("invalid padding with value %d\n", npadding);
455                   rc = gpg_error (GPG_ERR_INV_DATA);
456                   goto leave;
457                 }
458               rc = ksba_writer_write (writer,
459                                       dfparm.lastblock, 
460                                       dfparm.blklen - npadding);
461               if (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 = gpg_error (GPG_ERR_INV_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", gpg_strerror (rc));
483       goto leave;
484     }
485   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
486
487
488  leave:
489   if (rc)
490     {
491       gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
492       log_error ("message decryption failed: %s\n", gpg_strerror (rc));
493     }
494   ksba_cms_release (cms);
495   gpgsm_destroy_reader (b64reader);
496   gpgsm_destroy_writer (b64writer);
497   keydb_release (kh); 
498   if (in_fp)
499     fclose (in_fp);
500   if (dfparm.hd)
501     gcry_cipher_close (dfparm.hd); 
502   return rc;
503 }
504
505