From 0f26760d9f550fd9aaa7d0c4f18f8571b7818142 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 16 Nov 2001 17:56:23 +0000 Subject: [PATCH] Base code for gpgsm --verify does work --- kbx/keybox-search-desc.h | 1 + kbx/keybox-search.c | 18 ++ sm/Makefile.am | 1 + sm/certchain.c | 7 +- sm/certcheck.c | 106 ++++++++--- sm/certdump.c | 96 +++++----- sm/certpath.c | 7 +- sm/gpgsm.c | 4 + sm/gpgsm.h | 7 +- sm/keydb.c | 13 ++ sm/keydb.h | 1 + sm/server.c | 15 +- sm/verify.c | 374 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 562 insertions(+), 88 deletions(-) create mode 100644 sm/verify.c diff --git a/kbx/keybox-search-desc.h b/kbx/keybox-search-desc.h index 22bcba69b..88ffde8d0 100644 --- a/kbx/keybox-search-desc.h +++ b/kbx/keybox-search-desc.h @@ -42,6 +42,7 @@ typedef enum { KEYDB_SEARCH_MODE_FPR, KEYDB_SEARCH_MODE_ISSUER, KEYDB_SEARCH_MODE_ISSUER_SN, + KEYDB_SEARCH_MODE_SUBJECT, KEYDB_SEARCH_MODE_FIRST, KEYDB_SEARCH_MODE_NEXT } KeydbSearchMode; diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 3468a8ecf..2a4ceca94 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -205,6 +205,20 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name, const unsigned char *sn) && blob_cmp_name (blob, 0 /* issuer */, name, namelen)); } +static int +has_subject (KEYBOXBLOB blob, const char *name) +{ + size_t namelen; + + return_val_if_fail (name, 0); + + if (blob_get_type (blob) != BLOBTYPE_X509) + return 0; + + namelen = strlen (name); + return blob_cmp_name (blob, 1 /* subject */, name, namelen); +} + /* @@ -316,6 +330,10 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) if (has_issuer_sn (blob, desc[n].u.name, desc[n].sn)) goto found; break; + case KEYDB_SEARCH_MODE_SUBJECT: + if (has_subject (blob, desc[n].u.name)) + goto found; + break; case KEYDB_SEARCH_MODE_SHORT_KID: /* if (has_short_kid (blob, desc[n].u.kid[1])) */ /* goto found; */ diff --git a/sm/Makefile.am b/sm/Makefile.am index ab34f10b6..4b74672ab 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -34,6 +34,7 @@ gpgsm_SOURCES = \ certdump.c \ certcheck.c \ certpath.c \ + verify.c \ import.c gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a ../kbx/libkeybox.a \ diff --git a/sm/certchain.c b/sm/certchain.c index aef1612cc..518acfe3a 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -50,8 +50,7 @@ gpgsm_validate_path (KsbaCert cert) goto leave; } - log_debug ("validate path for certificate:\n"); - gpgsm_dump_cert (cert); + gpgsm_dump_cert ("subject", cert); subject_cert = cert; @@ -87,7 +86,7 @@ gpgsm_validate_path (KsbaCert cert) /* find the next cert up the tree */ keydb_search_reset (kh); - rc = keydb_search_issuer (kh, issuer); + rc = keydb_search_subject (kh, issuer); if (rc) { log_debug ("failed to find issuer's certificate: rc=%d\n", rc); @@ -105,7 +104,7 @@ gpgsm_validate_path (KsbaCert cert) } log_debug ("got issuer's certificate:\n"); - gpgsm_dump_cert (issuer_cert); + gpgsm_dump_cert ("issuer", issuer_cert); if (gpgsm_check_cert_sig (issuer_cert, subject_cert) ) { diff --git a/sm/certcheck.c b/sm/certcheck.c index a86aa2d9e..8a9c2c2b2 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -34,13 +34,26 @@ #include "keydb.h" #include "i18n.h" + static int -do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits, - const byte *asn, size_t asnlen, GCRY_MPI *r_val) +do_encode_md (GCRY_MD_HD md, int algo, unsigned int nbits, + GCRY_MPI *r_val) { int nframe = (nbits+7) / 8; byte *frame; int i, n; + byte asn[100]; + size_t asnlen; + size_t len; + + asnlen = DIM(asn); + if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) + { + log_error ("No object identifier for algo %d\n", algo); + return GPGSM_Internal_Error; + } + + len = gcry_md_get_algo_dlen (algo); if ( len + asnlen + 4 > nframe ) { @@ -68,6 +81,15 @@ do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits, memcpy ( frame+n, asn, asnlen ); n += asnlen; memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len; assert ( n == nframe ); + if (DBG_X509) + { + int j; + log_debug ("encoded hash:"); + for (j=0; j < nframe; j++) + log_printf (" %02X", frame[j]); + log_printf ("\n"); + } + gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, &nframe); xfree (frame); return 0; @@ -81,12 +103,6 @@ do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits, int gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert) { - /* OID for MD5 as defined in PKCS#1 (rfc2313) */ - static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 (md5) */ - { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 - }; - GCRY_MD_HD md; int rc, algo; GCRY_MPI frame; @@ -120,21 +136,6 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert) log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); return map_gcry_err (rc); } - /*gcry_sexp_dump (s_sig);*/ - - - /* FIXME: need to map the algo to the ASN OID - we assume a fixed - one for now */ - rc = do_encode_md (md, algo, 16, 2048, asn, DIM(asn), &frame); - if (rc) - { - /* fixme: clean up some things */ - return rc; - } - /* put hash into the S-Exp s_hash */ - if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) - BUG (); - /*fputs ("hash:\n", stderr); gcry_sexp_dump (s_hash);*/ p = ksba_cert_get_public_key (issuer_cert); if (DBG_X509) @@ -146,7 +147,64 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert) log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); return map_gcry_err (rc); } - /*gcry_sexp_dump (s_pkey);*/ + + rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame); + if (rc) + { + /* fixme: clean up some things */ + return rc; + } + /* put hash into the S-Exp s_hash */ + if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) + BUG (); + + + rc = gcry_pk_verify (s_sig, s_hash, s_pkey); + if (DBG_CRYPTO) + log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc)); + return map_gcry_err (rc); +} + + + +int +gpgsm_check_cms_signature (KsbaCert cert, const char *sigval, + GCRY_MD_HD md, int algo) +{ + int rc; + GCRY_MPI frame; + char *p; + GCRY_SEXP s_sig, s_hash, s_pkey; + + rc = gcry_sexp_sscan (&s_sig, NULL, sigval, strlen(sigval)); + if (rc) + { + log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); + return map_gcry_err (rc); + } + + p = ksba_cert_get_public_key (cert); + if (DBG_X509) + log_debug ("public key: %s\n", p); + + rc = gcry_sexp_sscan ( &s_pkey, NULL, p, strlen(p)); + if (rc) + { + log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); + return map_gcry_err (rc); + } + + + rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame); + if (rc) + { + /* fixme: clean up some things */ + return rc; + } + /* put hash into the S-Exp s_hash */ + if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) + BUG (); + rc = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_CRYPTO) diff --git a/sm/certdump.c b/sm/certdump.c index 5dfce2a02..9685b1aa8 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -39,12 +39,12 @@ print_integer (unsigned char *p) unsigned long len; if (!p) - fputs ("none", stdout); + log_printf ("none"); else { len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; for (p+=4; len; len--, p++) - printf ("%02X", *p); + log_printf ("%02X", *p); } } @@ -53,17 +53,17 @@ print_time (time_t t) { if (!t) - fputs ("none", stdout); + log_printf ("none"); else if ( t == (time_t)(-1) ) - fputs ("error", stdout); + log_printf ("error"); else { struct tm *tp; tp = gmtime (&t); - printf ("%04d-%02d-%02d %02d:%02d:%02d", - 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, - tp->tm_hour, tp->tm_min, tp->tm_sec); + log_printf ("%04d-%02d-%02d %02d:%02d:%02d", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); assert (!tp->tm_isdst); } } @@ -71,61 +71,55 @@ print_time (time_t t) static void print_dn (char *p) { - if (!p) - fputs ("error", stdout); + log_printf ("error"); else - printf ("`%s'", p); + log_printf ("`%s'", p); } void -gpgsm_dump_cert (KsbaCert cert) +gpgsm_dump_cert (const char *text, KsbaCert cert) { unsigned char *p; char *dn; time_t t; - if (!cert) + log_debug ("BEGIN Certificate `%s':\n", text? text:""); + if (cert) { - fputs ("[no certificate]\n", stdout); - return; + p = ksba_cert_get_serial (cert); + log_debug (" serial: "); + print_integer (p); + ksba_free (p); + log_printf ("\n"); + + t = ksba_cert_get_validity (cert, 0); + log_debug (" notBefore: "); + print_time (t); + log_printf ("\n"); + t = ksba_cert_get_validity (cert, 1); + log_debug (" notAfter: "); + print_time (t); + log_printf ("\n"); + + dn = ksba_cert_get_issuer (cert); + log_debug (" issuer: "); + print_dn (dn); + ksba_free (dn); + log_printf ("\n"); + + dn = ksba_cert_get_subject (cert); + log_debug (" subject: "); + print_dn (dn); + ksba_free (dn); + log_printf ("\n"); + + log_debug (" hash algo: %d\n", ksba_cert_get_digest_algo (cert)); + + p = gpgsm_get_fingerprint_string (cert, 0); + log_debug (" SHA1 Fingerprint: %s\n", p); + xfree (p); } - - p = ksba_cert_get_serial (cert); - fputs ("serial: ", stdout); - print_integer (p); - ksba_free (p); - putchar ('\n'); - - t = ksba_cert_get_validity (cert, 0); - fputs ("notBefore: ", stdout); - print_time (t); - putchar ('\n'); - t = ksba_cert_get_validity (cert, 1); - fputs ("notAfter: ", stdout); - print_time (t); - putchar ('\n'); - - dn = ksba_cert_get_issuer (cert); - fputs ("issuer: ", stdout); - print_dn (dn); - ksba_free (dn); - putchar ('\n'); - - dn = ksba_cert_get_subject (cert); - fputs ("subject: ", stdout); - print_dn (dn); - ksba_free (dn); - putchar ('\n'); - - printf ("hash algo: %d\n", ksba_cert_get_digest_algo (cert)); - - p = gpgsm_get_fingerprint_string (cert, 0); - printf ("SHA1 Fingerprint=%s\n", p); - xfree (p); + log_debug ("END Certificate\n"); } - - - - diff --git a/sm/certpath.c b/sm/certpath.c index aef1612cc..518acfe3a 100644 --- a/sm/certpath.c +++ b/sm/certpath.c @@ -50,8 +50,7 @@ gpgsm_validate_path (KsbaCert cert) goto leave; } - log_debug ("validate path for certificate:\n"); - gpgsm_dump_cert (cert); + gpgsm_dump_cert ("subject", cert); subject_cert = cert; @@ -87,7 +86,7 @@ gpgsm_validate_path (KsbaCert cert) /* find the next cert up the tree */ keydb_search_reset (kh); - rc = keydb_search_issuer (kh, issuer); + rc = keydb_search_subject (kh, issuer); if (rc) { log_debug ("failed to find issuer's certificate: rc=%d\n", rc); @@ -105,7 +104,7 @@ gpgsm_validate_path (KsbaCert cert) } log_debug ("got issuer's certificate:\n"); - gpgsm_dump_cert (issuer_cert); + gpgsm_dump_cert ("issuer", issuer_cert); if (gpgsm_check_cert_sig (issuer_cert, subject_cert) ) { diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 39db2433e..53b8dcd01 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -912,6 +912,7 @@ main ( int argc, char **argv) break; case aVerify: + gpgsm_verify (0); /* if ((rc = verify_signatures( argc, argv ) )) */ /* log_error ("verify signatures failed: %s\n", gpg_errstr(rc) ); */ break; @@ -1023,6 +1024,8 @@ gpgsm_exit (int rc) #warning no update_random_seed_file update_random_seed_file(); #endif +#if 0 + /* at this time a bit annoying */ if (opt.debug & DBG_MEMSTAT_VALUE) { gcry_control( GCRYCTL_DUMP_MEMORY_STATS ); @@ -1030,6 +1033,7 @@ gpgsm_exit (int rc) } if (opt.debug) gcry_control (GCRYCTL_DUMP_SECMEM_STATS ); +#endif gcry_control (GCRYCTL_TERM_SECMEM ); rc = rc? rc : log_get_errorcount(0)? 2 : gpgsm_errors_seen? 1 : 0; exit (rc); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index a4361dc1c..d60eb035a 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -106,10 +106,12 @@ char *gpgsm_get_fingerprint (KsbaCert cert, int algo, char *array, int *r_len); char *gpgsm_get_fingerprint_string (KsbaCert cert, int algo); /*-- certdump.c --*/ -void gpgsm_dump_cert (KsbaCert cert); +void gpgsm_dump_cert (const char *text, KsbaCert cert); /*-- certcheck.c --*/ int gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert); +int gpgsm_check_cms_signature (KsbaCert cert, const char *sigval, + GCRY_MD_HD md, int hash_algo); /*-- certpath.c --*/ @@ -121,6 +123,9 @@ int gpgsm_validate_path (KsbaCert cert); /*-- import.c --*/ int gpgsm_import (int in_fd); +/*-- verify.c --*/ +int gpgsm_verify (int in_fd); + diff --git a/sm/keydb.c b/sm/keydb.c index ef839edfb..6ca7a3393 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -852,5 +852,18 @@ keydb_search_issuer_sn (KEYDB_HANDLE hd, return rc; } +int +keydb_search_subject (KEYDB_HANDLE hd, const char *name) +{ + KEYDB_SEARCH_DESC desc; + int rc; + + memset (&desc, 0, sizeof desc); + desc.mode = KEYDB_SEARCH_MODE_SUBJECT; + desc.u.name = name; + rc = keydb_search (hd, &desc, 1); + return rc; +} + diff --git a/sm/keydb.h b/sm/keydb.h index 71f457fef..7029d0796 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -58,6 +58,7 @@ int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr); int keydb_search_issuer (KEYDB_HANDLE hd, const char *issuer); int keydb_search_issuer_sn (KEYDB_HANDLE hd, const char *issuer, const unsigned char *serial); +int keydb_search_subject (KEYDB_HANDLE hd, const char *issuer); #endif /*GNUPG_KEYDB_H*/ diff --git a/sm/server.c b/sm/server.c index daea4962a..7c4318bb2 100644 --- a/sm/server.c +++ b/sm/server.c @@ -97,14 +97,21 @@ cmd_decrypt (ASSUAN_CONTEXT ctx, char *line) This does a verify operation on the message send to the input-FD. The result is written out using status lines. If an output FD was given, the signed text will be written to that. - - The behavior for detached signatures has not yet been specified. */ + + If the signature is a detached one, the server will inquire about + the signed material and the client must provide it. + */ static int cmd_verify (ASSUAN_CONTEXT ctx, char *line) { - + int fd = assuan_get_input_fd (ctx); - return set_error (Not_Implemented, "fixme"); + if (fd == -1) + return set_error (No_Input, NULL); + + gpgsm_verify (fd); + + return 0; } diff --git a/sm/verify.c b/sm/verify.c new file mode 100644 index 000000000..31e7fcf8f --- /dev/null +++ b/sm/verify.c @@ -0,0 +1,374 @@ +/* verify.c - Verify a messages signature + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "gpgsm.h" +#include "keydb.h" +#include "i18n.h" + +struct reader_cb_parm_s { + FILE *fp; +}; + +/* FIXME: We need to write a generic reader callback which should be able + to detect and convert base-64 */ +static int +reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) +{ + struct reader_cb_parm_s *parm = cb_value; + size_t n; + int c = 0; + + *nread = 0; + if (!buffer) + return -1; /* not supported */ + + for (n=0; n < count; n++) + { + c = getc (parm->fp); + if (c == EOF) + { + if ( ferror (parm->fp) ) + return -1; + if (n) + break; /* return what we have before an EOF */ + return -1; + } + *(byte *)buffer++ = c; + } + + *nread = n; + return 0; +} + +/* fixme: duplicated from import.c */ +static void +store_cert (KsbaCert cert) +{ + KEYDB_HANDLE kh; + int rc; + + kh = keydb_new (0); + if (!kh) + { + log_error (_("failed to allocated keyDB handle\n")); + return; + } + rc = keydb_locate_writable (kh, 0); + if (rc) + log_error (_("error finding writable keyDB: %s\n"), gpgsm_strerror (rc)); + + rc = keydb_insert_cert (kh, cert); + if (rc) + { + log_error (_("error storing certificate: %s\n"), gpgsm_strerror (rc)); + } + keydb_release (kh); +} + + + +static void +print_integer (unsigned char *p) +{ + unsigned long len; + + if (!p) + printf ("none"); + else + { + len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + for (p+=4; len; len--, p++) + printf ("%02X", *p); + } +} + + + + + +int +gpgsm_verify (int in_fd) +{ + int i, rc; + KsbaError err; + KsbaReader reader = NULL; + KsbaWriter writer = NULL; + KsbaCMS cms = NULL; + KsbaStopReason stopreason; + KsbaCert cert; + KEYDB_HANDLE kh; + GCRY_MD_HD data_md = NULL; + struct reader_cb_parm_s rparm; + int signer; + int algo; + int is_detached; + + memset (&rparm, 0, sizeof rparm); + + kh = keydb_new (0); + if (!kh) + { + log_error (_("failed to allocated keyDB handle\n")); + rc = GPGSM_General_Error; + goto leave; + } + + + rparm.fp = fdopen ( dup (in_fd), "rb"); + if (!rparm.fp) + { + log_error ("fdopen() failed: %s\n", strerror (errno)); + rc = seterr (IO_Error); + goto leave; + } + + /* setup a skaba reader which uses a callback function so that we can + strip off a base64 encoding when necessary */ + reader = ksba_reader_new (); + writer = ksba_writer_new (); + if (!reader || !writer) + { + rc = seterr (Out_Of_Core); + goto leave; + } + + rc = ksba_reader_set_cb (reader, reader_cb, &rparm ); + if (rc) + { + ksba_reader_release (reader); + rc = map_ksba_err (rc); + goto leave; + } + + cms = ksba_cms_new (); + if (!cms) + { + rc = seterr (Out_Of_Core); + goto leave; + } + + err = ksba_cms_set_reader_writer (cms, reader, writer); + if (err) + { + log_debug ("ksba_cms_set_reader_writer failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + data_md = gcry_md_open (0, 0); + if (!data_md) + { + rc = map_gcry_err (gcry_errno()); + log_error ("md_open failed: %s\n", gcry_strerror (-1)); + goto leave; + } + + is_detached = 0; + do + { + err = ksba_cms_parse (cms, &stopreason); + if (err) + { + log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + log_debug ("ksba_cms_parse - stop reason %d\n", stopreason); + if (stopreason == KSBA_SR_NEED_HASH) + { + is_detached = 1; + log_debug ("Detached signature\n"); + } + if (stopreason == KSBA_SR_BEGIN_DATA) + log_error ("error: only detached signatuires are supportted\n"); + + if (stopreason == KSBA_SR_NEED_HASH + || stopreason == KSBA_SR_BEGIN_DATA) + { /* We are now able to enable the hash algorithms */ + for (i=0; (algo = ksba_cms_get_digest_algo_list (cms, i)) >= 0; i++) + { + if (algo) + gcry_md_enable (data_md, algo); + } + } + + + } + while (stopreason != KSBA_SR_READY); + + for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++) + { + log_debug ("storing certifcate %d\n", i); + /* Fixme: we should mark the stored certificates as temporary + and put them in a cache first */ + store_cert (cert); + ksba_cert_release (cert); + } + + cert = NULL; + err = 0; + for (signer=0; signer < 1; signer++) + { + char *issuer = NULL; + char *sigval = NULL; + unsigned char *serial; + char *msgdigest = NULL; + size_t msgdigestlen; + + err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial); + if (err) + break; + printf ("signer %d - issuer: `%s'\n", signer, issuer? issuer:"[NONE]"); + printf ("signer %d - serial: ", signer); + print_integer (serial); + putchar ('\n'); + + err = ksba_cms_get_message_digest (cms, signer, + &msgdigest, &msgdigestlen); + if (err) + break; + + algo = ksba_cms_get_digest_algo (cms, signer); + printf ("signer %d - digest algo: %d\n", signer, algo); + if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) ) + { + log_debug ("digest algo %d has not been enabled\n", algo); + goto next_signer; + } + + sigval = ksba_cms_get_sig_val (cms, signer); + printf ("signer %d - signature: `%s'\n", + signer, sigval? sigval: "[ERROR]"); + + /* Find the certificate of the signer */ + keydb_search_reset (kh); + rc = keydb_search_issuer_sn (kh, issuer, serial); + if (rc) + { + log_debug ("failed to find the certificate: %s\n", + gpgsm_strerror(rc)); + goto next_signer; + } + + rc = keydb_get_cert (kh, &cert); + if (rc) + { + log_debug ("failed to get cert: %s\n", gpgsm_strerror (rc)); + goto next_signer; + } + + if (msgdigest) + { /* Signed attributes are available. */ + GCRY_MD_HD md; + unsigned char *s; + + /* check that the message digest in the signed attributes + matches the one we calculated on the data */ + s = gcry_md_read (data_md, algo); + if ( !s || !msgdigestlen + || gcry_md_get_algo_dlen (algo) != msgdigestlen + || !s || memcmp (s, msgdigest, msgdigestlen) ) + { + log_error ("message digest attribute does not " + "match calculated one\n"); + /*goto next_signer; FIXME: only for debugging commented*/ + } + + md = gcry_md_open (algo, 0); + if (!md) + { + log_error ("md_open failed: %s\n", gcry_strerror (-1)); + goto next_signer; + } + ksba_cms_set_hash_function (cms, HASH_FNC, md); + rc = ksba_cms_hash_signed_attrs (cms, signer); + if (rc) + { + log_debug ("hashing signed attrs failed: %s\n", + ksba_strerror (rc)); + gcry_md_close (md); + goto next_signer; + } + rc = gpgsm_check_cms_signature (cert, sigval, md, algo); + gcry_md_close (md); + } + else + { + rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo); + } + + if (rc) + { + log_error ("invalid signature: %s\n", gpgsm_strerror (rc)); + goto next_signer; + } + log_debug ("signature is good - checking certs\n"); + /* FIXME: validate_path */ + rc = gpgsm_validate_path (cert); + if (rc) + { + log_error ("invalid certification path: %s\n", gpgsm_strerror (rc)); + goto next_signer; + } + log_info ("signature is good\n"); + + + next_signer: + rc = 0; + xfree (issuer); + xfree (serial); + xfree (sigval); + xfree (msgdigest); + ksba_cert_release (cert); + cert = NULL; + } + rc = 0; + if (err) + { + log_debug ("ksba error: %s\n", ksba_strerror (err)); + rc = map_ksba_err (rc); + } + + + + leave: + ksba_cms_release (cms); + ksba_reader_release (reader); + keydb_release (kh); + gcry_md_close (data_md); + if (rparm.fp) + fclose (rparm.fp); + return rc; +} + +