diff --git a/sm/ChangeLog b/sm/ChangeLog index 386538b45..6e9dc0acb 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,30 @@ +2002-08-09 Werner Koch + + * gpgsm.c (emergency_cleanup): New. + (main): Initialize the signal handler. + + * sign.c (gpgsm_sign): Reset the hash context for subsequent + signers and release it at the end. + +2002-08-05 Werner Koch + + * server.c (cmd_signer): New command "SIGNER" + (register_commands): Register it. + (cmd_sign): Pass the signer list to gpgsm_sign. + * certlist.c (gpgsm_add_to_certlist): Add SECRET argument, check + for secret key if set and changed all callers. + * sign.c (gpgsm_sign): New argument SIGNERLIST and implemt + multiple signers. + * gpgsm.c (main): Support more than one -u. + + * server.c (cmd_recipient): Return reason code 1 for No_Public_Key + which is actually what gets returned from add_to_certlist. + +2002-07-26 Werner Koch + + * certcheck.c (gpgsm_check_cert_sig): Implement proper cleanup. + (gpgsm_check_cms_signature): Ditto. + 2002-07-22 Werner Koch * keydb.c (keydb_add_resource): Register a lock file. diff --git a/sm/certcheck.c b/sm/certcheck.c index 612a3d2d6..4700fe723 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -138,12 +138,16 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert) if (!n) { log_error ("libksba did not return a proper S-Exp\n"); + gcry_md_close (md); + ksba_free (p); return GNUPG_Bug; } rc = gcry_sexp_sscan ( &s_sig, NULL, p, n); + ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); + gcry_md_close (md); return map_gcry_err (rc); } @@ -152,29 +156,42 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert) if (!n) { log_error ("libksba did not return a proper S-Exp\n"); + gcry_md_close (md); + ksba_free (p); + gcry_sexp_release (s_sig); return GNUPG_Bug; } rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); + gcry_md_close (md); + gcry_sexp_release (s_sig); 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 */ + gcry_md_close (md); + gcry_sexp_release (s_sig); + gcry_sexp_release (s_pkey); return rc; } + /* put hash into the S-Exp s_hash */ if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) BUG (); - + gcry_mpi_release (frame); rc = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_CRYPTO) log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc)); + gcry_md_close (md); + gcry_sexp_release (s_sig); + gcry_sexp_release (s_hash); + gcry_sexp_release (s_pkey); return map_gcry_err (rc); } @@ -208,15 +225,19 @@ gpgsm_check_cms_signature (KsbaCert cert, KsbaConstSexp sigval, if (!n) { log_error ("libksba did not return a proper S-Exp\n"); + ksba_free (p); + gcry_sexp_release (s_sig); return GNUPG_Bug; } if (DBG_X509) log_printhex ("public key: ", p, n); rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc)); + gcry_sexp_release (s_sig); return map_gcry_err (rc); } @@ -224,17 +245,22 @@ gpgsm_check_cms_signature (KsbaCert cert, KsbaConstSexp sigval, rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame); if (rc) { - /* fixme: clean up some things */ + gcry_sexp_release (s_sig); + gcry_sexp_release (s_pkey); return rc; } /* put hash into the S-Exp s_hash */ if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) BUG (); - + gcry_mpi_release (frame); + rc = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_CRYPTO) log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc)); + gcry_sexp_release (s_sig); + gcry_sexp_release (s_hash); + gcry_sexp_release (s_sig); return map_gcry_err (rc); } diff --git a/sm/certlist.c b/sm/certlist.c index ca61eb0d2..8a8570fdf 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -133,10 +133,12 @@ same_subject_issuer (const char *subject, const char *issuer, KsbaCert cert) -/* add a certificate to a list of certificate and make sure that it is - a valid certificate */ +/* Add a certificate to a list of certificate and make sure that it is + a valid certificate. With SECRET set to true a secret key must be + avaibale for the certificate. */ int -gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr) +gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret, + CERTLIST *listaddr) { int rc; KEYDB_SEARCH_DESC desc; @@ -161,7 +163,8 @@ gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr) rc = keydb_get_cert (kh, &cert); if (!rc) { - rc = gpgsm_cert_use_encrypt_p (cert); + rc = secret? gpgsm_cert_use_sign_p (cert) + : gpgsm_cert_use_encrypt_p (cert); if (rc == GNUPG_Wrong_Key_Usage) { /* There might be another certificate with the @@ -206,7 +209,8 @@ gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr) if (!keydb_get_cert (kh, &cert2)) { int tmp = (same_subject_issuer (subject, issuer, cert2) - && (gpgsm_cert_use_encrypt_p (cert2) + && ((secret? gpgsm_cert_use_sign_p (cert2): + gpgsm_cert_use_encrypt_p (cert2)) == GNUPG_Wrong_Key_Usage)); ksba_cert_release (cert2); if (tmp) @@ -218,6 +222,19 @@ gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr) xfree (subject); xfree (issuer); + if (!rc && secret) + { + char *p; + + rc = GNUPG_No_Secret_Key; + p = gpgsm_get_keygrip_hexstring (cert); + if (p) + { + if (!gpgsm_agent_havekey (p)) + rc = 0; + xfree (p); + } + } if (!rc) rc = gpgsm_validate_path (ctrl, cert, NULL); if (!rc) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 9efeca79f..d17f1c66d 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -403,6 +403,7 @@ static char *build_list (const char *text, static void set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ); +static void emergency_cleanup (void); static int check_special_filename (const char *fname); static int open_read (const char *filename); static FILE *open_fwrite (const char *filename); @@ -601,6 +602,7 @@ main ( int argc, char **argv) enum cmd_and_opt_values cmd = 0; struct server_control_s ctrl; CERTLIST recplist = NULL; + CERTLIST signerlist = NULL; /* trap_unaligned ();*/ set_strusage (my_strusage); @@ -626,7 +628,7 @@ main ( int argc, char **argv) may_coredump = disable_core_dumps (); - /* Fixme: init_signals();*/ + gnupg_init_signals (0, emergency_cleanup); create_dotlock (NULL); /* register locking cleanup */ i18n_init(); @@ -922,9 +924,10 @@ main ( int argc, char **argv) case oTextmodeShort: /*fixme:opt.textmode = 2;*/ break; case oTextmode: /*fixme:opt.textmode=1;*/ break; - case oUser: /* store the local users */ - opt.local_user = pargs.r.ret_str; - add_to_strlist ( &locusr, pargs.r.ret_str); + case oUser: /* store the local users, the first one is the default */ + if (!opt.local_user) + opt.local_user = pargs.r.ret_str; + add_to_strlist (&locusr, pargs.r.ret_str); break; case oNoSecmemWarn: @@ -1059,15 +1062,39 @@ main ( int argc, char **argv) keydb_add_resource (sl->d, 0, 0); FREE_STRLIST(nrings); + + for (sl = locusr; sl; sl = sl->next) + { + int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist); + if (rc) + { + log_error (_("can't sign using `%s': %s\n"), + sl->d, gnupg_strerror (rc)); + gpgsm_status2 (&ctrl, STATUS_INV_RECP, + rc == -1? "1": + rc == GNUPG_No_Public_Key? "1": + rc == GNUPG_Ambiguous_Name? "2": + rc == GNUPG_Wrong_Key_Usage? "3": + rc == GNUPG_Certificate_Revoked? "4": + rc == GNUPG_Certificate_Expired? "5": + rc == GNUPG_No_CRL_Known? "6": + rc == GNUPG_CRL_Too_Old? "7": + rc == GNUPG_No_Policy_Match? "8": + rc == GNUPG_No_Secret_Key? "9": + "0", + sl->d, NULL); + } + } for (sl = remusr; sl; sl = sl->next) { - int rc = gpgsm_add_to_certlist (&ctrl, sl->d, &recplist); + int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 0, &recplist); if (rc) { log_error (_("can't encrypt to `%s': %s\n"), sl->d, gnupg_strerror (rc)); gpgsm_status2 (&ctrl, STATUS_INV_RECP, rc == -1? "1": + rc == GNUPG_No_Public_Key? "1": rc == GNUPG_Ambiguous_Name? "2": rc == GNUPG_Wrong_Key_Usage? "3": rc == GNUPG_Certificate_Revoked? "4": @@ -1109,69 +1136,25 @@ main ( int argc, char **argv) break; case aSign: /* sign the given file */ - /* FIXME: W we don't handle --output yet. We should also allow + /* FIXME: We don't handle --output yet. We should also allow to concatenate multiple files for signing because that is what gpg does.*/ if (!argc) - gpgsm_sign (&ctrl, 0, detached_sig, stdout); /* create from stdin */ + gpgsm_sign (&ctrl, signerlist, + 0, detached_sig, stdout); /* create from stdin */ else if (argc == 1) - gpgsm_sign (&ctrl, open_read (*argv), - detached_sig, stdout); /* from file */ + gpgsm_sign (&ctrl, signerlist, + open_read (*argv), detached_sig, stdout); /* from file */ else wrong_args (_("--sign [datafile]")); break; -#if 0 - sl = NULL; - if (detached_sig) - { /* sign all files */ - for (; argc; argc--, argv++ ) - add_to_strlist ( &sl, *argv ); - } - else - { - if (argc > 1 ) - wrong_args (_("--sign [filename]")); - if (argc) - { - sl = xcalloc (1, sizeof *sl + strlen(fname)); - strcpy(sl->d, fname); - } - } - if ( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) ) - log_error ("signing failed: %s\n", gpg_errstr(rc) ); - free_strlist(sl); -#endif - break; case aSignEncr: /* sign and encrypt the given file */ log_error ("this command has not yet been implemented\n"); -#if 0 - if (argc > 1) - wrong_args(_("--sign --encrypt [filename]")); - if (argc) - { - sl = xcalloc( 1, sizeof *sl + strlen(fname)); - strcpy(sl->d, fname); - } - else - sl = NULL; - - if ( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) ) - log_error ("%s: sign+encrypt failed: %s\n", - print_fname_stdin(fname), gpg_errstr(rc) ); - free_strlist(sl); -#endif break; case aClearsign: /* make a clearsig */ log_error ("this command has not yet been implemented\n"); -#if 0 - if (argc > 1) - wrong_args (_("--clearsign [filename]")); - if ( (rc = clearsign_file(fname, locusr, NULL)) ) - log_error ("%s: clearsign failed: %s\n", - print_fname_stdin(fname), gpg_errstr(rc) ); -#endif break; case aVerify: @@ -1199,8 +1182,6 @@ main ( int argc, char **argv) case aVerifyFiles: log_error ("this command has not yet been implemented\n"); -/* if ((rc = verify_files( argc, argv ))) */ -/* log_error ("verify files failed: %s\n", gpg_errstr(rc) ); */ break; case aDecrypt: @@ -1244,18 +1225,6 @@ main ( int argc, char **argv) case aKeygen: /* generate a key */ log_error ("this function is not yet available from the commandline\n"); -/* if (opt.batch) */ -/* { */ -/* if (argc > 1) */ -/* wrong_args("--gen-key [parameterfile]"); */ -/* generate_keypair (argc? *argv : NULL); */ -/* } */ -/* else */ -/* { */ -/* if (argc) */ -/* wrong_args ("--gen-key"); */ -/* generate_keypair(NULL); */ -/* } */ break; case aImport: @@ -1279,16 +1248,6 @@ main ( int argc, char **argv) case aSendKeys: case aRecvKeys: log_error ("this command has not yet been implemented\n"); -/* sl = NULL; */ -/* for ( ; argc; argc--, argv++ ) */ -/* add_to_strlist (&sl, *argv); */ -/* if ( cmd == aSendKeys ) */ -/* ldap_export (sl); */ -/* else if (cmd == aRecvKeys ) */ -/* ldap_import (sl); */ -/* else */ -/* export_pubkeys (sl, (cmd == aExport)); */ -/* free_strlist (sl); */ break; @@ -1305,34 +1264,26 @@ main ( int argc, char **argv) default: - log_error ("invalid command\n"); -#if 0 - if (argc > 1) - wrong_args(_("[filename]")); - /* Issue some output for the unix newbie */ - if ( !fname && !opt.outfile && isatty( fileno(stdin) ) - && isatty (fileno(stdout) ) && isatty (fileno(stderr) ) ) - log_info (_("Go ahead and type your message ...\n")); - - if ( !(a = iobuf_open(fname)) ) - log_error (_("can't open `%s'\n"), print_fname_stdin(fname)); - else - { - if (!opt.no_armor) - iobuf_close(a); - } -#endif + log_error ("invalid command (there is no implicit command)\n"); break; } /* cleanup */ gpgsm_release_certlist (recplist); + gpgsm_release_certlist (signerlist); FREE_STRLIST(remusr); FREE_STRLIST(locusr); gpgsm_exit(0); return 8; /*NEVER REACHED*/ } +/* Note: This function is used by signal handlers!. */ +static void +emergency_cleanup (void) +{ + gcry_control (GCRYCTL_TERM_SECMEM ); +} + void gpgsm_exit (int rc) @@ -1351,7 +1302,7 @@ gpgsm_exit (int rc) if (opt.debug) gcry_control (GCRYCTL_DUMP_SECMEM_STATS ); #endif - gcry_control (GCRYCTL_TERM_SECMEM ); + emergency_cleanup (); 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 0d5294b44..3e5205980 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -197,7 +197,8 @@ int gpgsm_cert_use_encrypt_p (KsbaCert cert); int gpgsm_cert_use_verify_p (KsbaCert cert); int gpgsm_cert_use_decrypt_p (KsbaCert cert); int gpgsm_cert_use_cert_p (KsbaCert cert); -int gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr); +int gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret, + CERTLIST *listaddr); void gpgsm_release_certlist (CERTLIST list); int gpgsm_find_cert (const char *name, KsbaCert *r_cert); @@ -218,7 +219,8 @@ int gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp); /*-- sign.c --*/ int gpgsm_get_default_cert (KsbaCert *r_cert); -int gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp); +int gpgsm_sign (CTRL ctrl, CERTLIST signerlist, + int data_fd, int detached, FILE *out_fp); /*-- encrypt.c --*/ int gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int in_fd, FILE *out_fp); diff --git a/sm/server.c b/sm/server.c index 0e30ae873..71b6194c7 100644 --- a/sm/server.c +++ b/sm/server.c @@ -43,6 +43,7 @@ struct server_local_s { int list_internal; int list_external; CERTLIST recplist; + CERTLIST signerlist; }; @@ -182,7 +183,9 @@ reset_notify (ASSUAN_CONTEXT ctx) CTRL ctrl = assuan_get_pointer (ctx); gpgsm_release_certlist (ctrl->server_local->recplist); + gpgsm_release_certlist (ctrl->server_local->signerlist); ctrl->server_local->recplist = NULL; + ctrl->server_local->signerlist = NULL; close_message_fd (ctrl); assuan_close_input_fd (ctx); assuan_close_output_fd (ctx); @@ -239,10 +242,11 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line) CTRL ctrl = assuan_get_pointer (ctx); int rc; - rc = gpgsm_add_to_certlist (ctrl, line, &ctrl->server_local->recplist); + rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist); if (rc) gpgsm_status2 (ctrl, STATUS_INV_RECP, rc == -1? "1": + rc == GNUPG_No_Public_Key? "1": rc == GNUPG_Ambiguous_Name? "2": rc == GNUPG_Wrong_Key_Usage? "3": rc == GNUPG_Certificate_Revoked? "4": @@ -256,6 +260,47 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line) return map_to_assuan_status (rc); } +/* SIGNER + + Set the signer's keys for the signature creation. should + be the internal representation of the key; the server may accept any + other way of specification [we will support this]. If this is a + valid and usable signing key the server does respond with OK, + otherwise it returns an ERR with the reason why the key can't be + used, the signing will then not be done for this key. If the policy + is not to sign at all if not all signer keys are valid, the client + has to take care of this. All SIGNER commands are cumulative until + a RESET but they are *not* reset by an SIGN command becuase it can + be expected that set of signers are used for more than one sign + operation. + + Note that this command returns an INV_RECP status which is a bit + strange, but they are very similar. */ +static int +cmd_signer (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc; + + rc = gpgsm_add_to_certlist (ctrl, line, 1, &ctrl->server_local->signerlist); + if (rc) + gpgsm_status2 (ctrl, STATUS_INV_RECP, + rc == -1? "1": + rc == GNUPG_No_Public_Key? "1": + rc == GNUPG_Ambiguous_Name? "2": + rc == GNUPG_Wrong_Key_Usage? "3": + rc == GNUPG_Certificate_Revoked? "4": + rc == GNUPG_Certificate_Expired? "5": + rc == GNUPG_No_CRL_Known? "6": + rc == GNUPG_CRL_Too_Old? "7": + rc == GNUPG_No_Policy_Match? "8": + rc == GNUPG_No_Secret_Key? "9": + "0", + line, NULL); + + return map_to_assuan_status (rc); +} + /* ENCRYPT @@ -407,7 +452,9 @@ cmd_sign (ASSUAN_CONTEXT ctx, char *line) out_fp = fdopen ( dup(out_fd), "w"); if (!out_fp) return set_error (General_Error, "fdopen() failed"); - rc = gpgsm_sign (assuan_get_pointer (ctx), inp_fd, detached, out_fp); + + rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist, + inp_fd, detached, out_fp); fclose (out_fp); /* close and reset the fd */ @@ -676,6 +723,7 @@ register_commands (ASSUAN_CONTEXT ctx) int (*handler)(ASSUAN_CONTEXT, char *line); } table[] = { { "RECIPIENT", 0, cmd_recipient }, + { "SIGNER", 0, cmd_signer }, { "ENCRYPT", 0, cmd_encrypt }, { "DECRYPT", 0, cmd_decrypt }, { "VERIFY", 0, cmd_verify }, @@ -776,6 +824,8 @@ gpgsm_server (void) gpgsm_release_certlist (ctrl.server_local->recplist); ctrl.server_local->recplist = NULL; + gpgsm_release_certlist (ctrl.server_local->signerlist); + ctrl.server_local->signerlist = NULL; assuan_deinit_server (ctx); } diff --git a/sm/sign.c b/sm/sign.c index 4cce9f926..061dfeebc 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -1,5 +1,5 @@ /* sign.c - Sign a message - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -228,8 +228,6 @@ get_default_signer (void) return cert; } - - /* Depending on the options in CTRL add the certificate CERT as well as other certificate up in the chain to the Root-CA to the CMS object. */ @@ -290,10 +288,11 @@ add_certificate_list (CTRL ctrl, KsbaCMS cms, KsbaCert cert) Sign the data received on DATA-FD in embedded mode or in detached mode when DETACHED is true. Write the signature to OUT_FP. The - key used to sign is the default one - we will extend the function - to take a list of fingerprints in the future. */ + keys used to sign are taken from SIGNERLIST or the default one will + be used if the value of this argument is NULL. */ int -gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) +gpgsm_sign (CTRL ctrl, CERTLIST signerlist, + int data_fd, int detached, FILE *out_fp) { int i, rc; KsbaError err; @@ -301,13 +300,14 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) KsbaWriter writer; KsbaCMS cms = NULL; KsbaStopReason stopreason; - KsbaCert cert = NULL; KEYDB_HANDLE kh = NULL; GCRY_MD_HD data_md = NULL; int signer; const char *algoid; int algo; time_t signed_at; + CERTLIST cl; + int release_signerlist = 0; kh = keydb_new (0); if (!kh) @@ -353,47 +353,60 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) goto leave; } - - /* gather certificates of signers and store in theCMS object */ - /* fixme: process a list of fingerprints and store the certificate of - each given fingerprint */ - cert = get_default_signer (); - if (!cert) + /* If no list of signers is given, use a default one. */ + if (!signerlist) { - log_error ("no default signer found\n"); - rc = seterr (General_Error); - goto leave; + KsbaCert cert = get_default_signer (); + if (!cert) + { + log_error ("no default signer found\n"); + rc = seterr (General_Error); + goto leave; + } + signerlist = xtrycalloc (1, sizeof *signerlist); + if (!signerlist) + { + rc = GNUPG_Out_Of_Core; + ksba_cert_release (cert); + goto leave; + } + signerlist->cert = cert; + release_signerlist = 1; } - rc = gpgsm_cert_use_sign_p (cert); - if (rc) - goto leave; - err = ksba_cms_add_signer (cms, cert); - if (err) - { - log_error ("ksba_cms_add_signer failed: %s\n", ksba_strerror (err)); - rc = map_ksba_err (err); - goto leave; - } - rc = add_certificate_list (ctrl, cms, cert); - if (rc) - { - log_error ("failed to store list of certificates: %s\n", - gnupg_strerror(rc)); - goto leave; - } - ksba_cert_release (cert); cert = NULL; + /* Gather certificates of signers and store them in the CMS object. */ + for (cl=signerlist; cl; cl = cl->next) + { + rc = gpgsm_cert_use_sign_p (cl->cert); + if (rc) + goto leave; + + err = ksba_cms_add_signer (cms, cl->cert); + if (err) + { + log_error ("ksba_cms_add_signer failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + rc = add_certificate_list (ctrl, cms, cl->cert); + if (rc) + { + log_error ("failed to store list of certificates: %s\n", + gnupg_strerror(rc)); + goto leave; + } + /* Set the hash algorithm we are going to use */ + err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/); + if (err) + { + log_debug ("ksba_cms_add_digest_algo failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + } - /* Set the hash algorithm we are going to use */ - err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/); - if (err) - { - log_debug ("ksba_cms_add_digest_algo failed: %s\n", ksba_strerror (err)); - rc = map_ksba_err (err); - goto leave; - } - /* Prepare hashing (actually we are figuring out what we have set above)*/ data_md = gcry_md_open (0, 0); if (!data_md) @@ -417,7 +430,6 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) gcry_md_enable (data_md, algo); } - signer = 0; if (detached) { /* we hash the data right now so that we can store the message digest. ksba_cms_build() takes this as an flag that detached @@ -437,24 +449,30 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) rc = GNUPG_Bug; goto leave; } - err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); - if (err) + for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { - log_error ("ksba_cms_set_message_digest failed: %s\n", - ksba_strerror (err)); - rc = map_ksba_err (err); - goto leave; + err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); + if (err) + { + log_error ("ksba_cms_set_message_digest failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } } } signed_at = gnupg_get_time (); - err = ksba_cms_set_signing_time (cms, signer, signed_at); - if (err) + for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { - log_error ("ksba_cms_set_signing_time failed: %s\n", - ksba_strerror (err)); - rc = map_ksba_err (err); - goto leave; + err = ksba_cms_set_signing_time (cms, signer, signed_at); + if (err) + { + log_error ("ksba_cms_set_signing_time failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } } do @@ -473,10 +491,10 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) size_t digest_len; assert (!detached); - /* Fixme do this for all signers and get the algo to use from - the signer's certificate - does not make mich sense, bu we - should do this consistent as we have already done it above. - Code is mostly duplicated above. */ + /* Fixme: get the algo to use from the signer's certificate + - does not make much sense, but we should do this + consistent as we have already done it above. Code is + mostly duplicated above. */ algo = GCRY_MD_SHA1; rc = hash_and_copy_data (data_fd, data_md, writer); @@ -490,13 +508,17 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) rc = GNUPG_Bug; goto leave; } - err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); - if (err) + for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { - log_error ("ksba_cms_set_message_digest failed: %s\n", - ksba_strerror (err)); - rc = map_ksba_err (err); - goto leave; + err = ksba_cms_set_message_digest (cms, signer, + digest, digest_len); + if (err) + { + log_error ("ksba_cms_set_message_digest failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } } } else if (stopreason == KSBA_SR_NEED_SIG) @@ -504,7 +526,6 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) GCRY_MD_HD md; algo = GCRY_MD_SHA1; - signer = 0; md = gcry_md_open (algo, 0); if (DBG_HASHING) gcry_md_start_debug (md, "sign.attr"); @@ -515,70 +536,67 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) goto leave; } 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 leave; - } - - { /* This is all an temporary hack */ - char *sigval; - - ksba_cert_release (cert); - cert = get_default_signer (); - if (!cert) - { - log_error ("oops - failed to get cert again\n"); - rc = seterr (General_Error); - goto leave; - } - - sigval = NULL; - rc = gpgsm_create_cms_signature (cert, md, algo, &sigval); - if (rc) - goto leave; - - err = ksba_cms_set_sig_val (cms, signer, sigval); - xfree (sigval); - if (err) - { - log_error ("failed to store the signature: %s\n", - ksba_strerror (err)); - rc = map_ksba_err (err); - goto leave; - } - - /* And write a status message */ + for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { + char *sigval = NULL; char *buf, *fpr; - - fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); + + if (signer) + gcry_md_reset (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 leave; + } + + rc = gpgsm_create_cms_signature (cl->cert, md, algo, &sigval); + if (rc) + { + gcry_md_close (md); + goto leave; + } + + err = ksba_cms_set_sig_val (cms, signer, sigval); + xfree (sigval); + if (err) + { + log_error ("failed to store the signature: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + gcry_md_close (md); + goto leave; + } + + /* write a status message */ + fpr = gpgsm_get_fingerprint_hexstring (cl->cert, GCRY_MD_SHA1); if (!fpr) { rc = seterr (Out_Of_Core); + gcry_md_close (md); goto leave; } rc = asprintf (&buf, "%c %d %d 00 %lu %s", - detached? 'D':'S', - GCRY_PK_RSA, /* FIXME: get pk algo from cert */ - algo, - (ulong)signed_at, - fpr); + detached? 'D':'S', + GCRY_PK_RSA, /* FIXME: get pk algo from cert */ + algo, + (ulong)signed_at, + fpr); xfree (fpr); if (rc < 0) { rc = seterr (Out_Of_Core); + gcry_md_close (md); goto leave; } rc = 0; - gpgsm_status (ctrl, STATUS_SIG_CREATED, buf ); + gpgsm_status (ctrl, STATUS_SIG_CREATED, buf); free (buf); /* yes, we must use the regular free() here */ } + gcry_md_close (md); - } } } while (stopreason != KSBA_SR_READY); @@ -594,7 +612,8 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) leave: - ksba_cert_release (cert); + if (release_signerlist) + gpgsm_release_certlist (signerlist); ksba_cms_release (cms); gpgsm_destroy_writer (b64writer); keydb_release (kh); diff --git a/sm/verify.c b/sm/verify.c index f4af56885..3e44897e8 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -1,5 +1,5 @@ /* verify.c - Verify a messages signature - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -248,7 +248,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) cert = NULL; err = 0; - for (signer=0; signer < 1; signer++) + for (signer=0; ; signer++) { char *issuer = NULL; KsbaSexp sigval = NULL; @@ -265,7 +265,11 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) break; } if (err) - break; + { + if (signer && err == -1) + err = 0; + break; + } if (DBG_X509) { log_debug ("signer %d - issuer: `%s'\n",