ENGINE-633: Fixed refactored and fixed setting of default keys. Several 2.0 cases fail, as intended, as we won't support those anymore. The tests need to be updated now, and then maybe we're in business.

doxygen_doc
Krista Bennett 2021-06-16 16:45:12 +02:00
parent e856ec80c3
commit 635e795944
1 changed files with 106 additions and 58 deletions

View File

@ -4883,10 +4883,10 @@ static void get_message_version_from_headers(
{
*major_ver = 0;
*minor_ver = 0;
const stringpair_list_t* pEp_protocol_version = stringpair_list_find(field_list, X_PEP_MSG_VER_KEY);
const stringpair_list_t* pEp_message_version = stringpair_list_find(field_list, X_PEP_MSG_VER_KEY);
if (pEp_protocol_version && pEp_protocol_version->value)
pEp_version_major_minor(pEp_protocol_version->value->value, major_ver, minor_ver);
if (pEp_message_version && pEp_message_version->value)
pEp_version_major_minor(pEp_message_version->value->value, major_ver, minor_ver);
}
// CAN return PASS errors
@ -4952,6 +4952,52 @@ static PEP_STATUS _check_and_set_default_key(
return PEP_STATUS_OK; // We don't care about other errors here.
}
static const char* process_key_claim(message* src,
const char* imported_sender_key_fpr,
const char* signer_fpr,
int msg_major, int msg_minor,
stringlist_t* imported_key_list,
bool pEp_conformant) {
if (msg_major == 2 && msg_minor == 0)
return NULL;
// Senders with pEp versions >= than 2.2 will never send us a 2.0 message or less
// IF they know we are a pEp user.
//
// However, they COULD think we're OpenPGP - maybe imported the key from somewhere.
//
// So we have to only take the key IF the from-2.2-message-version is listed as
// 1.0. Everything else we support would have an inner message. And only then
// if the sender key has the right name. (FIXME: Have we changed 2.1 to do this?)
// FIXME: From SENDER >= 2.2, we should be VERY careful here -- check back on this one
//
const char *sender_key = NULL;
if (msg_major == 1) // pEp only: We only import from 2.1.34+ clients, which will use the correct name.
sender_key = imported_sender_key_fpr;
else if ((msg_major == 2 && msg_minor >= 1) || msg_major > 2) {
// We've been sent the inner message
// we require sender key filename to be correct and material to be present in this case
if (!EMPTYSTR(imported_sender_key_fpr) && !EMPTYSTR(src->_sender_fpr)) {
if (strcmp(imported_sender_key_fpr, src->_sender_fpr) == 0)
sender_key = src->_sender_fpr;
}
}
else if (!pEp_conformant) {
// For header keys, we will have been sent the head of the list here.
// For others, we were sent a reference to the last set of keys imported before this and checked to be
// sure there was only one.
if (imported_key_list) // not necessarily signer key!
sender_key = imported_key_list->value;
}
if (!EMPTYSTR(sender_key) && !EMPTYSTR(signer_fpr)) {
if (strcmp(sender_key, signer_fpr) != 0)
sender_key = NULL;
}
return sender_key;
}
// Rule for this function, since it is one of the three most complicated functions in this whole damned
// business:
@ -5205,17 +5251,15 @@ static PEP_STATUS _decrypt_message(
if (src->from->address) {
PEP_STATUS incoming_status = status;
const char* sender_key = NULL;
if (imported_sender_key_fpr) {// pEp message version 2.2 or greater
if (imported_sender_key_fpr) { // pEp protocol version 2.2 or greater, or someone knows to use the filename
sender_key = imported_sender_key_fpr; // FIXME: free
}
else if (!is_pEp_msg && header_key_imported) // autocrypt
sender_key = _imported_key_list->value;
else {
// We do this only with pEp messages 2.1 or less, or OpenPGP messages
if (!is_pEp_msg || (major_ver == 2 && minor_ver < 2) || major_ver < 2) {
if (_imported_key_list && !(_imported_key_list->next))
sender_key = _imported_key_list->value;
}
// Basically, this is everything else, since we can trust nothing on the wire really.
if (_imported_key_list && !(_imported_key_list->next))
sender_key = _imported_key_list->value;
} // Otherwise, too bad.
status = _check_and_set_default_key(session, src->from, sender_key);
@ -5346,30 +5390,41 @@ static PEP_STATUS _decrypt_message(
}
if (status == PEP_STATUS_OK && !has_inner) {
// If we're claiming to have a pEp version 2.2 or greater, we only take it
// if it had the right name during the import and if it was the ONLY key on the message?
// Senders with pEp versions greater than 2.2 will never send us a 2.0 message or less
// IF they know we are a pEp user.
//
// However, they COULD think we're OpenPGP - maybe imported the key from somewhere.
//
// So we have to only take the key IF the from-2.2-message-version is listed as
// 1.0. Everything else we support would have an inner message. And only then
// if the sender key has the right name. (FIXME: Have we changed 2.1 to do this?)
// FIXME: From SENDER >= 2.2, we should be VERY careful here -- check back on this one
//
const char *sender_key = NULL;
// FIXME: No, not possible. Has to come from INNER message.
if ((major_ver == 2 && minor_ver > 1) || major_ver > 2) {
if (imported_sender_key_fpr)
sender_key = imported_sender_key_fpr;
}
else if (header_key_imported && _imported_key_list) {
sender_key = _imported_key_list->value;
}
else if (*start && !((*start)->next)) {
if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
if (_keylist && !EMPTYSTR(_keylist->value) && *start && !EMPTYSTR((*start)->value)) {
sender_key = (*start)->value; // signer if sent from < 2.1
}
get_message_version_from_headers(src->opt_fields, &msg_major_ver, &msg_minor_ver);
const char* key_claim_fpr = NULL;
if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && _imported_key_list) {
// This is correct - we require sender key filename to be correct and material to be present in this case from any non-2.2+ version or OpenPGP, and we'll get 1 from 2.2+. Otherwise,
// we call shenanigans and don't trust the key to set defaults from.
if (imported_sender_key_fpr) {
key_claim_fpr = process_key_claim(src, imported_sender_key_fpr,
_imported_key_list->value, 1, 0,
_imported_key_list, true);
}
else {
stringlist_t* claim_node = header_key_imported ? _imported_key_list : *start;
key_claim_fpr = process_key_claim(src, NULL,
claim_node ? claim_node->value : NULL,
0, 0,
_imported_key_list, false);
}
}
if (!EMPTYSTR(key_claim_fpr))
status = _check_and_set_default_key(session, src->from, key_claim_fpr);
status = _check_and_set_default_key(session, src->from, sender_key);
free(imported_sender_key_fpr);
imported_sender_key_fpr = NULL;
@ -5417,7 +5472,7 @@ static PEP_STATUS _decrypt_message(
else if (strcasecmp(mime_type, "application/pEp.distribution") == 0)
filename = "file://distribution.pEp";
else if (strcasecmp(mime_type, "application/pgp-keys") == 0)
filename = "file://pEpkey.asc";
filename = "file://sender_key.asc";
else if (strcasecmp(mime_type, "application/pgp-signature") == 0)
filename = "file://electronic_signature.asc";
bloblist_t *bl = new_bloblist(value, size, mime_type, filename);
@ -5454,19 +5509,20 @@ static PEP_STATUS _decrypt_message(
&_changed_keys,
&imported_sender_key_fpr);
if (status == PEP_STATUS_OK && src->from && !is_me(session, src->from)) {
// If we're claiming to have a pEp version 2.2 or greater, we only take it
// if it had the right name during the import and if it was the ONLY key on the message?
const char* sender_key = NULL;
if ((major_ver == 2 && minor_ver > 1) || major_ver > 2) {
if (imported_sender_key_fpr)
sender_key = imported_sender_key_fpr;
}
else if (*start && !((*start)->next))
sender_key = (*start)->value; // signer if sent from < 2.1
const char* key_claim_fpr = NULL;
if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && _imported_key_list) {
bool filename_matched = !EMPTYSTR(imported_sender_key_fpr);
key_claim_fpr = process_key_claim(src, imported_sender_key_fpr,
_imported_key_list->value,
filename_matched ? 1 : 0, 0, // Not as redundant as you think
filename_matched ? _imported_key_list : *start,
filename_matched);
}
if (!EMPTYSTR(key_claim_fpr))
status = _check_and_set_default_key(session, src->from, key_claim_fpr);
status = _check_and_set_default_key(session, src->from, sender_key);
}
break;
default:
@ -5498,9 +5554,6 @@ static PEP_STATUS _decrypt_message(
// FIXME: replace with enums, check status
if (has_inner || wrap_info) { // Given that only wrap_info OUTER happens as of the end of wrap_info use, we don't need to strcmp it
// if (strcmp(wrap_info, "OUTER") == 0) {
// // this only occurs in with a direct outer wrapper
// // where the actual content is in the inner wrapper
message* inner_message = NULL;
// For a wrapped message, this is ALWAYS the second attachment; the
@ -5683,11 +5736,9 @@ static PEP_STATUS _decrypt_message(
imported_private_key_address = false;
free(private_il);
private_il = NULL;
free(imported_sender_key_fpr);
imported_sender_key_fpr = NULL;
// Generally imported from the outer decryption - inner messages lie along side it in the message.
// So should we always pass NULL here? Probably. FIXME.
// import keys from decrypted INNER source
status = import_keys_from_decrypted_msg(session, inner_message, is_pEp_msg,
&keys_were_imported,
@ -5695,23 +5746,20 @@ static PEP_STATUS _decrypt_message(
private_il,
&_imported_key_list,
&_changed_keys,
&imported_sender_key_fpr);
EMPTYSTR(imported_sender_key_fpr) ? &imported_sender_key_fpr : NULL);
if (status != PEP_STATUS_OK)
goto pEp_error;
if (!breaks_protocol && inner_message->from && !is_me(session, inner_message->from)) {
const char* sender_key = NULL;
// Set default?
if (!breaks_protocol && inner_message->from && !is_me(session, inner_message->from) && _imported_key_list) {
// We don't consider the pEp 2.0 case anymore, so no special processing
const char* key_claim_fpr = process_key_claim(inner_message, imported_sender_key_fpr,
_imported_key_list->value, msg_major_ver, msg_minor_ver,
NULL, true);
// Messages from clients 2.1 or greater should ALWAYS have sender_fpr on the inside. So...
if (!EMPTYSTR(inner_message->_sender_fpr))
sender_key = inner_message->_sender_fpr;
else { // !breaks_protocol is true, so this is a 2.0 message FROM a 2.0 client
if (_keylist) { // signer key, 2.0 sent from 2.0 client
sender_key = _keylist->value; // can be empty
}
}
status = _check_and_set_default_key(session, inner_message->from, sender_key);
status = _check_and_set_default_key(session, inner_message->from, key_claim_fpr);
if (status == PEP_OUT_OF_MEMORY)
goto enomem;
}