|
|
- /**
- * @file baseprotocol.c
- * @brief Implementation of basic functions for administrative pEp messages (preparation,
- * decoration, payload, extraction, etc.). These are used for
- * protocol messages in, for example, key sync and key reset.
- * The payloads of these messages are, in general, not human-readable.
- * @see baseprotocol.h
- * @license GNU General Public License 3.0 - see LICENSE.txt
- */
-
- #include "pEp_internal.h"
- #include "message_api.h"
- #include "baseprotocol.h"
-
- static PEP_STATUS _get_base_protocol_type_str(base_protocol_type type, const char** type_str) {
- *type_str = NULL;
- switch(type) {
- case BASE_SIGN:
- *type_str = _BASE_PROTO_MIME_TYPE_SIGN;
- break;
- case BASE_SYNC:
- *type_str = _BASE_PROTO_MIME_TYPE_SYNC;
- break;
- case BASE_DISTRIBUTION:
- *type_str = _BASE_PROTO_MIME_TYPE_DIST;
- break;
- default:
- return PEP_ILLEGAL_VALUE;
- }
- return PEP_STATUS_OK;
- }
-
- PEP_STATUS base_decorate_message(
- PEP_SESSION session,
- message *msg,
- base_protocol_type type,
- char *payload,
- size_t size,
- const char *fpr
- )
- {
- PEP_STATUS status = PEP_STATUS_OK;
-
- assert(msg);
- assert(payload);
- assert(size);
- assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
-
- if (!(msg && payload && size && type))
- return PEP_ILLEGAL_VALUE;
-
- bloblist_t *bl;
-
- const char* type_str = NULL;
-
- switch (type) {
- case BASE_SYNC:
- bl = bloblist_add(msg->attachments, payload, size,
- _BASE_PROTO_MIME_TYPE_SYNC, "sync.pEp");
- break;
- case BASE_DISTRIBUTION:
- bl = bloblist_add(msg->attachments, payload, size,
- _BASE_PROTO_MIME_TYPE_DIST, "distribution.pEp");
- break;
- default:
- status = _get_base_protocol_type_str(type, &type_str);
- if (status != PEP_STATUS_OK)
- return status;
- else if (!type_str)
- return PEP_UNKNOWN_ERROR;
-
- bl = bloblist_add(msg->attachments, payload, size,
- type_str, "ignore_this_attachment.pEp");
- type_str = NULL;
- }
-
- if (bl == NULL)
- goto enomem;
- else if (!msg->attachments)
- msg->attachments = bl;
-
- if (fpr && fpr[0] != '\0') {
- char *sign;
- size_t sign_size;
- status = sign_only(session, payload, size, fpr, &sign, &sign_size);
- if (status)
- goto error;
-
- assert(sign && sign_size);
-
- bl = bloblist_add(bl, sign, sign_size,
- _BASE_PROTO_MIME_TYPE_SIGN, "electronic_signature.asc");
- if (!bl)
- goto enomem;
- }
-
- return status;
-
- enomem:
- status = PEP_OUT_OF_MEMORY;
-
- error:
- return status;
- }
-
- PEP_STATUS base_prepare_message(
- PEP_SESSION session,
- const pEp_identity *me,
- const pEp_identity *partner,
- base_protocol_type type,
- char *payload,
- size_t size,
- const char *fpr,
- message **result
- )
- {
- PEP_STATUS status = PEP_STATUS_OK;
-
- assert(me);
- assert(partner);
- assert(payload);
- assert(size);
- assert(result);
- assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
-
- if (!(me && partner && payload && size && result && type))
- return PEP_ILLEGAL_VALUE;
-
- *result = NULL;
-
- message *msg = new_message(PEP_dir_outgoing);
- if (!msg)
- goto enomem;
-
- add_opt_field(msg, "pEp-auto-consume", "yes");
- msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation");
-
- msg->from = identity_dup(me);
- if (!msg->from)
- goto enomem;
-
- msg->to = new_identity_list(identity_dup(partner));
- if (!msg->to)
- goto enomem;
-
- msg->shortmsg = strdup("p≡p key management message - please ignore");
- assert(msg->shortmsg);
- if (!msg->shortmsg)
- goto enomem;
-
- msg->longmsg = strdup("This message is part of p≡p's concept to manage keys.\n\n"
- "You can safely ignore it. It will be deleted automatically.\n");
- assert(msg->longmsg);
- if (!msg->longmsg)
- goto enomem;
-
- status = base_decorate_message(session, msg, type, payload, size, fpr);
- if (status == PEP_STATUS_OK)
- *result = msg;
- return status;
-
- enomem:
- free_message(msg);
- return PEP_OUT_OF_MEMORY;
- }
-
- PEP_STATUS base_extract_message(
- PEP_SESSION session,
- message *msg,
- base_protocol_type type,
- size_t *size,
- const char **payload,
- char **fpr
- )
- {
- PEP_STATUS status = PEP_STATUS_OK;
-
- assert(session && msg && size && payload && fpr);
- assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
- if (!(session && msg && size && payload && fpr && type))
- return PEP_ILLEGAL_VALUE;
-
- *size = 0;
- *payload = NULL;
- *fpr = NULL;
-
- const char *_payload = NULL;
- size_t _payload_size = 0;
- const char *_sign = NULL;
- size_t _sign_size = 0;
- stringlist_t *keylist = NULL;
-
- const char* type_str = NULL;
-
- status = _get_base_protocol_type_str(type, &type_str);
- if (status != PEP_STATUS_OK || !type_str)
- return status;
-
- for (bloblist_t *bl = msg->attachments; bl ; bl = bl->next) {
- if (bl->mime_type && strcasecmp(bl->mime_type, type_str) == 0) {
- if (!_payload) {
- _payload = bl->value;
- _payload_size = bl->size;
- }
- else {
- status = PEP_DECRYPT_WRONG_FORMAT;
- goto the_end;
- }
- }
- else if (bl->mime_type && strcasecmp(bl->mime_type, _BASE_PROTO_MIME_TYPE_SIGN) == 0) {
- if (!_sign) {
- _sign = bl->value;
- _sign_size = bl->size;
- }
- else {
- status = PEP_DECRYPT_WRONG_FORMAT;
- goto the_end;
- }
- }
- }
-
- if (!(_payload && _payload_size))
- goto the_end;
-
- char *_fpr = NULL;
- if (_sign) {
- status = verify_text(session, _payload, _payload_size, _sign, _sign_size, &keylist);
- if (!(status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED) || !keylist || !keylist->value) {
- // signature invalid or does not match; ignore message
- status = PEP_STATUS_OK;
- goto the_end;
- }
-
- _fpr = strdup(keylist->value);
- assert(_fpr);
- if (!_fpr) {
- status = PEP_OUT_OF_MEMORY;
- goto the_end;
- }
- }
-
- *size = _payload_size;
- *payload = _payload;
- *fpr = _fpr;
- status = PEP_STATUS_OK;
-
- the_end:
- free_stringlist(keylist);
- return status;
- }
-
- PEP_STATUS try_base_prepare_message(
- PEP_SESSION session,
- const pEp_identity *me,
- const pEp_identity *partner,
- base_protocol_type type,
- char *payload,
- size_t size,
- const char *fpr,
- message **result
- )
- {
- PEP_STATUS status = PEP_STATUS_OK;
-
- assert(session && session->messageToSend && session->notifyHandshake);
- assert(me);
- assert(partner);
- assert(payload);
- assert(size);
- assert(result);
- assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
-
- if (!(session && session->messageToSend && session->notifyHandshake))
- return PEP_ILLEGAL_VALUE;
-
- if (!(me && partner && payload && size && result && type))
- return PEP_ILLEGAL_VALUE;
-
- // https://dev.pep.foundation/Engine/MessageToSendPassphrase
-
- // first try with empty passphrase
- char *passphrase = session->curr_passphrase;
- session->curr_passphrase = NULL;
- status = base_prepare_message(session, me, partner, type, payload, size, fpr, result);
- session->curr_passphrase = passphrase;
- if (!(status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE))
- return status;
-
- if (!EMPTYSTR(session->curr_passphrase)) {
- // try configured passphrase
- status = base_prepare_message(session, me, partner, type, payload, size, fpr, result);
- if (!(status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE))
- return status;
- }
-
- do {
- // then try passphrases from the cache
- status = session->messageToSend(NULL);
-
- // if there will be no passphrase then exit
- if (status == PEP_SYNC_NO_CHANNEL)
- break;
-
- // if a passphrase is needed ask the app
- if (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE) {
- pEp_identity* _me = identity_dup(me);
- if (!_me)
- return PEP_OUT_OF_MEMORY;
- session->notifyHandshake(_me, NULL, SYNC_PASSPHRASE_REQUIRED);
- }
- else if (status == PEP_STATUS_OK) {
- status = base_prepare_message(session, me, partner, type, payload, size, fpr, result);
- }
- } while (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE);
-
- return status;
- }
|