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

« back to all changes in this revision

Viewing changes to sm/verify.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
/* verify.c - Verify a messages signature
 
2
 *      Copyright (C) 2001, 2002, 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
static char *
 
38
strtimestamp_r (ksba_isotime_t atime)
 
39
{
 
40
  char *buffer = xmalloc (15);
 
41
  
 
42
  if (!atime || !*atime)
 
43
    strcpy (buffer, "none");
 
44
  else
 
45
    sprintf (buffer, "%.4s-%.2s-%.2s", atime, atime+4, atime+6);
 
46
  return buffer;
 
47
}
 
48
 
 
49
 
 
50
 
 
51
/* Hash the data for a detached signature */
 
52
static void
 
53
hash_data (int fd, gcry_md_hd_t md)
 
54
{
 
55
  FILE *fp;
 
56
  char buffer[4096];
 
57
  int nread;
 
58
 
 
59
  fp = fdopen ( dup (fd), "rb");
 
60
  if (!fp)
 
61
    {
 
62
      log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
 
63
      return;
 
64
    }
 
65
 
 
66
  do 
 
67
    {
 
68
      nread = fread (buffer, 1, DIM(buffer), fp);
 
69
      gcry_md_write (md, buffer, nread);
 
70
    }
 
71
  while (nread);
 
72
  if (ferror (fp))
 
73
      log_error ("read error on fd %d: %s\n", fd, strerror (errno));
 
74
  fclose (fp);
 
75
}
 
76
 
 
77
 
 
78
 
 
79
 
 
80
/* Perform a verify operation.  To verify detached signatures, data_fd
 
81
   must be different than -1.  With OUT_FP given and a non-detached
 
82
   signature, the signed material is written to that stream. */
 
83
int
 
84
gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
 
85
{
 
86
  int i, rc;
 
87
  Base64Context b64reader = NULL;
 
88
  Base64Context b64writer = NULL;
 
89
  ksba_reader_t reader;
 
90
  ksba_writer_t writer = NULL;
 
91
  ksba_cms_t cms = NULL;
 
92
  ksba_stop_reason_t stopreason;
 
93
  ksba_cert_t cert;
 
94
  KEYDB_HANDLE kh;
 
95
  gcry_md_hd_t data_md = NULL;
 
96
  int signer;
 
97
  const char *algoid;
 
98
  int algo;
 
99
  int is_detached;
 
100
  FILE *fp = NULL;
 
101
  char *p;
 
102
 
 
103
  kh = keydb_new (0);
 
104
  if (!kh)
 
105
    {
 
106
      log_error (_("failed to allocated keyDB handle\n"));
 
107
      rc = gpg_error (GPG_ERR_GENERAL);
 
108
      goto leave;
 
109
    }
 
110
 
 
111
 
 
112
  fp = fdopen ( dup (in_fd), "rb");
 
113
  if (!fp)
 
114
    {
 
115
      rc = gpg_error (gpg_err_code_from_errno (errno));
 
116
      log_error ("fdopen() failed: %s\n", strerror (errno));
 
117
      goto leave;
 
118
    }
 
119
 
 
120
  rc = gpgsm_create_reader (&b64reader, ctrl, fp, 0, &reader);
 
121
  if (rc)
 
122
    {
 
123
      log_error ("can't create reader: %s\n", gpg_strerror (rc));
 
124
      goto leave;
 
125
    }
 
126
 
 
127
  if (out_fp)
 
128
    {
 
129
      rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
 
130
      if (rc)
 
131
        {
 
132
          log_error ("can't create writer: %s\n", gpg_strerror (rc));
 
133
          goto leave;
 
134
        }
 
135
    }
 
136
 
 
137
  rc = ksba_cms_new (&cms);
 
138
  if (rc)
 
139
    goto leave;
 
140
 
 
141
  rc = ksba_cms_set_reader_writer (cms, reader, writer);
 
142
  if (rc)
 
143
    {
 
144
      log_error ("ksba_cms_set_reader_writer failed: %s\n",
 
145
                 gpg_strerror (rc));
 
146
      goto leave;
 
147
    }
 
148
 
 
149
  rc = gcry_md_open (&data_md, 0, 0);
 
150
  if (rc)
 
151
    {
 
152
      log_error ("md_open failed: %s\n", gpg_strerror (rc));
 
153
      goto leave;
 
154
    }
 
155
  if (DBG_HASHING)
 
156
    gcry_md_start_debug (data_md, "vrfy.data");
 
157
 
 
158
  is_detached = 0;
 
159
  do 
 
160
    {
 
161
      rc = ksba_cms_parse (cms, &stopreason);
 
162
      if (rc)
 
163
        {
 
164
          log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
 
165
          goto leave;
 
166
        }
 
167
 
 
168
      if (stopreason == KSBA_SR_NEED_HASH)
 
169
        {
 
170
          is_detached = 1;
 
171
          if (opt.verbose)
 
172
            log_info ("detached signature\n");
 
173
        }
 
174
 
 
175
      if (stopreason == KSBA_SR_NEED_HASH
 
176
          || stopreason == KSBA_SR_BEGIN_DATA)
 
177
        { /* We are now able to enable the hash algorithms */
 
178
          for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
 
179
            {
 
180
              algo = gcry_md_map_name (algoid);
 
181
              if (!algo)
 
182
                log_error ("unknown hash algorithm `%s'\n",
 
183
                           algoid? algoid:"?");
 
184
              else
 
185
                gcry_md_enable (data_md, algo);
 
186
            }
 
187
          if (is_detached)
 
188
            {
 
189
              if (data_fd == -1)
 
190
                log_info ("detached signature w/o data "
 
191
                          "- assuming certs-only\n");
 
192
              else
 
193
                hash_data (data_fd, data_md);  
 
194
            }
 
195
          else
 
196
            {
 
197
              ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
 
198
            }
 
199
        }
 
200
      else if (stopreason == KSBA_SR_END_DATA)
 
201
        { /* The data bas been hashed */
 
202
 
 
203
        }
 
204
    }
 
205
  while (stopreason != KSBA_SR_READY);   
 
206
 
 
207
  if (b64writer)
 
208
    {
 
209
      rc = gpgsm_finish_writer (b64writer);
 
210
      if (rc) 
 
211
        {
 
212
          log_error ("write failed: %s\n", gpg_strerror (rc));
 
213
          goto leave;
 
214
        }
 
215
    }
 
216
 
 
217
  if (data_fd != -1 && !is_detached)
 
218
    {
 
219
      log_error ("data given for a non-detached signature\n");
 
220
      rc = gpg_error (GPG_ERR_CONFLICT);
 
221
      goto leave;
 
222
    }
 
223
 
 
224
  for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
 
225
    {
 
226
      /* Fixme: it might be better to check the validity of the
 
227
         certificate first before entering it into the DB.  This way
 
228
         we would avoid cluttering the DB with invalid
 
229
         certificates. */
 
230
      keydb_store_cert (cert, 0, NULL);
 
231
      ksba_cert_release (cert);
 
232
    }
 
233
 
 
234
  cert = NULL;
 
235
  for (signer=0; ; signer++)
 
236
    {
 
237
      char *issuer = NULL;
 
238
      ksba_sexp_t sigval = NULL;
 
239
      ksba_isotime_t sigtime, keyexptime;
 
240
      ksba_sexp_t serial;
 
241
      char *msgdigest = NULL;
 
242
      size_t msgdigestlen;
 
243
      char *ctattr;
 
244
 
 
245
      rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
 
246
      if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
 
247
          && data_fd == -1 && is_detached)
 
248
        {
 
249
          log_info ("certs-only message accepted\n");
 
250
          rc = 0;
 
251
          break;
 
252
        }
 
253
      if (rc)
 
254
        {
 
255
          if (signer && rc == -1)
 
256
            rc = 0;
 
257
          break;
 
258
        }
 
259
 
 
260
      gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
 
261
 
 
262
      if (DBG_X509)
 
263
        {
 
264
          log_debug ("signer %d - issuer: `%s'\n",
 
265
                     signer, issuer? issuer:"[NONE]");
 
266
          log_debug ("signer %d - serial: ", signer);
 
267
          gpgsm_dump_serial (serial);
 
268
          log_printf ("\n");
 
269
        }
 
270
 
 
271
      rc = ksba_cms_get_signing_time (cms, signer, sigtime);
 
272
      if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
 
273
        *sigtime = 0;
 
274
      else if (rc)
 
275
        {
 
276
          log_error ("error getting signing time: %s\n", gpg_strerror (rc));
 
277
          *sigtime = 0; /* (we can't encode an error in the time string.) */
 
278
        }
 
279
 
 
280
      rc = ksba_cms_get_message_digest (cms, signer,
 
281
                                        &msgdigest, &msgdigestlen);
 
282
      if (!rc)
 
283
        {
 
284
          size_t is_enabled;
 
285
 
 
286
          algoid = ksba_cms_get_digest_algo (cms, signer);
 
287
          algo = gcry_md_map_name (algoid);
 
288
          if (DBG_X509)
 
289
            log_debug ("signer %d - digest algo: %d\n", signer, algo);
 
290
          is_enabled = sizeof algo;
 
291
          if ( gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED,
 
292
                             &algo, &is_enabled)
 
293
               || !is_enabled)
 
294
            {
 
295
              log_error ("digest algo %d has not been enabled\n", algo);
 
296
              goto next_signer;
 
297
            }
 
298
        }
 
299
      else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
 
300
        {
 
301
          assert (!msgdigest);
 
302
          rc = 0;
 
303
          algoid = NULL;
 
304
          algo = 0; 
 
305
        }
 
306
      else /* real error */
 
307
        break;
 
308
 
 
309
      rc = ksba_cms_get_sigattr_oids (cms, signer,
 
310
                                      "1.2.840.113549.1.9.3", &ctattr);
 
311
      if (!rc) 
 
312
        {
 
313
          const char *s;
 
314
 
 
315
          if (DBG_X509)
 
316
            log_debug ("signer %d - content-type attribute: %s",
 
317
                       signer, ctattr);
 
318
 
 
319
          s = ksba_cms_get_content_oid (cms, 1);
 
320
          if (!s || strcmp (ctattr, s))
 
321
            {
 
322
              log_error ("content-type attribute does not match "
 
323
                         "actual content-type\n");
 
324
              ksba_free (ctattr);
 
325
              ctattr = NULL;
 
326
              goto next_signer;
 
327
            }
 
328
          ksba_free (ctattr);
 
329
          ctattr = NULL;
 
330
        }
 
331
      else if (rc != -1)
 
332
        {
 
333
          log_error ("error getting content-type attribute: %s\n",
 
334
                     gpg_strerror (rc));
 
335
          goto next_signer;
 
336
        }
 
337
      rc = 0;
 
338
 
 
339
 
 
340
      sigval = ksba_cms_get_sig_val (cms, signer);
 
341
      if (!sigval)
 
342
        {
 
343
          log_error ("no signature value available\n");
 
344
          goto next_signer;
 
345
        }
 
346
      if (DBG_X509)
 
347
        log_debug ("signer %d - signature available", signer);
 
348
 
 
349
      /* Find the certificate of the signer */
 
350
      keydb_search_reset (kh);
 
351
      rc = keydb_search_issuer_sn (kh, issuer, serial);
 
352
      if (rc)
 
353
        {
 
354
          if (rc == -1)
 
355
            {
 
356
              log_error ("certificate not found\n");
 
357
              rc = gpg_error (GPG_ERR_NO_PUBKEY);
 
358
            }
 
359
          else
 
360
            log_error ("failed to find the certificate: %s\n",
 
361
                       gpg_strerror(rc));
 
362
          {
 
363
            char numbuf[50];
 
364
            sprintf (numbuf, "%d", rc);
 
365
 
 
366
            gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
 
367
                           numbuf, NULL);
 
368
          }
 
369
          /* fixme: we might want to append the issuer and serial
 
370
             using our standard notation */
 
371
          goto next_signer;
 
372
        }
 
373
 
 
374
      rc = keydb_get_cert (kh, &cert);
 
375
      if (rc)
 
376
        {
 
377
          log_error ("failed to get cert: %s\n", gpg_strerror (rc));
 
378
          goto next_signer;
 
379
        }
 
380
 
 
381
      log_info (_("Signature made "));
 
382
      if (*sigtime)
 
383
        gpgsm_dump_time (sigtime);
 
384
      else
 
385
        log_printf (_("[date not given]"));
 
386
      log_printf (_(" using certificate ID %08lX\n"),
 
387
                  gpgsm_get_short_fingerprint (cert));
 
388
 
 
389
 
 
390
      if (msgdigest)
 
391
        { /* Signed attributes are available. */
 
392
          gcry_md_hd_t md;
 
393
          unsigned char *s;
 
394
 
 
395
          /* check that the message digest in the signed attributes
 
396
             matches the one we calculated on the data */
 
397
          s = gcry_md_read (data_md, algo);
 
398
          if ( !s || !msgdigestlen
 
399
               || gcry_md_get_algo_dlen (algo) != msgdigestlen
 
400
               || !s || memcmp (s, msgdigest, msgdigestlen) )
 
401
            {
 
402
              char *fpr;
 
403
 
 
404
              log_error ("invalid signature: message digest attribute "
 
405
                         "does not match calculated one\n");
 
406
              fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
 
407
              gpgsm_status (ctrl, STATUS_BADSIG, fpr);
 
408
              xfree (fpr);
 
409
              goto next_signer; 
 
410
            }
 
411
            
 
412
          rc = gcry_md_open (&md, algo, 0);
 
413
          if (rc)
 
414
            {
 
415
              log_error ("md_open failed: %s\n", gpg_strerror (rc));
 
416
              goto next_signer;
 
417
            }
 
418
          if (DBG_HASHING)
 
419
            gcry_md_start_debug (md, "vrfy.attr");
 
420
 
 
421
          ksba_cms_set_hash_function (cms, HASH_FNC, md);
 
422
          rc = ksba_cms_hash_signed_attrs (cms, signer);
 
423
          if (rc)
 
424
            {
 
425
              log_error ("hashing signed attrs failed: %s\n",
 
426
                         gpg_strerror (rc));
 
427
              gcry_md_close (md);
 
428
              goto next_signer;
 
429
            }
 
430
          rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
 
431
          gcry_md_close (md);
 
432
        }
 
433
      else
 
434
        {
 
435
          rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
 
436
        }
 
437
 
 
438
      if (rc)
 
439
        {
 
440
          char *fpr;
 
441
 
 
442
          log_error ("invalid signature: %s\n", gpg_strerror (rc));
 
443
          fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
 
444
          gpgsm_status (ctrl, STATUS_BADSIG, fpr);
 
445
          xfree (fpr);
 
446
          goto next_signer;
 
447
        }
 
448
      rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
 
449
      if (rc)
 
450
        {
 
451
          gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
 
452
                                      gpg_err_code (rc));
 
453
          rc = 0;
 
454
        }
 
455
 
 
456
      if (DBG_X509)
 
457
        log_debug ("signature okay - checking certs\n");
 
458
      rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL, 0);
 
459
      if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
 
460
        {
 
461
          gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
 
462
          rc = 0;
 
463
        }
 
464
      else
 
465
        gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
 
466
      
 
467
      {
 
468
        char *buf, *fpr, *tstr;
 
469
 
 
470
        fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
 
471
        tstr = strtimestamp_r (sigtime);
 
472
        buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
 
473
        sprintf (buf, "%s %s %s %s", fpr, tstr,
 
474
                 *sigtime? sigtime : "0",
 
475
                 *keyexptime? keyexptime : "0" );
 
476
        xfree (tstr);
 
477
        xfree (fpr);
 
478
        gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
 
479
        xfree (buf);
 
480
      }
 
481
 
 
482
      if (rc) /* of validate_chain */
 
483
        {
 
484
          log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
 
485
          if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
 
486
              || gpg_err_code (rc) == GPG_ERR_BAD_CERT
 
487
              || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
 
488
              || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
 
489
            gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
 
490
                                        gpg_err_code (rc));
 
491
          else
 
492
            gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL, 
 
493
                                        gpg_err_code (rc));
 
494
          goto next_signer;
 
495
        }
 
496
 
 
497
      for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
 
498
        {
 
499
          log_info (!i? _("Good signature from")
 
500
                      : _("                aka"));
 
501
          log_printf (" \"");
 
502
          gpgsm_print_name (log_get_stream (), p);
 
503
          log_printf ("\"\n");
 
504
          ksba_free (p);
 
505
        }
 
506
 
 
507
      gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
 
508
          
 
509
 
 
510
    next_signer:
 
511
      rc = 0;
 
512
      xfree (issuer);
 
513
      xfree (serial);
 
514
      xfree (sigval);
 
515
      xfree (msgdigest);
 
516
      ksba_cert_release (cert);
 
517
      cert = NULL;
 
518
    }
 
519
  rc = 0;
 
520
 
 
521
 leave:
 
522
  ksba_cms_release (cms);
 
523
  gpgsm_destroy_reader (b64reader);
 
524
  gpgsm_destroy_writer (b64writer);
 
525
  keydb_release (kh); 
 
526
  gcry_md_close (data_md);
 
527
  if (fp)
 
528
    fclose (fp);
 
529
 
 
530
  if (rc)
 
531
    {
 
532
      char numbuf[50];
 
533
      sprintf (numbuf, "%d", rc );
 
534
      gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
 
535
                     numbuf, NULL);
 
536
    }
 
537
 
 
538
  return rc;
 
539
}
 
540