Blob Blame History Raw
From e09f681427d700282988885a80dc2bc8d4573718 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Tue, 17 May 2016 20:21:01 +0200
Subject: [PATCH] Return dedicated error code for all subkeys expired or
 revoked.

* src/gpgme.h.in (GPGME_STATUS_KEY_CONSIDERED): New.
(GPGME_SIGSUM_TOFU_CONFLICT): New.
* src/status-table.c (KEY_CONSIDERED): New.
* src/op-support.c (_gpgme_parse_inv_recp): Add argc KC_FPR and
KC_FLAGS.  Use calloc.  Detect all expired or revoked subkeys.
(_gpgme_parse_key_considered): New.
* src/sign.c (op_data_t): Add fields KC_FPR and KC_FLAGS.
(release_op_data): Free KC_FPR.
(_gpgme_sign_status_handler): Handle STATUS_KEY_CONSIDERED.
* src/encrypt.c (op_data_t): Add fields KC_FPR and KC_FLAGS.
(release_op_data): Free KC_FPR.
(_gpgme_encrypt_status_handler): Handle STATUS_KEY_CONSIDERED.

Signed-off-by: Werner Koch <wk@gnupg.org>
(cherry picked from commit 315fb73d4a774e2c699ac1804f5377559b4d0027)
---
 src/encrypt.c      | 26 ++++++++++++++++++++--
 src/gpgme.h.in     | 10 +++++++--
 src/op-support.c   | 65 +++++++++++++++++++++++++++++++++++++++++++++++-------
 src/ops.h          |  8 ++++++-
 src/sign.c         | 25 ++++++++++++++++++++-
 src/status-table.c |  1 +
 6 files changed, 121 insertions(+), 14 deletions(-)

diff --git a/src/encrypt.c b/src/encrypt.c
index 9f5134d..8672cd3 100644
--- a/src/encrypt.c
+++ b/src/encrypt.c
@@ -39,6 +39,12 @@ typedef struct
   /* The error code from a FAILURE status line or 0.  */
   gpg_error_t failure_code;
 
+  /* The fingerprint from the last KEY_CONSIDERED status line.  */
+  char *kc_fpr;
+
+  /* The flags from the last KEY_CONSIDERED status line.  */
+  unsigned int kc_flags;
+
   /* A pointer to the next pointer of the last invalid recipient in
      the list.  This makes appending new invalid recipients painless
      while preserving the order.  */
@@ -60,6 +66,8 @@ release_op_data (void *hook)
       free (invalid_recipient);
       invalid_recipient = next;
     }
+
+  free (opd->kc_fpr);
 }
 
 
@@ -128,12 +136,26 @@ _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
         return opd->failure_code;
       break;
 
+    case GPGME_STATUS_KEY_CONSIDERED:
+      /* This is emitted during gpg's key lookup to give information
+       * about the lookup results.  We store the last one so it can be
+       * used in connection with INV_RECP.  */
+      free (opd->kc_fpr);
+      opd->kc_fpr = NULL;
+      err = _gpgme_parse_key_considered (args, &opd->kc_fpr, &opd->kc_flags);
+      if (err)
+        return err;
+      break;
+
     case GPGME_STATUS_INV_RECP:
-      err = _gpgme_parse_inv_recp (args, opd->lastp);
+      err = _gpgme_parse_inv_recp (args, 0, opd->kc_fpr, opd->kc_flags,
+                                   opd->lastp);
       if (err)
-	return err;
+        return err;
 
       opd->lastp = &(*opd->lastp)->next;
+      free (opd->kc_fpr);
+      opd->kc_fpr = NULL;
       break;
 
     case GPGME_STATUS_NO_RECP:
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 6cea2c7..cad95f3 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -531,7 +531,8 @@ typedef enum
     GPGME_STATUS_BEGIN_SIGNING = 90,
     GPGME_STATUS_KEY_NOT_CREATED = 91,
     GPGME_STATUS_INQUIRE_MAXLEN = 92,
-    GPGME_STATUS_FAILURE = 93
+    GPGME_STATUS_FAILURE = 93,
+    GPGME_STATUS_KEY_CONSIDERED = 94
   }
 gpgme_status_code_t;
 
@@ -860,7 +861,12 @@ typedef struct _gpgme_key *gpgme_key_t;
 struct _gpgme_invalid_key
 {
   struct _gpgme_invalid_key *next;
+
+  /* The string used to request the key.  Despite the name this may
+   * not be a fingerprint.  */
   char *fpr;
+
+  /* The error code.  */
   gpgme_error_t reason;
 };
 typedef struct _gpgme_invalid_key *gpgme_invalid_key_t;
@@ -1539,7 +1545,7 @@ struct _gpgme_signature
   /* Signature creation time.  */
   unsigned long timestamp;
 
-  /* Signature exipration time or 0.  */
+  /* Signature expiration time or 0.  */
   unsigned long exp_timestamp;
 
   /* Key should not have been used for signing.  */
diff --git a/src/op-support.c b/src/op-support.c
index 02940ef..d51d643 100644
--- a/src/op-support.c
+++ b/src/op-support.c
@@ -33,6 +33,11 @@
 #include "util.h"
 #include "debug.h"
 
+#if GPG_ERROR_VERSION_NUMBER < 0x011700  /* 1.23 */
+# define GPG_ERR_SUBKEYS_EXP_REV 217
+#endif
+
+
 
 gpgme_error_t
 _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook,
@@ -190,16 +195,19 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
 }
 
 
-/* Parse the INV_RECP or INV-SNDR status line in ARGS and return the
-   result in KEY.  */
+/* Parse the INV_RECP or INV_SNDR status line in ARGS and return the
+   result in KEY.  If KC_FPR (from the KEY_CONSIDERED status line) is
+   not NULL take the KC_FLAGS in account. */
 gpgme_error_t
-_gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
+_gpgme_parse_inv_recp (char *args, int for_signing,
+                       const char *kc_fpr, unsigned int kc_flags,
+                       gpgme_invalid_key_t *key)
 {
   gpgme_invalid_key_t inv_key;
   char *tail;
   long int reason;
 
-  inv_key = malloc (sizeof (*inv_key));
+  inv_key = calloc (1, sizeof (*inv_key));
   if (!inv_key)
     return gpg_error_from_syserror ();
   inv_key->next = NULL;
@@ -214,9 +222,11 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
 
   switch (reason)
     {
-    default:
     case 0:
-      inv_key->reason = gpg_error (GPG_ERR_GENERAL);
+      if (kc_fpr && (kc_flags & 2))
+        inv_key->reason = gpg_error (GPG_ERR_SUBKEYS_EXP_OR_REV);
+      else
+        inv_key->reason = gpg_error (GPG_ERR_GENERAL);
       break;
 
     case 1:
@@ -274,6 +284,10 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
     case 14:
       inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID);
       break;
+
+    default:
+      inv_key->reason = gpg_error (GPG_ERR_GENERAL);
+      break;
     }
 
   while (*tail && *tail == ' ')
@@ -287,14 +301,49 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
 	  return gpg_error_from_syserror ();
 	}
     }
-  else
-    inv_key->fpr = NULL;
 
   *key = inv_key;
   return 0;
 }
 
 
+
+/* Parse a KEY_CONSIDERED status line in ARGS and store the
+ * fingerprint and the flags at R_FPR and R_FLAGS.  The caller must
+ * free the value at R_FPR on success.  */
+gpgme_error_t
+_gpgme_parse_key_considered (const char *args,
+                             char **r_fpr, unsigned int *r_flags)
+{
+  char *pend;
+  size_t n;
+
+  *r_fpr = NULL;
+
+  pend = strchr (args, ' ');
+  if (!pend || pend == args)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* Bogus status line.  */
+  n = pend - args;
+  *r_fpr = malloc (n + 1);
+  if (!*r_fpr)
+    return gpg_error_from_syserror ();
+  memcpy (*r_fpr, args, n);
+  (*r_fpr)[n] = 0;
+  args = pend + 1;
+
+  gpg_err_set_errno (0);
+  *r_flags = strtoul (args, &pend, 0);
+  if (errno || args == pend || (*pend && *pend != ' '))
+    {
+      free (*r_fpr);
+      *r_fpr = NULL;
+      return trace_gpg_error (GPG_ERR_INV_ENGINE);
+    }
+
+  return 0;
+}
+
+
 /* Parse the PLAINTEXT status line in ARGS and return the result in
    FILENAMEP.  */
 gpgme_error_t
diff --git a/src/ops.h b/src/ops.h
index 3662d57..9c27529 100644
--- a/src/ops.h
+++ b/src/ops.h
@@ -57,9 +57,15 @@ gpgme_error_t _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type,
 /* Prepare a new operation on CTX.  */
 gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int synchronous);
 
+/* Parse the KEY_CONSIDERED status line.  */
+gpgme_error_t _gpgme_parse_key_considered (const char *args,
+                                           char **r_fpr, unsigned int *r_flags);
+
 /* Parse the INV_RECP status line in ARGS and return the result in
    KEY.  */
-gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key);
+gpgme_error_t _gpgme_parse_inv_recp (char *args, int for_signing,
+                                     const char *kc_fpr, unsigned int kc_flags,
+                                     gpgme_invalid_key_t *key);
 
 /* Parse the PLAINTEXT status line in ARGS and return the result in
    FILENAMEP.  */
diff --git a/src/sign.c b/src/sign.c
index 6c9fc03..d8650a9 100644
--- a/src/sign.c
+++ b/src/sign.c
@@ -42,6 +42,12 @@ typedef struct
   /* The error code from a FAILURE status line or 0.  */
   gpg_error_t failure_code;
 
+  /* The fingerprint from the last KEY_CONSIDERED status line.  */
+  char *kc_fpr;
+
+  /* The flags from the last KEY_CONSIDERED status line.  */
+  unsigned int kc_flags;
+
   /* A pointer to the next pointer of the last invalid signer in
      the list.  This makes appending new invalid signers painless
      while preserving the order.  */
@@ -86,6 +92,7 @@ release_op_data (void *hook)
     }
 
   release_signatures (opd->result.signatures);
+  free (opd->kc_fpr);
 }
 
 
@@ -316,6 +323,17 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
       opd->last_sig_p = &(*opd->last_sig_p)->next;
       break;
 
+    case GPGME_STATUS_KEY_CONSIDERED:
+      /* This is emitted during gpg's key lookup to give information
+       * about the lookup results.  We store the last one so it can be
+       * used in connection with INV_RECP.  */
+      free (opd->kc_fpr);
+      opd->kc_fpr = NULL;
+      err = _gpgme_parse_key_considered (args, &opd->kc_fpr, &opd->kc_flags);
+      if (err)
+        return err;
+      break;
+
     case GPGME_STATUS_INV_RECP:
       if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
         break;
@@ -323,11 +341,16 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
     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);
+      free (opd->kc_fpr);
+      opd->kc_fpr = NULL;
+      err = _gpgme_parse_inv_recp (args, 1, opd->kc_fpr, opd->kc_flags,
+                                   opd->last_signer_p);
       if (err)
 	return err;
 
       opd->last_signer_p = &(*opd->last_signer_p)->next;
+      free (opd->kc_fpr);
+      opd->kc_fpr = NULL;
       break;
 
     case GPGME_STATUS_FAILURE:
diff --git a/src/status-table.c b/src/status-table.c
index 6d428d7..e70cb8b 100644
--- a/src/status-table.c
+++ b/src/status-table.c
@@ -84,6 +84,7 @@ static struct status_table_s status_table[] =
   { "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN },
   { "INV_RECP", GPGME_STATUS_INV_RECP },
   { "INV_SGNR", GPGME_STATUS_INV_SGNR },
+  { "KEY_CONSIDERED", GPGME_STATUS_KEY_CONSIDERED },
   { "KEY_CREATED", GPGME_STATUS_KEY_CREATED },
   { "KEY_NOT_CREATED",   GPGME_STATUS_KEY_NOT_CREATED  },
   { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED },
-- 
2.7.4