Base code for gpgsm --verify does work

This commit is contained in:
Werner Koch 2001-11-16 17:56:23 +00:00
parent 90d060c199
commit 0f26760d9f
13 changed files with 562 additions and 88 deletions

View File

@ -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;

View File

@ -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; */

View File

@ -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 \

View File

@ -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) )
{

View File

@ -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)

View File

@ -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");
}

View File

@ -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) )
{

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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*/

View File

@ -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;
}

374
sm/verify.c Normal file
View File

@ -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 <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>
#include <gcrypt.h>
#include <ksba.h>
#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;
}