9 #include "pEp_internal.h"
10 #include "keymanagement.h"
13 #define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
16 #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
18 // Space tolerant and case insensitive fingerprint string compare
31 if(fpra[ai] == 0 || fprb[bi] == 0)
35 else if(fpra[ai] == ' ')
39 else if(fprb[bi] == ' ')
43 else if(toupper(fpra[ai]) == toupper(fprb[bi]))
54 while(ai < fpras && bi < fprbs);
56 return ai == fpras && bi == fprbs;
59 PEP_STATUS elect_pubkey(
60 PEP_SESSION session, pEp_identity * identity
64 stringlist_t *keylist;
66 identity->comm_type = PEP_ct_unknown;
68 status = find_keys(session, identity->address, &keylist);
69 assert(status != PEP_OUT_OF_MEMORY);
70 if (status == PEP_OUT_OF_MEMORY)
71 return PEP_OUT_OF_MEMORY;
73 stringlist_t *_keylist;
74 for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
75 PEP_comm_type _comm_type_key;
77 status = get_key_rating(session, _keylist->value, &_comm_type_key);
78 assert(status != PEP_OUT_OF_MEMORY);
79 if (status == PEP_OUT_OF_MEMORY) {
80 free_stringlist(keylist);
81 return PEP_OUT_OF_MEMORY;
84 if (_comm_type_key != PEP_ct_compromized &&
85 _comm_type_key != PEP_ct_unknown)
87 if (identity->comm_type == PEP_ct_unknown ||
88 _comm_type_key > identity->comm_type)
90 identity->comm_type = _comm_type_key;
91 _fpr = _keylist->value;
99 identity->fpr = strdup(_fpr);
100 if (identity->fpr == NULL) {
101 free_stringlist(keylist);
102 return PEP_OUT_OF_MEMORY;
105 free_stringlist(keylist);
106 return PEP_STATUS_OK;
109 DYNAMIC_API PEP_STATUS update_identity(
110 PEP_SESSION session, pEp_identity * identity
113 pEp_identity *stored_identity;
118 assert(!EMPTYSTR(identity->address));
120 if (!(session && identity && !EMPTYSTR(identity->address)))
121 return PEP_ILLEGAL_VALUE;
123 if (identity->me || (identity->user_id && strcmp(identity->user_id, PEP_OWN_USERID) == 0)) {
125 return myself(session, identity);
128 int _no_user_id = EMPTYSTR(identity->user_id);
132 status = get_identity(session, identity->address, PEP_OWN_USERID,
134 if (status == PEP_STATUS_OK) {
135 free_identity(stored_identity);
136 return myself(session, identity);
139 free(identity->user_id);
141 identity->user_id = calloc(1, strlen(identity->address) + 6);
142 if (!identity->user_id)
144 return PEP_OUT_OF_MEMORY;
146 snprintf(identity->user_id, strlen(identity->address) + 6,
147 "TOFU_%s", identity->address);
150 status = get_identity(session,
155 assert(status != PEP_OUT_OF_MEMORY);
156 if (status == PEP_OUT_OF_MEMORY)
159 if (stored_identity) {
160 PEP_comm_type _comm_type_key;
161 status = get_key_rating(session, stored_identity->fpr, &_comm_type_key);
162 assert(status != PEP_OUT_OF_MEMORY);
163 if (status == PEP_OUT_OF_MEMORY)
166 if (EMPTYSTR(identity->username)) {
167 free(identity->username);
168 identity->username = strdup(stored_identity->username);
169 assert(identity->username);
170 if (identity->username == NULL){
171 status = PEP_OUT_OF_MEMORY;
176 if (EMPTYSTR(identity->fpr)) {
177 identity->fpr = strdup(stored_identity->fpr);
178 assert(identity->fpr);
179 if (identity->fpr == NULL)
180 return PEP_OUT_OF_MEMORY;
181 if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
182 PEP_STATUS status = elect_pubkey(session, identity);
183 if (status != PEP_STATUS_OK)
187 identity->comm_type = stored_identity->comm_type;
190 else /* !EMPTYSTR(identity->fpr) */ {
191 if (_same_fpr(identity->fpr,
192 strlen(identity->fpr),
193 stored_identity->fpr,
194 strlen(stored_identity->fpr))) {
195 if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
196 identity->comm_type = _comm_type_key;
198 identity->comm_type = stored_identity->comm_type;
199 if (identity->comm_type == PEP_ct_unknown) {
200 identity->comm_type = _comm_type_key;
204 status = get_trust(session, identity);
205 assert(status != PEP_OUT_OF_MEMORY);
206 if (status == PEP_OUT_OF_MEMORY)
208 if (identity->comm_type < stored_identity->comm_type)
209 identity->comm_type = PEP_ct_unknown;
213 if (identity->lang[0] == 0) {
214 identity->lang[0] = stored_identity->lang[0];
215 identity->lang[1] = stored_identity->lang[1];
216 identity->lang[2] = 0;
219 identity->flags = stored_identity->flags;
221 else /* stored_identity == NULL */ {
224 if (!EMPTYSTR(identity->fpr)) {
225 PEP_comm_type _comm_type_key;
227 status = get_key_rating(session, identity->fpr, &_comm_type_key);
228 assert(status != PEP_OUT_OF_MEMORY);
229 if (status == PEP_OUT_OF_MEMORY)
232 identity->comm_type = _comm_type_key;
234 else /* EMPTYSTR(identity->fpr) */ {
235 PEP_STATUS status = elect_pubkey(session, identity);
236 if (status != PEP_STATUS_OK)
241 status = PEP_STATUS_OK;
243 if (identity->comm_type != PEP_ct_unknown && !EMPTYSTR(identity->user_id)) {
244 assert(!EMPTYSTR(identity->username)); // this should not happen
246 if (EMPTYSTR(identity->username)) { // mitigate
247 free(identity->username);
248 identity->username = strdup("anonymous");
249 assert(identity->username);
250 if (identity->username == NULL){
251 status = PEP_OUT_OF_MEMORY;
256 // Identity doesn't get stored if call was just about checking existing
257 // user by address (i.e. no user id given but already stored)
258 if (!(_no_user_id && stored_identity))
260 status = set_identity(session, identity);
261 assert(status == PEP_STATUS_OK);
262 if (status != PEP_STATUS_OK) {
268 if (identity->comm_type != PEP_ct_compromized &&
269 identity->comm_type < PEP_ct_strong_but_unconfirmed)
270 if (session->examine_identity)
271 session->examine_identity(identity, session->examine_management);
275 if (stored_identity){
276 free_identity(stored_identity);
282 PEP_STATUS elect_ownkey(
283 PEP_SESSION session, pEp_identity * identity
287 stringlist_t *keylist = NULL;
290 identity->fpr = NULL;
292 status = find_keys(session, identity->address, &keylist);
293 assert(status != PEP_OUT_OF_MEMORY);
294 if (status == PEP_OUT_OF_MEMORY)
295 return PEP_OUT_OF_MEMORY;
297 if (keylist != NULL && keylist->value != NULL)
300 identity->comm_type = PEP_ct_unknown;
302 stringlist_t *_keylist;
303 for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
306 if (session->use_only_own_private_keys)
308 status = own_key_is_listed(session, _keylist->value, &is_own);
309 assert(status == PEP_STATUS_OK);
310 if (status != PEP_STATUS_OK) {
311 free_stringlist(keylist);
316 // TODO : also accept synchronized device group keys ?
318 if (!session->use_only_own_private_keys || is_own)
320 PEP_comm_type _comm_type_key;
322 status = get_key_rating(session, _keylist->value, &_comm_type_key);
323 assert(status != PEP_OUT_OF_MEMORY);
324 if (status == PEP_OUT_OF_MEMORY) {
325 free_stringlist(keylist);
326 return PEP_OUT_OF_MEMORY;
329 if (_comm_type_key != PEP_ct_compromized &&
330 _comm_type_key != PEP_ct_unknown)
332 if (identity->comm_type == PEP_ct_unknown ||
333 _comm_type_key > identity->comm_type)
335 identity->comm_type = _comm_type_key;
336 _fpr = _keylist->value;
344 identity->fpr = strdup(_fpr);
345 assert(identity->fpr);
346 if (identity->fpr == NULL)
348 free_stringlist(keylist);
349 return PEP_OUT_OF_MEMORY;
352 free_stringlist(keylist);
354 return PEP_STATUS_OK;
357 DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
359 pEp_identity *stored_identity;
364 assert(!EMPTYSTR(identity->address));
366 assert(EMPTYSTR(identity->user_id) ||
367 strcmp(identity->user_id, PEP_OWN_USERID) == 0);
369 if (!(session && identity && !EMPTYSTR(identity->address) &&
370 (EMPTYSTR(identity->user_id) ||
371 strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
372 return PEP_ILLEGAL_VALUE;
374 identity->comm_type = PEP_ct_pEp;
377 if (EMPTYSTR(identity->user_id))
379 free(identity->user_id);
380 identity->user_id = strdup(PEP_OWN_USERID);
381 assert(identity->user_id);
382 if (identity->user_id == NULL)
383 return PEP_OUT_OF_MEMORY;
386 DEBUG_LOG("myself", "debug", identity->address);
388 status = get_identity(session,
393 assert(status != PEP_OUT_OF_MEMORY);
394 if (status == PEP_OUT_OF_MEMORY)
395 return PEP_OUT_OF_MEMORY;
399 if (EMPTYSTR(identity->fpr)) {
400 identity->fpr = strdup(stored_identity->fpr);
401 assert(identity->fpr);
402 if (identity->fpr == NULL)
404 return PEP_OUT_OF_MEMORY;
408 identity->flags = stored_identity->flags;
410 else if (!EMPTYSTR(identity->fpr))
412 // App must have a good reason to give fpr, such as explicit
413 // import of private key, or similar.
415 // Take given fpr as-is.
421 status = elect_ownkey(session, identity);
422 assert(status == PEP_STATUS_OK);
423 if (status != PEP_STATUS_OK) {
430 bool revoked = false;
432 if (!EMPTYSTR(identity->fpr))
434 status = key_revoked(session, identity->fpr, &revoked);
436 // Forces re-election if key is missing and own-key-only not forced
437 if (!session->use_only_own_private_keys && status == PEP_KEY_NOT_FOUND)
439 status = elect_ownkey(session, identity);
440 assert(status == PEP_STATUS_OK);
441 if (status != PEP_STATUS_OK) {
445 else if (status != PEP_STATUS_OK)
451 if (EMPTYSTR(identity->fpr) || revoked)
455 r_fpr = identity->fpr;
456 identity->fpr = NULL;
459 DEBUG_LOG("generating key pair", "debug", identity->address);
460 status = generate_keypair(session, identity);
461 assert(status != PEP_OUT_OF_MEMORY);
462 if (status != PEP_STATUS_OK) {
464 snprintf(buf, 11, "%d", status);
465 DEBUG_LOG("generating key pair failed", "debug", buf);
473 status = set_revoked(session, r_fpr,
474 identity->fpr, time(NULL));
476 if (status != PEP_STATUS_OK) {
484 status = key_expired(session, identity->fpr,
485 time(NULL) + (7*24*3600), // In a week
488 assert(status == PEP_STATUS_OK);
489 if (status != PEP_STATUS_OK) {
493 if (status == PEP_STATUS_OK && expired) {
494 timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
495 renew_key(session, identity->fpr, ts);
500 status = set_identity(session, identity);
501 assert(status == PEP_STATUS_OK);
502 if (status != PEP_STATUS_OK) {
506 return PEP_STATUS_OK;
510 DYNAMIC_API PEP_STATUS register_examine_function(
512 examine_identity_t examine_identity,
518 return PEP_ILLEGAL_VALUE;
520 session->examine_management = management;
521 session->examine_identity = examine_identity;
523 return PEP_STATUS_OK;
526 DYNAMIC_API PEP_STATUS do_keymanagement(
527 retrieve_next_identity_t retrieve_next_identity,
532 pEp_identity *identity;
535 assert(retrieve_next_identity);
538 if (!retrieve_next_identity || !management)
539 return PEP_ILLEGAL_VALUE;
541 status = init(&session);
542 assert(status == PEP_STATUS_OK);
543 if (status != PEP_STATUS_OK)
546 log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
548 while ((identity = retrieve_next_identity(management)))
550 assert(identity->address);
551 if(identity->address)
553 DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
556 status = myself(session, identity);
558 status = recv_key(session, identity->address);
561 assert(status != PEP_OUT_OF_MEMORY);
562 if(status == PEP_OUT_OF_MEMORY)
563 return PEP_OUT_OF_MEMORY;
565 free_identity(identity);
568 log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
571 return PEP_STATUS_OK;
574 DYNAMIC_API PEP_STATUS key_compromized(
579 PEP_STATUS status = PEP_STATUS_OK;
583 assert(!EMPTYSTR(ident->fpr));
585 if (!(session && ident && ident->fpr))
586 return PEP_ILLEGAL_VALUE;
590 revoke_key(session, ident->fpr, NULL);
591 myself(session, ident);
595 status = mark_as_compromized(session, ident->fpr);
601 DYNAMIC_API PEP_STATUS key_reset_trust(
606 PEP_STATUS status = PEP_STATUS_OK;
611 assert(!EMPTYSTR(ident->fpr));
612 assert(!EMPTYSTR(ident->address));
613 assert(!EMPTYSTR(ident->user_id));
615 if (!(session && ident && !ident->me && ident->fpr && ident->address &&
617 return PEP_ILLEGAL_VALUE;
619 status = update_identity(session, ident);
620 if (status != PEP_STATUS_OK)
623 if (ident->comm_type == PEP_ct_mistrusted)
624 ident->comm_type = PEP_ct_unknown;
626 ident->comm_type &= ~PEP_ct_confirmed;
628 status = set_identity(session, ident);
629 if (status != PEP_STATUS_OK)
632 if (ident->comm_type == PEP_ct_unknown)
633 status = update_identity(session, ident);
637 DYNAMIC_API PEP_STATUS trust_personal_key(
642 PEP_STATUS status = PEP_STATUS_OK;
646 assert(!EMPTYSTR(ident->address));
647 assert(!EMPTYSTR(ident->user_id));
648 assert(!EMPTYSTR(ident->fpr));
651 if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
652 EMPTYSTR(ident->fpr) || ident->me)
653 return PEP_ILLEGAL_VALUE;
655 status = update_identity(session, ident);
656 if (status != PEP_STATUS_OK)
659 if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
660 ident->comm_type |= PEP_ct_confirmed;
661 status = set_identity(session, ident);
664 // MISSING: S/MIME has to be handled depending on trusted CAs
665 status = PEP_CANNOT_SET_TRUST;
671 DYNAMIC_API PEP_STATUS own_key_is_listed(
677 PEP_STATUS status = PEP_STATUS_OK;
680 assert(session && fpr && fpr[0] && listed);
682 if (!(session && fpr && fpr[0] && listed))
683 return PEP_ILLEGAL_VALUE;
687 sqlite3_reset(session->own_key_is_listed);
688 sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
692 result = sqlite3_step(session->own_key_is_listed);
695 count = sqlite3_column_int(session->own_key_is_listed, 0);
697 status = PEP_STATUS_OK;
701 status = PEP_UNKNOWN_ERROR;
704 sqlite3_reset(session->own_key_is_listed);
708 DYNAMIC_API PEP_STATUS own_identities_retrieve(
710 identity_list **own_identities
713 PEP_STATUS status = PEP_STATUS_OK;
715 assert(session && own_identities);
716 if (!(session && own_identities))
717 return PEP_ILLEGAL_VALUE;
719 *own_identities = NULL;
720 identity_list *_own_identities = new_identity_list(NULL);
721 if (_own_identities == NULL)
724 sqlite3_reset(session->own_identities_retrieve);
727 // address, fpr, username, user_id, comm_type, lang, flags
728 const char *address = NULL;
729 const char *fpr = NULL;
730 const char *username = NULL;
731 const char *user_id = NULL;
732 PEP_comm_type comm_type = PEP_ct_unknown;
733 const char *lang = NULL;
734 unsigned int flags = 0;
736 identity_list *_bl = _own_identities;
738 result = sqlite3_step(session->own_identities_retrieve);
741 address = (const char *)
742 sqlite3_column_text(session->own_identities_retrieve, 0);
744 sqlite3_column_text(session->own_identities_retrieve, 1);
745 user_id = PEP_OWN_USERID;
746 username = (const char *)
747 sqlite3_column_text(session->own_identities_retrieve, 2);
748 comm_type = PEP_ct_pEp;
749 lang = (const char *)
750 sqlite3_column_text(session->own_identities_retrieve, 3);
751 flags = (unsigned int)
752 sqlite3_column_int(session->own_key_is_listed, 4);
754 pEp_identity *ident = new_identity(address, fpr, user_id, username);
757 ident->comm_type = comm_type;
758 if (lang && lang[0]) {
759 ident->lang[0] = lang[0];
760 ident->lang[1] = lang[1];
764 ident->flags = flags;
766 _bl = identity_list_add(_bl, ident);
768 free_identity(ident);
778 status = PEP_UNKNOWN_ERROR;
779 result = SQLITE_DONE;
781 } while (result != SQLITE_DONE);
783 sqlite3_reset(session->own_identities_retrieve);
784 if (status == PEP_STATUS_OK)
785 *own_identities = _own_identities;
787 free_identity_list(_own_identities);
792 free_identity_list(_own_identities);
793 status = PEP_OUT_OF_MEMORY;