* util.h (digitp, hexdigitp): New ctype like macros.
[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 static void
54 print_integer (unsigned char *p)
55 {
56   unsigned long len;
57
58   if (!p)
59     log_printf ("none");
60   else
61     {
62       len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
63       for (p+=4; len; len--, p++)
64         log_printf ("%02X", *p);
65     }
66 }
67
68 /* decrypt the session key and fill in the parm structure.  The
69    algo and the IV is expected to be already in PARM. */
70 static int 
71 prepare_decryption (const char *hexkeygrip, const char *enc_val,
72                     struct decrypt_filter_parm_s *parm)
73 {
74   char *seskey = NULL;
75   size_t n, seskeylen;
76   int rc;
77
78   rc = gpgsm_agent_pkdecrypt (hexkeygrip, enc_val, strlen (enc_val),
79                               &seskey, &seskeylen);
80   if (rc)
81     {
82       log_error ("error decrypting session key: %s\n", gnupg_strerror (rc));
83       goto leave;
84     }
85
86   if (DBG_CRYPTO)
87     log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
88
89   n=0;
90   if (n + 7 > seskeylen )
91     {
92       rc = seterr (Invalid_Session_Key);
93       goto leave; 
94     }
95
96   if (seskey[n] != 2 )  /* wrong block type version */
97     { 
98       rc = seterr (Invalid_Session_Key);
99       goto leave; 
100     }
101
102   for (n++; n < seskeylen && seskey[n]; n++) /* skip the random bytes */
103     ;
104   n++; /* and the zero byte */
105   if (n >= seskeylen )
106     { 
107       rc = seterr (Invalid_Session_Key);
108       goto leave; 
109     }
110   
111   if (DBG_CRYPTO)
112     log_printhex ("session key:", seskey+n, seskeylen-n);
113
114   parm->hd = gcry_cipher_open (parm->algo, parm->mode, 0);
115   if (!parm->hd)
116     {
117       rc = gcry_errno ();
118       log_error ("error creating decryptor: %s\n", gcry_strerror (rc));
119       rc = map_gcry_err (rc);
120       goto leave;
121     }
122                         
123   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
124   if (rc == GCRYERR_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", gcry_strerror(rc) );
133       rc = map_gcry_err (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 KsbaError  
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 KSBA_Bug;
164
165   if (maxoutlen < 2*parm->blklen)
166     return KSBA_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 KSBA_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   KsbaError err;
245   Base64Context b64reader = NULL;
246   Base64Context b64writer = NULL;
247   KsbaReader reader;
248   KsbaWriter writer;
249   KsbaCMS cms = NULL;
250   KsbaStopReason stopreason;
251   KEYDB_HANDLE kh;
252   int recp;
253   FILE *in_fp = NULL;
254   struct decrypt_filter_parm_s dfparm;
255
256   memset (&dfparm, 0, sizeof dfparm);
257
258   kh = keydb_new (0);
259   if (!kh)
260     {
261       log_error (_("failed to allocated keyDB handle\n"));
262       rc = GNUPG_General_Error;
263       goto leave;
264     }
265
266
267   in_fp = fdopen ( dup (in_fd), "rb");
268   if (!in_fp)
269     {
270       log_error ("fdopen() failed: %s\n", strerror (errno));
271       rc = seterr (IO_Error);
272       goto leave;
273     }
274
275   rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, &reader);
276   if (rc)
277     {
278       log_error ("can't create reader: %s\n", gnupg_strerror (rc));
279       goto leave;
280     }
281
282   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
283   if (rc)
284     {
285       log_error ("can't create writer: %s\n", gnupg_strerror (rc));
286       goto leave;
287     }
288
289   cms = ksba_cms_new ();
290   if (!cms)
291     {
292       rc = seterr (Out_Of_Core);
293       goto leave;
294     }
295
296   err = ksba_cms_set_reader_writer (cms, reader, writer);
297   if (err)
298     {
299       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
300                  ksba_strerror (err));
301       rc = map_ksba_err (err);
302       goto leave;
303     }
304
305   /* parser loop */
306   do 
307     {
308       err = ksba_cms_parse (cms, &stopreason);
309       if (err)
310         {
311           log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
312           rc = map_ksba_err (err);
313           goto leave;
314         }
315
316       if (stopreason == KSBA_SR_BEGIN_DATA
317           || stopreason == KSBA_SR_DETACHED_DATA)
318         {
319           int algo, mode;
320           const char *algoid;
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               log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
328               rc = GNUPG_Unsupported_Algorithm;
329               goto leave;
330             }
331           dfparm.algo = algo;
332           dfparm.mode = mode;
333           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
334           if (dfparm.blklen > sizeof (dfparm.helpblock))
335             return GNUPG_Bug;
336
337           rc = ksba_cms_get_content_enc_iv (cms,
338                                             dfparm.iv,
339                                             sizeof (dfparm.iv),
340                                             &dfparm.ivlen);
341           if (rc)
342             {
343               log_error ("error getting IV: %s\n", ksba_strerror (err));
344               rc = map_ksba_err (err);
345               goto leave;
346             }
347           
348           for (recp=0; recp < 1; recp++)
349             {
350               char *issuer;
351               unsigned char *serial;
352               char *enc_val;
353               char *hexkeygrip = NULL;
354
355               err = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
356               if (err)
357                 log_error ("recp %d - error getting info: %s\n",
358                            recp, ksba_strerror (err));
359               else
360                 {
361                   KsbaCert cert = NULL;
362
363                   log_debug ("recp %d - issuer: `%s'\n",
364                              recp, issuer? issuer:"[NONE]");
365                   log_debug ("recp %d - serial: ", recp);
366                   print_integer (serial);
367                   log_printf ("\n");
368
369                   keydb_search_reset (kh);
370                   rc = keydb_search_issuer_sn (kh, issuer, serial);
371                   if (rc)
372                     {
373                       log_debug ("failed to find the certificate: %s\n",
374                                  gnupg_strerror(rc));
375                       goto oops;
376                     }
377
378                   rc = keydb_get_cert (kh, &cert);
379                   if (rc)
380                     {
381                       log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
382                       goto oops;                    }
383
384                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
385
386                 oops:
387                   xfree (issuer);
388                   xfree (serial);
389                   ksba_cert_release (cert);
390                 }
391
392               enc_val = ksba_cms_get_enc_val (cms, recp);
393               if (!enc_val)
394                 log_error ("recp %d - error getting encrypted session key\n",
395                            recp);
396               else
397                 {
398                   log_debug ("recp %d - enc-val: `%s'\n",
399                              recp, enc_val);
400                   rc = prepare_decryption (hexkeygrip, enc_val,
401                                            &dfparm);
402                   xfree (enc_val);
403                   if (rc)
404                     log_error ("decrypting session key failed: %s\n",
405                                gnupg_strerror (rc));
406                   else
407                     { /* setup the bulk decrypter */
408                       ksba_writer_set_filter (writer,
409                                               decrypt_filter,
410                                               &dfparm);
411                     }
412                 }
413             }
414         }
415       else if (stopreason == KSBA_SR_END_DATA)
416         {
417           ksba_writer_set_filter (writer, NULL, NULL);
418           if (dfparm.any_data)
419             { /* write the last block with padding removed */
420               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
421               if (!npadding || npadding > dfparm.blklen)
422                 {
423                   log_error ("invalid padding with value %d\n", npadding);
424                   rc = seterr (Invalid_Data);
425                   goto leave;
426                 }
427               rc = ksba_writer_write (writer,
428                                       dfparm.lastblock, 
429                                       dfparm.blklen - npadding);
430               if (rc)
431                 {
432                   rc = map_ksba_err (rc);
433                   goto leave;
434                 }
435               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
436                 {
437                   if (dfparm.lastblock[i] != npadding)
438                     {
439                       log_error ("inconsistent padding\n");
440                       rc = seterr (Invalid_Data);
441                       goto leave;
442                     }
443                 }
444             }
445         }
446
447     }
448   while (stopreason != KSBA_SR_READY);   
449
450   rc = gpgsm_finish_writer (b64writer);
451   if (rc) 
452     {
453       log_error ("write failed: %s\n", gnupg_strerror (rc));
454       goto leave;
455     }
456
457
458  leave:
459   ksba_cms_release (cms);
460   gpgsm_destroy_reader (b64reader);
461   gpgsm_destroy_writer (b64writer);
462   keydb_release (kh); 
463   if (in_fp)
464     fclose (in_fp);
465   if (dfparm.hd)
466     gcry_cipher_close (dfparm.hd); 
467   return rc;
468 }
469
470