NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
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 "options.h"
41 
48 static int create_gpgme_context(gpgme_ctx_t *ctx)
49 {
50  const char *const c_autocrypt_dir =
51  cs_subset_path(NeoMutt->sub, "autocrypt_dir");
52  gpgme_error_t err = gpgme_new(ctx);
53  if (!err)
54  err = gpgme_ctx_set_engine_info(*ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
55  if (err)
56  {
57  mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
58  return -1;
59  }
60 
61  return 0;
62 }
63 
68 {
70  return 0;
71 }
72 
81 static 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 
111 cleanup:
112  gpgme_data_release(dh);
113  return rc;
114 }
115 
116 #if 0
117 
124 int 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;
140 cleanup:
141  gpgme_key_unref(key);
142  gpgme_release(ctx);
143  return rc;
144 }
145 #endif
146 
155 int 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  char buf[1024] = { 0 };
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, sizeof(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, "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  mutt_buffer_strcpy(keyid, keyresult->fpr);
192  mutt_debug(LL_DEBUG1, "Generated key with id %s\n", mutt_buffer_string(keyid));
193 
194  /* Get gpgme_key_t to create the secondary key and export keydata */
195  err = gpgme_get_key(ctx, mutt_buffer_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", mutt_buffer_string(keydata));
212 
213  rc = 0;
214 
215 cleanup:
216  gpgme_key_unref(primary_key);
217  gpgme_release(ctx);
218  return rc;
219 }
220 
228 int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata)
229 {
230  int rc = -1;
231  gpgme_ctx_t ctx = NULL;
232  gpgme_key_t key = NULL;
233 
234  OptAutocryptGpgme = true;
235  if (mutt_gpgme_select_secret_key(keyid))
236  goto cleanup;
237 
238  if (create_gpgme_context(&ctx))
239  goto cleanup;
240 
241  if (gpgme_get_key(ctx, mutt_buffer_string(keyid), &key, 0))
242  goto cleanup;
243 
244  if (key->revoked || key->expired || key->disabled || key->invalid ||
245  !key->can_encrypt || !key->can_sign)
246  {
247  /* L10N: After selecting a key for an autocrypt account,
248  this is displayed if the key was revoked/expired/disabled/invalid
249  or can't be used for both signing and encryption.
250  %s is the key fingerprint. */
251  mutt_error(_("The key %s is not usable for autocrypt"), mutt_buffer_string(keyid));
252  goto cleanup;
253  }
254 
255  if (export_keydata(ctx, key, keydata))
256  goto cleanup;
257 
258  rc = 0;
259 
260 cleanup:
261  OptAutocryptGpgme = false;
262  gpgme_key_unref(key);
263  gpgme_release(ctx);
264  return rc;
265 }
266 
276  struct Buffer *keydata)
277 {
278  int rc = -1;
279 
280  /* L10N: During autocrypt account creation, this prompt asks the
281  user whether they want to create a new GPG key for the account,
282  or select an existing account from the keyring. */
283  const char *prompt = _("(c)reate new, or (s)elect existing GPG key?");
284  /* L10N: The letters corresponding to the
285  "(c)reate new, or (s)elect existing GPG key?" prompt. */
286  const char *letters = _("cs");
287 
288  int choice = mutt_multi_choice(prompt, letters);
289  switch (choice)
290  {
291  case 2: /* select existing */
292  rc = mutt_autocrypt_gpgme_select_key(keyid, keydata);
293  if (rc == 0)
294  break;
295 
296  /* L10N: During autocrypt account creation, if selecting an existing key fails
297  for some reason, we prompt to see if they want to create a key instead. */
298  if (mutt_yesorno(_("Create a new GPG key for this account, instead?"), MUTT_YES) == MUTT_NO)
299  break;
300  /* fallthrough */
301 
302  case 1: /* create new */
303  rc = mutt_autocrypt_gpgme_create_key(addr, keyid, keydata);
304  }
305 
306  return rc;
307 }
308 
316 int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
317 {
318  int rc = -1;
319  gpgme_ctx_t ctx = NULL;
320  gpgme_data_t dh = NULL;
321 
322  if (create_gpgme_context(&ctx))
323  goto cleanup;
324 
325  struct Buffer *raw_keydata = mutt_buffer_pool_get();
326  if (!mutt_b64_buffer_decode(raw_keydata, keydata))
327  goto cleanup;
328 
329  if (gpgme_data_new_from_mem(&dh, mutt_buffer_string(raw_keydata),
330  mutt_buffer_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  mutt_buffer_strcpy(keyid, result->imports->fpr);
342 
343  rc = 0;
344 
345 cleanup:
346  gpgme_data_release(dh);
347  gpgme_release(ctx);
348  mutt_buffer_pool_release(&raw_keydata);
349  return rc;
350 }
351 
357 bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid)
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 
376 cleanup:
377  gpgme_key_unref(key);
378  gpgme_release(ctx);
379  return rc;
380 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
int mutt_autocrypt_gpgme_init(void)
Initialise GPGME.
Definition: gpgme.c:67
#define mutt_error(...)
Definition: logging.h:88
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_create_key(struct Address *addr, struct Buffer *keyid, struct Buffer *keydata)
Create a GPGME key.
Definition: gpgme.c:155
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:35
WHERE bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:33
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
Container for Accounts, Notifications.
Definition: neomutt.h:36
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1351
int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata)
Select a Autocrypt key.
Definition: gpgme.c:228
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:191
Convenience wrapper for the config headers.
Email Address Handling.
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Convenience wrapper for the core headers.
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:275
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:48
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid)
Is a key id valid?
Definition: gpgme.c:357
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
Definition: crypt_gpgme.c:3976
Shared constants/structs that are private to Autocrypt.
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:209
API for encryption/signing of emails.
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:49
Ask the user a question.
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Log at debug level 1.
Definition: logging.h:40
#define mutt_message(...)
Definition: logging.h:87
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
void pgp_gpgme_init(void)
Implements CryptModuleSpecs::init() -.
Definition: crypt_gpgme.c:4164
Handling of global boolean variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Convenience wrapper for the library headers.
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
Read a key from GPGME.
Definition: gpgme.c:316