From e09f681427d700282988885a80dc2bc8d4573718 Mon Sep 17 00:00:00 2001 From: Werner Koch 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 (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