~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to sm/decrypt.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 (ctrl_t ctrl, 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 (ctrl, 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. */
 
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 right way 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
 
 
239
/* Perform a decrypt operation.  */
 
240
int
 
241
gpgsm_decrypt (ctrl_t 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
              /* If it seems that this is not an encrypted message we
 
337
                 return a more sensible error code. */
 
338
              if (!algoid)
 
339
                rc = gpg_error (GPG_ERR_NO_DATA);
 
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", gpg_strerror (rc));
 
356
              goto leave;
 
357
            }
 
358
          
 
359
          for (recp=0; !any_key; recp++)
 
360
            {
 
361
              char *issuer;
 
362
              ksba_sexp_t serial;
 
363
              ksba_sexp_t enc_val;
 
364
              char *hexkeygrip = NULL;
 
365
              char *desc = NULL;
 
366
 
 
367
              rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
 
368
              if (rc == -1 && recp)
 
369
                break; /* no more recipients */
 
370
              if (rc)
 
371
                log_error ("recp %d - error getting info: %s\n",
 
372
                           recp, gpg_strerror (rc));
 
373
              else
 
374
                {
 
375
                  ksba_cert_t 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
                  desc = gpgsm_format_keydesc (cert);
 
413
 
 
414
                oops:
 
415
                  xfree (issuer);
 
416
                  xfree (serial);
 
417
                  ksba_cert_release (cert);
 
418
                }
 
419
 
 
420
              if (!hexkeygrip)
 
421
                ;
 
422
              else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
 
423
                log_error ("recp %d - error getting encrypted session key\n",
 
424
                           recp);
 
425
              else
 
426
                {
 
427
                  rc = prepare_decryption (ctrl,
 
428
                                           hexkeygrip, desc, enc_val, &dfparm);
 
429
                  xfree (enc_val);
 
430
                  if (rc)
 
431
                    {
 
432
                      log_info ("decrypting session key failed: %s\n",
 
433
                                gpg_strerror (rc));
 
434
                    }
 
435
                  else
 
436
                    { /* setup the bulk decrypter */
 
437
                      any_key = 1;
 
438
                      ksba_writer_set_filter (writer,
 
439
                                              decrypt_filter,
 
440
                                              &dfparm);
 
441
                    }
 
442
                }
 
443
              xfree (hexkeygrip);
 
444
              xfree (desc);
 
445
            }
 
446
          if (!any_key)
 
447
            {
 
448
              rc = gpg_error (GPG_ERR_NO_SECKEY);
 
449
              goto leave;
 
450
            }
 
451
        }
 
452
      else if (stopreason == KSBA_SR_END_DATA)
 
453
        {
 
454
          ksba_writer_set_filter (writer, NULL, NULL);
 
455
          if (dfparm.any_data)
 
456
            { /* write the last block with padding removed */
 
457
              int i, npadding = dfparm.lastblock[dfparm.blklen-1];
 
458
              if (!npadding || npadding > dfparm.blklen)
 
459
                {
 
460
                  log_error ("invalid padding with value %d\n", npadding);
 
461
                  rc = gpg_error (GPG_ERR_INV_DATA);
 
462
                  goto leave;
 
463
                }
 
464
              rc = ksba_writer_write (writer,
 
465
                                      dfparm.lastblock, 
 
466
                                      dfparm.blklen - npadding);
 
467
              if (rc)
 
468
                  goto leave;
 
469
 
 
470
              for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
 
471
                {
 
472
                  if (dfparm.lastblock[i] != npadding)
 
473
                    {
 
474
                      log_error ("inconsistent padding\n");
 
475
                      rc = gpg_error (GPG_ERR_INV_DATA);
 
476
                      goto leave;
 
477
                    }
 
478
                }
 
479
            }
 
480
        }
 
481
 
 
482
    }
 
483
  while (stopreason != KSBA_SR_READY);   
 
484
 
 
485
  rc = gpgsm_finish_writer (b64writer);
 
486
  if (rc) 
 
487
    {
 
488
      log_error ("write failed: %s\n", gpg_strerror (rc));
 
489
      goto leave;
 
490
    }
 
491
  gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
 
492
 
 
493
 
 
494
 leave:
 
495
  if (rc)
 
496
    {
 
497
      gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
 
498
      log_error ("message decryption failed: %s <%s>\n",
 
499
                 gpg_strerror (rc), gpg_strsource (rc));
 
500
    }
 
501
  ksba_cms_release (cms);
 
502
  gpgsm_destroy_reader (b64reader);
 
503
  gpgsm_destroy_writer (b64writer);
 
504
  keydb_release (kh); 
 
505
  if (in_fp)
 
506
    fclose (in_fp);
 
507
  if (dfparm.hd)
 
508
    gcry_cipher_close (dfparm.hd); 
 
509
  return rc;
 
510
}
 
511
 
 
512