Trace the use of GPG_ERR_INV_ENGINE.
[gpgme.git] / src / sign.c
index 03007bd..67280e9 100644 (file)
@@ -3,17 +3,17 @@
    Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
 
    This file is part of GPGME.
+
    GPGME is free software; you can redistribute it and/or modify it
    under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; either version 2.1 of
    the License, or (at your option) any later version.
-   
+
    GPGME 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
    Lesser General Public License for more details.
-   
+
    You should have received a copy of the GNU Lesser General Public
    License along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
@@ -46,6 +46,11 @@ typedef struct
 
   /* Likewise for signature information.  */
   gpgme_new_signature_t *last_sig_p;
+
+  /* Flags used while processing the status lines.  */
+  unsigned int ignore_inv_recp:1;
+  unsigned int inv_sgnr_seen:1;
+  unsigned int sig_created_seen:1;
 } *op_data_t;
 
 
@@ -144,7 +149,7 @@ parse_sig_created (char *args, gpgme_new_signature_t *sigp)
 
   sig = malloc (sizeof (*sig));
   if (!sig)
-    return gpg_error_from_errno (errno);
+    return gpg_error_from_syserror ();
 
   sig->next = NULL;
   switch (*args)
@@ -164,23 +169,23 @@ parse_sig_created (char *args, gpgme_new_signature_t *sigp)
     default:
       /* The backend engine is not behaving.  */
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
 
   args++;
   if (*args != ' ')
     {
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
 
-  errno = 0;
+  gpg_err_set_errno (0);
   sig->pubkey_algo = strtol (args, &tail, 0);
   if (errno || args == tail || *tail != ' ')
     {
       /* The crypto backend does not behave.  */
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
   args = tail;
 
@@ -189,7 +194,7 @@ parse_sig_created (char *args, gpgme_new_signature_t *sigp)
     {
       /* The crypto backend does not behave.  */
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
   args = tail;
 
@@ -200,7 +205,7 @@ parse_sig_created (char *args, gpgme_new_signature_t *sigp)
     {
       /* The crypto backend does not behave.  */
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
   args = tail;
 
@@ -209,7 +214,7 @@ parse_sig_created (char *args, gpgme_new_signature_t *sigp)
     {
       /* The crypto backend does not behave.  */
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
   args = tail;
   while (*args == ' ')
@@ -219,7 +224,7 @@ parse_sig_created (char *args, gpgme_new_signature_t *sigp)
     {
       /* The crypto backend does not behave.  */
       free (sig);
-      return gpg_error (GPG_ERR_INV_ENGINE);
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
     }
 
   tail = strchr (args, ' ');
@@ -258,6 +263,7 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
   switch (code)
     {
     case GPGME_STATUS_SIG_CREATED:
+      opd->sig_created_seen = 1;
       err = parse_sig_created (args, opd->last_sig_p);
       if (err)
        return err;
@@ -266,6 +272,12 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
       break;
 
     case GPGME_STATUS_INV_RECP:
+      if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
+        break;
+      /* FALLTROUGH */
+    case GPGME_STATUS_INV_SGNR:
+      if (code == GPGME_STATUS_INV_SGNR)
+        opd->inv_sgnr_seen = 1;
       err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
       if (err)
        return err;
@@ -274,8 +286,14 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
       break;
 
     case GPGME_STATUS_EOF:
+      /* The UI server does not send information about the created
+         signature.  This is irrelevant for this protocol and thus we
+         should not check for that.  */
       if (opd->result.invalid_signers)
-       return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+       err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+      else if (!opd->sig_created_seen
+               && ctx->protocol != GPGME_PROTOCOL_UISERVER)
+       err = gpg_error (GPG_ERR_GENERAL);
       break;
 
     default:
@@ -297,8 +315,8 @@ sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
 }
 
 
-gpgme_error_t
-_gpgme_op_sign_init_result (gpgme_ctx_t ctx)
+static gpgme_error_t
+sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
 {
   gpgme_error_t err;
   void *hook;
@@ -311,9 +329,18 @@ _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
     return err;
   opd->last_signer_p = &opd->result.invalid_signers;
   opd->last_sig_p = &opd->result.signatures;
+  opd->ignore_inv_recp = !!ignore_inv_recp;
+  opd->inv_sgnr_seen = 0;
+  opd->sig_created_seen = 0;
   return 0;
 }
 
+gpgme_error_t
+_gpgme_op_sign_init_result (gpgme_ctx_t ctx)
+{
+  return sign_init_result (ctx, 0);
+}
+
 
 static gpgme_error_t
 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
@@ -325,7 +352,10 @@ sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
   if (err)
     return err;
 
-  err = _gpgme_op_sign_init_result (ctx);
+  /* If we are using the CMS protocol, we ignore the INV_RECP status
+     code if a newer GPGSM is in use.  GPGMS does not support combined
+     sign+encrypt and thus this can't harm.  */
+  err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
   if (err)
     return err;
 
@@ -360,9 +390,15 @@ gpgme_error_t
 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
                     gpgme_sig_mode_t mode)
 {
+  gpg_error_t err;
   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
              "plain=%p, sig=%p, mode=%i", plain, sig, mode);
-  return TRACE_ERR (sign_start (ctx, 0, plain, sig, mode));
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = sign_start (ctx, 0, plain, sig, mode);
+  return TRACE_ERR (err);
 }
 
 
@@ -373,8 +409,12 @@ gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
 {
   gpgme_error_t err;
 
-  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
              "plain=%p, sig=%p, mode=%i", plain, sig, mode);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
   err = sign_start (ctx, 1, plain, sig, mode);
   if (!err)
     err = _gpgme_wait_one (ctx);