gpgme-tool: Fix chain_id -> chain-id in KEYLIST XML.
[gpgme.git] / src / verify.c
index bf73a8cc523248da0aa2523898a9b71cbeaf3a18..a61cc9500fd289cf85291b80049497bf51fdf062 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)
@@ -255,18 +317,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;
+      gpg_err_set_errno (0);
       sig->pubkey_algo = strtol (end, &tail, 0);
       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;
@@ -288,7 +350,7 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
       end = tail;
       while (*end == ' ')
        end++;
-      
+
       /* Parse the return code.  */
       if (end[0] && (!end[1] || end[1] == ' '))
        {
@@ -297,11 +359,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 +372,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,7 +386,7 @@ 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;
 }
@@ -348,7 +410,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, ' ');
@@ -360,7 +422,7 @@ parse_valid_sig (gpgme_signature_t sig, char *args)
       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
        return 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);
@@ -380,7 +442,7 @@ parse_valid_sig (gpgme_signature_t sig, char *args)
          if (end)
            {
              /* Parse the pubkey algo.  */
-             errno = 0;
+             gpg_err_set_errno (0);
              sig->pubkey_algo = strtol (end, &tail, 0);
              if (errno || end == tail || *tail != ' ')
                return gpg_error (GPG_ERR_INV_ENGINE);
@@ -393,7 +455,7 @@ 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);
@@ -483,23 +545,23 @@ parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
        /* There is notation data without a previous notation
           name.  The crypto backend misbehaves.  */
        return 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;
@@ -580,7 +642,7 @@ 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);
@@ -754,7 +816,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 +856,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 +877,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 +901,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 +948,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 +984,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 +1018,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;
        }