Browse Source

ENGINE-775: encrypt_message, identity_rating, set_own_key, trust_personal_key, update_identity, get_valid_pubkey

test-README.md
parent
commit
d0fd825b5e
3 changed files with 302 additions and 229 deletions
  1. +100
    -44
      src/keymanagement.c
  2. +201
    -184
      src/message_api.c
  3. +1
    -1
      src/pEpEngine.c

+ 100
- 44
src/keymanagement.c View File

@ -39,6 +39,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
)
@ -345,6 +346,10 @@ 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.
//
// If any default key requires a password, it will simply
// bounce back and ask for it. If an elected key requires one,
// it will do the same. Returns PASSPHRASE errors, use with caution.
PEP_STATUS get_valid_pubkey(PEP_SESSION session,
pEp_identity* stored_identity,
bool* is_identity_default,
@ -367,16 +372,25 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
// 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;
}
}
status = validate_fpr(session, stored_identity, check_blacklist, true);
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;
case PEP_PASSPHRASE_REQUIRED:
case PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED:
case PEP_WRONG_PASSPHRASE:
return status; // We're not messing around here.
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;
@ -388,23 +402,41 @@ PEP_STATUS get_valid_pubkey(PEP_SESSION session,
// 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;
}
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;
case PEP_PASSPHRASE_REQUIRED:
case PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED:
case PEP_WRONG_PASSPHRASE:
return status; // We're not messing around here.
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)) {
status = validate_fpr(session, stored_identity, false, true); // blacklist already filtered of needed
if (status == PEP_PASSPHRASE_REQUIRED ||
status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED ||
status == PEP_WRONG_PASSPHRASE) {
return status;
}
}
}
else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
first_reject_status = status;
@ -470,6 +502,11 @@ static void adjust_pEp_trust_status(PEP_SESSION session, pEp_identity* identity)
}
// NEVER called on an own identity. So get_valid_pubkey
// and friends should NEVER return with a password error,
// because its internal validate_fpr will always
// be called on a non-own identity.
// But we'll make sure it gets propagated if we do.
static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
pEp_identity* return_id,
pEp_identity* stored_ident,
@ -488,28 +525,36 @@ static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
&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;
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;
case PEP_PASSPHRASE_REQUIRED:
case PEP_WRONG_PASSPHRASE:
case PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED:
// These should NEVER happen here. If they do,
// we must bail and return the status.
return status;
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))
@ -589,6 +634,10 @@ static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
return status;
}
// CAN return PASSPHRASE errors by returning myself for
// a discovered own identity (i.e. we had no user for it).
// SHOULD not under other circumstances; if it does,
// something internal has failed badly and very unexpectedly.
DYNAMIC_API PEP_STATUS update_identity(
PEP_SESSION session, pEp_identity * identity
)
@ -1508,6 +1557,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
@ -1908,6 +1963,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,


+ 201
- 184
src/message_api.c View File

@ -1808,6 +1808,107 @@ static bool failed_test(PEP_STATUS status)
return false;
}
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 it turned out to be an own identity, we
// just internally called _myself on it.
if (!is_me(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
status = myself(session, _il->ident);
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,
@ -1886,6 +1987,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:
{
@ -1897,181 +2002,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) {
@ -4806,6 +4815,8 @@ DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
return PEP_STATUS_OK;
}
// CAN return PASSPHRASE errors on own keys because
// of myself or discovered own identities
DYNAMIC_API PEP_STATUS identity_rating(
PEP_SESSION session,
pEp_identity *ident,
@ -4825,25 +4836,31 @@ DYNAMIC_API PEP_STATUS identity_rating(
if (ident->me)
status = _myself(session, ident, false, true, true);
else
else { // Since we don't blacklist own keys, we only check it in here
status = update_identity(session, ident);
bool is_blacklisted = false;
if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
if (status != PEP_STATUS_OK) {
return status; // DB ERROR
}
if (is_blacklisted) {
bool user_default, ident_default, address_default;
status = get_valid_pubkey(session, ident,
&ident_default, &user_default,
&address_default,
true);
if (status != PEP_STATUS_OK || ident->fpr == NULL) {
ident->comm_type = PEP_ct_key_not_found;
status = PEP_STATUS_OK;
// double-check, in case update_identity had to call
// _myself internally
if (!ident->me) {
bool is_blacklisted = false;
if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
if (status != PEP_STATUS_OK) {
return status; // DB ERROR
}
if (is_blacklisted) {
bool user_default, ident_default, address_default;
status = get_valid_pubkey(session, ident,
&ident_default, &user_default,
&address_default,
true);
if (status != PEP_STATUS_OK || ident->fpr == NULL) {
ident->comm_type = PEP_ct_key_not_found;
status = PEP_STATUS_OK;
}
}
}
}
}


+ 1
- 1
src/pEpEngine.c View File

@ -4942,7 +4942,7 @@ PEP_STATUS _generate_keypair(PEP_SESSION session,
return status;
}
// SHOULD NOT (in implementation) ever return PASSPHRASE errors
DYNAMIC_API PEP_STATUS get_key_rating(
PEP_SESSION session,
const char *fpr,


Loading…
Cancel
Save