...
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 "../asn.1/Distribution.h"
15 PEP_STATUS has_key_reset_been_sent(
18 const char* revoked_fpr,
25 assert(!EMPTYSTR(user_id));
27 if (!session || !contacted || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
28 return PEP_ILLEGAL_VALUE;
32 char* alias_default = NULL;
34 PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
36 if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
38 alias_default = strdup(user_id);
41 sqlite3_reset(session->was_id_for_revoke_contacted);
42 sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
44 sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, user_id, -1,
46 int result = sqlite3_step(session->was_id_for_revoke_contacted);
49 *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
53 sqlite3_reset(session->was_id_for_revoke_contacted);
55 return PEP_UNKNOWN_DB_ERROR;
58 sqlite3_reset(session->was_id_for_revoke_contacted);
62 //static const char *sql_set_revoke_contact_as_notified =
63 // "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
65 PEP_STATUS set_reset_contact_notified(
67 const char* revoke_fpr,
68 const char* contact_id
71 PEP_STATUS status = PEP_STATUS_OK;
73 assert(session && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
75 if (!session || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
76 return PEP_ILLEGAL_VALUE;
78 sqlite3_reset(session->set_revoke_contact_as_notified);
79 sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1,
81 sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, contact_id, -1,
86 result = sqlite3_step(session->set_revoke_contact_as_notified);
89 status = PEP_STATUS_OK;
93 status = PEP_UNKNOWN_DB_ERROR;
96 sqlite3_reset(session->set_revoke_contact_as_notified);
101 PEP_STATUS receive_key_reset(PEP_SESSION session,
102 message* reset_msg) {
104 if (!session || !reset_msg)
105 return PEP_ILLEGAL_VALUE;
107 pEp_identity* sender_id = reset_msg->from;
110 return PEP_MALFORMED_KEY_RESET_MSG;
112 PEP_STATUS status = update_identity(session, sender_id);
113 if (!sender_id->user_id)
114 return PEP_UNKNOWN_ERROR;
116 if (is_me(session, sender_id))
117 return PEP_ILLEGAL_VALUE;
119 if (!reset_msg->longmsg || strncmp(reset_msg->longmsg, "OLD: ", 5) != 0)
120 return PEP_MALFORMED_KEY_RESET_MSG;
122 status = PEP_STATUS_OK;
123 char* old_fpr = NULL;
124 char* new_fpr = NULL;
126 stringlist_t* keylist = NULL;
127 pEp_identity* temp_ident = identity_dup(sender_id);
129 status = PEP_OUT_OF_MEMORY;
134 char* p = strtok_r(reset_msg->longmsg, "\r\n", &rest);
135 if (!EMPTYSTR(p + 5))
136 old_fpr = strdup(p + 5);
138 status = PEP_MALFORMED_KEY_RESET_MSG;
142 bool own_key = false;
143 status = is_own_key(session, old_fpr, &own_key);
146 // Nope, no one can make us our own default. If we want to do that,
147 // that's keysync, NOT key reset.
148 status = PEP_ILLEGAL_VALUE;
152 p = strtok_r(NULL, "\r\n", &rest);
153 if (strncmp(p, "NEW: ", 5) != 0 || EMPTYSTR(p + 5)) {
154 status = PEP_MALFORMED_KEY_RESET_MSG;
158 new_fpr = strdup(p + 5);
160 // Reset the original key
161 status = key_reset(session, old_fpr, temp_ident, NULL, NULL);
162 if (status != PEP_STATUS_OK)
165 status = find_keys(session, new_fpr, &keylist);
166 if (status != PEP_STATUS_OK)
170 status = PEP_KEY_NOT_FOUND;
174 // alright, we've checked as best we can. Let's set that baby.
175 sender_id->fpr = new_fpr;
177 // This only sets as the default, does NOT TRUST IN ANY WAY
178 sender_id->comm_type = sender_id->comm_type & (~PEP_ct_confirmed);
179 status = set_identity(session, sender_id);
181 sender_id->fpr = NULL; // ownership for free
183 free_stringlist(keylist);
186 free_identity(temp_ident);
190 PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
194 const char* new_fpr) {
196 if (!dst || !recip->user_id || !recip->address)
197 return PEP_ILLEGAL_VALUE;
199 if (!old_fpr || !new_fpr)
200 return PEP_ILLEGAL_VALUE;
203 // Get own identity user has corresponded with
204 pEp_identity* own_identity = NULL;
206 PEP_STATUS status = get_own_ident_for_contact_id(session,
209 if (status != PEP_STATUS_OK)
212 message* reset_message = new_message(PEP_dir_outgoing);
213 reset_message->from = own_identity;
214 reset_message->to = new_identity_list(identity_dup(recip)); // ?
216 const char* oldtag = "OLD: ";
217 const char* newtag = "\nNEW: ";
218 const size_t taglens = 11;
219 size_t full_len = taglens + strlen(old_fpr) + strlen(new_fpr) + 2; // \n and \0
220 char* longmsg = calloc(full_len, 1);
221 strlcpy(longmsg, oldtag, full_len);
222 strlcat(longmsg, old_fpr, full_len);
223 strlcat(longmsg, newtag, full_len);
224 strlcat(longmsg, new_fpr, full_len);
225 strlcat(longmsg, "\n", full_len);
226 reset_message->longmsg = longmsg;
227 reset_message->shortmsg = strdup("Key reset");
229 message* output_msg = NULL;
231 status = encrypt_message(session, reset_message, NULL,
232 &output_msg, PEP_enc_PGP_MIME,
233 PEP_encrypt_flag_key_reset_only);
235 if (status == PEP_STATUS_OK)
238 free_message(reset_message);
242 PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
244 const char* new_fpr) {
248 assert(session->messageToSend);
250 if (!session || !old_fpr || !new_fpr)
251 return PEP_ILLEGAL_VALUE;
253 messageToSend_t send_cb = session->messageToSend;
255 return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
257 identity_list* recent_contacts = NULL;
258 message* reset_msg = NULL;
260 PEP_STATUS status = get_last_contacted(session, &recent_contacts);
262 if (status != PEP_STATUS_OK)
265 identity_list* curr_id_ptr = recent_contacts;
267 for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
268 pEp_identity* curr_id = curr_id_ptr->ident;
273 const char* user_id = curr_id->user_id;
275 // Should be impossible, but?
279 // Check if it's us - if so, pointless...
280 if (is_me(session, curr_id))
283 // Check if they've already been told - this shouldn't be the case, but...
284 bool contacted = false;
285 status = has_key_reset_been_sent(session, user_id, old_fpr, &contacted);
286 if (status != PEP_STATUS_OK)
292 // if not, make em a message
295 status = create_standalone_key_reset_message(session,
301 if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them
302 status = PEP_STATUS_OK;
306 if (status != PEP_STATUS_OK) {
312 status = send_cb(reset_msg);
314 if (status != PEP_STATUS_OK) {
319 // Put into notified DB
320 status = set_reset_contact_notified(session, old_fpr, user_id);
321 if (status != PEP_STATUS_OK)
326 free_identity_list(recent_contacts);
330 DYNAMIC_API PEP_STATUS key_reset_identity(
336 if (!session || !ident || (ident && (EMPTYSTR(ident->user_id) || EMPTYSTR(ident->address))))
337 return PEP_ILLEGAL_VALUE;
339 return key_reset(session, fpr, ident, NULL, NULL);
342 DYNAMIC_API PEP_STATUS key_reset_user(
348 if (!session || EMPTYSTR(user_id))
349 return PEP_ILLEGAL_VALUE;
351 pEp_identity* input_ident = new_identity(NULL, NULL, user_id, NULL);
353 return PEP_OUT_OF_MEMORY;
355 if (is_me(session, input_ident) && EMPTYSTR(fpr))
356 return PEP_ILLEGAL_VALUE;
358 PEP_STATUS status = key_reset(session, fpr, input_ident, NULL, NULL);
359 free_identity(input_ident);
363 DYNAMIC_API PEP_STATUS key_reset_all_own_keys(PEP_SESSION session) {
364 return key_reset(session, NULL, NULL, NULL, NULL);
367 // Notes to integrate into header:
368 // IF there is an ident, it must have a user_id.
369 PEP_STATUS key_reset(
373 identity_list** own_identities,
374 stringlist_t** own_revoked_fprs
377 if (!session || (ident && EMPTYSTR(ident->user_id)))
378 return PEP_ILLEGAL_VALUE;
380 PEP_STATUS status = PEP_STATUS_OK;
382 char* fpr_copy = NULL;
384 char* user_id = NULL;
385 char* new_key = NULL;
386 pEp_identity* tmp_ident = NULL;
387 identity_list* key_idents = NULL;
388 stringlist_t* keys = NULL;
390 if (!EMPTYSTR(key_id)) {
391 fpr_copy = strdup(key_id);
393 return PEP_OUT_OF_MEMORY;
396 // This is true when we don't have a user_id and address and the fpr isn't specified
397 bool reset_all_for_user = !fpr_copy && (!ident || EMPTYSTR(ident->address));
399 // FIXME: does this need to be done everywhere?> I think not.
401 user_id = strdup(ident->user_id);
403 status = PEP_OUT_OF_MEMORY;
408 status = get_default_own_userid(session, &user_id);
409 if (status != PEP_STATUS_OK || !user_id)
413 // FIXME: Make sure this can't result in a double-free in recursive calls
414 tmp_ident = (ident ? identity_dup(ident) : new_identity(NULL, NULL, user_id, NULL));
416 if (reset_all_for_user) {
417 status = get_all_keys_for_user(session, user_id, &keys);
419 if (status == PEP_STATUS_OK) {
420 stringlist_t* curr_key;
422 for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
423 // FIXME: Is the ident really necessary?
424 status = key_reset(session, curr_key->value, tmp_ident, own_identities, own_revoked_fprs);
425 if (status != PEP_STATUS_OK)
432 // tmp_ident => tmp_ident->user_id (was checked)
434 // !(EMPTYSTR(fpr) && (!tmp_ident || EMPTYSTR(tmp_ident->address)))
435 // => fpr || (tmp_ident && tmp_ident->address)
437 // so: We have an fpr or we have an ident with user_id and address
440 // We are guaranteed to have an ident w/ id + addr here.
441 // Get the default key.
442 pEp_identity* stored_ident = NULL;
443 status = get_identity(session, tmp_ident->address,
444 tmp_ident->user_id, &stored_ident);
447 if (status == PEP_STATUS_OK) {
448 // transfer ownership
449 fpr_copy = stored_ident->fpr;
450 stored_ident->fpr = NULL;
451 free_identity(stored_ident);
454 if (!fpr_copy || status == PEP_CANNOT_FIND_IDENTITY) {
455 // There's no identity default. Try resetting user default
456 status = get_user_default_key(session, tmp_ident->user_id, &fpr_copy);
459 if (!fpr_copy || status != PEP_STATUS_OK) // No default to free. We're done here.
463 // Ok - now we have at least an ident with user_id and an fpr.
464 // Now it matters if we're talking about ourselves or a partner.
465 bool is_own_private = false;
466 if (is_me(session, tmp_ident)) {
467 bool own_key = false;
468 status = is_own_key(session, fpr_copy, &own_key);
470 if (status != PEP_STATUS_OK)
473 status = PEP_ILLEGAL_VALUE;
477 status = contains_priv_key(session, fpr_copy, &is_own_private);
478 if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
482 // Up to this point, we haven't cared about whether or not we
483 // had a full identity. Now we have to deal with that in the
484 // case of own identities with private keys.
486 if (is_own_private) {
488 // If there's no address, we want to reset this key for every identity
489 // it's a part of. Since this means generating new keys, we have to
490 // grab all the identities associated with it.
491 if (EMPTYSTR(tmp_ident->address)) {
492 status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
494 if (status != PEP_CANNOT_FIND_IDENTITY) {
495 if (status == PEP_STATUS_OK) {
496 // now have ident list, or should
497 identity_list* curr_ident;
499 for (curr_ident = key_idents; curr_ident && curr_ident->ident;
500 curr_ident = curr_ident->next) {
502 pEp_identity* this_identity = curr_ident->ident;
503 // Do the full reset on this identity
504 status = key_reset(session, fpr_copy, this_identity, own_identities, own_revoked_fprs);
506 // Ident list gets freed below, do not free here!
508 if (status != PEP_STATUS_OK)
513 // Ok, we've either now reset for each own identity with this key, or
514 // we got an error and want to bail anyway.
519 // Base case for is_own_private starts here
521 status = revoke_key(session, fpr_copy, NULL);
523 // If we have a full identity, we have some cleanup and generation tasks here
524 if (!EMPTYSTR(tmp_ident->address)) {
526 if (status == PEP_STATUS_OK) {
527 tmp_ident->fpr = NULL;
528 status = myself(session, tmp_ident);
530 if (status == PEP_STATUS_OK && tmp_ident->fpr && strcmp(fpr_copy, tmp_ident->fpr) != 0) {
531 new_key = strdup(tmp_ident->fpr);
532 // status = set_own_key(session, tmp_ident, new_key);
535 if (own_revoked_fprs) {
536 // We can dedup this later
537 if (!(*own_revoked_fprs))
538 *own_revoked_fprs = new_stringlist(NULL);
540 char* revkey = strdup(fpr_copy);
542 status = PEP_OUT_OF_MEMORY;
545 stringlist_add(*own_revoked_fprs, revkey);
548 // mistrust fpr from trust
549 tmp_ident->fpr = fpr_copy;
551 tmp_ident->comm_type = PEP_ct_mistrusted;
552 status = set_trust(session, tmp_ident);
553 tmp_ident->fpr = NULL;
555 // Done with old use of ident.
556 if (status == PEP_STATUS_OK) {
557 // Update fpr for outgoing
558 status = myself(session, tmp_ident);
561 if (status == PEP_STATUS_OK && own_identities) {
562 if (!(*own_identities))
563 *own_identities = new_identity_list(NULL);
565 pEp_identity* new_ident = identity_dup(tmp_ident);
567 status = PEP_OUT_OF_MEMORY;
570 identity_list_add(*own_identities, new_ident);
574 if (status == PEP_STATUS_OK)
575 // cascade that mistrust for anyone using this key
576 status = mark_as_compromised(session, fpr_copy);
578 if (status == PEP_STATUS_OK)
579 status = remove_fpr_as_default(session, fpr_copy);
580 if (status == PEP_STATUS_OK)
581 status = add_mistrusted_key(session, fpr_copy);
583 // If there's a new key, do the DB linkage with the revoked one, and
584 // send the key reset mail opportunistically to recently contacted
587 // add to revocation list
588 if (status == PEP_STATUS_OK)
589 status = set_revoked(session, fpr_copy, new_key, time(NULL));
590 // for all active communication partners:
591 // active_send revocation
592 if (status == PEP_STATUS_OK)
593 status = send_key_reset_to_recents(session, fpr_copy, new_key);
595 } // end is_own_private
597 // if it's mistrusted, make it not be so.
598 bool mistrusted_key = false;
599 is_mistrusted_key(session, fpr_copy, &mistrusted_key);
602 delete_mistrusted_key(session, fpr_copy);
604 if (tmp_ident->user_id)
605 status = clear_trust_info(session, tmp_ident->user_id, fpr_copy);
607 // This is a public key (or a private key that isn't ours, which means
608 // we want it gone anyway)
610 // Delete this key from the keyring.
611 // FIXME: when key election disappears, so should this!
612 status = delete_keypair(session, fpr_copy);
615 // REGARDLESS OF WHO OWNS THE KEY, WE NOW NEED TO REMOVE IT AS A DEFAULT.
616 PEP_STATUS cached_status = status;
617 // remove fpr from all identities
618 // remove fpr from all users
619 status = remove_fpr_as_default(session, fpr_copy);
620 // delete key from DB - this does NOT touch the keyring!
621 // Note: for own priv keys, we cannot do this. But we'll never encrypt to/from it.
622 if (status == PEP_STATUS_OK && !is_own_private) {
623 status = remove_key(session, fpr_copy);
625 if (status == PEP_STATUS_OK)
626 status = cached_status;
631 free_identity(tmp_ident);
634 free_identity_list(key_idents);
635 free_stringlist(keys);
640 static stringlist_t* collect_key_material(PEP_SESSION session, stringlist_t* fprs) {
641 stringlist_t* keydata = NULL;
642 stringlist_t* curr_fpr = fprs;
644 if (curr_fpr->value) {
645 char* key_material = NULL;
647 PEP_STATUS status = export_key(session, curr_fpr->value, &key_material, &datasize);
649 free_stringlist(keydata);
652 if (datasize > 0 && key_material) {
654 keydata = new_stringlist(NULL);
656 stringlist_add(keydata, key_material);
659 curr_fpr = curr_fpr->next;
664 PEP_STATUS key_reset_own_and_deliver_revocations(PEP_SESSION session,
665 identity_list** own_identities,
666 stringlist_t** revocations,
667 stringlist_t** keys) {
669 if (!(session && own_identities && revocations && keys))
670 return PEP_ILLEGAL_VALUE;
672 stringlist_t* revoked_fprs = NULL;
673 identity_list* affected_idents = NULL;
675 PEP_STATUS status = key_reset(session, NULL, NULL, &affected_idents, &revoked_fprs);
677 // FIXME: free things
678 if (status != PEP_STATUS_OK)
681 dedup_stringlist(revoked_fprs);
683 *revocations = collect_key_material(session, revoked_fprs);
684 stringlist_t* keydata = NULL;
686 if (affected_idents) {
687 keydata = new_stringlist(NULL);
688 identity_list* curr_ident = affected_idents;
690 if (curr_ident->ident && curr_ident->ident->fpr) {
691 char* key_material = NULL;
693 status = export_key(session, curr_ident->ident->fpr, &key_material, &datasize);
695 free_stringlist(keydata);
698 if (datasize > 0 && key_material)
699 stringlist_add(keydata, key_material);
701 curr_ident = curr_ident->next;
705 *own_identities = affected_idents;
709 return PEP_STATUS_OK;
712 PEP_STATUS key_reset_commands_to_PER(const keyreset_command_list *command_list, char **cmds, size_t *size)
714 PEP_STATUS status = PEP_STATUS_OK;
716 assert(command_list && cmds);
717 if (!(command_list && cmds))
718 return PEP_ILLEGAL_VALUE;
723 Distribution_t *dist = (Distribution_t *) calloc(1, sizeof(Distribution_t));
728 dist->present = Distribution_PR_keyreset;
729 dist->choice.keyreset.present = KeyReset_PR_commands;
731 // convert to ASN.1 struct
733 for (const keyreset_command_list *cl = command_list; cl && cl->command; cl = cl->next) {
734 Command_t *c = (Command_t *) calloc(1, sizeof(Command_t));
739 if (!Identity_from_Struct(cl->command->ident, &c->ident)) {
744 if (OCTET_STRING_fromString(&c->newkey, cl->command->new_key)) {
745 ASN_STRUCT_FREE(asn_DEF_Command, c);
749 if (ASN_SEQUENCE_ADD(&dist->choice.keyreset.choice.commands.commandlist, c)) {
750 ASN_STRUCT_FREE(asn_DEF_Command, c);
759 status = encode_Distribution_message(dist, &_cmds, &_size);
768 status = PEP_OUT_OF_MEMORY;
771 ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
775 PEP_STATUS PER_to_key_reset_commands(const char *cmds, size_t size, keyreset_command_list **command_list)
777 assert(command_list && cmds);
778 if (!(command_list && cmds))
779 return PEP_ILLEGAL_VALUE;
781 *command_list = NULL;
782 keyreset_command_list *result = NULL;
784 Distribution_t *dist = NULL;
785 PEP_STATUS status = decode_Distribution_message(cmds, size, &dist);
789 assert(dist && dist->present == Distribution_PR_keyreset
790 && dist->choice.keyreset.present == KeyReset_PR_commands);
792 if (!(dist && dist->present == Distribution_PR_keyreset
793 && dist->choice.keyreset.present == KeyReset_PR_commands)) {
794 status = PEP_ILLEGAL_VALUE;
798 result = new_keyreset_command_list(NULL);
802 struct Commands__commandlist *cl = &dist->choice.keyreset.choice.commands.commandlist;
803 keyreset_command_list *_result = result;
804 for (int i=0; i<cl->list.count; i++) {
805 pEp_identity *ident = Identity_to_Struct(&cl->list.array[i]->ident, NULL);
809 const char *new_key = (const char *) cl->list.array[i]->newkey.buf;
810 keyreset_command *command = new_keyreset_command(ident, new_key);
812 free_identity(ident);
816 _result = keyreset_command_list_add(_result, command);
817 free_identity(ident);
822 *command_list = result;
826 status = PEP_OUT_OF_MEMORY;
827 free_keyreset_command_list(result);
830 ASN_STRUCT_FREE(asn_DEF_Distribution, dist);