From 305d8668ca724982c50fe4e05315c48a20cc33e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Wed, 22 Dec 2021 12:13:23 +0100 Subject: [PATCH] core: Detect bad passphrase error on certificate import * src/import.c (gpgme_op_import_result): Check fpr for NULL. (parse_error): New. (import_status_handler): Handle error status line. * doc/gpgme.texi (gpgme_import_status_t): Mention that fpr can be NULL. * tests/gpg/t-import.c (check_result): Check fpr for NULL. * tests/run-threaded.c (delete_impres): Check fpr for NULL. -- When importing an encrypted certificate a wrong passphrase may be entered. In this case gpgsm emits a status line with a bad passphrase error and an "invalid object" error. To make it possible for callers to handle a wrong passphrase error more gracefully, an import status with bad passphrase error is added to the import result for each status line with bad passphrase error. GnuPG-bug-id: 5713 --- doc/gpgme.texi | 4 +++- src/import.c | 54 +++++++++++++++++++++++++++++++++++++++++++- tests/gpg/t-import.c | 9 ++++---- tests/run-threaded.c | 3 ++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index cc8ff5e5..01a55032 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -5115,7 +5115,9 @@ This is a pointer to the next status structure in the linked list, or @code{NULL} if this is the last element. @item char *fpr -This is the fingerprint of the key that was considered. +This is the fingerprint of the key that was considered, or @code{NULL} +if the fingerprint of the key is not known, e.g. because the key to +import was encrypted and decryption failed. @item gpgme_error_t result If the import was not successful, this is the error value that caused diff --git a/src/import.c b/src/import.c index 9874b698..ae7b972a 100644 --- a/src/import.c +++ b/src/import.c @@ -103,7 +103,7 @@ gpgme_op_import_result (gpgme_ctx_t ctx) while (impstat) { TRACE_LOG ("import[%i] for %s = 0x%x (%s)", - i, impstat->fpr, impstat->status, + i, impstat->fpr ? impstat->fpr : "null", impstat->status, gpgme_strerror (impstat->result)); impstat = impstat->next; i++; @@ -223,6 +223,49 @@ parse_import_res (char *args, gpgme_import_result_t result) } +/* Parses an error on a status line and adds a corresponding import status. + Currently, only supports "import.parsep12 11". */ +static gpgme_error_t +parse_error (char *args, gpgme_import_status_t *import_status) +{ + gpgme_import_status_t import; + char *tail; + long int nr; + + tail = strchr (args, ' '); + if (!tail) + return 0; + + *tail = '\0'; + if (strcmp( args, "import.parsep12" )) + return 0; + + args = tail + 1; + + gpg_err_set_errno (0); + nr = strtol (args, &tail, 0); + if (errno || args == tail || !(*tail == ' ' || !*tail)) + { + /* The crypto backend does not behave. */ + return trace_gpg_error (GPG_ERR_INV_ENGINE); + } + if (nr != GPG_ERR_BAD_PASSPHRASE) + return 0; + + import = malloc (sizeof (*import)); + if (!import) + return gpg_error_from_syserror (); + import->next = NULL; + + import->result = gpg_error (GPG_ERR_BAD_PASSPHRASE); + import->status = 0; + import->fpr = 0; + + *import_status = import; + return 0; +} + + static gpgme_error_t import_status_handler (void *priv, gpgme_status_code_t code, char *args) { @@ -252,6 +295,15 @@ import_status_handler (void *priv, gpgme_status_code_t code, char *args) err = parse_import_res (args, &opd->result); break; + case GPGME_STATUS_ERROR: + err = parse_error (args, opd->lastp); + if (err) + return err; + + if (*opd->lastp) + opd->lastp = &(*opd->lastp)->next; + break; + default: break; } diff --git a/tests/gpg/t-import.c b/tests/gpg/t-import.c index 159e5652..1f7fdbc3 100644 --- a/tests/gpg/t-import.c +++ b/tests/gpg/t-import.c @@ -149,16 +149,17 @@ check_result (gpgme_import_result_t result, const char *fpr, int secret) exit (1); } } - if (strcmp (fpr, result->imports->fpr)) + if (!result->imports->fpr || strcmp (fpr, result->imports->fpr)) { fprintf (stderr, "Unexpected fingerprint %s\n", - result->imports->fpr); + result->imports->fpr ? result->imports->fpr : "null"); exit (1); } - if (result->imports->next && strcmp (fpr, result->imports->next->fpr)) + if (result->imports->next + && (!result->imports->next->fpr || strcmp (fpr, result->imports->next->fpr))) { fprintf (stderr, "Unexpected fingerprint on second status %s\n", - result->imports->next->fpr); + result->imports->next->fpr ? result->imports->next->fpr : "null"); exit (1); } if (result->imports->result != 0) diff --git a/tests/run-threaded.c b/tests/run-threaded.c index c0e033bb..634b6811 100644 --- a/tests/run-threaded.c +++ b/tests/run-threaded.c @@ -517,7 +517,8 @@ delete_impres (gpgme_import_result_t r, gpgme_protocol_t proto) for (st=r->imports; st; st = st->next) { - delete_fpr (st->fpr, proto); + if (st->fpr) + delete_fpr (st->fpr, proto); } }