Add ftp and git URLs to AUTHORS.
[gpgme.git] / src / verify.c
index ef1ccd6..37b2bd4 100644 (file)
@@ -3,17 +3,17 @@
    Copyright (C) 2001, 2002, 2003, 2004, 2005 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
@@ -28,6 +28,7 @@
 #include <assert.h>
 
 #include "gpgme.h"
+#include "debug.h"
 #include "util.h"
 #include "context.h"
 #include "ops.h"
@@ -82,12 +83,73 @@ gpgme_op_verify_result (gpgme_ctx_t ctx)
   void *hook;
   op_data_t opd;
   gpgme_error_t err;
+  gpgme_signature_t sig;
 
+  TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
   opd = hook;
   if (err || !opd)
-    return NULL;
+    {
+      TRACE_SUC0 ("result=(null)");
+      return NULL;
+    }
+
+  /* It is possible that we saw a new signature only followed by an
+     ERROR line for that.  In particular a missing X.509 key triggers
+     this.  In this case it is surprising that the summary field has
+     not been updated.  We fix it here by explicitly looking for this
+     case.  The real fix would be to have GPGME emit ERRSIG.  */
+  for (sig = opd->result.signatures; sig; sig = sig->next)
+    {
+      if (!sig->summary)
+        {
+          switch (gpg_err_code (sig->status))
+            {
+            case GPG_ERR_KEY_EXPIRED:
+              sig->summary |= GPGME_SIGSUM_KEY_EXPIRED;
+              break;
+
+            case GPG_ERR_NO_PUBKEY:
+              sig->summary |= GPGME_SIGSUM_KEY_MISSING;
+              break;
+
+            default:
+              break;
+            }
+        }
+    }
 
+  /* Now for some tracing stuff. */
+  if (_gpgme_debug_trace ())
+    {
+      int i;
+
+      for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++)
+       {
+         TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
+                     i, sig->fpr, sig->summary, gpg_strerror (sig->status));
+         TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
+                     i, sig->timestamp, sig->exp_timestamp,
+                     sig->wrong_key_usage ? "wrong key usage" : "",
+                     sig->pka_trust == 1 ? "pka bad"
+                     : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
+                     sig->chain_model ? "chain model" : "");
+         TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
+                     i, sig->validity, gpg_strerror (sig->validity_reason),
+                     gpgme_pubkey_algo_name (sig->pubkey_algo),
+                     gpgme_hash_algo_name (sig->hash_algo));
+         if (sig->pka_address)
+           {
+             TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
+           }
+         if (sig->notations)
+           {
+             TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
+           }
+       }
+    }
+
+  TRACE_SUC1 ("result=%p", &opd->result);
   return &opd->result;
 }
 
@@ -97,7 +159,7 @@ static void
 calc_sig_summary (gpgme_signature_t sig)
 {
   unsigned long sum = 0;
-  
+
   /* Calculate the red/green flag.  */
   if (sig->validity == GPGME_VALIDITY_FULL
       || sig->validity == GPGME_VALIDITY_ULTIMATE)
@@ -141,7 +203,7 @@ calc_sig_summary (gpgme_signature_t sig)
       sum |= GPGME_SIGSUM_SYS_ERROR;
       break;
     }
-  
+
   /* Now look at the certain reason codes.  */
   switch (gpg_err_code (sig->validity_reason))
     {
@@ -149,7 +211,7 @@ calc_sig_summary (gpgme_signature_t sig)
       if (sig->validity == GPGME_VALIDITY_UNKNOWN)
         sum |= GPGME_SIGSUM_CRL_TOO_OLD;
       break;
-        
+
     case GPG_ERR_CERT_REVOKED:
       sum |= GPGME_SIGSUM_KEY_REVOKED;
       break;
@@ -161,15 +223,15 @@ calc_sig_summary (gpgme_signature_t sig)
   /* Check other flags. */
   if (sig->wrong_key_usage)
     sum |= GPGME_SIGSUM_BAD_POLICY;
-  
+
   /* Set the valid flag when the signature is unquestionable
-     valid. */
+     valid.  (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
   if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
     sum |= GPGME_SIGSUM_VALID;
-  
+
   sig->summary = sum;
 }
-  
+
 
 static gpgme_error_t
 prepare_new_sig (op_data_t opd)
@@ -189,7 +251,7 @@ prepare_new_sig (op_data_t opd)
     {
       sig = calloc (1, sizeof (*sig));
       if (!sig)
-        return gpg_error_from_errno (errno);
+        return gpg_error_from_syserror ();
       if (!opd->result.signatures)
         opd->result.signatures = sig;
       if (opd->current_sig)
@@ -202,7 +264,8 @@ prepare_new_sig (op_data_t opd)
 }
 
 static gpgme_error_t
-parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
+parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
+               gpgme_protocol_t protocol)
 {
   gpgme_signature_t sig;
   char *end = strchr (args, ' ');
@@ -255,18 +318,18 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
       /* Parse the pubkey algo.  */
       if (!end)
        goto parse_err_sig_fail;
-      errno = 0;
-      sig->pubkey_algo = strtol (end, &tail, 0);
+      gpg_err_set_errno (0);
+      sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
       if (errno || end == tail || *tail != ' ')
        goto parse_err_sig_fail;
       end = tail;
       while (*end == ' ')
        end++;
-     
+
       /* Parse the hash algo.  */
       if (!*end)
        goto parse_err_sig_fail;
-      errno = 0;
+      gpg_err_set_errno (0);
       sig->hash_algo = strtol (end, &tail, 0);
       if (errno || end == tail || *tail != ' ')
        goto parse_err_sig_fail;
@@ -284,11 +347,11 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
       /* Parse the timestamp.  */
       sig->timestamp = _gpgme_parse_timestamp (end, &tail);
       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
-       return gpg_error (GPG_ERR_INV_ENGINE);
+       return trace_gpg_error (GPG_ERR_INV_ENGINE);
       end = tail;
       while (*end == ' ')
        end++;
-      
+
       /* Parse the return code.  */
       if (end[0] && (!end[1] || end[1] == ' '))
        {
@@ -297,11 +360,11 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
            case '4':
              sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
              break;
-             
+
            case '9':
              sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
              break;
-             
+
            default:
              sig->status = gpg_error (GPG_ERR_GENERAL);
            }
@@ -310,12 +373,12 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
        goto parse_err_sig_fail;
 
       goto parse_err_sig_ok;
-      
+
     parse_err_sig_fail:
       sig->status = gpg_error (GPG_ERR_GENERAL);
     parse_err_sig_ok:
       break;
-      
+
     default:
       return gpg_error (GPG_ERR_GENERAL);
     }
@@ -324,14 +387,14 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
     {
       sig->fpr = strdup (args);
       if (!sig->fpr)
-       return gpg_error_from_errno (errno);
+       return gpg_error_from_syserror ();
     }
   return 0;
 }
 
 
 static gpgme_error_t
-parse_valid_sig (gpgme_signature_t sig, char *args)
+parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
 {
   char *end = strchr (args, ' ');
   if (end)
@@ -348,7 +411,7 @@ parse_valid_sig (gpgme_signature_t sig, char *args)
     free (sig->fpr);
   sig->fpr = strdup (args);
   if (!sig->fpr)
-    return gpg_error_from_errno (errno);
+    return gpg_error_from_syserror ();
 
   /* Skip the creation date.  */
   end = strchr (end, ' ');
@@ -358,12 +421,12 @@ parse_valid_sig (gpgme_signature_t sig, char *args)
 
       sig->timestamp = _gpgme_parse_timestamp (end, &tail);
       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
-       return gpg_error (GPG_ERR_INV_ENGINE);
+       return trace_gpg_error (GPG_ERR_INV_ENGINE);
       end = tail;
-     
+
       sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
       if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
-       return gpg_error (GPG_ERR_INV_ENGINE);
+       return trace_gpg_error (GPG_ERR_INV_ENGINE);
       end = tail;
 
       while (*end == ' ')
@@ -380,10 +443,11 @@ parse_valid_sig (gpgme_signature_t sig, char *args)
          if (end)
            {
              /* Parse the pubkey algo.  */
-             errno = 0;
-             sig->pubkey_algo = strtol (end, &tail, 0);
+             gpg_err_set_errno (0);
+             sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
+                                                     protocol);
              if (errno || end == tail || *tail != ' ')
-               return gpg_error (GPG_ERR_INV_ENGINE);
+               return trace_gpg_error (GPG_ERR_INV_ENGINE);
              end = tail;
 
              while (*end == ' ')
@@ -393,10 +457,10 @@ parse_valid_sig (gpgme_signature_t sig, char *args)
                {
                  /* Parse the hash algo.  */
 
-                 errno = 0;
+                 gpg_err_set_errno (0);
                  sig->hash_algo = strtol (end, &tail, 0);
                  if (errno || end == tail || *tail != ' ')
-                   return gpg_error (GPG_ERR_INV_ENGINE);
+                   return trace_gpg_error (GPG_ERR_INV_ENGINE);
                  end = tail;
                }
            }
@@ -429,7 +493,7 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
       if (notation)
        /* There is another notation name without data for the
           previous one.  The crypto backend misbehaves.  */
-       return gpg_error (GPG_ERR_INV_ENGINE);
+       return trace_gpg_error (GPG_ERR_INV_ENGINE);
 
       err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
       if (err)
@@ -482,24 +546,24 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
       if (!notation || !notation->name)
        /* There is notation data without a previous notation
           name.  The crypto backend misbehaves.  */
-       return gpg_error (GPG_ERR_INV_ENGINE);
-      
+       return trace_gpg_error (GPG_ERR_INV_ENGINE);
+
       if (!notation->value)
        {
          dest = notation->value = malloc (len);
          if (!dest)
-           return gpg_error_from_errno (errno);
+           return gpg_error_from_syserror ();
        }
       else
        {
          int cur_len = strlen (notation->value);
          dest = realloc (notation->value, len + strlen (notation->value));
          if (!dest)
-           return gpg_error_from_errno (errno);
+           return gpg_error_from_syserror ();
          notation->value = dest;
          dest += cur_len;
        }
-      
+
       err = _gpgme_decode_percent_string (args, &dest, len, 0);
       if (err)
        return err;
@@ -507,7 +571,7 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
       notation->value_len += strlen (dest);
     }
   else
-    return gpg_error (GPG_ERR_INV_ENGINE);
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
   return 0;
 }
 
@@ -545,7 +609,7 @@ parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
   sig->chain_model = 0;
   if (*args)
     {
-      sig->validity_reason = _gpgme_map_gnupg_error (args);
+      sig->validity_reason = atoi (args);
       while (*args && *args != ' ')
         args++;
       if (*args)
@@ -580,12 +644,12 @@ parse_error (gpgme_signature_t sig, char *args, int set_status)
       if (where)
        *where = '\0';
 
-      where = args;      
+      where = args;
     }
   else
-    return gpg_error (GPG_ERR_INV_ENGINE);
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
 
-  err = _gpgme_map_gnupg_error (which);
+  err = atoi (which);
 
   if (!strcmp (where, "proc_pkt.plaintext")
       && gpg_err_code (err) == GPG_ERR_BAD_DATA)
@@ -641,12 +705,12 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
       if (sig && !opd->did_prepare_new_sig)
        calc_sig_summary (sig);
       opd->only_newsig_seen = 0;
-      return parse_new_sig (opd, code, args);
+      return parse_new_sig (opd, code, args, ctx->protocol);
 
     case GPGME_STATUS_VALIDSIG:
       opd->only_newsig_seen = 0;
-      return sig ? parse_valid_sig (sig, args)
-       : gpg_error (GPG_ERR_INV_ENGINE);
+      return sig ? parse_valid_sig (sig, args, ctx->protocol)
+       : trace_gpg_error (GPG_ERR_INV_ENGINE);
 
     case GPGME_STATUS_NODATA:
       opd->only_newsig_seen = 0;
@@ -667,7 +731,7 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_POLICY_URL:
       opd->only_newsig_seen = 0;
       return sig ? parse_notation (sig, code, args)
-       : gpg_error (GPG_ERR_INV_ENGINE);
+       : trace_gpg_error (GPG_ERR_INV_ENGINE);
 
     case GPGME_STATUS_TRUST_UNDEFINED:
     case GPGME_STATUS_TRUST_NEVER:
@@ -676,7 +740,7 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     case GPGME_STATUS_TRUST_ULTIMATE:
       opd->only_newsig_seen = 0;
       return sig ? parse_trust (sig, code, args)
-       : gpg_error (GPG_ERR_INV_ENGINE);
+       : trace_gpg_error (GPG_ERR_INV_ENGINE);
 
     case GPGME_STATUS_PKA_TRUST_BAD:
     case GPGME_STATUS_PKA_TRUST_GOOD:
@@ -684,7 +748,7 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
       /* Check that we only get one of these status codes per
          signature; if not the crypto backend misbehaves.  */
       if (!sig || sig->pka_trust || sig->pka_address)
-        return gpg_error (GPG_ERR_INV_ENGINE);
+        return trace_gpg_error (GPG_ERR_INV_ENGINE);
       sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
       end = strchr (args, ' ');
       if (end)
@@ -754,7 +818,7 @@ verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
 
 gpgme_error_t
 _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
-{  
+{
   void *hook;
   op_data_t opd;
 
@@ -794,7 +858,16 @@ gpgme_error_t
 gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
                       gpgme_data_t signed_text, gpgme_data_t plaintext)
 {
-  return verify_start (ctx, 0, sig, signed_text, plaintext);
+  gpg_error_t err;
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
+             "sig=%p, signed_text=%p, plaintext=%p",
+             sig, signed_text, plaintext);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = verify_start (ctx, 0, sig, signed_text, plaintext);
+  return TRACE_ERR (err);
 }
 
 
@@ -806,10 +879,17 @@ gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
 {
   gpgme_error_t err;
 
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
+             "sig=%p, signed_text=%p, plaintext=%p",
+             sig, signed_text, plaintext);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
   err = verify_start (ctx, 1, sig, signed_text, plaintext);
   if (!err)
     err = _gpgme_wait_one (ctx);
-  return err;
+  return TRACE_ERR (err);
 }
 
 \f
@@ -823,6 +903,9 @@ gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
   gpgme_verify_result_t result;
   gpgme_signature_t sig;
 
+  if (!ctx)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
   result = gpgme_op_verify_result (ctx);
   sig = result->signatures;
 
@@ -867,27 +950,27 @@ gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
        case GPG_ERR_NO_ERROR:
          *r_stat = GPGME_SIG_STAT_GOOD;
          break;
-         
+
        case GPG_ERR_BAD_SIGNATURE:
          *r_stat = GPGME_SIG_STAT_BAD;
          break;
-         
+
        case GPG_ERR_NO_PUBKEY:
          *r_stat = GPGME_SIG_STAT_NOKEY;
          break;
-         
+
        case GPG_ERR_NO_DATA:
          *r_stat = GPGME_SIG_STAT_NOSIG;
          break;
-         
+
        case GPG_ERR_SIG_EXPIRED:
          *r_stat = GPGME_SIG_STAT_GOOD_EXP;
          break;
-         
+
        case GPG_ERR_KEY_EXPIRED:
          *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
          break;
-         
+
        default:
          *r_stat = GPGME_SIG_STAT_ERROR;
          break;
@@ -903,7 +986,7 @@ gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
    number of the signature after a successful verify operation.  WHAT
    is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
    one.  WHATIDX is to be passed as 0 for most attributes . */
-unsigned long 
+unsigned long
 gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
                           _gpgme_attr_t what, int whatidx)
 {
@@ -937,22 +1020,22 @@ gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
        {
        case GPG_ERR_NO_ERROR:
          return GPGME_SIG_STAT_GOOD;
-         
+
        case GPG_ERR_BAD_SIGNATURE:
          return GPGME_SIG_STAT_BAD;
-         
+
        case GPG_ERR_NO_PUBKEY:
          return GPGME_SIG_STAT_NOKEY;
-         
+
        case GPG_ERR_NO_DATA:
          return GPGME_SIG_STAT_NOSIG;
-         
+
        case GPG_ERR_SIG_EXPIRED:
          return GPGME_SIG_STAT_GOOD_EXP;
-         
+
        case GPG_ERR_KEY_EXPIRED:
          return GPGME_SIG_STAT_GOOD_EXPKEY;
-         
+
        default:
          return GPGME_SIG_STAT_ERROR;
        }