goto cleanup;
}
- if (mutt_autocrypt_gpgme_create_key(addr, keyid, keydata))
+ if (mutt_autocrypt_gpgme_select_or_create_key(addr, keyid, keydata))
goto cleanup;
/* L10N:
/* This is slightly different from the autocrypt 1.1 spec.
* Avoid setting an empty peer.gossip_keydata with a value that matches
* the current peer.keydata. */
- if ((peer->gossip_keydata && (mutt_str_strcmp(peer->gossip_keydata, ac_hdr->keydata) != 0)) ||
+ if ((peer->gossip_keydata &&
+ (mutt_str_strcmp(peer->gossip_keydata, ac_hdr->keydata) != 0)) ||
(!peer->gossip_keydata && (mutt_str_strcmp(peer->keydata, ac_hdr->keydata) != 0)))
{
import_gpg = true;
#include <stdbool.h>
#include "mutt/mutt.h"
#include "address/lib.h"
+#include "config/lib.h"
+#include "curs_lib.h"
#include "globals.h"
#include "ncrypt/crypt_gpgme.h"
+#include "options.h"
/**
* create_gpgme_context - Create a GPGME context
return rc;
}
+/**
+ * mutt_autocrypt_gpgme_select_key - Select a Autocrypt key
+ * @param[in] keyid Key id to select
+ * @param[out] keydata Buffer for resulting Key data
+ * @retval 0 Success
+ * @retval -1 Error
+ */
+int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata)
+{
+ int rc = -1;
+ gpgme_ctx_t ctx = NULL;
+ gpgme_key_t key = NULL;
+
+ OptAutocryptGpgme = true;
+ if (mutt_gpgme_select_secret_key(keyid))
+ goto cleanup;
+
+ if (create_gpgme_context(&ctx))
+ goto cleanup;
+
+ if (gpgme_get_key(ctx, mutt_b2s(keyid), &key, 0))
+ goto cleanup;
+
+ if (key->revoked || key->expired || key->disabled || key->invalid ||
+ !key->can_encrypt || !key->can_sign)
+ {
+ /* L10N:
+ After selecting a key for an autocrypt account,
+ this is displayed if the key was revoked/expired/disabled/invalid
+ or can't be used for both signing and encryption.
+ %s is the key fingerprint.
+ */
+ mutt_error(_("The key %s is not usable for autocrypt"), mutt_b2s(keyid));
+ goto cleanup;
+ }
+
+ if (export_keydata(ctx, key, keydata))
+ goto cleanup;
+
+ rc = 0;
+
+cleanup:
+ OptAutocryptGpgme = false;
+ gpgme_key_unref(key);
+ gpgme_release(ctx);
+ return rc;
+}
+
+/**
+ * mutt_autocrypt_gpgme_select_or_create_key - Ask the user to select or create an Autocrypt key
+ * @param addr Email Address
+ * @param keyid Key id
+ * @param keydata Key data
+ * @retval 0 Success
+ * @retval -1 Error
+ */
+int mutt_autocrypt_gpgme_select_or_create_key(struct Address *addr, struct Buffer *keyid,
+ struct Buffer *keydata)
+{
+ int rc = -1;
+
+ /* L10N:
+ During autocrypt account creation, this prompt asks the
+ user whether they want to create a new GPG key for the account,
+ or select an existing account from the keyring.
+ */
+ const char *prompt = _("(c)reate new, or (s)elect existing GPG key? ");
+ /* L10N:
+ The letters corresponding to the
+ "(c)reate new, or (s)elect existing GPG key?" prompt.
+ */
+ const char *letters = _("cs");
+
+ int choice = mutt_multi_choice(prompt, letters);
+ switch (choice)
+ {
+ case 2: /* select existing */
+ rc = mutt_autocrypt_gpgme_select_key(keyid, keydata);
+ if (rc == 0)
+ break;
+
+ /* L10N:
+ During autocrypt account creation, if selecting an existing key fails
+ for some reason, we prompt to see if they want to create a key instead.
+ */
+ if (mutt_yesorno(_("Create a new gpg key for this account, instead?"), MUTT_YES) == MUTT_NO)
+ break;
+ /* fallthrough */
+
+ case 1: /* create new */
+ rc = mutt_autocrypt_gpgme_create_key(addr, keyid, keydata);
+ }
+
+ return rc;
+}
+
/**
* mutt_autocrypt_gpgme_import_key - Read a key from GPGME
* @param keydata Buffer for key data
int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid);
int mutt_autocrypt_gpgme_init(void);
bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid);
+int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata);
+int mutt_autocrypt_gpgme_select_or_create_key(struct Address *addr, struct Buffer *keyid, struct Buffer *keydata);
#endif /* MUTT_AUTOCRYPT_AUTOCRYPT_PRIVATE_H */
return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
}
+/**
+ * mutt_gpgme_select_secret_key - Select a private Autocrypt key for a new account
+ * @param keyid Autocrypt Key id
+ * @retval 0 Success
+ * @retval -1 Error
+ *
+ * Unfortunately, the internal ncrypt/crypt_gpgme.c functions use CryptKeyInfo,
+ * and so aren't exportable.
+ *
+ * This function queries all private keys, provides the crypt_select_keys()
+ * menu, and returns the selected key fingerprint in keyid.
+ */
+int mutt_gpgme_select_secret_key(struct Buffer *keyid)
+{
+ int rc = -1, junk;
+ gpgme_error_t err;
+ gpgme_key_t key;
+ gpgme_user_id_t uid;
+ struct CryptKeyInfo *results = NULL, *k = NULL;
+ struct CryptKeyInfo **kend = NULL;
+ struct CryptKeyInfo *choice = NULL;
+
+ gpgme_ctx_t ctx = create_gpgme_context(false);
+
+ /* list all secret keys */
+ if (gpgme_op_keylist_start(ctx, NULL, 1))
+ goto cleanup;
+
+ kend = &results;
+
+ while (!(err = gpgme_op_keylist_next(ctx, &key)))
+ {
+ KeyFlags flags = KEYFLAG_NO_FLAGS;
+
+ if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
+ flags |= KEYFLAG_CANENCRYPT;
+ if (key_check_cap(key, KEY_CAP_CAN_SIGN))
+ flags |= KEYFLAG_CANSIGN;
+
+ if (key->revoked)
+ flags |= KEYFLAG_REVOKED;
+ if (key->expired)
+ flags |= KEYFLAG_EXPIRED;
+ if (key->disabled)
+ flags |= KEYFLAG_DISABLED;
+
+ int idx;
+ for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
+ {
+ k = mutt_mem_calloc(1, sizeof(*k));
+ k->kobj = key;
+ gpgme_key_ref(k->kobj);
+ k->idx = idx;
+ k->uid = uid->uid;
+ k->flags = flags;
+ if (uid->revoked)
+ k->flags |= KEYFLAG_REVOKED;
+ k->validity = uid->validity;
+ *kend = k;
+ kend = &k->next;
+ }
+ gpgme_key_unref(key);
+ }
+ if (gpg_err_code(err) != GPG_ERR_EOF)
+ mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
+ gpgme_op_keylist_end(ctx);
+
+ if (!results)
+ {
+ /* L10N:
+ mutt_gpgme_select_secret_key() tries to list all secret keys to choose
+ from. This error is displayed if no results were found.
+ */
+ mutt_error(_("No secret keys found"));
+ goto cleanup;
+ }
+
+ choice = crypt_select_key(results, NULL, "*", APPLICATION_PGP, &junk);
+ if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
+ goto cleanup;
+ mutt_buffer_strcpy(keyid, choice->kobj->subkeys->fpr);
+
+ rc = 0;
+
+cleanup:
+ crypt_free_key(&choice);
+ crypt_free_key(&results);
+ gpgme_release(ctx);
+ return rc;
+}
+
/**
* pgp_gpgme_make_key_attachment - Implements CryptModuleSpecs::pgp_make_key_attachment()
*/
struct AddressList;
struct Body;
+struct Buffer;
struct Email;
struct Mailbox;
struct State;
int smime_gpgme_verify_sender(struct Mailbox *m, struct Email *e);
const char *mutt_gpgme_print_version(void);
+int mutt_gpgme_select_secret_key (struct Buffer *keyid);
#endif /* MUTT_NCRYPT_CRYPT_GPGME_H */