merged in default

doxygen-key-id
commit 1327a2d5ad

@ -1277,7 +1277,7 @@
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-DSQLITE3_FROM_OS";
SDKROOT = iphoneos;
VALID_ARCHS = "$(VALID_ARCHS) x86_64";
VALID_ARCHS = "arm64 x86_64";
};
name = Debug;
};
@ -1340,7 +1340,7 @@
OTHER_CFLAGS = "-DSQLITE3_FROM_OS";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
VALID_ARCHS = "$(VALID_ARCHS) x86_64";
VALID_ARCHS = "arm64 x86_64";
};
name = Release;
};

@ -41,7 +41,7 @@ static PEP_STATUS update_identity_recip_list(PEP_SESSION session,
}
}
else
status = _myself(session, curr_identity, false, false, true);
status = _myself(session, curr_identity, false, false, false, true);
if (status == PEP_ILLEGAL_VALUE || status == PEP_OUT_OF_MEMORY)
return status;
}
@ -86,9 +86,9 @@ DYNAMIC_API PEP_STATUS MIME_decrypt_message(
if (!is_me(session, tmp_msg->from))
status = update_identity(session, (tmp_msg->from));
else
status = _myself(session, tmp_msg->from, false, false, true);
status = _myself(session, tmp_msg->from, false, true, false, true);
if (status == PEP_ILLEGAL_VALUE || status == PEP_OUT_OF_MEMORY)
if (status == PEP_ILLEGAL_VALUE || status == PEP_OUT_OF_MEMORY || PASS_ERROR(status))
goto pEp_error;
}

@ -70,9 +70,14 @@ static PEP_STATUS _generate_reset_structs(PEP_SESSION session,
if (!include_secret) { // This isn't to own recips, so shipping the rev'd key is OK. Own keys are revoked on each device.
status = export_key(session, old_fpr, &key_material_old, &datasize);
// Shouldn't happen, but we can't make presumptions about crypto engine
if (PASS_ERROR(status))
goto pEp_error;
if (datasize > 0 && key_material_old) {
if (status != PEP_STATUS_OK)
return status;
goto pEp_error;
if (!keys)
keys = new_bloblist(key_material_old, datasize,
@ -85,10 +90,13 @@ static PEP_STATUS _generate_reset_structs(PEP_SESSION session,
datasize = 0;
}
status = export_key(session, new_fpr, &key_material_new, &datasize);
// Shouldn't happen, but we can't make presumptions about crypto engine
if (PASS_ERROR(status))
goto pEp_error;
if (datasize > 0 && key_material_new) {
if (status != PEP_STATUS_OK)
return status;
goto pEp_error;
if (!keys)
keys = new_bloblist(key_material_new, datasize,
@ -100,8 +108,8 @@ static PEP_STATUS _generate_reset_structs(PEP_SESSION session,
datasize = 0;
if (include_secret) {
status = export_secret_key(session, new_fpr, &key_material_priv, &datasize);
if (status != PEP_STATUS_OK)
return status;
if (status != PEP_STATUS_OK) // includes PASS_ERROR
goto pEp_error;
if (datasize > 0 && key_material_priv) {
bloblist_add(keys, key_material_priv, datasize, "application/pgp-keys",
"file://pEpkey_priv.asc");
@ -115,6 +123,13 @@ static PEP_STATUS _generate_reset_structs(PEP_SESSION session,
*key_attachments = keys;
}
return status;
pEp_error:
free(key_material_old);
free(key_material_new);
free(key_material_priv);
free_bloblist(keys);
return status;
}
// For multiple idents under a single key
@ -142,9 +157,11 @@ static PEP_STATUS _generate_own_commandlist_msg(PEP_SESSION session,
&kr_commands,
true);
if (status != PEP_STATUS_OK)
return status; // FIXME
if (!key_attachments || !kr_commands)
return PEP_UNKNOWN_ERROR;
goto pEp_error;
if (!key_attachments || !kr_commands) {
status = PEP_UNKNOWN_ERROR;
goto pEp_error;
}
}
}
@ -157,7 +174,7 @@ static PEP_STATUS _generate_own_commandlist_msg(PEP_SESSION session,
size_t size = 0;
status = key_reset_commands_to_PER(kr_commands, &payload, &size);
if (status != PEP_STATUS_OK)
return status;
goto pEp_error;
// From and to our first ident - this only goes to us.
pEp_identity* from = identity_dup(from_idents->ident);
@ -166,17 +183,22 @@ static PEP_STATUS _generate_own_commandlist_msg(PEP_SESSION session,
BASE_KEYRESET, payload, size, NULL,
&msg);
if (status != PEP_STATUS_OK) {
free(msg);
return status;
if (status != PEP_STATUS_OK)
goto pEp_error;
if (!msg) {
status = PEP_OUT_OF_MEMORY;
goto pEp_error;
}
if (!msg->attachments) {
status = PEP_UNKNOWN_ERROR;
goto pEp_error;
}
if (!msg)
return PEP_OUT_OF_MEMORY;
if (!msg->attachments)
return PEP_UNKNOWN_ERROR;
if (!bloblist_join(msg->attachments, key_attachments))
return PEP_UNKNOWN_ERROR;
if (!bloblist_join(msg->attachments, key_attachments)) {
status = PEP_UNKNOWN_ERROR;
goto pEp_error;
}
if (msg)
*dst = msg;
@ -184,7 +206,16 @@ static PEP_STATUS _generate_own_commandlist_msg(PEP_SESSION session,
free_keyreset_command_list(kr_commands);
return status;
pEp_error:
if (!msg)
free_bloblist(key_attachments);
else
free(msg);
free_keyreset_command_list(kr_commands);
return status;
}
static PEP_STATUS _generate_keyreset_command_message(PEP_SESSION session,
@ -198,8 +229,7 @@ static PEP_STATUS _generate_keyreset_command_message(PEP_SESSION session,
if (!session || !from_ident || !old_fpr || !new_fpr || !dst)
return PEP_ILLEGAL_VALUE;
// safe cast
if (!is_me(session, (pEp_identity*)from_ident))
if (!is_me(session, from_ident))
return PEP_ILLEGAL_VALUE;
PEP_STATUS status = PEP_STATUS_OK;
@ -228,29 +258,41 @@ static PEP_STATUS _generate_keyreset_command_message(PEP_SESSION session,
&key_attachments,
&kr_list,
is_private);
// N.B. command list and key attachments are freed by
// _generate_reset_structs when status is not OK
if (status != PEP_STATUS_OK)
return status; // FIXME
return status;
if (!key_attachments || !kr_list)
return PEP_UNKNOWN_ERROR;
char* payload = NULL;
size_t size = 0;
status = key_reset_commands_to_PER(kr_list, &payload, &size);
if (status != PEP_STATUS_OK)
return status;
status = base_prepare_message(session, outgoing_ident, to_ident,
BASE_KEYRESET, payload, size, NULL,
&msg);
if (status) {
if (status != PEP_STATUS_OK) {
free(msg);
return status;
}
if (!msg)
return PEP_OUT_OF_MEMORY;
if (!msg->attachments)
if (!msg->attachments) {
free(msg);
return PEP_UNKNOWN_ERROR;
}
if (msg)
*dst = msg;
return status;
}
PEP_STATUS has_key_reset_been_sent(
@ -401,6 +443,8 @@ PEP_STATUS receive_key_reset(PEP_SESSION session,
if (!sender_id->user_id)
return PEP_UNKNOWN_ERROR;
}
if (status != PEP_STATUS_OK) // Do we need to be more specific??
return status;
bool sender_own_key = false;
bool from_me = is_me(session, sender_id);
@ -506,7 +550,9 @@ PEP_STATUS receive_key_reset(PEP_SESSION session,
free(curr_ident->user_id);
curr_ident->user_id = NULL;
status = update_identity(session, curr_ident);
if (status != PEP_STATUS_OK)
return status;
// Ok, now check the old fpr to see if we have an entry for it
// temp fpr set for function call
curr_ident->fpr = old_fpr;

@ -14,6 +14,7 @@
#include "pEp_internal.h"
#include "keymanagement.h"
#include "KeySync_fsm.h"
#include "blacklist.h"
@ -42,6 +43,7 @@ static bool key_matches_address(PEP_SESSION session, const char* address,
return retval;
}
// Does not return PASSPHRASE errors
PEP_STATUS elect_pubkey(
PEP_SESSION session, pEp_identity * identity, bool check_blacklist
)
@ -109,10 +111,13 @@ PEP_STATUS elect_pubkey(
// own_must_contain_private is usually true when calling;
// we only set it to false when we have the idea of
// possibly having an own pubkey that we need to check on its own
// N.B. Checked for PASSPHRASE errors - will now return them always
// False value of "renew_private" prevents their possibility, though.
static PEP_STATUS validate_fpr(PEP_SESSION session,
pEp_identity* ident,
bool check_blacklist,
bool own_must_contain_private) {
bool own_must_contain_private,
bool renew_private) {
PEP_STATUS status = PEP_STATUS_OK;
@ -124,6 +129,7 @@ static PEP_STATUS validate_fpr(PEP_SESSION session,
bool has_private = false;
status = contains_priv_key(session, fpr, &has_private);
// N.B. Will not contain PEP_PASSPHRASE related returns here
if (ident->me && own_must_contain_private) {
if (status != PEP_STATUS_OK || !has_private)
return PEP_KEY_UNSUITABLE;
@ -176,6 +182,7 @@ static PEP_STATUS validate_fpr(PEP_SESSION session,
bool revoked, expired;
bool blacklisted = false;
// Should not need to decrypt key material
status = key_revoked(session, fpr, &revoked);
if (status != PEP_STATUS_OK) {
@ -185,11 +192,12 @@ static PEP_STATUS validate_fpr(PEP_SESSION session,
if (!revoked) {
time_t exp_time = (ident->me ?
time(NULL) + (7*24*3600) : time(NULL));
// Should not need to decrypt key material
status = key_expired(session, fpr,
exp_time,
&expired);
assert(status == PEP_STATUS_OK);
if (status != PEP_STATUS_OK)
return status;
@ -205,7 +213,9 @@ static PEP_STATUS validate_fpr(PEP_SESSION session,
}
}
if (ident->me && has_private &&
// Renew key if it's expired, our own, has a private part,
// isn't too weak, and we didn't say "DON'T DO THIS"
if (renew_private && ident->me && has_private &&
(ct >= PEP_ct_strong_but_unconfirmed) &&
!revoked && expired) {
// extend key
@ -213,6 +223,9 @@ static PEP_STATUS validate_fpr(PEP_SESSION session,
status = renew_key(session, fpr, ts);
free_timestamp(ts);
if (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE)
return status;
if (status == PEP_STATUS_OK) {
// if key is valid (second check because pEp key might be extended above)
// Return fpr
@ -341,6 +354,11 @@ PEP_STATUS get_user_default_key(PEP_SESSION session, const char* user_id,
// Also, we presume that if the stored_identity was sent in
// without an fpr, there wasn't one in the trust DB for this
// identity.
//
// Will now NOT return passphrase errors, as we tell
// validate_fpr NOT to renew it. And we specifically suppress them
// with "PEP_KEY_UNSUITABLE"
//
PEP_STATUS get_valid_pubkey(PEP_SESSION session,
pEp_identity* stored_identity,
bool* is_identity_default,
@ -360,19 +378,28 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
PEP_STATUS first_reject_status = PEP_KEY_NOT_FOUND;
char* stored_fpr = stored_identity->fpr;
// Input: stored identity retrieved from database
// if stored identity contains a default key
if (!EMPTYSTR(stored_fpr)) {
status = validate_fpr(session, stored_identity, check_blacklist, true);
if (status == PEP_STATUS_OK && !EMPTYSTR(stored_identity->fpr)) {
*is_identity_default = *is_address_default = true;
return status;
}
else if (status != PEP_KEY_NOT_FOUND) {
first_reject_status = status;
first_reject_comm_type = stored_identity->comm_type;
}
}
// Won't ask for passphrase, won't return PASSPHRASE status
// Because of non-renewal
status = validate_fpr(session, stored_identity, check_blacklist, true, false);
switch (status) {
case PEP_STATUS_OK:
if (!EMPTYSTR(stored_identity->fpr)) {
*is_identity_default = *is_address_default = true;
return status;
}
break;
case PEP_KEY_NOT_FOUND:
break;
default:
first_reject_status = status;
first_reject_comm_type = stored_identity->comm_type;
}
}
// if no valid default stored identity key found
free(stored_identity->fpr);
stored_identity->fpr = NULL;
@ -383,24 +410,38 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
if (!EMPTYSTR(user_fpr)) {
// There exists a default key for user, so validate
stored_identity->fpr = user_fpr;
status = validate_fpr(session, stored_identity, check_blacklist, true);
if (status == PEP_STATUS_OK && stored_identity->fpr) {
*is_user_default = true;
*is_address_default = key_matches_address(session,
stored_identity->address,
stored_identity->fpr);
return status;
}
else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
first_reject_status = status;
first_reject_comm_type = stored_identity->comm_type;
}
// Won't ask for passphrase, won't return PASSPHRASE status
// Because of non-renewal
status = validate_fpr(session, stored_identity, check_blacklist, true, false);
switch (status) {
case PEP_STATUS_OK:
if (!EMPTYSTR(stored_identity->fpr)) {
*is_user_default = true;
*is_address_default = key_matches_address(session,
stored_identity->address,
stored_identity->fpr);
return status;
}
break;
case PEP_KEY_NOT_FOUND:
break;
default:
if (first_reject_status != PEP_KEY_NOT_FOUND) {
first_reject_status = status;
first_reject_comm_type = stored_identity->comm_type;
}
}
}
status = elect_pubkey(session, stored_identity, check_blacklist);
if (status == PEP_STATUS_OK) {
if (!EMPTYSTR(stored_identity->fpr))
validate_fpr(session, stored_identity, false, true); // blacklist already filtered of needed
if (!EMPTYSTR(stored_identity->fpr)) {
// Won't ask for passphrase, won't return PASSPHRASE status
// Because of non-renewal
status = validate_fpr(session, stored_identity, false, true, false); // blacklist already filtered of needed
}
}
else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
first_reject_status = status;
@ -428,6 +469,11 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
}
break;
}
// should never happen, but we will MAKE sure
if (PASS_ERROR(status))
status = PEP_KEY_UNSUITABLE; // renew it on your own time, baby
return status;
}
@ -466,6 +512,11 @@ static void adjust_pEp_trust_status(PEP_SESSION session, pEp_identity* identity)
}
// NEVER called on an own identity.
// But we also make sure get_valid_pubkey
// and friends NEVER return with a password error.
// (get_valid_pubkey tells validate_fpr not to try renewal)
// Will not return PASSPHRASE errors.
static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
pEp_identity* return_id,
pEp_identity* stored_ident,
@ -483,29 +534,31 @@ static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
&is_identity_default,
&is_user_default,
&is_address_default,
false);
if (status == PEP_STATUS_OK && stored_ident->fpr && *(stored_ident->fpr) != '\0') {
// set identity comm_type from trust db (user_id, FPR)
status = get_trust(session, stored_ident);
if (status == PEP_CANNOT_FIND_IDENTITY || stored_ident->comm_type == PEP_ct_unknown) {
// This is OK - there is no trust DB entry, but we
// found a key. We won't store this, but we'll
// use it.
PEP_comm_type ct = PEP_ct_unknown;
status = get_key_rating(session, stored_ident->fpr, &ct);
stored_ident->comm_type = ct;
}
}
else if (status != PEP_STATUS_OK) {
free(stored_ident->fpr);
stored_ident->fpr = NULL;
stored_ident->comm_type = PEP_ct_key_not_found;
}
else { // no key returned, but status ok?
if (stored_ident->comm_type == PEP_ct_unknown)
stored_ident->comm_type = PEP_ct_key_not_found;
false);
switch (status) {
case PEP_STATUS_OK:
if (!EMPTYSTR(stored_ident->fpr)) {
// set identity comm_type from trust db (user_id, FPR)
status = get_trust(session, stored_ident);
if (status == PEP_CANNOT_FIND_IDENTITY || stored_ident->comm_type == PEP_ct_unknown) {
// This is OK - there is no trust DB entry, but we
// found a key. We won't store this, but we'll
// use it.
PEP_comm_type ct = PEP_ct_unknown;
status = get_key_rating(session, stored_ident->fpr, &ct);
stored_ident->comm_type = ct;
}
}
else if (stored_ident->comm_type == PEP_ct_unknown)
stored_ident->comm_type = PEP_ct_key_not_found;
break;
default:
free(stored_ident->fpr);
stored_ident->fpr = NULL;
stored_ident->comm_type = PEP_ct_key_not_found;
}
free(return_id->fpr);
return_id->fpr = NULL;
if (status == PEP_STATUS_OK && !EMPTYSTR(stored_ident->fpr))
@ -585,6 +638,8 @@ static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
return status;
}
// Should not return PASSPHRASE errors because we force
// calls that can cause key renewal not to.
DYNAMIC_API PEP_STATUS update_identity(
PEP_SESSION session, pEp_identity * identity
)
@ -632,7 +687,8 @@ DYNAMIC_API PEP_STATUS update_identity(
if (_own_addr) {
free(identity->user_id);
identity->user_id = strdup(default_own_id);
return _myself(session, identity, false, false, true);
// Do not renew, do not generate
return _myself(session, identity, false, false, false, true);
}
}
}
@ -1055,7 +1111,8 @@ PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
PEP_STATUS _myself(PEP_SESSION session,
pEp_identity * identity,
bool do_keygen,
bool do_keygen,
bool do_renew,
bool ignore_flags,
bool read_only)
{
@ -1142,7 +1199,10 @@ PEP_STATUS _myself(PEP_SESSION session,
// Set usernames - priority is input username > stored name > address
// If there's an input username, we always patch the username with that
// input.
if (EMPTYSTR(identity->username) || read_only) {
// N.B. there was an || read_only here, but why? read_only ONLY means
// we don't write to the DB! So... removed. But how this managed to work
// before I don't know.
if (EMPTYSTR(identity->username)) {
bool stored_uname = (stored_identity && !EMPTYSTR(stored_identity->username));
char* uname = (stored_uname ? stored_identity->username : identity->address);
if (uname) {
@ -1167,34 +1227,43 @@ PEP_STATUS _myself(PEP_SESSION session,
if (stored_identity) {
if (!EMPTYSTR(stored_identity->fpr)) {
// Fall back / retrieve
status = validate_fpr(session, stored_identity, false, true);
if (status == PEP_OUT_OF_MEMORY)
goto pEp_free;
if (status == PEP_STATUS_OK) {
if (stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
identity->fpr = strdup(stored_identity->fpr);
assert(identity->fpr);
if (!identity->fpr) {
status = PEP_OUT_OF_MEMORY;
goto pEp_free;
}
valid_key_found = true;
}
else {
bool revoked = false;
status = key_revoked(session, stored_identity->fpr, &revoked);
if (status)
goto pEp_free;
if (revoked) {
revoked_fpr = strdup(stored_identity->fpr);
assert(revoked_fpr);
if (!revoked_fpr) {
status = validate_fpr(session, stored_identity, false, true, do_renew);
switch (status) {
// Only possible if we called this with do_renew = true
case PEP_OUT_OF_MEMORY:
case PEP_PASSPHRASE_REQUIRED:
case PEP_WRONG_PASSPHRASE:
goto pEp_free;
case PEP_STATUS_OK:
if (stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
identity->fpr = strdup(stored_identity->fpr);
assert(identity->fpr);
if (!identity->fpr) {
status = PEP_OUT_OF_MEMORY;
goto pEp_free;
}
valid_key_found = true;
}
}
}
else {
bool revoked = false;
status = key_revoked(session, stored_identity->fpr, &revoked);
if (status)
goto pEp_free;
if (revoked) {
revoked_fpr = strdup(stored_identity->fpr);
assert(revoked_fpr);
if (!revoked_fpr) {
status = PEP_OUT_OF_MEMORY;
goto pEp_free;
}
}
}
break;
default:
break;
}
}
// reconcile language, flags
transfer_ident_lang_and_flags(identity, stored_identity);
@ -1212,6 +1281,9 @@ PEP_STATUS _myself(PEP_SESSION session,
status = generate_keypair(session, identity);
assert(status != PEP_OUT_OF_MEMORY);
if (status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED)
goto pEp_free;
if (status != PEP_STATUS_OK) {
char buf[11];
snprintf(buf, 11, "%d", status); // uh, this is kludgey. FIXME
@ -1263,7 +1335,7 @@ pEp_free:
DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
{
return _myself(session, identity, true, false, false);
return _myself(session, identity, true, true, false, false);
}
DYNAMIC_API PEP_STATUS register_examine_function(
@ -1493,6 +1565,12 @@ pEp_free:
return status;
}
// Technically speaking, this should not EVER
// return PASSPHRASE errors, because
// this is never for an own identity (enforced), and thus
// validate_fpr will not call renew_key.
// If it ever does, the status gets propagated, but
// it is distinctly not OK.
DYNAMIC_API PEP_STATUS trust_personal_key(
PEP_SESSION session,
pEp_identity *ident
@ -1540,7 +1618,7 @@ DYNAMIC_API PEP_STATUS trust_personal_key(
// Set up a temp trusted identity for the input fpr without a comm type;
tmp_id = new_identity(ident->address, ident->fpr, ident->user_id, NULL);
status = validate_fpr(session, tmp_id, false, true);
status = validate_fpr(session, tmp_id, false, true, false);
if (status == PEP_STATUS_OK) {
// Validate fpr gets trust DB or, when that fails, key comm type. we checked
@ -1600,7 +1678,7 @@ DYNAMIC_API PEP_STATUS trust_personal_key(
if (!tmp_user_ident)
status = PEP_OUT_OF_MEMORY;
else {
status = validate_fpr(session, tmp_user_ident, false, true);
status = validate_fpr(session, tmp_user_ident, false, true, false);
if (status != PEP_STATUS_OK ||
tmp_user_ident->comm_type < PEP_ct_strong_but_unconfirmed ||
@ -1642,7 +1720,7 @@ DYNAMIC_API PEP_STATUS trust_own_key(
return PEP_ILLEGAL_VALUE;
// don't check blacklist or require a private key
PEP_STATUS status = validate_fpr(session, ident, false, false);
PEP_STATUS status = validate_fpr(session, ident, false, false, true);
if (status != PEP_STATUS_OK)
return status;
@ -1893,6 +1971,7 @@ DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **key
return _own_keys_retrieve(session, keylist, 0, true);
}
// Returns PASSPHRASE errors when necessary
DYNAMIC_API PEP_STATUS set_own_key(
PEP_SESSION session,
pEp_identity *me,
@ -1914,7 +1993,8 @@ DYNAMIC_API PEP_STATUS set_own_key(
if (me->fpr == fpr)
me->fpr = NULL;
status = _myself(session, me, false, true, false);
// renew if needed, but do not generate
status = _myself(session, me, false, true, true, false);
// we do not need a valid key but dislike other errors
if (status != PEP_STATUS_OK && status != PEP_GET_KEY_FAILED && status != PEP_KEY_UNSUITABLE)
return status;
@ -1936,12 +2016,15 @@ DYNAMIC_API PEP_STATUS set_own_key(
if (!me->fpr)
return PEP_OUT_OF_MEMORY;
status = validate_fpr(session, me, false, true);
status = validate_fpr(session, me, false, true, true);
if (status)
return status;
me->comm_type = PEP_ct_pEp;
status = set_identity(session, me);
if (status == PEP_STATUS_OK)
signal_Sync_event(session, Sync_PR_keysync, SynchronizeGroupKeys, NULL);
return status;
}
@ -2050,7 +2133,10 @@ static PEP_STATUS _wipe_default_key_if_invalid(PEP_SESSION session,
if (!ident->fpr)
return PEP_OUT_OF_MEMORY;
PEP_STATUS keystatus = validate_fpr(session, ident, true, false);
PEP_STATUS keystatus = validate_fpr(session, ident, true, false, true);
if (PASS_ERROR(status))
return status;
switch (keystatus) {
case PEP_STATUS_OK:
// Check for non-renewable expiry and
@ -2069,13 +2155,14 @@ static PEP_STATUS _wipe_default_key_if_invalid(PEP_SESSION session,
}
free(cached_fpr);
if (status == PEP_STATUS_OK)
// This may have been for a user default, not an identity default.
if (status == PEP_STATUS_OK && !(EMPTYSTR(ident->address)))
status = myself(session, ident);
return status;
}
PEP_STATUS clean_own_key_defaults(PEP_SESSION session) {
DYNAMIC_API PEP_STATUS clean_own_key_defaults(PEP_SESSION session) {
identity_list* idents = NULL;
PEP_STATUS status = own_identities_retrieve(session, &idents);
if (status != PEP_STATUS_OK)
@ -2096,7 +2183,9 @@ PEP_STATUS clean_own_key_defaults(PEP_SESSION session) {
if (!ident)
continue;
_wipe_default_key_if_invalid(session, ident);
status = _wipe_default_key_if_invalid(session, ident);
if (PASS_ERROR(status))
return status;
}
free_identity_list(idents);
@ -2120,8 +2209,11 @@ PEP_STATUS clean_own_key_defaults(PEP_SESSION session) {
return status;
}
else if (user_default_key) {
pEp_identity* empty_user = new_identity(NULL, user_default_key, NULL, own_id);
_wipe_default_key_if_invalid(session, empty_user);
pEp_identity* empty_user = new_identity(NULL, user_default_key, own_id, NULL);
status = _wipe_default_key_if_invalid(session, empty_user);
if (PASS_ERROR(status))
return status;
free(user_default_key);
}
free(own_id);

@ -120,6 +120,7 @@ DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity);
PEP_STATUS _myself(PEP_SESSION session,
pEp_identity * identity,
bool do_keygen,
bool do_renew,
bool ignore_flags,
bool read_only);
@ -384,6 +385,25 @@ DYNAMIC_API PEP_STATUS set_own_key(
const char *fpr
);
//
// clean_own_key_defaults()
//
// Remove any broken, unrenewable expired, or revoked
// own keys from identity and user defaults in the database.
//
// parameters:
// session (in) session to use
//
// return value:
// PEP_STATUS_OK if all went well
// PEP_PASSPHRASE_REQUIRED if a key needs to be renewed
// but cached passphrase isn't present
// PEP_WRONG_PASSPHRASE if passphrase required for expired key renewal
// but passphrase is the wrong one
// Otherwise, database and keyring errors as appropriate
//
DYNAMIC_API PEP_STATUS clean_own_key_defaults(PEP_SESSION session);
PEP_STATUS get_all_keys_for_user(PEP_SESSION session,
const char* user_id,
stringlist_t** keys);
@ -411,8 +431,6 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
bool* is_address_default,
bool check_blacklist);
PEP_STATUS clean_own_key_defaults(PEP_SESSION session);
#ifdef __cplusplus
}
#endif

@ -1378,18 +1378,24 @@ static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, cha
return rating;
}
// KB: Fixme - the first statement below is probably unnecessary now.
// Internal function WARNING:
// Only call this on an ident that might have its FPR set from retrieval!
// Should be called on ident that might have its FPR set from retrieval!
// (or on one without an fpr)
// We do not want myself() setting the fpr here.
//
// Cannot return passphrase statuses. No keygen or renewal allowed here.
static PEP_comm_type _get_comm_type(
PEP_SESSION session,
PEP_comm_type max_comm_type,
pEp_identity *ident
)
{
if (!ident)
return PEP_ILLEGAL_VALUE;
PEP_STATUS status = PEP_STATUS_OK;
if (max_comm_type == PEP_ct_compromised)
return PEP_ct_compromised;
@ -1400,7 +1406,7 @@ static PEP_comm_type _get_comm_type(
status = update_identity(session, ident);
}
else {
status = _myself(session, ident, false, false, true);
status = _myself(session, ident, false, false, false, true);
}
if (status == PEP_STATUS_OK) {
@ -1413,7 +1419,7 @@ static PEP_comm_type _get_comm_type(
}
else {
return PEP_ct_unknown;
}
}
}
static PEP_comm_type _get_comm_type_preview(
@ -1811,6 +1817,105 @@ static bool failed_test(PEP_STATUS status)
return false;
}
// CANNOT return PASSPHRASE errors, as no gen or renew allowed below
static PEP_STATUS _update_state_for_ident_list(
PEP_SESSION session,
pEp_identity* from_ident,
identity_list* ident_list,
stringlist_t** keylist,
PEP_comm_type* max_comm_type,
unsigned int* max_version_major,
unsigned int* max_version_minor,
bool* has_pEp_user,
bool* dest_keys_found,
bool suppress_update_for_bcc
)
{
if (!ident_list || !max_version_major || !max_version_minor
|| !has_pEp_user || !dest_keys_found
|| !keylist)
return PEP_ILLEGAL_VALUE;
PEP_STATUS status = PEP_STATUS_OK;
identity_list* _il = ident_list;
for ( ; _il && _il->ident; _il = _il->next) {
PEP_STATUS status = PEP_STATUS_OK;
if (!is_me(session, _il->ident)) {
status = update_identity(session, _il->ident);
if (status == PEP_CANNOT_FIND_IDENTITY) {
_il->ident->comm_type = PEP_ct_key_not_found;
status = PEP_STATUS_OK;
}
// 0 unless set, so safe.
if (!suppress_update_for_bcc) {
set_min_version( _il->ident->major_ver, _il->ident->minor_ver,
*max_version_major, *max_version_minor,
max_version_major, max_version_minor);
}
bool is_blacklisted = false;
if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
if (status != PEP_STATUS_OK) {
// DB error
status = PEP_UNENCRYPTED;
goto pEp_done;
}
if (is_blacklisted) {
bool user_default, ident_default, address_default;
status = get_valid_pubkey(session, _il->ident,
&ident_default, &user_default,
&address_default,
true);
if (status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
_il->ident->comm_type = PEP_ct_key_not_found;
status = PEP_STATUS_OK;
}
}
}
if (!(*has_pEp_user) && !EMPTYSTR(_il->ident->user_id))
is_pEp_user(session, _il->ident, has_pEp_user);
if (!suppress_update_for_bcc && from_ident) {
status = bind_own_ident_with_contact_ident(session, from_ident, _il->ident);
if (status != PEP_STATUS_OK) {
status = PEP_UNKNOWN_DB_ERROR;
goto pEp_done;
}
}
}
else // myself, but don't gen or renew
status = _myself(session, _il->ident, false, false, false, true);
if (status != PEP_STATUS_OK)
goto pEp_done;
if (!EMPTYSTR(_il->ident->fpr)) {
*keylist = stringlist_add(*keylist, _il->ident->fpr);
if (*keylist == NULL) {
status = PEP_OUT_OF_MEMORY;
goto pEp_done;
}
*max_comm_type = _get_comm_type(session, *max_comm_type,
_il->ident);
}
else {
*dest_keys_found = false;
// ? status = PEP_KEY_NOT_FOUND;
}
}
pEp_done:
return status;
}
DYNAMIC_API PEP_STATUS encrypt_message(
PEP_SESSION session,
message *src,
@ -1889,6 +1994,10 @@ DYNAMIC_API PEP_STATUS encrypt_message(
identity_list * _il = NULL;
//
// Update the identities and gather key and version information
// for sending
//
if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
// BCC limited support:
{
@ -1900,181 +2009,85 @@ DYNAMIC_API PEP_STATUS encrypt_message(
return PEP_ILLEGAL_VALUE;
}
PEP_STATUS _status = PEP_STATUS_OK;
if (!is_me(session, _il->ident)) {
_status = update_identity(session, _il->ident);
if (_status == PEP_CANNOT_FIND_IDENTITY) {
_il->ident->comm_type = PEP_ct_key_not_found;
_status = PEP_STATUS_OK;
}
// 0 unless set, so safe.
set_min_version( _il->ident->major_ver, _il->ident->minor_ver,
max_version_major, max_version_minor,
&max_version_major, &max_version_minor);
bool is_blacklisted = false;
if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
_status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
if (_status != PEP_STATUS_OK) {
// DB error
status = PEP_UNENCRYPTED;
goto pEp_error;
}
if (is_blacklisted) {
bool user_default, ident_default, address_default;
_status = get_valid_pubkey(session, _il->ident,
&ident_default, &user_default,
&address_default,
true);
if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
_il->ident->comm_type = PEP_ct_key_not_found;
_status = PEP_STATUS_OK;
}
}
}
if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
is_pEp_user(session, _il->ident, &has_pEp_user);
}
else
_status = myself(session, _il->ident);
if (_status != PEP_STATUS_OK) {
status = PEP_UNENCRYPTED;
goto pEp_error;
}
if (_il->ident->fpr && _il->ident->fpr[0]) {
_k = stringlist_add(_k, _il->ident->fpr);
if (_k == NULL)
goto enomem;
max_comm_type = _get_comm_type(session, max_comm_type,
_il->ident);
}
else {
dest_keys_found = false;
status = PEP_KEY_NOT_FOUND;
// If you think this call is a beast, try the cut-and-pasted code 3 x
PEP_STATUS _status = _update_state_for_ident_list(
session, src->from, _il,
&_k,
&max_comm_type,
&max_version_major,
&max_version_minor,
&has_pEp_user,
&dest_keys_found,
true);
switch (_status) {
case PEP_PASSPHRASE_REQUIRED:
case PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED:
case PEP_WRONG_PASSPHRASE:
status = _status;
goto pEp_error;
case PEP_STATUS_OK:
break;
default:
status = PEP_UNENCRYPTED;
goto pEp_error;
}
}
else // Non BCC
{
for (_il = src->to; _il && _il->ident; _il = _il->next) {
PEP_STATUS _status = PEP_STATUS_OK;
if (!is_me(session, _il->ident)) {
_status = update_identity(session, _il->ident);
if (_status == PEP_CANNOT_FIND_IDENTITY) {
_il->ident->comm_type = PEP_ct_key_not_found;
_status = PEP_STATUS_OK;
}
// 0 unless set, so safe.
set_min_version( _il->ident->major_ver, _il->ident->minor_ver,
max_version_major, max_version_minor,
&max_version_major, &max_version_minor);
bool is_blacklisted = false;
if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
_status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
if (_status != PEP_STATUS_OK) {
// DB error
status = PEP_UNENCRYPTED;
goto pEp_error;
}
if (is_blacklisted) {
bool user_default, ident_default, address_default;
_status = get_valid_pubkey(session, _il->ident,
&ident_default, &user_default,
&address_default,
true);
if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
_il->ident->comm_type = PEP_ct_key_not_found;
_status = PEP_STATUS_OK;
}
}
}
if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
is_pEp_user(session, _il->ident, &has_pEp_user);
_status = bind_own_ident_with_contact_ident(session, src->from, _il->ident);
if (_status != PEP_STATUS_OK) {
status = PEP_UNKNOWN_DB_ERROR;
goto pEp_error;
}
}
else
_status = myself(session, _il->ident);
if (_status != PEP_STATUS_OK) {
status = PEP_UNENCRYPTED;
goto pEp_error;
}
if (_il->ident->fpr && _il->ident->fpr[0]) {
_k = stringlist_add(_k, _il->ident->fpr);
if (_k == NULL)
goto enomem;
max_comm_type = _get_comm_type(session, max_comm_type,
_il->ident);
}
else {
dest_keys_found = false;
status = PEP_KEY_NOT_FOUND;
}
}
for (_il = src->cc; _il && _il->ident; _il = _il->next) {
PEP_STATUS _status = PEP_STATUS_OK;
if (!is_me(session, _il->ident)) {
_status = update_identity(session, _il->ident);
if (_status == PEP_CANNOT_FIND_IDENTITY) {
_il->ident->comm_type = PEP_ct_key_not_found;
_status = PEP_STATUS_OK;
}
bool is_blacklisted = false;
if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
_status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
if (_status != PEP_STATUS_OK) {
// DB error
status = PEP_UNENCRYPTED;
goto pEp_error;
}
if (is_blacklisted) {
bool user_default, ident_default, address_default;
_status = get_valid_pubkey(session, _il->ident,
&ident_default, &user_default,
&address_default,
true);
if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
_il->ident->comm_type = PEP_ct_key_not_found;
_status = PEP_STATUS_OK;
}
}
}
if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
is_pEp_user(session, _il->ident, &has_pEp_user);
}
else
_status = myself(session, _il->ident);
if (_status != PEP_STATUS_OK)
{
status = PEP_UNENCRYPTED;
goto pEp_error;
}
if (_il->ident->fpr && _il->ident->fpr[0]) {
_k = stringlist_add(_k, _il->ident->fpr);
if (_k == NULL)
goto enomem;
max_comm_type = _get_comm_type(session, max_comm_type,
_il->ident);
}
else {
dest_keys_found = false;
}
// If you think this call is a beast, try the cut-and-pasted code 3 x
PEP_STATUS _status = PEP_STATUS_OK;
if (src->to) {
_status = _update_state_for_ident_list(
session, src->from, src->to,
&_k,
&max_comm_type,
&max_version_major,
&max_version_minor,
&has_pEp_user,
&dest_keys_found,
false
);
switch (_status) {
case PEP_PASSPHRASE_REQUIRED:
case PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED:
case PEP_WRONG_PASSPHRASE:
goto pEp_error;
case PEP_STATUS_OK:
break;
default:
status = PEP_UNENCRYPTED;
goto pEp_error;
}
}
if (src->cc) {
_status = _update_state_for_ident_list(
session, src->from, src->cc,
&_k,
&max_comm_type,
&max_version_major,
&max_version_minor,
&has_pEp_user,
&dest_keys_found,
false
);
switch (_status) {
case PEP_PASSPHRASE_REQUIRED:
case PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED:
case PEP_WRONG_PASSPHRASE:
goto pEp_error;
case PEP_STATUS_OK:
break;
default:
status = PEP_UNENCRYPTED;
goto pEp_error;
}
}
}
if (max_version_major == 1)
if (max_version_major < 2)
force_v_1 = true;
if (enc_format == PEP_enc_auto) {
@ -2329,11 +2342,15 @@ DYNAMIC_API PEP_STATUS encrypt_message_and_add_priv_key(
status = encrypt_and_sign(session, keys, priv_key_data, priv_key_size,
&encrypted_key_text, &encrypted_key_size);
if (!encrypted_key_text) {
if (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE) {
free(encrypted_key_text);
goto pEp_free;
}
else if (!encrypted_key_text) {
status = PEP_UNKNOWN_ERROR;
goto pEp_free;
}
else if (status) {
else if (status != PEP_STATUS_OK) {
free(encrypted_key_text);
goto pEp_free; // FIXME - we need an error return overall
}
@ -3286,10 +3303,10 @@ static PEP_STATUS update_sender_to_pEp_trust(
free(sender->fpr);
sender->fpr = NULL;
PEP_STATUS status = PEP_STATUS_OK;
PEP_STATUS status = is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
// Seems status doesn't matter
is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
if (PASS_ERROR(status))
return status;
if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
free(sender->fpr);
@ -4212,7 +4229,12 @@ static PEP_STATUS _decrypt_message(
if (!cached_ownname)
cached_ownname = strdup(msg_from->address);
msg_from->username = NULL;
status = _myself(session, msg_from, false, false, myself_read_only);
// Don't renew for now: FIXME, SWIFT ticket coming with one To: etc...
status = _myself(session, msg_from, false, false, false, myself_read_only);
if (PASS_ERROR(status))
goto pEp_error;
free(msg_from->username);
msg_from->username = cached_ownname;
}
@ -4667,6 +4689,7 @@ DYNAMIC_API PEP_STATUS own_message_private_key_details(
// Note: if comm_type_determine is false, it generally means that
// we were unable to get key information for anyone in the list,
// likely because a key is missing.
// Cannot propagate PASSPHRASE errors.
static void _max_comm_type_from_identity_list(
identity_list *identities,
PEP_SESSION session,
@ -4674,6 +4697,7 @@ static void _max_comm_type_from_identity_list(
bool *comm_type_determined
)
{
identity_list * il;
for (il = identities; il != NULL; il = il->next)
{
@ -4681,7 +4705,7 @@ static void _max_comm_type_from_identity_list(
{
PEP_STATUS status = PEP_STATUS_OK;
*max_comm_type = _get_comm_type(session, *max_comm_type,
il->ident);
il->ident);
*comm_type_determined = true;
bool is_blacklisted = false;
@ -4693,7 +4717,8 @@ static void _max_comm_type_from_identity_list(
&ident_default, &user_default,
&address_default,
true);
if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
il->ident->comm_type = PEP_ct_key_not_found;
if (*max_comm_type > PEP_ct_no_encryption)
*max_comm_type = PEP_ct_no_encryption;
@ -4739,6 +4764,7 @@ DYNAMIC_API PEP_STATUS outgoing_message_rating(
)
{
PEP_comm_type max_comm_type = PEP_ct_pEp;
bool comm_type_determined = false;
assert(session);
@ -4809,6 +4835,12 @@ DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
return PEP_STATUS_OK;
}
// CAN return PASSPHRASE errors on own keys because
// of myself. Will not, however, return PASSPHRASE
// errors if the incoming ident isn't marked as an own
// identity.
// FIXME: document at top level - we RELY on knowing
// if this is an own identity in the input
DYNAMIC_API PEP_STATUS identity_rating(
PEP_SESSION session,
pEp_identity *ident,
@ -4827,28 +4859,29 @@ DYNAMIC_API PEP_STATUS identity_rating(
*rating = PEP_rating_undefined;
if (ident->me)
status = _myself(session, ident, false, true, true);
else
status = _myself(session, ident, false, true, true, true);
else { // Since we don't blacklist own keys, we only check it in here