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