NeoMutt  2020-08-07-1-gab41a1
Teaching an old dog new tricks
DOXYGEN
gpgme.c File Reference

Autocrypt GPGME handler. More...

#include "config.h"
#include <stddef.h>
#include <gpgme.h>
#include <stdbool.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "gui/lib.h"
#include "lib.h"
#include "ncrypt/lib.h"
#include "options.h"
+ Include dependency graph for gpgme.c:

Go to the source code of this file.

Functions

static int create_gpgme_context (gpgme_ctx_t *ctx)
 Create a GPGME context. More...
 
int mutt_autocrypt_gpgme_init (void)
 Initialise GPGME. More...
 
static int export_keydata (gpgme_ctx_t ctx, gpgme_key_t key, struct Buffer *keydata)
 Export Key data from GPGME into a Buffer. More...
 
int mutt_autocrypt_gpgme_create_key (struct Address *addr, struct Buffer *keyid, struct Buffer *keydata)
 Create a GPGME key. More...
 
int mutt_autocrypt_gpgme_select_key (struct Buffer *keyid, struct Buffer *keydata)
 Select a Autocrypt key. More...
 
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. More...
 
int mutt_autocrypt_gpgme_import_key (const char *keydata, struct Buffer *keyid)
 Read a key from GPGME. More...
 
bool mutt_autocrypt_gpgme_is_valid_key (const char *keyid)
 Is a key id valid? More...
 

Detailed Description

Autocrypt GPGME handler.

Authors
  • Kevin J. McCarthy

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file gpgme.c.

Function Documentation

◆ create_gpgme_context()

static int create_gpgme_context ( gpgme_ctx_t *  ctx)
static

Create a GPGME context.

Parameters
ctxGPGME context to initialise
Return values
0Success
-1Error

Definition at line 48 of file gpgme.c.

49 {
50  gpgme_error_t err = gpgme_new(ctx);
51  if (!err)
52  err = gpgme_ctx_set_engine_info(*ctx, GPGME_PROTOCOL_OpenPGP, NULL, C_AutocryptDir);
53  if (err)
54  {
55  mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
56  return -1;
57  }
58 
59  return 0;
60 }
char * C_AutocryptDir
Config: Location of autocrypt files, including the GPG keyring and SQLite database.
Definition: config.c:40
#define _(a)
Definition: message.h:28
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ mutt_autocrypt_gpgme_init()

int mutt_autocrypt_gpgme_init ( void  )

Initialise GPGME.

Definition at line 65 of file gpgme.c.

66 {
68  return 0;
69 }
void pgp_gpgme_init(void)
Implements CryptModuleSpecs::init()
Definition: crypt_gpgme.c:4130
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ export_keydata()

static int export_keydata ( gpgme_ctx_t  ctx,
gpgme_key_t  key,
struct Buffer keydata 
)
static

Export Key data from GPGME into a Buffer.

Parameters
ctxGPGME context
keyGPGME key
keydataBuffer for results
Return values
0Success
-1Error

Definition at line 79 of file gpgme.c.

80 {
81  int rc = -1;
82  gpgme_data_t dh = NULL;
83  gpgme_key_t export_keys[2] = { 0 };
84  size_t export_data_len;
85 
86  if (gpgme_data_new(&dh))
87  goto cleanup;
88 
89  /* This doesn't seem to work */
90 #if 0
91  if (gpgme_data_set_encoding (dh, GPGME_DATA_ENCODING_BASE64))
92  goto cleanup;
93 #endif
94 
95  export_keys[0] = key;
96  export_keys[1] = NULL;
97  if (gpgme_op_export_keys(ctx, export_keys, GPGME_EXPORT_MODE_MINIMAL, dh))
98  goto cleanup;
99 
100  char *export_data = gpgme_data_release_and_get_mem(dh, &export_data_len);
101  dh = NULL;
102 
103  mutt_b64_buffer_encode(keydata, export_data, export_data_len);
104  gpgme_free(export_data);
105  export_data = NULL;
106 
107  rc = 0;
108 
109 cleanup:
110  gpgme_data_release(dh);
111  return rc;
112 }
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_gpgme_create_key()

int mutt_autocrypt_gpgme_create_key ( struct Address addr,
struct Buffer keyid,
struct Buffer keydata 
)

Create a GPGME key.

Parameters
addrEmail Address
keyidKey id
keydataKey data
Return values
0Success
-1Error

Definition at line 153 of file gpgme.c.

155 {
156  int rc = -1;
157  gpgme_ctx_t ctx = NULL;
158  gpgme_genkey_result_t keyresult = NULL;
159  gpgme_key_t primary_key = NULL;
160  char buf[1024] = { 0 };
161 
162  /* GPGME says addresses should not be in idna form */
163  struct Address *copy = mutt_addr_copy(addr);
164  mutt_addr_to_local(copy);
165  mutt_addr_write(buf, sizeof(buf), copy, false);
166  mutt_addr_free(&copy);
167 
168  if (create_gpgme_context(&ctx))
169  goto cleanup;
170 
171  /* L10N: Message displayed just before a GPG key is generated for a created
172  autocrypt account. */
173  mutt_message(_("Generating autocrypt key..."));
174 
175  /* Primary key */
176  gpgme_error_t err = gpgme_op_createkey(ctx, buf, "ed25519", 0, 0, NULL,
177  GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE |
178  GPGME_CREATE_NOEXPIRE);
179  if (err)
180  {
181  /* L10N: GPGME was unable to generate a key for some reason.
182  %s is the error message returned by GPGME. */
183  mutt_error(_("Error creating autocrypt key: %s"), gpgme_strerror(err));
184  goto cleanup;
185  }
186  keyresult = gpgme_op_genkey_result(ctx);
187  if (!keyresult->fpr)
188  goto cleanup;
189  mutt_buffer_strcpy(keyid, keyresult->fpr);
190  mutt_debug(LL_DEBUG1, "Generated key with id %s\n", mutt_b2s(keyid));
191 
192  /* Get gpgme_key_t to create the secondary key and export keydata */
193  err = gpgme_get_key(ctx, mutt_b2s(keyid), &primary_key, 0);
194  if (err)
195  goto cleanup;
196 
197  /* Secondary key */
198  err = gpgme_op_createsubkey(ctx, primary_key, "cv25519", 0, 0,
199  GPGME_CREATE_NOPASSWD | GPGME_CREATE_NOEXPIRE);
200  if (err)
201  {
202  mutt_error(_("Error creating autocrypt key: %s"), gpgme_strerror(err));
203  goto cleanup;
204  }
205 
206  /* get keydata */
207  if (export_keydata(ctx, primary_key, keydata))
208  goto cleanup;
209  mutt_debug(LL_DEBUG1, "key has keydata *%s*\n", mutt_b2s(keydata));
210 
211  rc = 0;
212 
213 cleanup:
214  gpgme_key_unref(primary_key);
215  gpgme_release(ctx);
216  return rc;
217 }
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:79
#define mutt_message(...)
Definition: logging.h:83
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:34
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
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1349
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
#define mutt_b2s(buf)
Definition: buffer.h:41
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_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_gpgme_select_key()

int mutt_autocrypt_gpgme_select_key ( struct Buffer keyid,
struct Buffer keydata 
)

Select a Autocrypt key.

Parameters
[in]keyidKey id to select
[out]keydataBuffer for resulting Key data
Return values
0Success
-1Error

Definition at line 226 of file gpgme.c.

227 {
228  int rc = -1;
229  gpgme_ctx_t ctx = NULL;
230  gpgme_key_t key = NULL;
231 
232  OptAutocryptGpgme = true;
233  if (mutt_gpgme_select_secret_key(keyid))
234  goto cleanup;
235 
236  if (create_gpgme_context(&ctx))
237  goto cleanup;
238 
239  if (gpgme_get_key(ctx, mutt_b2s(keyid), &key, 0))
240  goto cleanup;
241 
242  if (key->revoked || key->expired || key->disabled || key->invalid ||
243  !key->can_encrypt || !key->can_sign)
244  {
245  /* L10N: After selecting a key for an autocrypt account,
246  this is displayed if the key was revoked/expired/disabled/invalid
247  or can't be used for both signing and encryption.
248  %s is the key fingerprint. */
249  mutt_error(_("The key %s is not usable for autocrypt"), mutt_b2s(keyid));
250  goto cleanup;
251  }
252 
253  if (export_keydata(ctx, key, keydata))
254  goto cleanup;
255 
256  rc = 0;
257 
258 cleanup:
259  OptAutocryptGpgme = false;
260  gpgme_key_unref(key);
261  gpgme_release(ctx);
262  return rc;
263 }
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:79
#define _(a)
Definition: message.h:28
WHERE bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:33
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:48
#define mutt_b2s(buf)
Definition: buffer.h:41
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
Definition: crypt_gpgme.c:3942
#define mutt_error(...)
Definition: logging.h:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_gpgme_select_or_create_key()

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.

Parameters
addrEmail Address
keyidKey id
keydataKey data
Return values
0Success
-1Error

Definition at line 273 of file gpgme.c.

275 {
276  int rc = -1;
277 
278  /* L10N: During autocrypt account creation, this prompt asks the
279  user whether they want to create a new GPG key for the account,
280  or select an existing account from the keyring. */
281  const char *prompt = _("(c)reate new, or (s)elect existing GPG key?");
282  /* L10N: The letters corresponding to the
283  "(c)reate new, or (s)elect existing GPG key?" prompt. */
284  const char *letters = _("cs");
285 
286  int choice = mutt_multi_choice(prompt, letters);
287  switch (choice)
288  {
289  case 2: /* select existing */
290  rc = mutt_autocrypt_gpgme_select_key(keyid, keydata);
291  if (rc == 0)
292  break;
293 
294  /* L10N: During autocrypt account creation, if selecting an existing key fails
295  for some reason, we prompt to see if they want to create a key instead. */
296  if (mutt_yesorno(_("Create a new GPG key for this account, instead?"), MUTT_YES) == MUTT_NO)
297  break;
298  /* fallthrough */
299 
300  case 1: /* create new */
301  rc = mutt_autocrypt_gpgme_create_key(addr, keyid, keydata);
302  }
303 
304  return rc;
305 }
int mutt_autocrypt_gpgme_create_key(struct Address *addr, struct Buffer *keyid, struct Buffer *keydata)
Create a GPGME key.
Definition: gpgme.c:153
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
#define _(a)
Definition: message.h:28
int mutt_autocrypt_gpgme_select_key(struct Buffer *keyid, struct Buffer *keydata)
Select a Autocrypt key.
Definition: gpgme.c:226
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:933
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_gpgme_import_key()

int mutt_autocrypt_gpgme_import_key ( const char *  keydata,
struct Buffer keyid 
)

Read a key from GPGME.

Parameters
keydataBuffer for key data
keyidBuffer for key id
Return values
0Success
-1Error

Definition at line 314 of file gpgme.c.

315 {
316  int rc = -1;
317  gpgme_ctx_t ctx = NULL;
318  gpgme_data_t dh = NULL;
319 
320  if (create_gpgme_context(&ctx))
321  goto cleanup;
322 
323  struct Buffer *raw_keydata = mutt_buffer_pool_get();
324  if (!mutt_b64_buffer_decode(raw_keydata, keydata))
325  goto cleanup;
326 
327  if (gpgme_data_new_from_mem(&dh, mutt_b2s(raw_keydata), mutt_buffer_len(raw_keydata), 0))
328  goto cleanup;
329 
330  if (gpgme_op_import(ctx, dh))
331  goto cleanup;
332 
333  gpgme_import_result_t result = gpgme_op_import_result(ctx);
334  if (!result->imports || !result->imports->fpr)
335  goto cleanup;
336  mutt_buffer_strcpy(keyid, result->imports->fpr);
337 
338  rc = 0;
339 
340 cleanup:
341  gpgme_data_release(dh);
342  gpgme_release(ctx);
343  mutt_buffer_pool_release(&raw_keydata);
344  return rc;
345 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:48
#define mutt_b2s(buf)
Definition: buffer.h:41
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:209
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_gpgme_is_valid_key()

bool mutt_autocrypt_gpgme_is_valid_key ( const char *  keyid)

Is a key id valid?

Parameters
keyidKey id to check
Return values
trueIf key id is valid

Definition at line 352 of file gpgme.c.

353 {
354  bool rc = false;
355  gpgme_ctx_t ctx = NULL;
356  gpgme_key_t key = NULL;
357 
358  if (!keyid)
359  return false;
360 
361  if (create_gpgme_context(&ctx))
362  goto cleanup;
363 
364  if (gpgme_get_key(ctx, keyid, &key, 0))
365  goto cleanup;
366 
367  rc = true;
368  if (key->revoked || key->expired || key->disabled || key->invalid || !key->can_encrypt)
369  rc = false;
370 
371 cleanup:
372  gpgme_key_unref(key);
373  gpgme_release(ctx);
374  return rc;
375 }
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function: