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>
This commit is contained in:
Werner Koch 2016-05-17 20:21:01 +02:00
parent 9b36ebf37a
commit 315fb73d4a
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
6 changed files with 124 additions and 16 deletions

View File

@ -39,6 +39,12 @@ typedef struct
/* The error code from a FAILURE status line or 0. */ /* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code; 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 /* A pointer to the next pointer of the last invalid recipient in
the list. This makes appending new invalid recipients painless the list. This makes appending new invalid recipients painless
while preserving the order. */ while preserving the order. */
@ -60,6 +66,8 @@ release_op_data (void *hook)
free (invalid_recipient); free (invalid_recipient);
invalid_recipient = next; 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; return opd->failure_code;
break; 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: 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) if (err)
return err; return err;
opd->lastp = &(*opd->lastp)->next; opd->lastp = &(*opd->lastp)->next;
free (opd->kc_fpr);
opd->kc_fpr = NULL;
break; break;
case GPGME_STATUS_NO_RECP: case GPGME_STATUS_NO_RECP:

View File

@ -532,7 +532,8 @@ typedef enum
GPGME_STATUS_BEGIN_SIGNING = 90, GPGME_STATUS_BEGIN_SIGNING = 90,
GPGME_STATUS_KEY_NOT_CREATED = 91, GPGME_STATUS_KEY_NOT_CREATED = 91,
GPGME_STATUS_INQUIRE_MAXLEN = 92, GPGME_STATUS_INQUIRE_MAXLEN = 92,
GPGME_STATUS_FAILURE = 93 GPGME_STATUS_FAILURE = 93,
GPGME_STATUS_KEY_CONSIDERED = 94
} }
gpgme_status_code_t; gpgme_status_code_t;
@ -861,7 +862,12 @@ typedef struct _gpgme_key *gpgme_key_t;
struct _gpgme_invalid_key struct _gpgme_invalid_key
{ {
struct _gpgme_invalid_key *next; struct _gpgme_invalid_key *next;
/* The string used to request the key. Despite the name this may
* not be a fingerprint. */
char *fpr; char *fpr;
/* The error code. */
gpgme_error_t reason; gpgme_error_t reason;
}; };
typedef struct _gpgme_invalid_key *gpgme_invalid_key_t; typedef struct _gpgme_invalid_key *gpgme_invalid_key_t;
@ -1518,7 +1524,8 @@ typedef enum
GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */ GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */
GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */ GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */
GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */ GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */
GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occurred. */ GPGME_SIGSUM_SYS_ERROR = 0x0800, /* A system error occurred. */
GPGME_SIGSUM_TOFU_CONFLICT=0x1000 /* Tofu conflict detected. */
} }
gpgme_sigsum_t; gpgme_sigsum_t;
@ -1541,7 +1548,7 @@ struct _gpgme_signature
/* Signature creation time. */ /* Signature creation time. */
unsigned long timestamp; unsigned long timestamp;
/* Signature exipration time or 0. */ /* Signature expiration time or 0. */
unsigned long exp_timestamp; unsigned long exp_timestamp;
/* Key should not have been used for signing. */ /* Key should not have been used for signing. */

View File

@ -33,6 +33,11 @@
#include "util.h" #include "util.h"
#include "debug.h" #include "debug.h"
#if GPG_ERROR_VERSION_NUMBER < 0x011700 /* 1.23 */
# define GPG_ERR_SUBKEYS_EXP_REV 217
#endif
gpgme_error_t gpgme_error_t
_gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook, _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 /* Parse the INV_RECP or INV_SNDR status line in ARGS and return the
result in KEY. */ 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_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; gpgme_invalid_key_t inv_key;
char *tail; char *tail;
long int reason; long int reason;
inv_key = malloc (sizeof (*inv_key)); inv_key = calloc (1, sizeof (*inv_key));
if (!inv_key) if (!inv_key)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
inv_key->next = NULL; inv_key->next = NULL;
@ -214,8 +222,10 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
switch (reason) switch (reason)
{ {
default:
case 0: case 0:
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); inv_key->reason = gpg_error (GPG_ERR_GENERAL);
break; break;
@ -274,6 +284,10 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
case 14: case 14:
inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID); inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID);
break; break;
default:
inv_key->reason = gpg_error (GPG_ERR_GENERAL);
break;
} }
while (*tail && *tail == ' ') while (*tail && *tail == ' ')
@ -287,14 +301,49 @@ _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
} }
} }
else
inv_key->fpr = NULL;
*key = inv_key; *key = inv_key;
return 0; 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 /* Parse the PLAINTEXT status line in ARGS and return the result in
FILENAMEP. */ FILENAMEP. */
gpgme_error_t gpgme_error_t

View File

@ -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. */ /* Prepare a new operation on CTX. */
gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int synchronous); 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 /* Parse the INV_RECP status line in ARGS and return the result in
KEY. */ 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 /* Parse the PLAINTEXT status line in ARGS and return the result in
FILENAMEP. */ FILENAMEP. */

View File

@ -42,6 +42,12 @@ typedef struct
/* The error code from a FAILURE status line or 0. */ /* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code; 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 /* A pointer to the next pointer of the last invalid signer in
the list. This makes appending new invalid signers painless the list. This makes appending new invalid signers painless
while preserving the order. */ while preserving the order. */
@ -86,6 +92,7 @@ release_op_data (void *hook)
} }
release_signatures (opd->result.signatures); 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; opd->last_sig_p = &(*opd->last_sig_p)->next;
break; 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: case GPGME_STATUS_INV_RECP:
if (opd->inv_sgnr_seen && opd->ignore_inv_recp) if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
break; break;
@ -323,11 +341,16 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
case GPGME_STATUS_INV_SGNR: case GPGME_STATUS_INV_SGNR:
if (code == GPGME_STATUS_INV_SGNR) if (code == GPGME_STATUS_INV_SGNR)
opd->inv_sgnr_seen = 1; 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) if (err)
return err; return err;
opd->last_signer_p = &(*opd->last_signer_p)->next; opd->last_signer_p = &(*opd->last_signer_p)->next;
free (opd->kc_fpr);
opd->kc_fpr = NULL;
break; break;
case GPGME_STATUS_FAILURE: case GPGME_STATUS_FAILURE:

View File

@ -84,6 +84,7 @@ static struct status_table_s status_table[] =
{ "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN }, { "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN },
{ "INV_RECP", GPGME_STATUS_INV_RECP }, { "INV_RECP", GPGME_STATUS_INV_RECP },
{ "INV_SGNR", GPGME_STATUS_INV_SGNR }, { "INV_SGNR", GPGME_STATUS_INV_SGNR },
{ "KEY_CONSIDERED", GPGME_STATUS_KEY_CONSIDERED },
{ "KEY_CREATED", GPGME_STATUS_KEY_CREATED }, { "KEY_CREATED", GPGME_STATUS_KEY_CREATED },
{ "KEY_NOT_CREATED", GPGME_STATUS_KEY_NOT_CREATED }, { "KEY_NOT_CREATED", GPGME_STATUS_KEY_NOT_CREATED },
{ "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED }, { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED },