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