* gpgsm.c (emergency_cleanup): New.
authorWerner Koch <wk@gnupg.org>
Fri, 9 Aug 2002 18:12:22 +0000 (18:12 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 9 Aug 2002 18:12:22 +0000 (18:12 +0000)
(main): Initialize the signal handler.

* sign.c (gpgsm_sign): Reset the hash context for subsequent
signers and release it at the end.

sm/ChangeLog
sm/certcheck.c
sm/certlist.c
sm/gpgsm.c
sm/gpgsm.h
sm/server.c
sm/sign.c
sm/verify.c

index 386538b..6e9dc0a 100644 (file)
@@ -1,3 +1,30 @@
+2002-08-09  Werner Koch  <wk@gnupg.org>
+
+       * 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  <wk@gnupg.org>
+
+       * 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  <wk@gnupg.org>
+
+       * certcheck.c (gpgsm_check_cert_sig): Implement proper cleanup.
+       (gpgsm_check_cms_signature): Ditto.
+
 2002-07-22  Werner Koch  <wk@gnupg.org>
 
        * keydb.c (keydb_add_resource): Register a lock file.
index 612a3d2..4700fe7 100644 (file)
@@ -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);
 }
 
index ca61eb0..8a8570f 100644 (file)
@@ -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)
index 9efeca7..d17f1c6 100644 (file)
@@ -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);
 }
index 0d5294b..3e52059 100644 (file)
@@ -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);
index 0e30ae8..71b6194 100644 (file)
@@ -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 <userID>
+
+  Set the signer's keys for the signature creation.  <userID> 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);
 }
index 4cce9f9..061dfee 100644 (file)
--- 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;
 
-  
-  /* 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)
+  /* Gather certificates of signers and store them in the CMS object. */
+  for (cl=signerlist; cl; cl = cl->next)
     {
-      log_debug ("ksba_cms_add_digest_algo failed: %s\n", ksba_strerror (err));
-      rc = map_ksba_err (err);
-      goto leave;
+      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;
+        }
     }
-
+  
   /* 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); 
index f4af568..3e44897 100644 (file)
@@ -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",