NeoMutt  2024-04-25-89-g194907
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
gpgme.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <gpg-error.h>
33#include <gpgme.h>
34#include <stdbool.h>
35#include <stddef.h>
36#include "private.h"
37#include "mutt/lib.h"
38#include "address/lib.h"
39#include "config/lib.h"
40#include "core/lib.h"
41#include "ncrypt/lib.h"
42#include "question/lib.h"
43#include "globals.h"
44
51static int create_gpgme_context(gpgme_ctx_t *ctx)
52{
53 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
54 gpgme_error_t err = gpgme_new(ctx);
55 if (err == GPG_ERR_NO_ERROR)
56 err = gpgme_ctx_set_engine_info(*ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
57 if (err != GPG_ERR_NO_ERROR)
58 {
59 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
60 return -1;
61 }
62
63 return 0;
64}
65
71{
73 return 0;
74}
75
84static int export_keydata(gpgme_ctx_t ctx, gpgme_key_t key, struct Buffer *keydata)
85{
86 int rc = -1;
87 gpgme_data_t dh = NULL;
88 gpgme_key_t export_keys[2] = { 0 };
89 size_t export_data_len;
90
91 if (gpgme_data_new(&dh))
92 goto cleanup;
93
94 /* This doesn't seem to work */
95#if 0
96 if (gpgme_data_set_encoding (dh, GPGME_DATA_ENCODING_BASE64))
97 goto cleanup;
98#endif
99
100 export_keys[0] = key;
101 export_keys[1] = NULL;
102 if (gpgme_op_export_keys(ctx, export_keys, GPGME_EXPORT_MODE_MINIMAL, dh))
103 goto cleanup;
104
105 char *export_data = gpgme_data_release_and_get_mem(dh, &export_data_len);
106 dh = NULL;
107
108 mutt_b64_buffer_encode(keydata, export_data, export_data_len);
109 gpgme_free(export_data);
110 export_data = NULL;
111
112 rc = 0;
113
114cleanup:
115 gpgme_data_release(dh);
116 return rc;
117}
118
119#if 0
127int mutt_autocrypt_gpgme_export_key(const char *keyid, struct Buffer *keydata)
128{
129 int rc = -1;
130 gpgme_ctx_t ctx = NULL;
131 gpgme_key_t key = NULL;
132
133 if (create_gpgme_context(&ctx))
134 goto cleanup;
135
136 if (gpgme_get_key(ctx, keyid, &key, 0))
137 goto cleanup;
138
139 if (export_keydata(ctx, key, keydata))
140 goto cleanup;
141
142 rc = 0;
143cleanup:
144 gpgme_key_unref(key);
145 gpgme_release(ctx);
146 return rc;
147}
148#endif
149
158int mutt_autocrypt_gpgme_create_key(struct Address *addr, struct Buffer *keyid,
159 struct Buffer *keydata)
160{
161 int rc = -1;
162 gpgme_ctx_t ctx = NULL;
163 gpgme_genkey_result_t keyresult = NULL;
164 gpgme_key_t primary_key = NULL;
165 struct Buffer *buf = buf_pool_get();
166
167 /* GPGME says addresses should not be in idna form */
168 struct Address *copy = mutt_addr_copy(addr);
169 mutt_addr_to_local(copy);
170 mutt_addr_write(buf, copy, false);
171 mutt_addr_free(&copy);
172
173 if (create_gpgme_context(&ctx))
174 goto cleanup;
175
176 /* L10N: Message displayed just before a GPG key is generated for a created
177 autocrypt account. */
178 mutt_message(_("Generating autocrypt key..."));
179
180 /* Primary key */
181 gpgme_error_t err = gpgme_op_createkey(ctx, buf_string(buf), "ed25519", 0, 0, NULL,
182 GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE |
183 GPGME_CREATE_NOEXPIRE);
184 if (err != GPG_ERR_NO_ERROR)
185 {
186 /* L10N: GPGME was unable to generate a key for some reason.
187 %s is the error message returned by GPGME. */
188 mutt_error(_("Error creating autocrypt key: %s"), gpgme_strerror(err));
189 goto cleanup;
190 }
191 keyresult = gpgme_op_genkey_result(ctx);
192 if (!keyresult->fpr)
193 goto cleanup;
194 buf_strcpy(keyid, keyresult->fpr);
195 mutt_debug(LL_DEBUG1, "Generated key with id %s\n", buf_string(keyid));
196
197 /* Get gpgme_key_t to create the secondary key and export keydata */
198 err = gpgme_get_key(ctx, buf_string(keyid), &primary_key, 0);
199 if (err)
200 goto cleanup;
201
202 /* Secondary key */
203 err = gpgme_op_createsubkey(ctx, primary_key, "cv25519", 0, 0,
204 GPGME_CREATE_NOPASSWD | GPGME_CREATE_NOEXPIRE);
205 if (err != GPG_ERR_NO_ERROR)
206 {
207 mutt_error(_("Error creating autocrypt key: %s"), gpgme_strerror(err));
208 goto cleanup;
209 }
210
211 /* get keydata */
212 if (export_keydata(ctx, primary_key, keydata))
213 goto cleanup;
214 mutt_debug(LL_DEBUG1, "key has keydata *%s*\n", buf_string(keydata));
215
216 rc = 0;
217
218cleanup:
219 gpgme_key_unref(primary_key);
220 gpgme_release(ctx);
221 buf_pool_release(&buf);
222 return rc;
223}
224
232int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata)
233{
234 int rc = -1;
235 gpgme_ctx_t ctx = NULL;
236 gpgme_key_t key = NULL;
237
238 OptAutocryptGpgme = true;
240 goto cleanup;
241
242 if (create_gpgme_context(&ctx))
243 goto cleanup;
244
245 if (gpgme_get_key(ctx, buf_string(keyid), &key, 0))
246 goto cleanup;
247
248 if (key->revoked || key->expired || key->disabled || key->invalid ||
249 !key->can_encrypt || !key->can_sign)
250 {
251 /* L10N: After selecting a key for an autocrypt account,
252 this is displayed if the key was revoked/expired/disabled/invalid
253 or can't be used for both signing and encryption.
254 %s is the key fingerprint. */
255 mutt_error(_("The key %s is not usable for autocrypt"), buf_string(keyid));
256 goto cleanup;
257 }
258
259 if (export_keydata(ctx, key, keydata))
260 goto cleanup;
261
262 rc = 0;
263
264cleanup:
265 OptAutocryptGpgme = false;
266 gpgme_key_unref(key);
267 gpgme_release(ctx);
268 return rc;
269}
270
280 struct Buffer *keydata)
281{
282 int rc = -1;
283
284 /* L10N: During autocrypt account creation, this prompt asks the
285 user whether they want to create a new GPG key for the account,
286 or select an existing account from the keyring. */
287 const char *prompt = _("(c)reate new, or (s)elect existing GPG key?");
288 /* L10N: The letters corresponding to the
289 "(c)reate new, or (s)elect existing GPG key?" prompt. */
290 const char *letters = _("cs");
291
292 int choice = mw_multi_choice(prompt, letters);
293 switch (choice)
294 {
295 case 2: /* select existing */
296 rc = mutt_autocrypt_gpgme_select_key(keyid, keydata);
297 if (rc == 0)
298 break;
299
300 /* L10N: During autocrypt account creation, if selecting an existing key fails
301 for some reason, we prompt to see if they want to create a key instead. */
302 if (query_yesorno(_("Create a new GPG key for this account, instead?"), MUTT_YES) != MUTT_YES)
303 break;
305
306 case 1: /* create new */
307 rc = mutt_autocrypt_gpgme_create_key(addr, keyid, keydata);
308 }
309
310 return rc;
311}
312
320int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
321{
322 int rc = -1;
323 gpgme_ctx_t ctx = NULL;
324 gpgme_data_t dh = NULL;
325 struct Buffer *raw_keydata = NULL;
326
327 if (create_gpgme_context(&ctx))
328 goto cleanup;
329
330 raw_keydata = buf_pool_get();
331 if (!mutt_b64_buffer_decode(raw_keydata, keydata))
332 goto cleanup;
333
334 if (gpgme_data_new_from_mem(&dh, buf_string(raw_keydata), buf_len(raw_keydata), 0))
335 {
336 goto cleanup;
337 }
338
339 if (gpgme_op_import(ctx, dh))
340 goto cleanup;
341
342 gpgme_import_result_t result = gpgme_op_import_result(ctx);
343 if (!result->imports || !result->imports->fpr)
344 goto cleanup;
345 buf_strcpy(keyid, result->imports->fpr);
346
347 rc = 0;
348
349cleanup:
350 gpgme_data_release(dh);
351 gpgme_release(ctx);
352 buf_pool_release(&raw_keydata);
353 return rc;
354}
355
362{
363 bool rc = false;
364 gpgme_ctx_t ctx = NULL;
365 gpgme_key_t key = NULL;
366
367 if (!keyid)
368 return false;
369
370 if (create_gpgme_context(&ctx))
371 goto cleanup;
372
373 if (gpgme_get_key(ctx, keyid, &key, 0))
374 goto cleanup;
375
376 rc = true;
377 if (key->revoked || key->expired || key->disabled || key->invalid || !key->can_encrypt)
378 rc = false;
379
380cleanup:
381 gpgme_key_unref(key);
382 gpgme_release(ctx);
383 return rc;
384}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:462
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1050
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:745
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1340
Email Address Handling.
size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:198
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:216
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:168
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
Definition: crypt_gpgme.c:3685
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: globals.c:62
bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid)
Is a key id valid?
Definition: gpgme.c:361
int mutt_autocrypt_gpgme_create_key(struct Address *addr, struct Buffer *keyid, struct Buffer *keydata)
Create a GPGME key.
Definition: gpgme.c:158
int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata)
Select a Autocrypt key.
Definition: gpgme.c:232
int mutt_autocrypt_gpgme_init(void)
Initialise GPGME.
Definition: gpgme.c:70
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:51
int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
Read a key from GPGME.
Definition: gpgme.c:320
static int export_keydata(gpgme_ctx_t ctx, gpgme_key_t key, struct Buffer *keydata)
Export Key data from GPGME into a Buffer.
Definition: gpgme.c:84
int mutt_autocrypt_gpgme_select_or_create_key(struct Address *addr, struct Buffer *keyid, struct Buffer *keydata)
Ask the user to select or create an Autocrypt key.
Definition: gpgme.c:279
void pgp_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
Definition: crypt_gpgme.c:3865
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition: lib.h:111
#define _(a)
Definition: message.h:28
API for encryption/signing of emails.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:326
GUI display the mailboxes in a side panel.
An email address.
Definition: address.h:36
String manipulation buffer.
Definition: buffer.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46