core: Return a better error code on certain decryption failures.
* src/decrypt.c (op_data_t): Add field first_status_error. (parse_status_error): Set it. (_gpgme_decrypt_status_handler): Prefer an ERROR code over a NO_SECKEY. -- GnuPG-bug-id: 3983 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
998fec8a4f
commit
2c4c569247
@ -53,7 +53,7 @@ typedef struct
|
|||||||
* status lines for each key the message has been encrypted to but
|
* status lines for each key the message has been encrypted to but
|
||||||
* that secret key is not available. This can't be done for hidden
|
* that secret key is not available. This can't be done for hidden
|
||||||
* recipients, though. We track it here to allow for a better error
|
* recipients, though. We track it here to allow for a better error
|
||||||
* message that the general DECRYPTION_FAILED. */
|
* message than the general DECRYPTION_FAILED. */
|
||||||
int any_no_seckey;
|
int any_no_seckey;
|
||||||
|
|
||||||
/* If the engine emits a DECRYPTION_INFO status and that does not
|
/* If the engine emits a DECRYPTION_INFO status and that does not
|
||||||
@ -61,6 +61,10 @@ typedef struct
|
|||||||
* is set. */
|
* is set. */
|
||||||
int not_integrity_protected;
|
int not_integrity_protected;
|
||||||
|
|
||||||
|
/* The error code from the first ERROR line. This is in some cases
|
||||||
|
* used to return a better matching error code to the caller. */
|
||||||
|
gpg_error_t first_status_error;
|
||||||
|
|
||||||
/* A pointer to the next pointer of the last recipient in the list.
|
/* A pointer to the next pointer of the last recipient in the list.
|
||||||
This makes appending new invalid signers painless while
|
This makes appending new invalid signers painless while
|
||||||
preserving the order. */
|
preserving the order. */
|
||||||
@ -222,6 +226,10 @@ parse_status_error (char *args, op_data_t opd)
|
|||||||
opd->not_integrity_protected = 1;
|
opd->not_integrity_protected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Record the first error code. */
|
||||||
|
if (err && !opd->first_status_error)
|
||||||
|
opd->first_status_error = err;
|
||||||
|
|
||||||
|
|
||||||
free (args2);
|
free (args2);
|
||||||
return 0;
|
return 0;
|
||||||
@ -360,17 +368,43 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
|
|||||||
* only a warning.
|
* only a warning.
|
||||||
* Fixme: These error values should probably be attributed to
|
* Fixme: These error values should probably be attributed to
|
||||||
* the underlying crypto engine (as error source). */
|
* the underlying crypto engine (as error source). */
|
||||||
if (opd->failed && opd->pkdecrypt_failed)
|
if (opd->failed)
|
||||||
return opd->pkdecrypt_failed;
|
{
|
||||||
else if (opd->failed && opd->any_no_seckey)
|
/* This comes from a specialized ERROR status line. */
|
||||||
return gpg_error (GPG_ERR_NO_SECKEY);
|
if (opd->pkdecrypt_failed)
|
||||||
else if (opd->failed || (opd->not_integrity_protected
|
return opd->pkdecrypt_failed;
|
||||||
&& !ctx->ignore_mdc_error))
|
|
||||||
return gpg_error (GPG_ERR_DECRYPT_FAILED);
|
/* For an integrity failure return just DECRYPTION_FAILED;
|
||||||
|
* the actual cause can be taken from an already set
|
||||||
|
* decryption result flag. */
|
||||||
|
if ((opd->not_integrity_protected && !ctx->ignore_mdc_error))
|
||||||
|
return gpg_error (GPG_ERR_DECRYPT_FAILED);
|
||||||
|
|
||||||
|
/* If we have any other ERROR code we prefer that over
|
||||||
|
* NO_SECKEY because it is probably the better matching
|
||||||
|
* code. For example a garbled message with multiple
|
||||||
|
* plaintext will return BAD_DATA here but may also have
|
||||||
|
* indicated a NO_SECKEY. */
|
||||||
|
if (opd->first_status_error)
|
||||||
|
return opd->first_status_error;
|
||||||
|
|
||||||
|
/* No secret key is pretty common reason. */
|
||||||
|
if (opd->any_no_seckey)
|
||||||
|
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
|
||||||
|
/* Generic decryption failed error code. */
|
||||||
|
return gpg_error (GPG_ERR_DECRYPT_FAILED);
|
||||||
|
}
|
||||||
else if (!opd->okay)
|
else if (!opd->okay)
|
||||||
return gpg_error (GPG_ERR_NO_DATA);
|
{
|
||||||
|
/* No data was found. */
|
||||||
|
return gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
}
|
||||||
else if (opd->failure_code)
|
else if (opd->failure_code)
|
||||||
return opd->failure_code;
|
{
|
||||||
|
/* The engine returned failure code at program exit. */
|
||||||
|
return opd->failure_code;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GPGME_STATUS_DECRYPTION_INFO:
|
case GPGME_STATUS_DECRYPTION_INFO:
|
||||||
@ -389,8 +423,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
|
|||||||
|
|
||||||
case GPGME_STATUS_ERROR:
|
case GPGME_STATUS_ERROR:
|
||||||
/* Note that this is an informational status code which should
|
/* Note that this is an informational status code which should
|
||||||
not lead to an error return unless it is something not
|
* not lead to an error return unless it is something not
|
||||||
related to the backend. */
|
* related to the backend. However, it is used to return a
|
||||||
|
* better matching final error code. */
|
||||||
err = parse_status_error (args, opd);
|
err = parse_status_error (args, opd);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
Loading…
Reference in New Issue
Block a user