1 // This file is under GNU General Public License 3.0
4 #include "pEp_internal.h"
5 #include "dynamic_api.h"
6 #include "message_api.h"
8 #include "distribution_codec.h"
10 #include "keymanagement.h"
11 #include "baseprotocol.h"
12 #include "../asn.1/Distribution.h"
13 #include "Sync_impl.h" // this seems... bad
18 // FIXME: these should be taken from sync/Distribution.fsm
20 #define KEY_RESET_MAJOR_VERSION 1L
21 #define KEY_RESET_MINOR_VERSION 0L
23 static void _add_auto_consume(message* msg) {
24 add_opt_field(msg, "pEp-auto-consume", "yes");
25 msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation");
28 static PEP_STATUS _generate_reset_structs(PEP_SESSION session,
29 const pEp_identity* reset_ident,
32 bloblist_t** key_attachments,
33 keyreset_command_list** command_list,
34 bool include_secret) {
36 if (!session || !reset_ident || EMPTYSTR(old_fpr) || EMPTYSTR(new_fpr) ||
37 !key_attachments || !command_list)
38 return PEP_ILLEGAL_VALUE;
40 // Ok, generate payload here...
41 pEp_identity* outgoing_ident = identity_dup(reset_ident);
43 return PEP_OUT_OF_MEMORY;
44 free(outgoing_ident->fpr);
45 outgoing_ident->fpr = strdup(old_fpr);
46 if (!outgoing_ident->fpr)
47 return PEP_OUT_OF_MEMORY;
49 keyreset_command* kr_command = new_keyreset_command(outgoing_ident, new_fpr);
51 return PEP_OUT_OF_MEMORY;
53 *command_list = new_keyreset_command_list(kr_command);
55 if (keyreset_command_list_add(*command_list, kr_command) == NULL)
56 return PEP_OUT_OF_MEMORY;
58 bloblist_t* keys = NULL;
60 char* key_material_old = NULL;
61 char* key_material_new = NULL;
62 char* key_material_priv = NULL;
66 PEP_STATUS status = PEP_STATUS_OK;
68 if (!include_secret) { // This isn't to own recips, so shipping the rev'd key is OK. Own keys are revoked on each device.
69 status = export_key(session, old_fpr, &key_material_old, &datasize);
70 if (datasize > 0 && key_material_old) {
71 if (status != PEP_STATUS_OK)
75 keys = new_bloblist(key_material_old, datasize,
76 "application/pgp-keys",
77 "file://pEpkey_old.asc");
79 bloblist_add(keys, key_material_old, datasize, "application/pgp-keys",
80 "file://pEpkey_old.asc");
84 status = export_key(session, new_fpr, &key_material_new, &datasize);
86 if (datasize > 0 && key_material_new) {
87 if (status != PEP_STATUS_OK)
91 keys = new_bloblist(key_material_new, datasize,
92 "application/pgp-keys",
93 "file://pEpkey_new_pub.asc");
95 bloblist_add(keys, key_material_new, datasize, "application/pgp-keys", "file://pEpkey_new_pub.asc");
99 status = export_secret_key(session, new_fpr, &key_material_priv, &datasize);
100 if (status != PEP_STATUS_OK)
102 if (datasize > 0 && key_material_priv) {
103 bloblist_add(keys, key_material_priv, datasize, "application/pgp-keys",
104 "file://pEpkey_priv.asc");
109 if (*key_attachments)
110 bloblist_join(*key_attachments, keys);
112 *key_attachments = keys;
117 // For multiple idents under a single key
118 // idents contain new fprs
119 static PEP_STATUS _generate_own_commandlist_msg(PEP_SESSION session,
120 identity_list* from_idents,
123 PEP_STATUS status = PEP_STATUS_OK;
125 identity_list* list_curr = from_idents;
126 keyreset_command_list* kr_commands = NULL;
127 bloblist_t* key_attachments = NULL;
129 for ( ; list_curr && list_curr->ident; list_curr = list_curr->next) {
130 pEp_identity* curr_ident = list_curr->ident;
132 if (curr_ident->flags & PEP_idf_devicegroup) {
134 PEP_STATUS status = _generate_reset_structs(session,
141 if (status != PEP_STATUS_OK)
142 return status; // FIXME
143 if (!key_attachments || !kr_commands)
144 return PEP_UNKNOWN_ERROR;
149 // There was nothing for us to send to self - we could be ungrouped,
151 return PEP_STATUS_OK;
153 char* payload = NULL;
155 status = key_reset_commands_to_PER(kr_commands, &payload, &size);
156 if (status != PEP_STATUS_OK)
159 // From and to our first ident - this only goes to us.
160 pEp_identity* from = identity_dup(from_idents->ident);
161 pEp_identity* to = identity_dup(from);
162 status = base_prepare_message(session, from, to,
163 BASE_KEYRESET, payload, size, NULL,
166 if (status != PEP_STATUS_OK) {
171 return PEP_OUT_OF_MEMORY;
172 if (!msg->attachments)
173 return PEP_UNKNOWN_ERROR;
175 if (!bloblist_join(msg->attachments, key_attachments))
176 return PEP_UNKNOWN_ERROR;
181 free_keyreset_command_list(kr_commands);
187 static PEP_STATUS _generate_keyreset_command_message(PEP_SESSION session,
188 const pEp_identity* from_ident,
189 const pEp_identity* to_ident,
195 if (!session || !from_ident || !old_fpr || !new_fpr || !dst)
196 return PEP_ILLEGAL_VALUE;
199 if (!is_me(session, (pEp_identity*)from_ident))
200 return PEP_ILLEGAL_VALUE;
202 PEP_STATUS status = PEP_STATUS_OK;
208 // Ok, generate payload here...
209 pEp_identity* outgoing_ident = identity_dup(from_ident);
211 return PEP_OUT_OF_MEMORY;
212 free(outgoing_ident->fpr);
213 outgoing_ident->fpr = strdup(old_fpr);
214 if (!outgoing_ident->fpr)
215 return PEP_OUT_OF_MEMORY;
217 keyreset_command_list* kr_list = NULL;
218 bloblist_t* key_attachments = NULL;
221 status = _generate_reset_structs(session,
228 if (status != PEP_STATUS_OK)
229 return status; // FIXME
230 if (!key_attachments || !kr_list)
231 return PEP_UNKNOWN_ERROR;
233 char* payload = NULL;
235 status = key_reset_commands_to_PER(kr_list, &payload, &size);
236 status = base_prepare_message(session, outgoing_ident, to_ident,
237 BASE_KEYRESET, payload, size, NULL,
244 return PEP_OUT_OF_MEMORY;
245 if (!msg->attachments)
246 return PEP_UNKNOWN_ERROR;
253 PEP_STATUS has_key_reset_been_sent(
255 const char* from_addr,
257 const char* revoked_fpr,
264 assert(!EMPTYSTR(user_id));
266 if (!session || !contacted || EMPTYSTR(from_addr) || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
267 return PEP_ILLEGAL_VALUE;
271 char* alias_default = NULL;
273 PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
275 if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
277 alias_default = strdup(user_id);
280 sqlite3_reset(session->was_id_for_revoke_contacted);
281 sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
283 sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, from_addr, -1,
285 sqlite3_bind_text(session->was_id_for_revoke_contacted, 3, user_id, -1,
287 int result = sqlite3_step(session->was_id_for_revoke_contacted);
290 *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
294 sqlite3_reset(session->was_id_for_revoke_contacted);
296 return PEP_UNKNOWN_DB_ERROR;
299 sqlite3_reset(session->was_id_for_revoke_contacted);
300 return PEP_STATUS_OK;
303 PEP_STATUS set_reset_contact_notified(
305 const char* own_address,
306 const char* revoke_fpr,
307 const char* contact_id
310 PEP_STATUS status = PEP_STATUS_OK;
312 assert(session && !EMPTYSTR(own_address) && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
314 if (!session || EMPTYSTR(own_address) || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
315 return PEP_ILLEGAL_VALUE;
317 sqlite3_reset(session->set_revoke_contact_as_notified);
318 sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1,
320 sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, own_address, -1,
322 sqlite3_bind_text(session->set_revoke_contact_as_notified, 3, contact_id, -1,
327 result = sqlite3_step(session->set_revoke_contact_as_notified);
330 status = PEP_STATUS_OK;
334 status = PEP_UNKNOWN_DB_ERROR;
337 sqlite3_reset(session->set_revoke_contact_as_notified);
341 // FIXME: fpr ownership
342 PEP_STATUS receive_key_reset(PEP_SESSION session,
343 message* reset_msg) {
345 if (!session || !reset_msg || !reset_msg->_sender_fpr)
346 return PEP_ILLEGAL_VALUE;
348 PEP_STATUS status = PEP_STATUS_OK;
350 stringlist_t* keylist = NULL;
352 char* sender_fpr = reset_msg->_sender_fpr;
354 bool revoked = false;
356 // Check to see if sender fpr is revoked already - if this was
357 // from us, we won't have done it yet for obvious reasons (i.e.
358 // we need to verify it's from us before we accept someone telling
359 // us to reset our private key), and if this was from someone else,
360 // a key reset message will be signed by their new key, because
361 // we presume the old one was compromised (and we remove trust from
362 // the replacement key until verified)
363 status = key_revoked(session, sender_fpr, &revoked);
365 if (status != PEP_STATUS_OK)
370 return PEP_ILLEGAL_VALUE; // could be an attack
374 bool mistrusted = false;
375 status = is_mistrusted_key(session, sender_fpr, &mistrusted);
377 if (status != PEP_STATUS_OK)
381 return PEP_ILLEGAL_VALUE;
385 // Parse reset message
387 pEp_identity* sender_id = reset_msg->from;
390 return PEP_MALFORMED_KEY_RESET_MSG;
392 if (is_me(session, sender_id)) {
393 // first off, we need to make sure we're up-to-date
394 status = myself(session, sender_id);
397 status = update_identity(session, sender_id);
398 if (!sender_id->user_id)
399 return PEP_UNKNOWN_ERROR;
402 bool sender_own_key = false;
403 bool from_me = is_me(session, sender_id);
405 if (is_me(session, sender_id)) {
406 // Do own-reset-checks
407 status = is_own_key(session, sender_fpr, &sender_own_key);
409 if (status != PEP_STATUS_OK)
412 // Should we mistrust the sender_fpr here??
414 return PEP_ILLEGAL_VALUE; // actually, this is an attack
416 // Make sure it's a TRUSTED own key
417 char* keyholder = sender_id->fpr;
419 sender_id->fpr = sender_fpr;
420 status = get_trust(session, sender_id);
421 sender_id->fpr = keyholder;
423 if (sender_id->comm_type < PEP_ct_pEp)
424 return PEP_ILLEGAL_VALUE;
427 status = PEP_STATUS_OK;
428 char* old_fpr = NULL;
429 char* new_fpr = NULL;
432 const char* payload = NULL;
434 char* not_used_fpr = NULL;
435 status = base_extract_message(session,
442 if (status != PEP_STATUS_OK)
445 if (!payload || size == 0)
446 return PEP_MALFORMED_KEY_RESET_MSG;
448 keyreset_command_list* resets = NULL;
450 status = PER_to_key_reset_commands(payload, size, &resets);
452 if (status != PEP_STATUS_OK)
456 return PEP_MALFORMED_KEY_RESET_MSG;
458 keyreset_command_list* curr_cl = resets;
460 stringpair_list_t* rev_pairs = NULL;
462 // Ok, go through the list of reset commands. Right now, this
463 // is actually only one, but could be more later.
464 for ( ; curr_cl && curr_cl->command; curr_cl = curr_cl->next) {
465 keyreset_command* curr_cmd = curr_cl->command;
466 if (!curr_cmd || !curr_cmd->ident || !curr_cmd->ident->fpr ||
467 !curr_cmd->ident->address) {
468 return PEP_MALFORMED_KEY_RESET_MSG;
470 pEp_identity* curr_ident = curr_cmd->ident;
472 old_fpr = curr_ident->fpr;
473 new_fpr = strdup(curr_cmd->new_key);
475 bool is_old_own = false;
476 // if it's our key and the old one is revoked, we skip it.
477 // Sorry, them's the rules/
478 if (sender_own_key) {
479 status = is_own_key(session, old_fpr, &is_old_own);
481 bool old_revoked = false;
482 status = key_revoked(session, old_fpr, &old_revoked);
488 // Make sure that this key is at least one we associate
489 // with the sender. FIXME: check key election interaction
490 // N.B. If we ever allow ourselves to send resets to ourselves
491 // for not-own stuff, this will have to be revised
493 status = find_keys(session, new_fpr, &keylist);
494 if (status != PEP_STATUS_OK)
497 status = PEP_MALFORMED_KEY_RESET_MSG;
501 // We need to update the identity to get the user_id
502 curr_ident->fpr = NULL; // ensure old_fpr is preserved
503 free(curr_ident->user_id);
504 curr_ident->user_id = NULL;
505 status = update_identity(session, curr_ident);
507 // Ok, now check the old fpr to see if we have an entry for it
508 // temp fpr set for function call
509 curr_ident->fpr = old_fpr;
510 status = get_trust(session, curr_ident);
511 if (status != PEP_STATUS_OK)
514 PEP_comm_type ct_result = curr_ident->comm_type;
516 // Basically, see if fpr is even in the database
517 // for this user - we'll get PEP_ct_unknown if it isn't
518 if (ct_result == PEP_ct_unknown)
519 return PEP_KEY_NOT_RESET;
521 // Alright, so we have a key to reset. Good.
523 // If this is a non-own user, for NOW, we presume key reset
524 // by email for non-own keys is ONLY in case of revoke-and-replace.
525 // This means we have, at a *minimum*, an object that once
526 // required the initial private key in order to replace that key
529 // The limitations on what this guarantees are known - this does
530 // not prevent, for example, replay attacks from someone with
531 // access to the original revocation cert are possible if they
532 // get to us before we receive this object from the original sender.
533 // The best we can do in this case is to NOT trust the new key.
534 // It will be used by default, but if the original was trusted,
535 // the rating will visibly change for the sender, and even if it was
536 // not, if we do use it, the sender can report unreadable mails to us
537 // and detect it that way. FIXME: We may need to have some kind
538 // of even alert the user when such a change occurs for their contacts
540 // If this is from US, we already made sure that the sender_fpr
541 // was a valid own key, so we don't consider it here.
544 status = key_revoked(session, old_fpr, &revoked);
547 return PEP_KEY_NOT_RESET;
549 // Also don't let someone change the replacement fpr
550 // if the replacement fpr was also revoked - we really need
551 // to detect that something fishy is going on at this point
552 // FIXME: ensure that PEP_KEY_NOT_RESET responses to
553 // automated key reset functions are propagated upward -
554 // app should be made aware if someone is trying to reset someone
555 // else's key and it's failing for some reason.
557 status = key_revoked(session, new_fpr, &revoked);
560 return PEP_KEY_NOT_RESET;
563 // Hooray! We apparently now are dealing with keys
564 // belonging to the user from a message at least marginally
566 if (!sender_own_key) {
567 // Clear all info (ALSO REMOVES OLD KEY RIGHT NOW!!!)
568 status = key_reset(session, old_fpr, curr_ident);
569 if (status != PEP_STATUS_OK)
572 // Make new key the default
573 curr_ident->fpr = new_fpr;
575 // Whether new_key is NULL or not, if this key is equal to the current user default, we
577 status = replace_main_user_fpr_if_equal(session, curr_ident->user_id,
580 // This only sets as the default, does NOT TRUST IN ANY WAY
581 PEP_comm_type new_key_rating = PEP_ct_unknown;
583 // No key is ever returned as "confirmed" from here - it's based on raw key
584 status = get_key_rating(session, new_fpr, &new_key_rating);
585 if (status != PEP_STATUS_OK)
588 if (new_key_rating >= PEP_ct_strong_but_unconfirmed) {
590 status = is_pEp_user(session, curr_ident, &is_pEp);
592 curr_ident->comm_type = PEP_ct_pEp_unconfirmed;
594 curr_ident->comm_type = new_key_rating & (~PEP_ct_confirmed);
597 curr_ident->comm_type = new_key_rating;
599 status = set_identity(session, curr_ident);
600 if (status != PEP_STATUS_OK)
604 // set new key as the default for this identity
605 // N.B. If for some reason this is only a pubkey,
606 // then so be it - but we need to double-check to
607 // ensure that in this case, we end up with a private one,
608 // so talk to vb about this.
610 // Make new key the default
612 // This is REQUIRED for set_own_key (see doc)
613 curr_ident->fpr = NULL;
615 status = set_own_key(session, curr_ident, new_fpr);
617 if (status != PEP_STATUS_OK)
620 // Whether new_key is NULL or not, if this key is equal to the current user default, we
622 status = replace_main_user_fpr_if_equal(session, curr_ident->user_id,
625 if (status != PEP_STATUS_OK)
628 status = myself(session, curr_ident);
630 if (status != PEP_STATUS_OK)
633 char* old_copy = NULL;
634 char* new_copy = NULL;
635 old_copy = strdup(old_fpr);
636 new_copy = strdup(new_fpr);
637 if (!old_copy || !new_copy)
638 return PEP_OUT_OF_MEMORY;
641 stringpair_t* revp = new_stringpair(old_copy, new_copy);
643 rev_pairs = new_stringpair_list(revp);
645 return PEP_OUT_OF_MEMORY;
648 stringpair_list_add(rev_pairs, revp);
657 // actually revoke - list only exists with own keys
658 stringpair_list_t* curr_rev_pair = rev_pairs;
659 while (curr_rev_pair && curr_rev_pair->value) {
660 char* rev_key = curr_rev_pair->value->key;
661 char* new_key = curr_rev_pair->value->value;
663 if (EMPTYSTR(rev_key) || EMPTYSTR(new_key))
664 return PEP_UNKNOWN_ERROR;
665 bool revoked = false;
666 status = key_revoked(session, rev_key, &revoked);
668 // key reset on old key
669 status = revoke_key(session, rev_key, NULL);
671 if (status != PEP_STATUS_OK)
674 // N.B. This sort of sucks because we overwrite this every time.
675 // But this case is infrequent and we don't rely on the binding.
677 if (status == PEP_STATUS_OK)
678 status = set_revoked(session, rev_key, new_key, time(NULL));
680 if (status != PEP_STATUS_OK)
683 curr_rev_pair = curr_rev_pair->next;
688 free_stringlist(keylist);
689 free_stringpair_list(rev_pairs);
695 PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
697 pEp_identity* own_identity,
700 const char* new_fpr) {
702 if (!dst || !own_identity || EMPTYSTR(own_identity->address)
703 || !recip || EMPTYSTR(recip->user_id)
704 || EMPTYSTR(recip->address))
705 return PEP_ILLEGAL_VALUE;
707 if (EMPTYSTR(old_fpr) || EMPTYSTR(new_fpr))
708 return PEP_ILLEGAL_VALUE;
712 message* reset_msg = NULL;
714 PEP_STATUS status = _generate_keyreset_command_message(session, own_identity,
716 old_fpr, new_fpr, false,
719 if (status != PEP_STATUS_OK)
723 return PEP_ILLEGAL_VALUE;
725 if (!reset_msg->attachments)
726 return PEP_UNKNOWN_ERROR;
728 message* output_msg = NULL;
730 status = encrypt_message(session, reset_msg, NULL,
731 &output_msg, PEP_enc_PGP_MIME,
732 PEP_encrypt_flag_key_reset_only);
734 if (status == PEP_STATUS_OK)
739 free_message(reset_msg);
743 PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
744 pEp_identity* from_ident,
746 const char* new_fpr) {
750 // assert(session->messageToSend); NO. Don't assert this, FFS.
752 if (!session || !old_fpr || !new_fpr)
753 return PEP_ILLEGAL_VALUE;
755 messageToSend_t send_cb = session->messageToSend;
757 return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
759 identity_list* recent_contacts = NULL;
760 message* reset_msg = NULL;
762 PEP_STATUS status = get_last_contacted(session, &recent_contacts);
764 if (status != PEP_STATUS_OK)
767 identity_list* curr_id_ptr = recent_contacts;
769 for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
770 pEp_identity* curr_id = curr_id_ptr->ident;
775 const char* user_id = curr_id->user_id;
777 // Should be impossible, but?
781 // Check if it's us - if so, pointless...
782 if (is_me(session, curr_id))
785 // Also, don't bother to send it to non-pEp-users
786 bool pEp_user = false;
787 status = is_pEp_user(session, curr_id, &pEp_user);
789 if (status != PEP_STATUS_OK)
795 // Check if they've already been told - this shouldn't be the case, but...
796 bool contacted = false;
797 status = has_key_reset_been_sent(session, from_ident->address, user_id, old_fpr, &contacted);
798 if (status != PEP_STATUS_OK)
804 // Make sure they've ever *contacted* this address
805 bool in_contact_w_this_address = false;
806 status = has_partner_contacted_address(session, curr_id->user_id, from_ident->address,
807 &in_contact_w_this_address);
809 if (!in_contact_w_this_address)
812 // if not, make em a message
815 status = create_standalone_key_reset_message(session,
822 if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them
823 status = PEP_STATUS_OK;
827 if (status != PEP_STATUS_OK) {
832 _add_auto_consume(reset_msg);
834 status = send_cb(reset_msg);
836 if (status != PEP_STATUS_OK) {
841 // Put into notified DB
842 status = set_reset_contact_notified(session, from_ident->address, old_fpr, user_id);
843 if (status != PEP_STATUS_OK)
848 free_identity_list(recent_contacts);
852 DYNAMIC_API PEP_STATUS key_reset_identity(
858 if (!session || !ident || (ident && (EMPTYSTR(ident->user_id) || EMPTYSTR(ident->address))))
859 return PEP_ILLEGAL_VALUE;
861 return key_reset(session, fpr, ident);
864 DYNAMIC_API PEP_STATUS key_reset_user(
870 if (!session || EMPTYSTR(user_id))
871 return PEP_ILLEGAL_VALUE;
873 pEp_identity* input_ident = new_identity(NULL, NULL, user_id, NULL);
875 return PEP_OUT_OF_MEMORY;
877 if (is_me(session, input_ident) && EMPTYSTR(fpr))
878 return PEP_ILLEGAL_VALUE;
880 PEP_STATUS status = key_reset(session, fpr, input_ident);
881 free_identity(input_ident);
885 DYNAMIC_API PEP_STATUS key_reset_all_own_keys(PEP_SESSION session) {
886 return key_reset(session, NULL, NULL);
889 static PEP_STATUS _dup_grouped_only(identity_list* idents, identity_list** filtered) {
891 return PEP_STATUS_OK;
893 identity_list* id_node;
894 pEp_identity* curr_ident = NULL;
896 identity_list* ret_list = NULL;
897 identity_list** ret_list_pp = &ret_list;
899 for (id_node = idents; id_node && id_node->ident; id_node = id_node->next) {
900 curr_ident = id_node->ident;
901 if (curr_ident->flags & PEP_idf_devicegroup) {
902 pEp_identity* new_ident = identity_dup(curr_ident);
904 free_identity_list(ret_list);
905 return PEP_OUT_OF_MEMORY;
907 identity_list* new_ident_il = new_identity_list(new_ident);
910 free_identity_list(ret_list);
911 return PEP_OUT_OF_MEMORY;
914 *ret_list_pp = new_ident_il;
915 ret_list_pp = &(new_ident_il->next);
918 *filtered = ret_list;
919 return PEP_STATUS_OK;
922 static PEP_STATUS _key_reset_device_group_for_shared_key(PEP_SESSION session,
923 identity_list* key_idents,
930 if (!session || !key_idents || EMPTYSTR(old_key))
931 return PEP_ILLEGAL_VALUE;
933 messageToSend_t send_cb = session->messageToSend;
935 return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
937 PEP_STATUS status = PEP_STATUS_OK;
939 // if we only want grouped identities, we do this:
941 identity_list* new_list = NULL;
942 status = _dup_grouped_only(key_idents, &new_list);
943 if (status != PEP_STATUS_OK)
945 key_idents = new_list; // local var change, won't impact caller
949 return PEP_STATUS_OK;
951 // each of these has the same key and needs a new one.
952 identity_list* curr_ident;
953 for (curr_ident = key_idents; curr_ident && curr_ident->ident; curr_ident = curr_ident->next) {
954 pEp_identity* ident = curr_ident->ident;
957 status = _generate_keypair(session, ident, true);
958 if (status != PEP_STATUS_OK)
962 // Ok, everyone's got a new keypair. Hoorah!
963 // generate, sign, and push messages into queue
964 message* outmsg = NULL;
965 status = _generate_own_commandlist_msg(session,
970 // Following will only be true if some idents were grouped,
971 // and will only include grouped idents!
973 message* enc_msg = NULL;
975 // encrypt this baby and get out
977 status = encrypt_message(session, outmsg, NULL, &enc_msg, PEP_enc_PGP_MIME, PEP_encrypt_flag_key_reset_only);
979 if (status != PEP_STATUS_OK) {
982 _add_auto_consume(enc_msg);
985 status = send_cb(enc_msg);
987 if (status != PEP_STATUS_OK) {
993 // Ok, we've signed everything we need to with the old key,
995 status = revoke_key(session, old_key, NULL);
997 if (status != PEP_STATUS_OK)
1000 for (curr_ident = key_idents; curr_ident && curr_ident->ident; curr_ident = curr_ident->next) {
1001 if (curr_ident->ident->flags & PEP_idf_devicegroup) {
1002 pEp_identity* ident = curr_ident->ident;
1004 // set own key, you fool.
1005 // Grab ownership first.
1006 char* new_key = ident->fpr;
1008 status = set_own_key(session, ident, new_key);
1009 if (status != PEP_STATUS_OK) {
1010 // scream loudly and cry, then hang head in shame
1015 // release ownership to the struct again
1016 ident->fpr = new_key;
1018 // N.B. This sort of sucks because we overwrite this every time.
1019 // But this case is infrequent and we don't rely on the binding.
1020 if (status == PEP_STATUS_OK)
1021 status = set_revoked(session, old_key, new_key, time(NULL));
1023 if (status != PEP_STATUS_OK)
1026 // Whether new_key is NULL or not, if this key is equal to the current user default, we
1028 status = replace_main_user_fpr_if_equal(session,
1033 if (status != PEP_STATUS_OK)
1036 pEp_identity* tmp_ident = identity_dup(ident);
1038 status = PEP_OUT_OF_MEMORY;
1041 free(tmp_ident->fpr);
1043 // for all active communication partners:
1044 // active_send revocation
1045 tmp_ident->fpr = strdup(old_key); // freed in free_identity
1046 if (status == PEP_STATUS_OK)
1047 status = send_key_reset_to_recents(session, tmp_ident, old_key, ident->fpr);
1048 free_identity(tmp_ident);
1052 if (status == PEP_STATUS_OK)
1053 // cascade that mistrust for anyone using this key
1054 status = mark_as_compromised(session, old_key);
1056 if (status == PEP_STATUS_OK)
1057 status = remove_fpr_as_default(session, old_key);
1058 if (status == PEP_STATUS_OK)
1059 status = add_mistrusted_key(session, old_key);
1066 DYNAMIC_API PEP_STATUS key_reset_own_grouped_keys(PEP_SESSION session) {
1070 return PEP_ILLEGAL_VALUE;
1072 stringlist_t* keys = NULL;
1073 char* user_id = NULL;
1074 PEP_STATUS status = get_default_own_userid(session, &user_id);
1076 if (status != PEP_STATUS_OK || !user_id)
1080 status = get_all_keys_for_user(session, user_id, &keys);
1083 if (status == PEP_STATUS_OK) {
1084 stringlist_t* curr_key;
1086 for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
1087 identity_list* key_idents = NULL;
1088 const char* own_key = curr_key->value;
1089 status = get_identities_by_main_key_id(session, own_key, &key_idents);
1091 if (status == PEP_CANNOT_FIND_IDENTITY) {
1092 status = PEP_STATUS_OK;
1095 else if (status == PEP_STATUS_OK)
1096 status = _key_reset_device_group_for_shared_key(session, key_idents, own_key, true);
1100 free_identity_list(key_idents);
1106 free_stringlist(keys);
1111 // Notes to integrate into header:
1112 // IF there is an ident, it must have a user_id.
1113 PEP_STATUS key_reset(
1114 PEP_SESSION session,
1119 if (!session || (ident && EMPTYSTR(ident->user_id)))
1120 return PEP_ILLEGAL_VALUE;
1122 PEP_STATUS status = PEP_STATUS_OK;
1124 char* fpr_copy = NULL;
1125 char* own_id = NULL;
1126 char* user_id = NULL;
1127 char* new_key = NULL;
1128 pEp_identity* tmp_ident = NULL;
1129 identity_list* key_idents = NULL;
1130 stringlist_t* keys = NULL;
1132 if (!EMPTYSTR(key_id)) {
1133 fpr_copy = strdup(key_id);
1135 return PEP_OUT_OF_MEMORY;
1138 // This is true when we don't have a user_id and address and the fpr isn't specified
1139 bool reset_all_for_user = !fpr_copy && (!ident || EMPTYSTR(ident->address));
1141 // FIXME: does this need to be done everywhere?> I think not.
1143 user_id = strdup(ident->user_id);
1145 status = PEP_OUT_OF_MEMORY;
1150 status = get_default_own_userid(session, &user_id);
1151 if (status != PEP_STATUS_OK || !user_id)
1155 // FIXME: Make sure this can't result in a double-free in recursive calls
1156 tmp_ident = (ident ? identity_dup(ident) : new_identity(NULL, NULL, user_id, NULL));
1158 if (reset_all_for_user) {
1159 status = get_all_keys_for_user(session, user_id, &keys);
1161 if (status == PEP_STATUS_OK) {
1162 stringlist_t* curr_key;
1164 for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
1165 // FIXME: Is the ident really necessary?
1166 status = key_reset(session, curr_key->value, tmp_ident);
1167 if (status != PEP_STATUS_OK && status != PEP_CANNOT_FIND_IDENTITY)
1170 status = PEP_STATUS_OK;
1176 // tmp_ident => tmp_ident->user_id (was checked)
1178 // !(EMPTYSTR(fpr) && (!tmp_ident || EMPTYSTR(tmp_ident->address)))
1179 // => fpr || (tmp_ident && tmp_ident->address)
1181 // so: We have an fpr or we have an ident with user_id and address
1184 // We are guaranteed to have an ident w/ id + addr here.
1185 // Get the default key.
1186 pEp_identity* stored_ident = NULL;
1187 status = get_identity(session, tmp_ident->address,
1188 tmp_ident->user_id, &stored_ident);
1190 // FIXME FIXME FIXME
1191 if (status == PEP_STATUS_OK) {
1192 // transfer ownership
1193 fpr_copy = stored_ident->fpr;
1194 stored_ident->fpr = NULL;
1195 free_identity(stored_ident);
1198 if (!fpr_copy || status == PEP_CANNOT_FIND_IDENTITY) {
1199 // There's no identity default. Try resetting user default
1200 status = get_user_default_key(session, tmp_ident->user_id, &fpr_copy);
1203 if (!fpr_copy || status != PEP_STATUS_OK) // No default to free. We're done here.
1207 // Ok - now we have at least an ident with user_id and an fpr.
1208 // Now it matters if we're talking about ourselves or a partner.
1209 bool is_own_private = false;
1210 if (is_me(session, tmp_ident)) {
1211 bool own_key = false;
1212 status = is_own_key(session, fpr_copy, &own_key);
1214 if (status != PEP_STATUS_OK)
1217 status = PEP_ILLEGAL_VALUE;
1221 status = contains_priv_key(session, fpr_copy, &is_own_private);
1222 if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
1226 // Up to this point, we haven't cared about whether or not we
1227 // had a full identity. Now we have to deal with that in the
1228 // case of own identities with private keys.
1230 if (is_own_private) {
1232 // This is now the "is_own" base case - we don't do this
1233 // per-identity, because all identities using this key will
1234 // need new ones. That said, this is really only a problem
1235 // with manual key management, something which we only support
1236 // to a limited extent in any event.
1238 bool is_grouped = false;
1239 status = deviceGrouped(session, &is_grouped);
1241 // Regardless of the single identity this is for, for own keys, we do this
1242 // for all keys associated with the identity.
1243 status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
1245 if (status != PEP_CANNOT_FIND_IDENTITY) {
1247 // N.B. Possible user default key replacement will happen inside
1248 // _key_reset_device_group_for_shared_key in the first case.
1249 // We handle the reassignment for the second case in the block here.
1251 status = _key_reset_device_group_for_shared_key(session, key_idents, fpr_copy, false);
1252 else if (status == PEP_STATUS_OK) {
1253 // now have ident list, or should
1254 identity_list* curr_ident;
1256 for (curr_ident = key_idents; curr_ident && curr_ident->ident;
1257 curr_ident = curr_ident->next) {
1259 pEp_identity* this_ident = curr_ident->ident;
1260 // Do the full reset on this identity
1261 // Base case for is_own_private starts here
1262 // Note that we reset this key for ANY own ident that has it. And if
1263 // tmp_ident did NOT have this key, it won't matter. We will reset the
1264 // key for all idents for this user.
1265 status = revoke_key(session, fpr_copy, NULL);
1267 // If we have a full identity, we have some cleanup and generation tasks here
1268 if (!EMPTYSTR(this_ident->address)) {
1270 if (status == PEP_STATUS_OK) {
1271 this_ident->fpr = NULL;
1272 status = myself(session, this_ident);
1274 if (status == PEP_STATUS_OK && this_ident->fpr && strcmp(fpr_copy, this_ident->fpr) != 0)
1275 new_key = strdup(this_ident->fpr);
1278 // mistrust fpr from trust
1279 this_ident->fpr = fpr_copy;
1281 this_ident->comm_type = PEP_ct_mistrusted;
1282 status = set_trust(session, this_ident);
1283 this_ident->fpr = NULL;
1285 // Done with old use of ident.
1286 if (status == PEP_STATUS_OK) {
1288 status = myself(session, this_ident);
1292 if (status == PEP_STATUS_OK)
1293 // cascade that mistrust for anyone using this key
1294 status = mark_as_compromised(session, fpr_copy);
1296 if (status == PEP_STATUS_OK)
1297 status = remove_fpr_as_default(session, fpr_copy);
1298 if (status == PEP_STATUS_OK)
1299 status = add_mistrusted_key(session, fpr_copy);
1301 // If there's a new key, do the DB linkage with the revoked one, and
1302 // send the key reset mail opportunistically to recently contacted
1305 // add to revocation list
1306 if (status == PEP_STATUS_OK)
1307 status = set_revoked(session, fpr_copy, new_key, time(NULL));
1308 // for all active communication partners:
1309 // active_send revocation
1311 tmp_ident->fpr = fpr_copy;
1312 if (status == PEP_STATUS_OK)
1313 status = send_key_reset_to_recents(session, this_ident, fpr_copy, new_key);
1314 tmp_ident->fpr = NULL;
1317 // Whether new_key is NULL or not, if this key is equal to the current user default, we
1319 status = replace_main_user_fpr_if_equal(session, this_ident->user_id, new_key, fpr_copy);
1320 } // Ident list gets freed below, do not free here!
1322 // Ok, we've either now reset for each own identity with this key, or
1323 // we got an error and want to bail anyway.
1327 return PEP_CANNOT_FIND_IDENTITY;
1328 } // end is_own_private
1330 // if it's mistrusted, make it not be so.
1331 bool mistrusted_key = false;
1332 is_mistrusted_key(session, fpr_copy, &mistrusted_key);
1335 delete_mistrusted_key(session, fpr_copy);
1337 if (tmp_ident->user_id)
1338 status = clear_trust_info(session, tmp_ident->user_id, fpr_copy);
1340 // This is a public key (or a private key that isn't ours, which means
1341 // we want it gone anyway)
1343 // Delete this key from the keyring.
1344 // FIXME: when key election disappears, so should this!
1345 status = delete_keypair(session, fpr_copy);
1348 // REGARDLESS OF WHO OWNS THE KEY, WE NOW NEED TO REMOVE IT AS A DEFAULT.
1349 PEP_STATUS cached_status = status;
1350 // remove fpr from all identities
1351 // remove fpr from all users
1352 status = remove_fpr_as_default(session, fpr_copy);
1353 // delete key from DB - this does NOT touch the keyring!
1354 // Note: for own priv keys, we cannot do this. But we'll never encrypt to/from it.
1355 if (status == PEP_STATUS_OK && !is_own_private) {
1356 status = remove_key(session, fpr_copy);
1358 if (status == PEP_STATUS_OK)
1359 status = cached_status;
1364 free_identity(tmp_ident);
1367 free_identity_list(key_idents);
1368 free_stringlist(keys);
1373 Distribution_t *Distribution_from_keyreset_command_list(
1374 const keyreset_command_list *command_list,
1375 Distribution_t *dist
1378 bool allocated = !dist;
1380 assert(command_list);
1385 dist = (Distribution_t *) calloc(1, sizeof(Distribution_t));
1391 dist->present = Distribution_PR_keyreset;
1392 dist->choice.keyreset.present = KeyReset_PR_commands;
1394 long *major = malloc(sizeof(long));
1398 *major = KEY_RESET_MAJOR_VERSION;
1399 dist->choice.keyreset.choice.commands.version.major = major;
1401 long *minor = malloc(sizeof(long));
1405 *minor = KEY_RESET_MINOR_VERSION;
1406 dist->choice.keyreset.choice.commands.version.minor = minor;
1408 for (const keyreset_command_list *cl = command_list; cl && cl->command; cl = cl->next) {
1409 Command_t *c = (Command_t *) calloc(1, sizeof(Command_t));
1414 if (!Identity_from_Struct(cl->command->ident, &c->ident)) {
1419 if (OCTET_STRING_fromString(&c->newkey, cl->command->new_key)) {
1420 ASN_STRUCT_FREE(asn_DEF_Command, c);
1424 if (ASN_SEQUENCE_ADD(&dist->choice.keyreset.choice.commands.commandlist, c)) {
1425 ASN_STRUCT_FREE(asn_DEF_Command, c);
1433 ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
1438 PEP_STATUS key_reset_commands_to_PER(const keyreset_command_list *command_list, char **cmds, size_t *size)
1440 PEP_STATUS status = PEP_STATUS_OK;
1442 assert(command_list && cmds);
1443 if (!(command_list && cmds))
1444 return PEP_ILLEGAL_VALUE;
1449 // convert from pEp engine struct
1451 Distribution_t *dist = Distribution_from_keyreset_command_list(command_list, NULL);
1460 status = encode_Distribution_message(dist, &_cmds, &_size);
1471 status = PEP_OUT_OF_MEMORY;
1474 ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
1478 keyreset_command_list * Distribution_to_keyreset_command_list(
1479 Distribution_t *dist,
1480 keyreset_command_list *command_list
1483 bool allocated = !command_list;
1490 command_list = new_keyreset_command_list(NULL);
1494 struct Commands__commandlist *cl = &dist->choice.keyreset.choice.commands.commandlist;
1495 keyreset_command_list *_result = command_list;
1496 for (int i=0; i<cl->list.count; i++) {
1497 pEp_identity *ident = Identity_to_Struct(&cl->list.array[i]->ident, NULL);
1501 const char *new_key = (const char *) cl->list.array[i]->newkey.buf;
1503 keyreset_command *command = new_keyreset_command(ident, new_key);
1505 free_identity(ident);
1509 _result = keyreset_command_list_add(_result, command);
1510 free_identity(ident);
1515 return command_list;
1519 free_keyreset_command_list(command_list);
1523 PEP_STATUS PER_to_key_reset_commands(const char *cmds, size_t size, keyreset_command_list **command_list)
1525 assert(command_list && cmds);
1526 if (!(command_list && cmds))
1527 return PEP_ILLEGAL_VALUE;
1529 *command_list = NULL;
1533 Distribution_t *dist = NULL;
1534 PEP_STATUS status = decode_Distribution_message(cmds, size, &dist);
1538 // check if these are key reset commands or not
1540 assert(dist && dist->present == Distribution_PR_keyreset
1541 && dist->choice.keyreset.present == KeyReset_PR_commands);
1543 if (!(dist && dist->present == Distribution_PR_keyreset
1544 && dist->choice.keyreset.present == KeyReset_PR_commands)) {
1545 status = PEP_ILLEGAL_VALUE;
1549 // convert to pEp engine struct
1551 keyreset_command_list *result = Distribution_to_keyreset_command_list(dist, NULL);
1557 *command_list = result;
1561 status = PEP_OUT_OF_MEMORY;
1562 free_keyreset_command_list(result);
1565 ASN_STRUCT_FREE(asn_DEF_Distribution, dist);