Fix a problem with dirmngr looked up certificates.
[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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h> 
26 #include <time.h>
27 #include <assert.h>
28
29 #include "gpgsm.h"
30 #include <gcrypt.h>
31 #include <ksba.h>
32
33 #include "keydb.h"
34 #include "i18n.h"
35
36 struct decrypt_filter_parm_s {
37   int algo;
38   int mode;
39   int blklen;
40   gcry_cipher_hd_t hd;
41   char iv[16];
42   size_t ivlen;
43   int any_data;  /* dod we push anything through the filter at all? */
44   unsigned char lastblock[16];  /* to strip the padding we have to
45                                    keep this one */
46   char helpblock[16];  /* needed because there is no block buffering in
47                           libgcrypt (yet) */
48   int  helpblocklen;
49 };
50
51
52
53 /* Decrypt the session key and fill in the parm structure.  The
54    algo and the IV is expected to be already in PARM. */
55 static int 
56 prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
57                     ksba_const_sexp_t 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 (ctrl, hexkeygrip, desc, 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. */
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 right way 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 processed or fewer bytes
150    are written. */
151 static gpg_error_t
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 gpg_error (GPG_ERR_BUG);
163
164   if (maxoutlen < 2*parm->blklen)
165     return gpg_error (GPG_ERR_BUG);
166   /* Make some space because 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 gpg_error (GPG_ERR_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_t ctrl, int in_fd, FILE *out_fp)
241 {
242   int rc;
243   Base64Context b64reader = NULL;
244   Base64Context b64writer = NULL;
245   ksba_reader_t reader;
246   ksba_writer_t writer;
247   ksba_cms_t cms = NULL;
248   ksba_stop_reason_t stopreason;
249   KEYDB_HANDLE kh;
250   int recp;
251   FILE *in_fp = NULL;
252   struct decrypt_filter_parm_s dfparm;
253
254   memset (&dfparm, 0, sizeof dfparm);
255
256   kh = keydb_new (0);
257   if (!kh)
258     {
259       log_error (_("failed to allocated keyDB handle\n"));
260       rc = gpg_error (GPG_ERR_GENERAL);
261       goto leave;
262     }
263
264
265   in_fp = fdopen ( dup (in_fd), "rb");
266   if (!in_fp)
267     {
268       rc = gpg_error (gpg_err_code_from_errno (errno));
269       log_error ("fdopen() failed: %s\n", strerror (errno));
270       goto leave;
271     }
272
273   rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, 0, &reader);
274   if (rc)
275     {
276       log_error ("can't create reader: %s\n", gpg_strerror (rc));
277       goto leave;
278     }
279
280   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
281   if (rc)
282     {
283       log_error ("can't create writer: %s\n", gpg_strerror (rc));
284       goto leave;
285     }
286
287   rc = ksba_cms_new (&cms);
288   if (rc)
289     goto leave;
290
291   rc = ksba_cms_set_reader_writer (cms, reader, writer);
292   if (rc)
293     {
294       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
295                  gpg_strerror (rc));
296       goto leave;
297     }
298
299   /* Parser loop. */
300   do 
301     {
302       rc = ksba_cms_parse (cms, &stopreason);
303       if (rc)
304         {
305           log_debug ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
306           goto leave;
307         }
308
309       if (stopreason == KSBA_SR_BEGIN_DATA
310           || stopreason == KSBA_SR_DETACHED_DATA)
311         {
312           int algo, mode;
313           const char *algoid;
314           int any_key = 0;
315           
316           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
317           algo = gcry_cipher_map_name (algoid);
318           mode = gcry_cipher_mode_from_oid (algoid);
319           if (!algo || !mode)
320             {
321               rc = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
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               else if (!algoid)
326                 log_info (_("(this does not seem to be an encrypted"
327                             " message)\n"));
328               {
329                 char numbuf[50];
330                 sprintf (numbuf, "%d", rc);
331                 gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
332                                numbuf, algoid?algoid:"?", NULL);
333               }
334
335               /* If it seems that this is not an encrypted message we
336                  return a more sensible error code. */
337               if (!algoid)
338                 rc = gpg_error (GPG_ERR_NO_DATA);
339
340               goto leave;
341             }
342           dfparm.algo = algo;
343           dfparm.mode = mode;
344           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
345           if (dfparm.blklen > sizeof (dfparm.helpblock))
346             return gpg_error (GPG_ERR_BUG);
347
348           rc = ksba_cms_get_content_enc_iv (cms,
349                                             dfparm.iv,
350                                             sizeof (dfparm.iv),
351                                             &dfparm.ivlen);
352           if (rc)
353             {
354               log_error ("error getting IV: %s\n", gpg_strerror (rc));
355               goto leave;
356             }
357           
358           for (recp=0; !any_key; recp++)
359             {
360               char *issuer;
361               ksba_sexp_t serial;
362               ksba_sexp_t enc_val;
363               char *hexkeygrip = NULL;
364               char *desc = NULL;
365
366               rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
367               if (rc == -1 && recp)
368                 break; /* no more recipients */
369               if (rc)
370                 log_error ("recp %d - error getting info: %s\n",
371                            recp, gpg_strerror (rc));
372               else
373                 {
374                   ksba_cert_t cert = NULL;
375
376                   log_debug ("recp %d - issuer: `%s'\n",
377                              recp, issuer? issuer:"[NONE]");
378                   log_debug ("recp %d - serial: ", recp);
379                   gpgsm_dump_serial (serial);
380                   log_printf ("\n");
381
382                   keydb_search_reset (kh);
383                   rc = keydb_search_issuer_sn (kh, issuer, serial);
384                   if (rc)
385                     {
386                       log_error ("failed to find the certificate: %s\n",
387                                  gpg_strerror(rc));
388                       goto oops;
389                     }
390
391                   rc = keydb_get_cert (kh, &cert);
392                   if (rc)
393                     {
394                       log_error ("failed to get cert: %s\n", gpg_strerror (rc));
395                       goto oops;     
396                     }
397                   /* Just in case there is a problem with the own
398                      certificate we print this message - should never
399                      happen of course */
400                   rc = gpgsm_cert_use_decrypt_p (cert);
401                   if (rc)
402                     {
403                       char numbuf[50];
404                       sprintf (numbuf, "%d", rc);
405                       gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
406                                      numbuf, NULL);
407                       rc = 0;
408                     }
409
410                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
411                   desc = gpgsm_format_keydesc (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 (ctrl,
427                                            hexkeygrip, desc, enc_val, &dfparm);
428                   xfree (enc_val);
429                   if (rc)
430                     {
431                       log_info ("decrypting session key failed: %s\n",
432                                 gpg_strerror (rc));
433                     }
434                   else
435                     { /* setup the bulk decrypter */
436                       any_key = 1;
437                       ksba_writer_set_filter (writer,
438                                               decrypt_filter,
439                                               &dfparm);
440                     }
441                 }
442               xfree (hexkeygrip);
443               xfree (desc);
444             }
445           if (!any_key)
446             {
447               rc = gpg_error (GPG_ERR_NO_SECKEY);
448               goto leave;
449             }
450         }
451       else if (stopreason == KSBA_SR_END_DATA)
452         {
453           ksba_writer_set_filter (writer, NULL, NULL);
454           if (dfparm.any_data)
455             { /* write the last block with padding removed */
456               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
457               if (!npadding || npadding > dfparm.blklen)
458                 {
459                   log_error ("invalid padding with value %d\n", npadding);
460                   rc = gpg_error (GPG_ERR_INV_DATA);
461                   goto leave;
462                 }
463               rc = ksba_writer_write (writer,
464                                       dfparm.lastblock, 
465                                       dfparm.blklen - npadding);
466               if (rc)
467                   goto leave;
468
469               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
470                 {
471                   if (dfparm.lastblock[i] != npadding)
472                     {
473                       log_error ("inconsistent padding\n");
474                       rc = gpg_error (GPG_ERR_INV_DATA);
475                       goto leave;
476                     }
477                 }
478             }
479         }
480
481     }
482   while (stopreason != KSBA_SR_READY);   
483
484   rc = gpgsm_finish_writer (b64writer);
485   if (rc) 
486     {
487       log_error ("write failed: %s\n", gpg_strerror (rc));
488       goto leave;
489     }
490   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
491
492
493  leave:
494   if (rc)
495     {
496       gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
497       log_error ("message decryption failed: %s <%s>\n",
498                  gpg_strerror (rc), gpg_strsource (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