Delta Chat Core C-Library
mrpgp.c
1 /*******************************************************************************
2  *
3  * Delta Chat Core
4  * Copyright (C) 2017 Björn Petersen
5  * Contact: r10s@b44t.com, http://b44t.com
6  *
7  * This program is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later
10  * version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program. If not, see http://www.gnu.org/licenses/ .
19  *
20  ******************************************************************************/
21 
22 
23 /* End-to-end-encryption and other cryptographic functions based upon OpenSSL
24 and BSD's netpgp.
25 
26 If we want to switch to other encryption engines, here are the functions to
27 be replaced.
28 
29 However, eg. GpgME cannot (easily) be used standalone and GnuPG's licence
30 would not allow the original creator of Delta Chat to release a proprietary
31 version, which, however, is required for the Apple store. (NB: the original
32 creator is the only person who could do this, a normal licensee is not
33 allowed to do so at all)
34 
35 So, we do not see a simple alternative - but everyone is welcome to implement
36 one :-) */
37 
38 
39 #include <openssl/ssl.h>
40 #include <openssl/rand.h>
41 #include <openssl/rsa.h>
42 #include <openssl/evp.h>
43 #include <netpgp-extra.h>
44 #include "mrmailbox_internal.h"
45 #include "mrkey.h"
46 #include "mrkeyring.h"
47 #include "mrpgp.h"
48 
49 
50 static pgp_io_t s_io;
51 
52 
53 void mrpgp_init(mrmailbox_t* mailbox)
54 {
55  #ifdef __APPLE__
56  OPENSSL_init();
57  #else
58  SSL_library_init(); /* older, but more compatible function, simply defined as OPENSSL_init_ssl().
59  SSL_library_init() should be called from the main thread before OpenSSL is called from other threads.
60  libEtPan may call SSL_library_init() again later, however, this should be no problem.
61  SSL_library_init() always returns "1", so it is safe to discard the return value */
62  #endif
63 
64  /* setup i/o structure */
65  memset(&s_io, 0, sizeof(pgp_io_t));
66  s_io.outs = stdout;
67  s_io.errs = stderr;
68  s_io.res = stderr;
69 }
70 
71 
72 void mrpgp_exit(mrmailbox_t* mailbox)
73 {
74 }
75 
76 
77 void mrpgp_rand_seed(mrmailbox_t* mailbox, const void* buf, size_t bytes)
78 {
79  if( buf == NULL || bytes <= 0 ) {
80  return;
81  }
82 
83  RAND_seed(buf, bytes);
84 }
85 
86 
87 /*******************************************************************************
88  * Key generatation
89  ******************************************************************************/
90 
91 
92 static unsigned add_key_prefs(pgp_create_sig_t *sig)
93 {
94  /* similar to pgp_add_key_prefs(), Mimic of GPG default settings, limited to supported algos */
95  return
96  /* Symmetric algo prefs */
97  pgp_write_ss_header(sig->output, 6, PGP_PTAG_SS_PREFERRED_SKA) &&
98  pgp_write_scalar(sig->output, PGP_SA_AES_256, 1) &&
99  pgp_write_scalar(sig->output, PGP_SA_AES_128, 1) &&
100  pgp_write_scalar(sig->output, PGP_SA_CAST5, 1) &&
101  pgp_write_scalar(sig->output, PGP_SA_TRIPLEDES, 1) &&
102  pgp_write_scalar(sig->output, PGP_SA_IDEA, 1) &&
103 
104  /* Hash algo prefs, the first algo is the preferred algo */
105  pgp_write_ss_header(sig->output, 6, PGP_PTAG_SS_PREFERRED_HASH) &&
106  pgp_write_scalar(sig->output, PGP_HASH_SHA256, 1) &&
107  pgp_write_scalar(sig->output, PGP_HASH_SHA384, 1) &&
108  pgp_write_scalar(sig->output, PGP_HASH_SHA512, 1) &&
109  pgp_write_scalar(sig->output, PGP_HASH_SHA224, 1) &&
110  pgp_write_scalar(sig->output, PGP_HASH_SHA1, 1) && /* Edit for Autocrypt/Delta Chat: due to the weak SHA1, it should not be preferred */
111 
112  /* Compression algo prefs */
113  pgp_write_ss_header(sig->output, 2/*1+number of following items*/, PGP_PTAG_SS_PREF_COMPRESS) &&
114  pgp_write_scalar(sig->output, PGP_C_ZLIB, 1) /*&& -- not sure if Delta Chat will support bzip2 on all platforms, however, this is not that important as typical files are compressed themselves and text is not that big
115  pgp_write_scalar(sig->output, PGP_C_BZIP2, 1) -- if you re-enable this, do not forget to modifiy the header count*/;
116 }
117 
118 
119 static void add_selfsigned_userid(pgp_key_t *skey, pgp_key_t *pkey, const uint8_t *userid, time_t key_expiry)
120 {
121  /* similar to pgp_add_selfsigned_userid() which, however, uses different key flags */
122  pgp_create_sig_t *sig;
123  pgp_subpacket_t sigpacket;
124  pgp_memory_t *mem_sig = NULL;
125  pgp_output_t *sigoutput = NULL;
126 
127  /* create sig for this pkt */
128  sig = pgp_create_sig_new();
129  pgp_sig_start_key_sig(sig, &skey->key.seckey.pubkey, NULL, userid, PGP_CERT_POSITIVE);
130 
131  pgp_add_creation_time(sig, time(NULL));
132  pgp_add_key_expiration_time(sig, key_expiry);
133  pgp_add_primary_userid(sig, 1);
134  pgp_add_key_flags(sig, PGP_KEYFLAG_SIGN_DATA|PGP_KEYFLAG_CERT_KEYS);
135  add_key_prefs(sig);
136  pgp_add_key_features(sig); /* will add 0x01 - modification detection */
137 
138  pgp_end_hashed_subpkts(sig);
139 
140  pgp_add_issuer_keyid(sig, skey->pubkeyid); /* the issuer keyid is not hashed by definition */
141 
142  pgp_setup_memory_write(&sigoutput, &mem_sig, 128);
143  pgp_write_sig(sigoutput, sig, &skey->key.seckey.pubkey, &skey->key.seckey);
144 
145  /* add this packet to key */
146  sigpacket.length = pgp_mem_len(mem_sig);
147  sigpacket.raw = pgp_mem_data(mem_sig);
148 
149  /* add user id and signature to key */
150  pgp_update_userid(skey, userid, &sigpacket, &sig->sig.info);
151  if(pkey) {
152  pgp_update_userid(pkey, userid, &sigpacket, &sig->sig.info);
153  }
154 
155  /* cleanup */
156  pgp_create_sig_delete(sig);
157  pgp_output_delete(sigoutput);
158  pgp_memory_free(mem_sig);
159 }
160 
161 
162 static void add_subkey_binding_signature(pgp_subkeysig_t* p, pgp_key_t* primarykey, pgp_key_t* subkey, pgp_key_t* seckey)
163 {
164  /*add "0x18: Subkey Binding Signature" packet, PGP_SIG_SUBKEY */
165  pgp_create_sig_t* sig;
166  pgp_output_t* sigoutput = NULL;
167  pgp_memory_t* mem_sig = NULL;
168 
169  sig = pgp_create_sig_new();
170  pgp_sig_start_key_sig(sig, &primarykey->key.pubkey, &subkey->key.pubkey, NULL, PGP_SIG_SUBKEY);
171 
172  pgp_add_creation_time(sig, time(NULL));
173  pgp_add_key_expiration_time(sig, 0);
174  pgp_add_key_flags(sig, PGP_KEYFLAG_ENC_STORAGE|PGP_KEYFLAG_ENC_COMM); /* NB: algo/hash/compression preferences are not added to subkeys */
175 
176  pgp_end_hashed_subpkts(sig);
177 
178  pgp_add_issuer_keyid(sig, seckey->pubkeyid); /* the issuer keyid is not hashed by definition */
179 
180  pgp_setup_memory_write(&sigoutput, &mem_sig, 128);
181  pgp_write_sig(sigoutput, sig, &seckey->key.seckey.pubkey, &seckey->key.seckey);
182 
183  p->subkey = primarykey->subkeyc-1; /* index of subkey in array */
184  p->packet.length = mem_sig->length;
185  p->packet.raw = mem_sig->buf; mem_sig->buf = NULL; /* move ownership to packet */
186  copy_sig_info(&p->siginfo, &sig->sig.info); /* not sure, if this is okay, however, siginfo should be set up, otherwise we get "bad info-type" errors */
187 
188  pgp_create_sig_delete(sig);
189  pgp_output_delete(sigoutput);
190  free(mem_sig); /* do not use pgp_memory_free() as this would also free mem_sig->buf which is owned by the packet */
191 }
192 
193 
194 int mrpgp_create_keypair(mrmailbox_t* mailbox, const char* addr, mrkey_t* ret_public_key, mrkey_t* ret_private_key)
195 {
196  int success = 0;
197  pgp_key_t seckey, pubkey, subkey;
198  uint8_t subkeyid[PGP_KEY_ID_SIZE];
199  uint8_t* user_id = NULL;
200  pgp_memory_t *pubmem = pgp_memory_new(), *secmem = pgp_memory_new();
201  pgp_output_t *pubout = pgp_output_new(), *secout = pgp_output_new();
202 
203  memset(&seckey, 0, sizeof(pgp_key_t));
204  memset(&pubkey, 0, sizeof(pgp_key_t));
205  memset(&subkey, 0, sizeof(pgp_key_t));
206 
207  if( mailbox==NULL || addr==NULL || ret_public_key==NULL || ret_private_key==NULL
208  || pubmem==NULL || secmem==NULL || pubout==NULL || secout==NULL ) {
209  goto cleanup;
210  }
211 
212  /* Generate User ID. For convention, use the same address as given in `Autocrypt: to=...` in angle brackets
213  (RFC 2822 grammar angle-addr, see also https://autocrypt.org/en/latest/level0.html#type-p-openpgp-based-key-data )
214  We do not add the name to the ID for the following reasons:
215  - privacy
216  - the name may be changed
217  - shorter keys
218  - the name is already taken from From:
219  - not Autocrypt:-standard */
220  user_id = (uint8_t*)mr_mprintf("<%s>", addr);
221 
222  /* generate two keypairs */
223  if( !pgp_rsa_generate_keypair(&seckey, 3072/*bits*/, 65537UL/*e*/, NULL, NULL, NULL, 0)
224  || !pgp_rsa_generate_keypair(&subkey, 3072/*bits*/, 65537UL/*e*/, NULL, NULL, NULL, 0) ) {
225  goto cleanup;
226  }
227 
228 
229  /* Create public key, bind public subkey to public key
230  ------------------------------------------------------------------------ */
231 
232  pubkey.type = PGP_PTAG_CT_PUBLIC_KEY;
233  pgp_pubkey_dup(&pubkey.key.pubkey, &seckey.key.pubkey);
234  memcpy(pubkey.pubkeyid, seckey.pubkeyid, PGP_KEY_ID_SIZE);
235  pgp_fingerprint(&pubkey.pubkeyfpr, &seckey.key.pubkey, 0);
236  add_selfsigned_userid(&seckey, &pubkey, (const uint8_t*)user_id, 0/*never expire*/);
237 
238  EXPAND_ARRAY((&pubkey), subkey);
239  {
240  pgp_subkey_t* p = &pubkey.subkeys[pubkey.subkeyc++];
241  pgp_pubkey_dup(&p->key.pubkey, &subkey.key.pubkey);
242  pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, &pubkey.key.pubkey, PGP_HASH_SHA1);
243  memcpy(p->id, subkeyid, PGP_KEY_ID_SIZE);
244  }
245 
246  EXPAND_ARRAY((&pubkey), subkeysig);
247  add_subkey_binding_signature(&pubkey.subkeysigs[pubkey.subkeysigc++], &pubkey, &subkey, &seckey);
248 
249 
250  /* Create secret key, bind secret subkey to secret key
251  ------------------------------------------------------------------------ */
252 
253  EXPAND_ARRAY((&seckey), subkey);
254  {
255  pgp_subkey_t* p = &seckey.subkeys[seckey.subkeyc++];
256  pgp_seckey_dup(&p->key.seckey, &subkey.key.seckey);
257  pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, &seckey.key.pubkey, PGP_HASH_SHA1);
258  memcpy(p->id, subkeyid, PGP_KEY_ID_SIZE);
259  }
260 
261  EXPAND_ARRAY((&seckey), subkeysig);
262  add_subkey_binding_signature(&seckey.subkeysigs[seckey.subkeysigc++], &seckey, &subkey, &seckey);
263 
264 
265  /* Done with key generation, write binary keys to memory
266  ------------------------------------------------------------------------ */
267 
268  pgp_writer_set_memory(pubout, pubmem);
269  if( !pgp_write_xfer_key(pubout, &pubkey, 0/*armored*/)
270  || pubmem->buf == NULL || pubmem->length <= 0 ) {
271  goto cleanup;
272  }
273 
274  pgp_writer_set_memory(secout, secmem);
275  if( !pgp_write_xfer_key(secout, &seckey, 0/*armored*/)
276  || secmem->buf == NULL || secmem->length <= 0 ) {
277  goto cleanup;
278  }
279 
280  mrkey_set_from_raw(ret_public_key, pubmem->buf, pubmem->length, MR_PUBLIC);
281  mrkey_set_from_raw(ret_private_key, secmem->buf, secmem->length, MR_PRIVATE);
282 
283  success = 1;
284 
285 cleanup:
286  if( pubout ) { pgp_output_delete(pubout); }
287  if( secout ) { pgp_output_delete(secout); }
288  if( pubmem ) { pgp_memory_free(pubmem); }
289  if( secmem ) { pgp_memory_free(secmem); }
290  pgp_key_free(&seckey); /* not: pgp_keydata_free() which will also free the pointer itself (we created it on the stack) */
291  pgp_key_free(&pubkey);
292  pgp_key_free(&subkey);
293  free(user_id);
294  return success;
295 }
296 
297 
298 /*******************************************************************************
299  * Check keys
300  ******************************************************************************/
301 
302 
303 int mrpgp_is_valid_key(mrmailbox_t* mailbox, const mrkey_t* raw_key)
304 {
305  int key_is_valid = 0;
306  pgp_keyring_t* public_keys = calloc(1, sizeof(pgp_keyring_t));
307  pgp_keyring_t* private_keys = calloc(1, sizeof(pgp_keyring_t));
308  pgp_memory_t* keysmem = pgp_memory_new();
309 
310  if( mailbox==NULL || raw_key==NULL
311  || raw_key->m_binary == NULL || raw_key->m_bytes <= 0
312  || public_keys==NULL || private_keys==NULL || keysmem==NULL ) {
313  goto cleanup;
314  }
315 
316  pgp_memory_add(keysmem, raw_key->m_binary, raw_key->m_bytes);
317 
318  pgp_filter_keys_from_mem(&s_io, public_keys, private_keys, NULL, 0, keysmem); /* function returns 0 on any error in any packet - this does not mean, we cannot use the key. We check the details below therefore. */
319 
320  if( raw_key->m_type == MR_PUBLIC && public_keys->keyc >= 1 ) {
321  key_is_valid = 1;
322  }
323  else if( raw_key->m_type == MR_PRIVATE && private_keys->keyc >= 1 ) {
324  key_is_valid = 1;
325  }
326 
327 cleanup:
328  if( keysmem ) { pgp_memory_free(keysmem); }
329  if( public_keys ) { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
330  if( private_keys ) { pgp_keyring_purge(private_keys); free(private_keys); }
331  return key_is_valid;
332 }
333 
334 
335 int mrpgp_calc_fingerprint(mrmailbox_t* mailbox, const mrkey_t* raw_key, uint8_t** ret_fingerprint, size_t* ret_fingerprint_bytes)
336 {
337  int success = 0;
338  pgp_keyring_t* public_keys = calloc(1, sizeof(pgp_keyring_t));
339  pgp_keyring_t* private_keys = calloc(1, sizeof(pgp_keyring_t));
340  pgp_memory_t* keysmem = pgp_memory_new();
341 
342  if( mailbox==NULL || raw_key==NULL || ret_fingerprint==NULL || *ret_fingerprint!=NULL || ret_fingerprint_bytes==NULL || *ret_fingerprint_bytes!=0
343  || raw_key->m_binary == NULL || raw_key->m_bytes <= 0
344  || public_keys==NULL || private_keys==NULL || keysmem==NULL ) {
345  goto cleanup;
346  }
347 
348  pgp_memory_add(keysmem, raw_key->m_binary, raw_key->m_bytes);
349 
350  pgp_filter_keys_from_mem(&s_io, public_keys, private_keys, NULL, 0, keysmem);
351 
352  if( raw_key->m_type != MR_PUBLIC || public_keys->keyc <= 0 ) {
353  goto cleanup;
354  }
355 
356  pgp_key_t* key0 = &public_keys->keys[0];
357  pgp_pubkey_t* pubkey0 = &key0->key.pubkey;
358  if( !pgp_fingerprint(&key0->pubkeyfpr, pubkey0, 0) ) {
359  goto cleanup;
360  }
361 
362  *ret_fingerprint_bytes = key0->pubkeyfpr.length;
363  *ret_fingerprint = malloc(*ret_fingerprint_bytes);
364  memcpy(*ret_fingerprint, key0->pubkeyfpr.fingerprint, *ret_fingerprint_bytes);
365 
366  success = 1;
367 
368 cleanup:
369  if( keysmem ) { pgp_memory_free(keysmem); }
370  if( public_keys ) { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
371  if( private_keys ) { pgp_keyring_purge(private_keys); free(private_keys); }
372  return success;
373 }
374 
375 
376 int mrpgp_split_key(mrmailbox_t* mailbox, const mrkey_t* private_in, mrkey_t* ret_public_key)
377 {
378  int success = 0;
379  pgp_keyring_t* public_keys = calloc(1, sizeof(pgp_keyring_t));
380  pgp_keyring_t* private_keys = calloc(1, sizeof(pgp_keyring_t));
381  pgp_memory_t* keysmem = pgp_memory_new();
382  pgp_memory_t* pubmem = pgp_memory_new();
383  pgp_output_t* pubout = pgp_output_new();
384 
385  if( mailbox == NULL || private_in==NULL || ret_public_key==NULL
386  || public_keys==NULL || private_keys==NULL || keysmem==NULL || pubmem==NULL || pubout==NULL ) {
387  goto cleanup;
388  }
389 
390  pgp_memory_add(keysmem, private_in->m_binary, private_in->m_bytes);
391  pgp_filter_keys_from_mem(&s_io, public_keys, private_keys, NULL, 0, keysmem);
392 
393  if( private_in->m_type!=MR_PRIVATE || private_keys->keyc <= 0 ) {
394  mrmailbox_log_warning(mailbox, 0, "Split key: Given key is no private key.");
395  goto cleanup;
396  }
397 
398  if( public_keys->keyc <= 0 ) {
399  mrmailbox_log_warning(mailbox, 0, "Split key: Given key does not contain a public key.");
400  goto cleanup;
401  }
402 
403  pgp_writer_set_memory(pubout, pubmem);
404  if( !pgp_write_xfer_key(pubout, &public_keys->keys[0], 0/*armored*/)
405  || pubmem->buf == NULL || pubmem->length <= 0 ) {
406  goto cleanup;
407  }
408 
409  mrkey_set_from_raw(ret_public_key, pubmem->buf, pubmem->length, MR_PUBLIC);
410 
411  success = 1;
412 
413 cleanup:
414  if( pubout ) { pgp_output_delete(pubout); }
415  if( pubmem ) { pgp_memory_free(pubmem); }
416  if( keysmem ) { pgp_memory_free(keysmem); }
417  if( public_keys ) { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
418  if( private_keys ) { pgp_keyring_purge(private_keys); free(private_keys); }
419  return success;
420 }
421 
422 
423 /*******************************************************************************
424  * Public key encrypt/decrypt
425  ******************************************************************************/
426 
427 
428 int mrpgp_pk_encrypt( mrmailbox_t* mailbox,
429  const void* plain_text,
430  size_t plain_bytes,
431  const mrkeyring_t* raw_public_keys_for_encryption,
432  const mrkey_t* raw_private_key_for_signing,
433  int use_armor,
434  void** ret_ctext,
435  size_t* ret_ctext_bytes)
436 {
437  pgp_keyring_t* public_keys = calloc(1, sizeof(pgp_keyring_t));
438  pgp_keyring_t* private_keys = calloc(1, sizeof(pgp_keyring_t));
439  pgp_keyring_t* dummy_keys = calloc(1, sizeof(pgp_keyring_t));
440  pgp_memory_t* keysmem = pgp_memory_new();
441  pgp_memory_t* signedmem = NULL;
442  int i, success = 0;
443 
444  if( mailbox==NULL || plain_text==NULL || plain_bytes==0 || ret_ctext==NULL || ret_ctext_bytes==NULL
445  || raw_public_keys_for_encryption==NULL || raw_public_keys_for_encryption->m_count<=0
446  || keysmem==NULL || public_keys==NULL || private_keys==NULL || dummy_keys==NULL ) {
447  goto cleanup;
448  }
449 
450  *ret_ctext = NULL;
451  *ret_ctext_bytes = 0;
452 
453  /* setup keys (the keys may come from pgp_filter_keys_fileread(), see also pgp_keyring_add(rcpts, key)) */
454  for( i = 0; i < raw_public_keys_for_encryption->m_count; i++ ) {
455  pgp_memory_add(keysmem, raw_public_keys_for_encryption->m_keys[i]->m_binary, raw_public_keys_for_encryption->m_keys[i]->m_bytes);
456  }
457 
458  pgp_filter_keys_from_mem(&s_io, public_keys, private_keys/*should stay empty*/, NULL, 0, keysmem);
459  if( public_keys->keyc <=0 || private_keys->keyc!=0 ) {
460  mrmailbox_log_warning(mailbox, 0, "Encryption-keyring contains unexpected data (%i/%i)", public_keys->keyc, private_keys->keyc);
461  goto cleanup;
462  }
463 
464  /* encrypt */
465  {
466  const void* signed_text = NULL;
467  size_t signed_bytes = 0;
468  int encrypt_raw_packet = 0;
469 
470  if( raw_private_key_for_signing ) {
471  pgp_memory_clear(keysmem);
472  pgp_memory_add(keysmem, raw_private_key_for_signing->m_binary, raw_private_key_for_signing->m_bytes);
473  pgp_filter_keys_from_mem(&s_io, dummy_keys, private_keys, NULL, 0, keysmem);
474  if( private_keys->keyc <= 0 ) {
475  mrmailbox_log_warning(mailbox, 0, "No key for signing found.");
476  goto cleanup;
477  }
478 
479  pgp_key_t* sk0 = &private_keys->keys[0];
480  signedmem = pgp_sign_buf(&s_io, plain_text, plain_bytes, &sk0->key.seckey, time(NULL)/*birthtime*/, 0/*duration*/, "sha1", 0/*armored*/, 0/*cleartext*/);
481  if( signedmem == NULL ) {
482  mrmailbox_log_warning(mailbox, 0, "Signing failed.");
483  goto cleanup;
484  }
485  signed_text = signedmem->buf;
486  signed_bytes = signedmem->length;
487  encrypt_raw_packet = 1;
488  }
489  else {
490  signed_text = plain_text;
491  signed_bytes = plain_bytes;
492  encrypt_raw_packet = 0;
493  }
494 
495  pgp_memory_t* outmem = pgp_encrypt_buf(&s_io, signed_text, signed_bytes, public_keys, use_armor, NULL/*cipher*/, encrypt_raw_packet);
496  if( outmem == NULL ) {
497  mrmailbox_log_warning(mailbox, 0, "Encryption failed.");
498  goto cleanup;
499  }
500  *ret_ctext = outmem->buf;
501  *ret_ctext_bytes = outmem->length;
502  free(outmem); /* do not use pgp_memory_free() as we took ownership of the buffer */
503  }
504 
505  success = 1;
506 
507 cleanup:
508  if( keysmem ) { pgp_memory_free(keysmem); }
509  if( signedmem ) { pgp_memory_free(signedmem); }
510  if( public_keys ) { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
511  if( private_keys ) { pgp_keyring_purge(private_keys); free(private_keys); }
512  if( dummy_keys ) { pgp_keyring_purge(dummy_keys); free(dummy_keys); }
513  return success;
514 }
515 
516 
517 int mrpgp_pk_decrypt( mrmailbox_t* mailbox,
518  const void* ctext,
519  size_t ctext_bytes,
520  const mrkeyring_t* raw_private_keys_for_decryption,
521  const mrkey_t* raw_public_key_for_validation,
522  int use_armor,
523  void** ret_plain,
524  size_t* ret_plain_bytes,
525  int* ret_validation_errors)
526 {
527  pgp_keyring_t* public_keys = calloc(1, sizeof(pgp_keyring_t)); /*should be 0 after parsing*/
528  pgp_keyring_t* private_keys = calloc(1, sizeof(pgp_keyring_t));
529  pgp_keyring_t* dummy_keys = calloc(1, sizeof(pgp_keyring_t));
530  pgp_validation_t* vresult = calloc(1, sizeof(pgp_validation_t));
531  key_id_t* recipients_key_ids = NULL;
532  unsigned recipients_count = 0;
533  pgp_memory_t* keysmem = pgp_memory_new();
534  int i, success = 0;
535 
536  if( mailbox==NULL || ctext==NULL || ctext_bytes==0 || ret_plain==NULL || ret_plain_bytes==NULL || ret_validation_errors==NULL
537  || raw_private_keys_for_decryption==NULL || raw_private_keys_for_decryption->m_count<=0
538  || vresult==NULL || keysmem==NULL || public_keys==NULL || private_keys==NULL ) {
539  goto cleanup;
540  }
541 
542  *ret_plain = NULL;
543  *ret_plain_bytes = 0;
544 
545  /* setup keys (the keys may come from pgp_filter_keys_fileread(), see also pgp_keyring_add(rcpts, key)) */
546  for( i = 0; i < raw_private_keys_for_decryption->m_count; i++ ) {
547  pgp_memory_add(keysmem, raw_private_keys_for_decryption->m_keys[i]->m_binary, raw_private_keys_for_decryption->m_keys[i]->m_bytes);
548  }
549 
550  pgp_filter_keys_from_mem(&s_io, dummy_keys/*should stay empty*/, private_keys, NULL, 0, keysmem);
551  if( private_keys->keyc<=0 ) {
552  mrmailbox_log_warning(mailbox, 0, "Decryption-keyring contains unexpected data (%i/%i)", public_keys->keyc, private_keys->keyc);
553  goto cleanup;
554  }
555 
556  if( raw_public_key_for_validation ) {
557  pgp_memory_clear(keysmem);
558  pgp_memory_add(keysmem, raw_public_key_for_validation->m_binary, raw_public_key_for_validation->m_bytes);
559  pgp_filter_keys_from_mem(&s_io, public_keys, dummy_keys/*should stay empty*/, NULL, 0, keysmem);
560  }
561 
562  /* decrypt */
563  {
564  pgp_memory_t* outmem = pgp_decrypt_and_validate_buf(&s_io, vresult, ctext, ctext_bytes, private_keys, public_keys,
565  use_armor, &recipients_key_ids, &recipients_count);
566  if( outmem == NULL ) {
567  mrmailbox_log_warning(mailbox, 0, "Decryption failed.");
568  goto cleanup;
569  }
570  *ret_plain = outmem->buf;
571  *ret_plain_bytes = outmem->length;
572  free(outmem); /* do not use pgp_memory_free() as we took ownership of the buffer */
573 
574  /* validate */
575  *ret_validation_errors = 0;
576  if( vresult->validc <= 0 && vresult->invalidc <= 0 && vresult->unknownc <= 0 )
577  {
578  /* no valid nor invalid signatures found */
579  *ret_validation_errors = MR_VALIDATE_NO_SIGNATURE;
580  }
581  else if( raw_public_key_for_validation==NULL || vresult->unknownc > 0 )
582  {
583  /* at least one valid or invalid signature found, but no key for verification */
584  *ret_validation_errors = MR_VALIDATE_UNKNOWN_SIGNATURE;
585  }
586  else if( vresult->invalidc > 0 )
587  {
588  /* at least one invalid signature found */
589  *ret_validation_errors = MR_VALIDATE_BAD_SIGNATURE;
590  }
591  else
592  {
593  /* only valid signatures found */
594  ;
595  }
596  }
597 
598  success = 1;
599 
600 cleanup:
601  if( keysmem ) { pgp_memory_free(keysmem); }
602  if( public_keys ) { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
603  if( private_keys ) { pgp_keyring_purge(private_keys); free(private_keys); }
604  if( dummy_keys ) { pgp_keyring_purge(dummy_keys); free(dummy_keys); }
605  if( vresult ) { pgp_validate_result_free(vresult); }
606  if( recipients_key_ids ) { free(recipients_key_ids); }
607  return success;
608 }
An object representing a single mailbox.
Definition: mrmailbox.h:141