Key generation and signing using the OpenPGP card does rudimentary work.
[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, 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", gpg_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 = gpg_error (GPG_ERR_INV_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 = gpg_error (GPG_ERR_INV_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 = gpg_error (GPG_ERR_INV_SESSION_KEY);
109           goto leave; 
110         }
111     }
112
113   if (DBG_CRYPTO)
114     log_printhex ("session key:", seskey+n, seskeylen-n);
115
116   rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0);
117   if (rc)
118     {
119       log_error ("error creating decryptor: %s\n", gpg_strerror (rc));
120       goto leave;
121     }
122                         
123   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
124   if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
125     {
126       log_info (_("WARNING: message was encrypted with "
127                   "a weak key in the symmetric cipher.\n"));
128       rc = 0;
129     }
130   if (rc)
131     {
132       log_error("key setup failed: %s\n", gpg_strerror(rc) );
133       goto leave;
134     }
135
136   gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
137
138  leave:
139   xfree (seskey);
140   return rc;
141 }
142
143
144 /* This function is called by the KSBA writer just before the actual
145    write is done.  The function must take INLEN bytes from INBUF,
146    decrypt it and store it inoutbuf which has a maximum size of
147    maxoutlen.  The valid bytes in outbuf should be return in outlen.
148    Due to different buffer sizes or different length of input and
149    output, it may happen that fewer bytes are process or fewer bytes
150    are written. */
151 static KsbaError  
152 decrypt_filter (void *arg,
153                 const void *inbuf, size_t inlen, size_t *inused,
154                 void *outbuf, size_t maxoutlen, size_t *outlen)
155 {
156   struct decrypt_filter_parm_s *parm = arg;
157   int blklen = parm->blklen;
158   size_t orig_inlen = inlen;
159
160   /* fixme: Should we issue an error when we have not seen one full block? */
161   if (!inlen)
162     return KSBA_Bug;
163
164   if (maxoutlen < 2*parm->blklen)
165     return KSBA_Bug;
166   /* make some space becuase we will later need an extra block at the end */
167   maxoutlen -= blklen;
168
169   if (parm->helpblocklen)
170     {
171       int i, j;
172
173       for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
174         parm->helpblock[i] = ((const char*)inbuf)[j];
175       inlen -= j;
176       if (blklen > maxoutlen)
177         return KSBA_Bug;
178       if (i < blklen)
179         {
180           parm->helpblocklen = i;
181           *outlen = 0;
182         }
183       else
184         {
185           parm->helpblocklen = 0;
186           if (parm->any_data)
187             {
188               memcpy (outbuf, parm->lastblock, blklen);
189               *outlen =blklen;
190             }
191           else
192             *outlen = 0;
193           gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
194                                parm->helpblock, blklen);
195           parm->any_data = 1;
196         }
197       *inused = orig_inlen - inlen;
198       return 0;
199     }
200
201
202   if (inlen > maxoutlen)
203     inlen = maxoutlen;
204   if (inlen % blklen)
205     { /* store the remainder away */
206       parm->helpblocklen = inlen%blklen;
207       inlen = inlen/blklen*blklen;
208       memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
209     }
210
211   *inused = inlen + parm->helpblocklen;
212   if (inlen)
213     {
214       assert (inlen >= blklen);
215       if (parm->any_data)
216         {
217           gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
218                                inbuf, inlen);
219           memcpy (outbuf, parm->lastblock, blklen);
220           memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
221           *outlen = inlen;
222         }
223       else
224         {
225           gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
226           memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
227           *outlen = inlen - blklen;
228           parm->any_data = 1;
229         }
230     }
231   else
232     *outlen = 0;
233   return 0;
234 }
235
236
237 \f
238 /* Perform a decrypt operation.  */
239 int
240 gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
241 {
242   int rc;
243   KsbaError err;
244   Base64Context b64reader = NULL;
245   Base64Context b64writer = NULL;
246   KsbaReader reader;
247   KsbaWriter writer;
248   KsbaCMS cms = NULL;
249   KsbaStopReason 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, &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   cms = ksba_cms_new ();
289   if (!cms)
290     {
291       rc = gpg_error (GPG_ERR_ENOMEM);
292       goto leave;
293     }
294
295   err = ksba_cms_set_reader_writer (cms, reader, writer);
296   if (err)
297     {
298       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
299                  ksba_strerror (err));
300       rc = map_ksba_err (err);
301       goto leave;
302     }
303
304   /* parser loop */
305   do 
306     {
307       err = ksba_cms_parse (cms, &stopreason);
308       if (err)
309         {
310           log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
311           rc = map_ksba_err (err);
312           goto leave;
313         }
314
315       if (stopreason == KSBA_SR_BEGIN_DATA
316           || stopreason == KSBA_SR_DETACHED_DATA)
317         {
318           int algo, mode;
319           const char *algoid;
320           int any_key = 0;
321           
322           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
323           algo = gcry_cipher_map_name (algoid);
324           mode = gcry_cipher_mode_from_oid (algoid);
325           if (!algo || !mode)
326             {
327               rc = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
328               log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
329               if (algoid && !strcmp (algoid, "1.2.840.113549.3.2"))
330                 log_info (_("(this is the RC2 algorithm)\n"));
331               else if (!algoid)
332                 log_info (_("(this does not seem to be an encrypted"
333                             " message)\n"));
334               {
335                 char numbuf[50];
336                 sprintf (numbuf, "%d", rc);
337                 gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
338                                numbuf, algoid?algoid:"?", NULL);
339               }
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", ksba_strerror (err));
356               rc = map_ksba_err (err);
357               goto leave;
358             }
359           
360           for (recp=0; !any_key; recp++)
361             {
362               char *issuer;
363               KsbaSexp serial;
364               KsbaSexp enc_val;
365               char *hexkeygrip = NULL;
366
367               err = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
368               if (err == -1 && recp)
369                 break; /* no more recipients */
370               if (err)
371                 log_error ("recp %d - error getting info: %s\n",
372                            recp, ksba_strerror (err));
373               else
374                 {
375                   KsbaCert 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
413                 oops:
414                   xfree (issuer);
415                   xfree (serial);
416                   ksba_cert_release (cert);
417                 }
418
419               if (!hexkeygrip)
420                 ;
421               else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
422                 log_error ("recp %d - error getting encrypted session key\n",
423                            recp);
424               else
425                 {
426                   rc = prepare_decryption (hexkeygrip, enc_val, &dfparm);
427                   xfree (enc_val);
428                   if (rc)
429                     {
430                       log_debug ("decrypting session key failed: %s\n",
431                                  gpg_strerror (rc));
432                     }
433                   else
434                     { /* setup the bulk decrypter */
435                       any_key = 1;
436                       ksba_writer_set_filter (writer,
437                                               decrypt_filter,
438                                               &dfparm);
439                     }
440                 }
441             }
442           if (!any_key)
443             {
444               rc = gpg_error (GPG_ERR_NO_SECKEY);
445               goto leave;
446             }
447         }
448       else if (stopreason == KSBA_SR_END_DATA)
449         {
450           ksba_writer_set_filter (writer, NULL, NULL);
451           if (dfparm.any_data)
452             { /* write the last block with padding removed */
453               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
454               if (!npadding || npadding > dfparm.blklen)
455                 {
456                   log_error ("invalid padding with value %d\n", npadding);
457                   rc = gpg_error (GPG_ERR_INV_DATA);
458                   goto leave;
459                 }
460               rc = ksba_writer_write (writer,
461                                       dfparm.lastblock, 
462                                       dfparm.blklen - npadding);
463               if (rc)
464                 {
465                   rc = map_ksba_err (rc);
466                   goto leave;
467                 }
468               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
469                 {
470                   if (dfparm.lastblock[i] != npadding)
471                     {
472                       log_error ("inconsistent padding\n");
473                       rc = gpg_error (GPG_ERR_INV_DATA);
474                       goto leave;
475                     }
476                 }
477             }
478         }
479
480     }
481   while (stopreason != KSBA_SR_READY);   
482
483   rc = gpgsm_finish_writer (b64writer);
484   if (rc) 
485     {
486       log_error ("write failed: %s\n", gpg_strerror (rc));
487       goto leave;
488     }
489   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
490
491
492  leave:
493   if (rc)
494     gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
495   ksba_cms_release (cms);
496   gpgsm_destroy_reader (b64reader);
497   gpgsm_destroy_writer (b64writer);
498   keydb_release (kh); 
499   if (in_fp)
500     fclose (in_fp);
501   if (dfparm.hd)
502     gcry_cipher_close (dfparm.hd); 
503   return rc;
504 }
505
506