Removing kludgy fix - this really needs to be done in the app. But fdik and I still need to talk about trust records :)
1 // This file is under GNU General Public License 3.0
4 #include "pEp_internal.h"
5 #include "message_api.h"
10 #include "baseprotocol.h"
11 #include "KeySync_fsm.h"
13 #include "resource_id.h"
21 // These are globals used in generating message IDs and should only be
22 // computed once, as they're either really constants or OS-dependent
24 int _pEp_rand_max_bits;
27 static bool is_a_pEpmessage(const message *msg)
29 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
30 if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
36 static bool is_wrapper(message* src)
41 unsigned char pEpstr[] = PEP_SUBJ_STRING;
42 if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
43 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0) ||
44 (strcmp(src->shortmsg, "p=p") == 0)) {
45 char* plaintext = src->longmsg;
47 const char *line_end = strchr(plaintext, '\n');
49 if (line_end != NULL) {
50 size_t n = line_end - plaintext;
52 char* copycat = calloc(n + 1, 1);
55 strlcpy(copycat, plaintext, n+1);
57 if (strstr(copycat, PEP_MSG_WRAP_KEY) && strstr(copycat, "OUTER"))
71 * static stringpair_t* search_optfields(const message* msg, const char* key) {
73 * stringpair_list_t* opt_fields = msg->opt_fields;
75 * const stringpair_list_t* curr;
77 * for (curr = opt_fields; curr && curr->value; curr = curr->next) {
78 * if (curr->value->key) {
79 * if (strcasecmp(curr->value->key, key) == 0)
88 static char * keylist_to_string(const stringlist_t *keylist)
91 size_t size = stringlist_length(keylist);
93 const stringlist_t *_kl;
94 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
95 size += strlen(_kl->value);
98 char *result = calloc(size, 1);
103 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
104 _r = stpcpy(_r, _kl->value);
105 if (_kl->next && _kl->next->value)
106 _r = stpcpy(_r, ",");
116 static const char * rating_to_string(PEP_rating rating)
119 case PEP_rating_cannot_decrypt:
120 return "cannot_decrypt";
121 case PEP_rating_have_no_key:
122 return "have_no_key";
123 case PEP_rating_unencrypted:
124 return "unencrypted";
125 case PEP_rating_unencrypted_for_some: // don't use this any more
127 case PEP_rating_unreliable:
129 case PEP_rating_reliable:
131 case PEP_rating_trusted:
133 case PEP_rating_trusted_and_anonymized:
134 return "trusted_and_anonymized";
135 case PEP_rating_fully_anonymous:
136 return "fully_anonymous";
137 case PEP_rating_mistrust:
139 case PEP_rating_b0rken:
141 case PEP_rating_under_attack:
142 return "under_attack";
148 bool _memnmemn(const char* needle,
150 const char* haystack,
151 size_t haystack_size)
153 if (needle_size > haystack_size) {
156 else if (needle_size == 0) {
161 const char* haystack_ptr = haystack;
163 size_t remaining_hay = haystack_size;
164 for (i = 0; i < haystack_size && (remaining_hay >= needle_size); i++, haystack_ptr++) {
166 const char* needle_ptr = needle;
167 if (*haystack_ptr == *needle) {
168 const char* haystack_tmp = haystack_ptr;
171 for (j = 0; j < needle_size; j++) {
172 if (*needle_ptr++ != *haystack_tmp++) {
185 void add_opt_field(message *msg, const char *name, const char *value)
187 assert(msg && name && value);
189 if (msg && name && value) {
190 stringpair_t *pair = new_stringpair(name, value);
194 stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
197 free_stringpair(pair);
201 if (msg->opt_fields == NULL)
202 msg->opt_fields = field;
206 void replace_opt_field(message *msg,
211 assert(msg && name && value);
213 if (msg && name && value) {
214 stringpair_list_t* opt_fields = msg->opt_fields;
215 stringpair_t* pair = NULL;
219 pair = opt_fields->value;
220 if (pair && (strcmp(name, pair->key) == 0))
224 opt_fields = opt_fields->next;
231 pair->value = strdup(value);
235 add_opt_field(msg, name, value);
240 static void decorate_message(
243 stringlist_t *keylist,
251 replace_opt_field(msg, "X-pEp-Version", PEP_VERSION, clobber);
253 if (rating != PEP_rating_undefined)
254 replace_opt_field(msg, "X-EncStatus", rating_to_string(rating), clobber);
257 char *_keylist = keylist_to_string(keylist);
258 replace_opt_field(msg, "X-KeyList", _keylist, clobber);
263 static char* _get_resource_ptr_noown(char* uri) {
264 char* uri_delim = strstr(uri, "://");
271 static bool string_equality(const char *s1, const char *s2)
273 if (s1 == NULL || s2 == NULL)
278 return strcmp(s1, s2) == 0;
281 static bool is_mime_type(const bloblist_t *bl, const char *mt)
285 return bl && string_equality(bl->mime_type, mt);
289 // This function presumes the file ending is a proper substring of the
290 // filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
291 // return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
292 // return false. This is desired behaviour.
294 static bool is_fileending(const bloblist_t *bl, const char *fe)
298 if (bl == NULL || bl->filename == NULL || fe == NULL || is_cid_uri(bl->filename))
301 assert(bl && bl->filename);
303 size_t fe_len = strlen(fe);
304 size_t fn_len = strlen(bl->filename);
306 if (fn_len <= fe_len)
309 assert(fn_len > fe_len);
311 return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
314 char * encapsulate_message_wrap_info(const char *msg_wrap_info, const char *longmsg)
316 assert(msg_wrap_info);
318 if (!msg_wrap_info) {
322 char *result = strdup(longmsg);
331 const char * const newlines = "\n\n";
332 const size_t NL_LEN = 2;
334 const size_t bufsize = PEP_MSG_WRAP_KEY_LEN + strlen(msg_wrap_info) + NL_LEN + strlen(longmsg) + 1;
335 char * ptext = calloc(bufsize, 1);
340 strlcpy(ptext, PEP_MSG_WRAP_KEY, bufsize);
341 strlcat(ptext, msg_wrap_info, bufsize);
342 strlcat(ptext, newlines, bufsize);
343 strlcat(ptext, longmsg, bufsize);
348 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
352 unsigned char pEpstr[] = PEP_SUBJ_STRING;
353 assert(strcmp(shortmsg, "pEp") != 0 && _unsigned_signed_strcmp(pEpstr, shortmsg, PEP_SUBJ_BYTELEN) != 0);
355 if (!shortmsg || strcmp(shortmsg, "pEp") == 0 ||
356 _unsigned_signed_strcmp(pEpstr, shortmsg, PEP_SUBJ_BYTELEN) == 0) {
361 char *result = strdup(longmsg);
370 const char * const newlines = "\n\n";
371 const size_t NL_LEN = 2;
373 const size_t bufsize = PEP_SUBJ_KEY_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
374 char * ptext = calloc(bufsize, 1);
379 strlcpy(ptext, PEP_SUBJ_KEY, bufsize);
380 strlcat(ptext, shortmsg, bufsize);
381 strlcat(ptext, newlines, bufsize);
382 strlcat(ptext, longmsg, bufsize);
387 static PEP_STATUS replace_subject(message* msg) {
388 unsigned char pEpstr[] = PEP_SUBJ_STRING;
389 if (msg->shortmsg && *(msg->shortmsg) != '\0') {
390 char* longmsg = combine_short_and_long(msg->shortmsg, msg->longmsg);
392 return PEP_OUT_OF_MEMORY;
395 msg->longmsg = longmsg;
400 msg->shortmsg = strdup("pEp");
402 msg->shortmsg = strdup((char*)pEpstr);
406 return PEP_OUT_OF_MEMORY;
408 return PEP_STATUS_OK;
411 unsigned long long get_bitmask(int num_bits) {
415 unsigned long long bitmask = 0;
417 for (i = 1; i < num_bits; i++) {
418 bitmask = bitmask << 1;
424 static char* get_base_36_rep(unsigned long long value, int num_sig_bits) {
426 int bufsize = ((int) ceil((double) num_sig_bits / _pEp_log2_36)) + 1;
429 // https://en.wikipedia.org/wiki/Base36#C_implementation
430 // ok, we supposedly have a 64-bit kinda sorta random blob
431 const char base_36_symbols[37] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
433 char* retbuf = calloc(bufsize, 1);
438 int i = bufsize - 1; // (end index)
441 retbuf[--i] = base_36_symbols[value % 36];
449 static char* message_id_prand_part(void) {
451 int num_bits = _pEp_rand_max_bits;
456 const int DESIRED_BITS = 64;
458 num_bits = MIN(num_bits, DESIRED_BITS);
463 unsigned long long bitmask = get_bitmask(num_bits);
465 unsigned long long output_value = 0;
471 int randval = rand();
472 unsigned long long temp_val = randval & bitmask;
474 output_value |= temp_val;
476 i -= MIN(num_bits, i);
478 bitshift = MIN(num_bits, i);
479 output_value <<= bitshift;
480 bitmask = get_bitmask(bitshift);
483 return get_base_36_rep(output_value, DESIRED_BITS);
486 static PEP_STATUS generate_message_id(message* msg) {
488 if (!msg || !msg->from || !msg->from->address)
489 return PEP_ILLEGAL_VALUE;
491 char* time_prefix = NULL;
492 char* random_id = NULL;
495 size_t buf_len = 2; // NUL + @
497 char* from_addr = msg->from->address;
498 char* domain_ptr = strstr(from_addr, "@");
499 if (!domain_ptr || *(domain_ptr + 1) == '\0')
500 domain_ptr = "localhost";
504 buf_len += strlen(domain_ptr);
511 time_t curr_time = time(NULL);
513 time_prefix = get_base_36_rep(curr_time, (int) ceil(log2((double) curr_time)));
518 buf_len += strlen(time_prefix);
520 random_id = message_id_prand_part();
526 buf_len += strlen(random_id);
528 // make a new uuid - depending on rand() impl, time precision, etc,
529 // we may still not be unique. We'd better make sure. So.
532 uuid_generate_random(uuid);
533 uuid_unparse_upper(uuid, new_uuid);
535 buf_len += strlen(new_uuid);
537 buf_len += 6; // "pEp" and 3 '.' chars
539 retval = calloc(buf_len, 1);
544 strlcpy(retval, "pEp.", buf_len);
545 strlcat(retval, time_prefix, buf_len);
546 strlcat(retval, ".", buf_len);
547 strlcat(retval, random_id, buf_len);
548 strlcat(retval, ".", buf_len);
549 strlcat(retval, new_uuid, buf_len);
550 strlcat(retval, "@", buf_len);
551 strlcat(retval, domain_ptr, buf_len);
558 return PEP_STATUS_OK;
563 return PEP_OUT_OF_MEMORY;
567 WARNING: For the moment, this only works for the first line of decrypted
568 plaintext because we don't need more. IF WE DO, THIS MUST BE EXPANDED, or
569 we need a delineated section to parse separately
571 Does case-insensitive compare of keys, so sending in a lower-cased
572 string constant saves a bit of computation
574 static PEP_STATUS get_data_from_encapsulated_line(const char* plaintext, const char* key,
575 const size_t keylen, char** data,
576 char** modified_msg) {
578 char* _modified = NULL;
580 if (strncasecmp(plaintext, key, keylen) == 0) {
581 const char *line_end = strchr(plaintext, '\n');
583 if (line_end == NULL) {
584 _data = strdup(plaintext + keylen);
587 return PEP_OUT_OF_MEMORY;
590 size_t n = line_end - plaintext;
592 if (*(line_end - 1) == '\r')
593 _data = strndup(plaintext + keylen, n - (keylen + 1));
595 _data = strndup(plaintext + keylen, n - keylen);
598 return PEP_OUT_OF_MEMORY;
600 while (*(plaintext + n) && (*(plaintext + n) == '\n' || *(plaintext + n) == '\r'))
603 if (*(plaintext + n)) {
604 _modified = strdup(plaintext + n);
606 if (_modified == NULL)
607 return PEP_OUT_OF_MEMORY;
612 *modified_msg = _modified;
613 return PEP_STATUS_OK;
617 static int separate_short_and_long(const char *src, char **shortmsg, char** msg_wrap_info, char **longmsg)
619 char *_shortmsg = NULL;
620 char *_msg_wrap_info = NULL;
621 char *_longmsg = NULL;
625 assert(msg_wrap_info);
628 if (src == NULL || shortmsg == NULL || msg_wrap_info == NULL || longmsg == NULL)
633 *msg_wrap_info = NULL;
635 // We generated the input here. If we ever need more than one header value to be
636 // encapsulated and hidden in the encrypted text, we will have to modify this.
637 // As is, we're either doing this with a version 1.0 client, in which case
638 // the only encapsulated header value is subject, or 2.0+, in which the
639 // message wrap info is the only encapsulated header value. If we need this
640 // to be more complex, we're going to have to do something more elegant
642 PEP_STATUS status = get_data_from_encapsulated_line(src, PEP_SUBJ_KEY_LC,
644 &_shortmsg, &_longmsg);
647 if (status == PEP_STATUS_OK)
648 *shortmsg = _shortmsg;
653 status = get_data_from_encapsulated_line(src, PEP_MSG_WRAP_KEY_LC,
654 PEP_MSG_WRAP_KEY_LEN,
655 &_msg_wrap_info, &_longmsg);
656 if (_msg_wrap_info) {
657 if (status == PEP_STATUS_OK)
658 *msg_wrap_info = _msg_wrap_info;
664 // If there was no secret data hiding in the first line...
665 if (!_shortmsg && !_msg_wrap_info) {
666 _longmsg = strdup(src);
668 if (_longmsg == NULL)
678 free(_msg_wrap_info);
684 static PEP_STATUS copy_fields(message *dst, const message *src)
690 return PEP_ILLEGAL_VALUE;
692 free_timestamp(dst->sent);
695 dst->sent = timestamp_dup(src->sent);
696 if (dst->sent == NULL)
697 return PEP_OUT_OF_MEMORY;
700 free_timestamp(dst->recv);
703 dst->recv = timestamp_dup(src->recv);
704 if (dst->recv == NULL)
705 return PEP_OUT_OF_MEMORY;
708 free_identity(dst->from);
711 dst->from = identity_dup(src->from);
712 if (dst->from == NULL)
713 return PEP_OUT_OF_MEMORY;
716 free_identity_list(dst->to);
718 if (src->to && src->to->ident) {
719 dst->to = identity_list_dup(src->to);
721 return PEP_OUT_OF_MEMORY;
724 free_identity(dst->recv_by);
727 dst->recv_by = identity_dup(src->recv_by);
728 if (dst->recv_by == NULL)
729 return PEP_OUT_OF_MEMORY;
732 free_identity_list(dst->cc);
734 if (src->cc && src->cc->ident) {
735 dst->cc = identity_list_dup(src->cc);
737 return PEP_OUT_OF_MEMORY;
740 free_identity_list(dst->bcc);
742 if (src->bcc && src->bcc->ident) {
743 dst->bcc = identity_list_dup(src->bcc);
744 if (dst->bcc == NULL)
745 return PEP_OUT_OF_MEMORY;
748 free_identity_list(dst->reply_to);
749 dst->reply_to = NULL;
750 if (src->reply_to && src->reply_to->ident) {
751 dst->reply_to = identity_list_dup(src->reply_to);
752 if (dst->reply_to == NULL)
753 return PEP_OUT_OF_MEMORY;
756 free_stringlist(dst->in_reply_to);
757 dst->in_reply_to = NULL;
758 if (src->in_reply_to && src->in_reply_to->value) {
759 dst->in_reply_to = stringlist_dup(src->in_reply_to);
760 if (dst->in_reply_to == NULL)
761 return PEP_OUT_OF_MEMORY;
764 free_stringlist(dst->references);
765 dst->references = NULL;
766 if (src->references) {
767 dst->references = stringlist_dup(src->references);
768 if (dst->references == NULL)
769 return PEP_OUT_OF_MEMORY;
772 free_stringlist(dst->keywords);
773 dst->keywords = NULL;
774 if (src->keywords && src->keywords->value) {
775 dst->keywords = stringlist_dup(src->keywords);
776 if (dst->keywords == NULL)
777 return PEP_OUT_OF_MEMORY;
781 dst->comments = NULL;
783 dst->comments = strdup(src->comments);
784 assert(dst->comments);
785 if (dst->comments == NULL)
786 return PEP_OUT_OF_MEMORY;
789 free_stringpair_list(dst->opt_fields);
790 dst->opt_fields = NULL;
791 if (src->opt_fields) {
792 dst->opt_fields = stringpair_list_dup(src->opt_fields);
793 if (dst->opt_fields == NULL)
794 return PEP_OUT_OF_MEMORY;
797 return PEP_STATUS_OK;
800 // FIXME: error mem leakage
801 static message* extract_minimal_envelope(const message* src,
802 PEP_msg_direction direct) {
804 message* envelope = new_message(direct);
808 envelope->shortmsg = _pEp_subj_copy();
809 if (!envelope->shortmsg)
813 envelope->from = identity_dup(src->from);
819 envelope->to = identity_list_dup(src->to);
825 envelope->cc = identity_list_dup(src->cc);
831 envelope->bcc = identity_list_dup(src->bcc);
836 // For Outlook Force-Encryption
837 // const char* pull_keys[] = {"pEp-auto-consume",
838 // "pEp-force-protection",
839 // "X-pEp-Never-Unsecure"};
840 // int pull_keys_len = 3; // UPDATE WHEN MORE ADDED ABOVE
843 // stringpair_t* opt_add = NULL;
844 // for( ; i < pull_keys_len; i++) {
845 // opt_add = search_optfields(src, pull_keys[i]);
846 // stringpair_list_t* add_ptr = NULL;
848 // add_ptr = stringpair_list_add(src->opt_fields, stringpair_dup(opt_add));
856 envelope->enc_format = src->enc_format;
865 static message * clone_to_empty_message(const message * src)
868 message * msg = NULL;
874 msg = calloc(1, sizeof(message));
881 status = copy_fields(msg, src);
882 if (status != PEP_STATUS_OK)
892 static message* wrap_message_as_attachment(message* envelope,
893 message* attachment, message_wrap_type wrap_type, bool keep_orig_subject) {
898 message* _envelope = envelope;
900 PEP_STATUS status = PEP_STATUS_OK;
902 replace_opt_field(attachment, "X-pEp-Version", PEP_VERSION, true);
904 if (!_envelope && (wrap_type != PEP_message_transport)) {
905 _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
906 status = generate_message_id(_envelope);
908 if (status != PEP_STATUS_OK)
911 const char* inner_type_string = "";
913 case PEP_message_key_reset:
914 inner_type_string = "KEY_RESET";
917 inner_type_string = "INNER";
919 attachment->longmsg = encapsulate_message_wrap_info(inner_type_string, attachment->longmsg);
920 _envelope->longmsg = encapsulate_message_wrap_info("OUTER", _envelope->longmsg);
922 else if (_envelope) {
923 _envelope->longmsg = encapsulate_message_wrap_info("TRANSPORT", _envelope->longmsg);
929 if (!attachment->id || attachment->id[0] == '\0') {
930 free(attachment->id);
931 if (!_envelope->id) {
932 status = generate_message_id(_envelope);
934 if (status != PEP_STATUS_OK)
938 attachment->id = strdup(_envelope->id);
941 char* message_text = NULL;
943 /* prevent introduction of pEp in inner message */
945 if (!attachment->shortmsg) {
946 attachment->shortmsg = strdup("");
947 if (!attachment->shortmsg)
951 /* Turn message into a MIME-blob */
952 status = _mime_encode_message_internal(attachment, false, &message_text, true);
954 if (status != PEP_STATUS_OK)
957 size_t message_len = strlen(message_text);
959 bloblist_t* message_blob = new_bloblist(message_text, message_len,
960 "message/rfc822", NULL);
962 _envelope->attachments = message_blob;
963 if (keep_orig_subject && attachment->shortmsg)
964 _envelope->shortmsg = strdup(attachment->shortmsg);
969 free_message(_envelope);
974 static PEP_STATUS encrypt_PGP_inline(
979 PEP_encrypt_flags_t flags
985 PEP_STATUS status = encrypt_and_sign(session, keys, src->longmsg,
986 strlen(src->longmsg), &ctext, &csize);
990 dst->enc_format = PEP_enc_inline;
992 // shortmsg is being copied
994 dst->shortmsg = strdup(src->shortmsg);
995 assert(dst->shortmsg);
997 return PEP_OUT_OF_MEMORY;
1000 // id is staying the same
1002 dst->id = strdup(src->id);
1005 return PEP_OUT_OF_MEMORY;
1008 char *_ctext = realloc(ctext, csize + 1);
1011 return PEP_OUT_OF_MEMORY;
1014 dst->longmsg = _ctext;
1016 // longmsg_formatted is unsupported
1018 // attachments are going unencrypted
1019 bloblist_t *bl = bloblist_dup(src->attachments);
1021 return PEP_OUT_OF_MEMORY;
1022 dst->attachments = bl;
1024 return PEP_STATUS_OK;
1027 static PEP_STATUS encrypt_PGP_MIME(
1028 PEP_SESSION session,
1032 PEP_encrypt_flags_t flags
1035 PEP_STATUS status = PEP_STATUS_OK;
1036 bool free_ptext = false;
1039 char *mimetext = NULL;
1041 assert(dst->longmsg == NULL);
1042 dst->enc_format = PEP_enc_PGP_MIME;
1045 dst->shortmsg = strdup(src->shortmsg);
1047 message *_src = calloc(1, sizeof(message));
1051 // _src->longmsg = ptext;
1052 _src->longmsg = src->longmsg;
1053 _src->longmsg_formatted = src->longmsg_formatted;
1054 _src->attachments = src->attachments;
1055 _src->enc_format = PEP_enc_none;
1056 bool mime_encode = !is_wrapper(_src);
1057 status = _mime_encode_message_internal(_src, true, &mimetext, mime_encode);
1058 assert(status == PEP_STATUS_OK);
1059 if (status != PEP_STATUS_OK)
1069 if (mimetext == NULL)
1072 if (flags & PEP_encrypt_flag_force_unsigned)
1073 status = encrypt_only(session, keys, mimetext, strlen(mimetext),
1076 status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
1082 dst->longmsg = strdup("this message was encrypted with p≡p "
1083 "https://pEp-project.org");
1084 assert(dst->longmsg);
1085 if (dst->longmsg == NULL)
1088 char *v = strdup("Version: 1");
1093 bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
1096 dst->attachments = _a;
1098 _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
1103 return PEP_STATUS_OK;
1106 status = PEP_OUT_OF_MEMORY;
1116 static bool _has_PGP_MIME_format(message* msg) {
1117 if (!msg || !msg->attachments || !msg->attachments->next)
1119 if (msg->attachments->next->next)
1121 if (!msg->attachments->mime_type ||
1122 strcmp(msg->attachments->mime_type, "application/pgp-encrypted") != 0)
1124 if (!msg->attachments->next->mime_type ||
1125 strcmp(msg->attachments->next->mime_type, "application/octet-stream") != 0)
1130 static PEP_rating _rating(PEP_comm_type ct)
1132 if (ct == PEP_ct_unknown)
1133 return PEP_rating_undefined;
1135 else if (ct == PEP_ct_key_not_found)
1136 return PEP_rating_have_no_key;
1138 else if (ct == PEP_ct_compromised)
1139 return PEP_rating_under_attack;
1141 else if (ct == PEP_ct_mistrusted)
1142 return PEP_rating_mistrust;
1144 if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
1145 ct == PEP_ct_my_key_not_included)
1146 return PEP_rating_unencrypted;
1148 if (ct >= PEP_ct_confirmed_enc_anon)
1149 return PEP_rating_trusted_and_anonymized;
1151 else if (ct >= PEP_ct_strong_encryption)
1152 return PEP_rating_trusted;
1154 else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
1155 return PEP_rating_reliable;
1158 return PEP_rating_unreliable;
1161 static bool is_encrypted_attachment(const bloblist_t *blob)
1165 if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
1168 char *ext = strrchr(blob->filename, '.');
1172 if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
1173 if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0)
1176 if (strcmp(ext, ".asc") == 0 && blob->size > 0) {
1177 const char* pubk_needle = "BEGIN PGP PUBLIC KEY";
1178 size_t pubk_needle_size = strlen(pubk_needle);
1179 const char* privk_needle = "BEGIN PGP PRIVATE KEY";
1180 size_t privk_needle_size = strlen(privk_needle);
1182 if (!(_memnmemn(pubk_needle, pubk_needle_size, blob->value, blob->size)) &&
1183 !(_memnmemn(privk_needle, privk_needle_size, blob->value, blob->size)))
1190 static bool is_encrypted_html_attachment(const bloblist_t *blob)
1193 assert(blob->filename);
1194 if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
1197 const char* bare_filename_ptr = _get_resource_ptr_noown(blob->filename);
1198 bare_filename_ptr += strlen(bare_filename_ptr) - 15;
1199 if (strncmp(bare_filename_ptr, "PGPexch.htm.", 12) == 0) {
1200 if (strcmp(bare_filename_ptr + 11, ".pgp") == 0 ||
1201 strcmp(bare_filename_ptr + 11, ".asc") == 0)
1208 static char * without_double_ending(const char *filename)
1211 if (filename == NULL || is_cid_uri(filename))
1214 char *ext = strrchr(filename, '.');
1218 char *result = strndup(filename, ext - filename);
1223 static PEP_rating decrypt_rating(PEP_STATUS status)
1226 case PEP_UNENCRYPTED:
1228 case PEP_VERIFY_NO_KEY:
1229 case PEP_VERIFIED_AND_TRUSTED:
1230 return PEP_rating_unencrypted;
1233 case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
1234 return PEP_rating_unreliable;
1236 case PEP_DECRYPTED_AND_VERIFIED:
1237 return PEP_rating_reliable;
1239 case PEP_DECRYPT_NO_KEY:
1240 return PEP_rating_have_no_key;
1242 case PEP_DECRYPT_WRONG_FORMAT:
1243 case PEP_CANNOT_DECRYPT_UNKNOWN:
1244 return PEP_rating_cannot_decrypt;
1247 return PEP_rating_undefined;
1251 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
1257 if (session == NULL || fpr == NULL)
1258 return PEP_rating_undefined;
1261 PEP_comm_type bare_comm_type = PEP_ct_unknown;
1262 PEP_comm_type resulting_comm_type = PEP_ct_unknown;
1263 PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
1264 if (status != PEP_STATUS_OK)
1265 return PEP_rating_undefined;
1267 PEP_comm_type least_comm_type = PEP_ct_unknown;
1268 least_trust(session, fpr, &least_comm_type);
1270 if (least_comm_type == PEP_ct_unknown) {
1271 resulting_comm_type = bare_comm_type;
1272 } else if (least_comm_type < PEP_ct_strong_but_unconfirmed ||
1273 bare_comm_type < PEP_ct_strong_but_unconfirmed) {
1274 // take minimum if anything bad
1275 resulting_comm_type = least_comm_type < bare_comm_type ?
1279 resulting_comm_type = least_comm_type;
1281 return _rating(resulting_comm_type);
1284 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
1285 return ((rating1 < rating2) ? rating1 : rating2);
1288 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, char* sender_fpr, PEP_rating sender_rating)
1290 PEP_rating rating = sender_rating;
1292 assert(keylist && keylist->value);
1293 if (keylist == NULL || keylist->value == NULL)
1294 return PEP_rating_undefined;
1297 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
1300 if(_same_fpr(sender_fpr, strlen(sender_fpr), _kl->value, strlen(_kl->value)))
1303 PEP_rating _rating_ = key_rating(session, _kl->value);
1305 if (_rating_ <= PEP_rating_mistrust)
1308 rating = worst_rating(rating, _rating_);
1314 // Internal function WARNING:
1315 // Only call this on an ident that might have its FPR set from retrieval!
1316 // (or on one without an fpr)
1317 // We do not want myself() setting the fpr here.
1318 static PEP_comm_type _get_comm_type(
1319 PEP_SESSION session,
1320 PEP_comm_type max_comm_type,
1324 PEP_STATUS status = PEP_STATUS_OK;
1326 if (max_comm_type == PEP_ct_compromised)
1327 return PEP_ct_compromised;
1329 if (max_comm_type == PEP_ct_mistrusted)
1330 return PEP_ct_mistrusted;
1332 if (!is_me(session, ident))
1333 status = update_identity(session, ident);
1336 status = _myself(session, ident, false, false, true);
1338 if (status == PEP_STATUS_OK) {
1339 if (ident->comm_type == PEP_ct_compromised)
1340 return PEP_ct_compromised;
1341 else if (ident->comm_type == PEP_ct_mistrusted)
1342 return PEP_ct_mistrusted;
1344 return MIN(max_comm_type, ident->comm_type);
1347 return PEP_ct_unknown;
1351 static PEP_comm_type _get_comm_type_preview(
1352 PEP_SESSION session,
1353 PEP_comm_type max_comm_type,
1360 PEP_STATUS status = PEP_STATUS_OK;
1362 if (max_comm_type == PEP_ct_compromised)
1363 return PEP_ct_compromised;
1365 if (max_comm_type == PEP_ct_mistrusted)
1366 return PEP_ct_mistrusted;
1368 PEP_comm_type comm_type = PEP_ct_unknown;
1369 if (ident && !EMPTYSTR(ident->address) && !EMPTYSTR(ident->user_id)) {
1370 pEp_identity *ident2;
1371 status = get_identity(session, ident->address, ident->user_id, &ident2);
1372 comm_type = ident2 ? ident2->comm_type : PEP_ct_unknown;
1373 free_identity(ident2);
1375 if (status == PEP_STATUS_OK) {
1376 if (comm_type == PEP_ct_compromised)
1377 comm_type = PEP_ct_compromised;
1378 else if (comm_type == PEP_ct_mistrusted)
1379 comm_type = PEP_ct_mistrusted;
1381 comm_type = _MIN(max_comm_type, comm_type);
1384 comm_type = PEP_ct_unknown;
1390 // static void free_bl_entry(bloblist_t *bl)
1394 // free(bl->mime_type);
1395 // free(bl->filename);
1400 static bool is_key(const bloblist_t *bl)
1402 return (// workaround for Apple Mail bugs
1403 (is_mime_type(bl, "application/x-apple-msg-attachment") &&
1404 is_fileending(bl, ".asc")) ||
1405 // as binary, by file name
1406 ((bl->mime_type == NULL ||
1407 is_mime_type(bl, "application/octet-stream")) &&
1408 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
1409 is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
1410 // explicit mime type
1411 is_mime_type(bl, "application/pgp-keys") ||
1412 // as text, by file name
1413 (is_mime_type(bl, "text/plain") &&
1414 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
1415 is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
1419 // static void remove_attached_keys(message *msg)
1422 // bloblist_t *last = NULL;
1423 // for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
1424 // bloblist_t *next = bl->next;
1426 // if (is_key(bl)) {
1428 // last->next = next;
1431 // msg->attachments = next;
1433 // free_bl_entry(bl);
1443 static bool compare_first_n_bytes(const char* first, const char* second, size_t n) {
1445 for (i = 0; i < n; i++) {
1447 char num2 = *second;
1462 bool import_attached_keys(
1463 PEP_SESSION session,
1465 identity_list **private_idents
1471 if (session == NULL || msg == NULL)
1474 bool remove = false;
1478 bloblist_t* prev = NULL;
1480 bool do_not_advance = false;
1481 const char* pubkey_header = "-----BEGIN PGP PUBLIC KEY BLOCK-----";
1482 const char* privkey_header = "-----BEGIN PGP PRIVATE KEY BLOCK-----";
1483 // Hate my magic numbers at your peril, but I don't want a strlen each time
1484 const size_t PUBKEY_HSIZE = 36;
1485 const size_t PRIVKEY_HSIZE = 37;
1487 for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
1490 do_not_advance = false;
1491 if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
1494 char* blob_value = bl->value;
1495 size_t blob_size = bl->size;
1496 bool free_blobval = false;
1498 if (is_encrypted_attachment(bl)) {
1500 char* bl_ptext = NULL;
1501 size_t bl_psize = 0;
1502 stringlist_t* bl_keylist = NULL;
1503 PEP_STATUS _status = decrypt_and_verify(session,
1504 blob_value, blob_size,
1506 &bl_ptext, &bl_psize,
1509 free_stringlist(bl_keylist); // we don't care about key encryption as long as we decrypt
1510 if (_status == PEP_DECRYPTED || _status == PEP_DECRYPTED_AND_VERIFIED) {
1511 free_blobval = true;
1512 blob_value = bl_ptext;
1513 blob_size = bl_psize;
1516 // This is an encrypted attachment we can do nothing with.
1517 // We shouldn't delete it or import it, because we can't
1525 identity_list *local_private_idents = NULL;
1526 PEP_STATUS import_status = import_key(session, blob_value, blob_size, &local_private_idents);
1527 bloblist_t* to_delete = NULL;
1528 switch (import_status) {
1529 case PEP_NO_KEY_IMPORTED:
1531 case PEP_KEY_IMPORT_STATUS_UNKNOWN:
1532 // We'll delete armoured stuff, at least
1533 if (blob_size <= PUBKEY_HSIZE)
1535 if ((!compare_first_n_bytes(pubkey_header, (const char*)blob_value, PUBKEY_HSIZE)) &&
1536 (!compare_first_n_bytes(privkey_header, (const char*)blob_value, PRIVKEY_HSIZE)))
1538 // else fall through and delete
1539 case PEP_KEY_IMPORTED:
1543 prev->next = bl->next;
1545 msg->attachments = bl->next;
1547 to_delete->next = NULL;
1548 free_bloblist(to_delete);
1549 do_not_advance = true;
1553 // bad stuff, but ok.
1556 if (private_idents && *private_idents == NULL && local_private_idents != NULL)
1557 *private_idents = local_private_idents;
1559 free_identity_list(local_private_idents);
1563 if (!do_not_advance) {
1572 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
1574 char *keydata = NULL;
1577 PEP_STATUS status = export_key(session, fpr, &keydata, &size);
1578 assert(status == PEP_STATUS_OK);
1579 if (status != PEP_STATUS_OK)
1583 bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
1584 "file://pEpkey.asc");
1586 if (msg->attachments == NULL && bl)
1587 msg->attachments = bl;
1589 return PEP_STATUS_OK;
1592 #define ONE_WEEK (7*24*3600)
1594 void attach_own_key(PEP_SESSION session, message *msg)
1599 if (msg->dir == PEP_dir_incoming)
1602 assert(msg->from && msg->from->fpr);
1603 if (msg->from == NULL || msg->from->fpr == NULL)
1606 if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
1609 char *revoked_fpr = NULL;
1610 uint64_t revocation_date = 0;
1612 if(get_revoked(session, msg->from->fpr,
1613 &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
1614 revoked_fpr != NULL)
1616 time_t now = time(NULL);
1618 if (now < (time_t)revocation_date + ONE_WEEK)
1620 _attach_key(session, revoked_fpr, msg);
1626 PEP_cryptotech determine_encryption_format(message *msg)
1630 if (is_PGP_message_text(msg->longmsg)) {
1631 msg->enc_format = PEP_enc_inline;
1632 return PEP_crypt_OpenPGP;
1634 else if (msg->attachments && msg->attachments->next &&
1635 is_mime_type(msg->attachments, "application/pgp-encrypted") &&
1636 is_PGP_message_text(msg->attachments->next->value)
1638 msg->enc_format = PEP_enc_PGP_MIME;
1639 return PEP_crypt_OpenPGP;
1641 else if (msg->attachments && msg->attachments->next &&
1642 is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
1643 is_PGP_message_text(msg->attachments->value)
1645 msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
1646 return PEP_crypt_OpenPGP;
1649 msg->enc_format = PEP_enc_none;
1650 return PEP_crypt_none;
1654 static void _cleanup_src(message* src, bool remove_attached_key) {
1660 char* longmsg = NULL;
1661 char* shortmsg = NULL;
1662 char* msg_wrap_info = NULL;
1664 separate_short_and_long(src->longmsg, &shortmsg, &msg_wrap_info,
1669 free(msg_wrap_info);
1670 src->longmsg = longmsg;
1672 if (remove_attached_key) {
1673 // End of the attachment list
1674 if (src->attachments) {
1675 bloblist_t* tmp = src->attachments;
1676 while (tmp->next && tmp->next->next) {
1679 free_bloblist(tmp->next);
1685 DYNAMIC_API PEP_STATUS encrypt_message(
1686 PEP_SESSION session,
1688 stringlist_t * extra,
1690 PEP_enc_format enc_format,
1691 PEP_encrypt_flags_t flags
1694 PEP_STATUS status = PEP_STATUS_OK;
1695 message * msg = NULL;
1696 stringlist_t * keys = NULL;
1697 message* _src = src;
1699 bool added_key_to_real_src = false;
1702 assert(src && src->from);
1705 if (!(session && src && src->from && dst))
1706 return PEP_ILLEGAL_VALUE;
1708 if (src->dir == PEP_dir_incoming)
1709 return PEP_ILLEGAL_VALUE;
1711 determine_encryption_format(src);
1712 // TODO: change this for multi-encryption in message format 2.0
1713 if (src->enc_format != PEP_enc_none)
1714 return PEP_ILLEGAL_VALUE;
1716 bool force_v_1 = flags & PEP_encrypt_flag_force_version_1;
1720 if (!src->from->user_id || src->from->user_id[0] == '\0') {
1721 char* own_id = NULL;
1722 status = get_default_own_userid(session, &own_id);
1724 free(src->from->user_id);
1725 src->from->user_id = own_id; // ownership transfer
1729 status = myself(session, src->from);
1730 if (status != PEP_STATUS_OK)
1733 keys = new_stringlist(src->from->fpr);
1737 stringlist_t *_k = keys;
1740 _k = stringlist_append(_k, extra);
1745 bool dest_keys_found = true;
1746 bool has_pEp_user = false;
1748 PEP_comm_type max_comm_type = PEP_ct_pEp;
1750 identity_list * _il = NULL;
1752 if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
1753 // BCC limited support:
1755 // - App splits mails with BCC in multiple mails.
1756 // - Each email is encrypted separately
1758 if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
1760 // Only one Bcc with no other recipient allowed for now
1761 return PEP_ILLEGAL_VALUE;
1764 PEP_STATUS _status = PEP_STATUS_OK;
1765 if (!is_me(session, _il->ident)) {
1766 _status = update_identity(session, _il->ident);
1767 if (_status == PEP_CANNOT_FIND_IDENTITY) {
1768 _il->ident->comm_type = PEP_ct_key_not_found;
1769 _status = PEP_STATUS_OK;
1771 bool is_blacklisted = false;
1772 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
1773 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
1774 if (_status != PEP_STATUS_OK) {
1776 status = PEP_UNENCRYPTED;
1779 if (is_blacklisted) {
1780 bool user_default, ident_default, address_default;
1781 _status = get_valid_pubkey(session, _il->ident,
1782 &ident_default, &user_default,
1785 if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
1786 _il->ident->comm_type = PEP_ct_key_not_found;
1787 _status = PEP_STATUS_OK;
1791 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
1792 is_pEp_user(session, _il->ident, &has_pEp_user);
1795 _status = myself(session, _il->ident);
1796 if (_status != PEP_STATUS_OK) {
1797 status = PEP_UNENCRYPTED;
1801 if (_il->ident->fpr && _il->ident->fpr[0]) {
1802 _k = stringlist_add(_k, _il->ident->fpr);
1805 max_comm_type = _get_comm_type(session, max_comm_type,
1809 dest_keys_found = false;
1810 status = PEP_KEY_NOT_FOUND;
1815 for (_il = src->to; _il && _il->ident; _il = _il->next) {
1816 PEP_STATUS _status = PEP_STATUS_OK;
1817 if (!is_me(session, _il->ident)) {
1818 _status = update_identity(session, _il->ident);
1819 if (_status == PEP_CANNOT_FIND_IDENTITY) {
1820 _il->ident->comm_type = PEP_ct_key_not_found;
1821 _status = PEP_STATUS_OK;
1823 bool is_blacklisted = false;
1824 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
1825 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
1826 if (_status != PEP_STATUS_OK) {
1828 status = PEP_UNENCRYPTED;
1831 if (is_blacklisted) {
1832 bool user_default, ident_default, address_default;
1833 _status = get_valid_pubkey(session, _il->ident,
1834 &ident_default, &user_default,
1837 if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
1838 _il->ident->comm_type = PEP_ct_key_not_found;
1839 _status = PEP_STATUS_OK;
1843 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
1844 is_pEp_user(session, _il->ident, &has_pEp_user);
1846 _status = bind_own_ident_with_contact_ident(session, src->from, _il->ident);
1847 if (_status != PEP_STATUS_OK) {
1848 status = PEP_UNKNOWN_DB_ERROR;
1854 _status = myself(session, _il->ident);
1856 if (_status != PEP_STATUS_OK) {
1857 status = PEP_UNENCRYPTED;
1861 if (_il->ident->fpr && _il->ident->fpr[0]) {
1862 _k = stringlist_add(_k, _il->ident->fpr);
1865 max_comm_type = _get_comm_type(session, max_comm_type,
1869 dest_keys_found = false;
1870 status = PEP_KEY_NOT_FOUND;
1874 for (_il = src->cc; _il && _il->ident; _il = _il->next) {
1875 PEP_STATUS _status = PEP_STATUS_OK;
1876 if (!is_me(session, _il->ident)) {
1877 _status = update_identity(session, _il->ident);
1878 if (_status == PEP_CANNOT_FIND_IDENTITY) {
1879 _il->ident->comm_type = PEP_ct_key_not_found;
1880 _status = PEP_STATUS_OK;
1882 bool is_blacklisted = false;
1883 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
1884 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
1885 if (_status != PEP_STATUS_OK) {
1887 status = PEP_UNENCRYPTED;
1890 if (is_blacklisted) {
1891 bool user_default, ident_default, address_default;
1892 _status = get_valid_pubkey(session, _il->ident,
1893 &ident_default, &user_default,
1896 if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
1897 _il->ident->comm_type = PEP_ct_key_not_found;
1898 _status = PEP_STATUS_OK;
1902 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
1903 is_pEp_user(session, _il->ident, &has_pEp_user);
1906 _status = myself(session, _il->ident);
1907 if (_status != PEP_STATUS_OK)
1909 status = PEP_UNENCRYPTED;
1913 if (_il->ident->fpr && _il->ident->fpr[0]) {
1914 _k = stringlist_add(_k, _il->ident->fpr);
1917 max_comm_type = _get_comm_type(session, max_comm_type,
1921 dest_keys_found = false;
1926 if (enc_format == PEP_enc_none || !dest_keys_found ||
1927 stringlist_length(keys) == 0 ||
1928 _rating(max_comm_type) < PEP_rating_reliable)
1930 free_stringlist(keys);
1931 if ((has_pEp_user || !session->passive_mode) &&
1932 !(flags & PEP_encrypt_flag_force_no_attached_key)) {
1933 attach_own_key(session, src);
1934 added_key_to_real_src = true;
1936 decorate_message(src, PEP_rating_undefined, NULL, true, true);
1937 return PEP_UNENCRYPTED;
1940 // FIXME - we need to deal with transport types (via flag)
1941 if ((enc_format != PEP_enc_inline) && (!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
1942 message_wrap_type wrap_type = ((flags & PEP_encrypt_flag_key_reset_only) ? PEP_message_key_reset : PEP_message_default);
1943 _src = wrap_message_as_attachment(NULL, src, wrap_type, false);
1949 if (enc_format != PEP_enc_inline && !session->unencrypted_subject) {
1950 status = replace_subject(_src);
1951 if (status == PEP_OUT_OF_MEMORY)
1954 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1955 added_key_to_real_src = true;
1957 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1958 attach_own_key(session, _src);
1960 msg = clone_to_empty_message(_src);
1964 switch (enc_format) {
1965 case PEP_enc_PGP_MIME:
1966 case PEP_enc_PEP: // BUG: should be implemented extra
1967 status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
1970 case PEP_enc_inline:
1971 status = encrypt_PGP_inline(session, _src, keys, msg, flags);
1976 status = PEP_ILLEGAL_VALUE;
1980 if (status == PEP_OUT_OF_MEMORY)
1983 if (status != PEP_STATUS_OK)
1987 free_stringlist(keys);
1989 if (msg && msg->shortmsg == NULL) {
1990 msg->shortmsg = strdup("");
1991 assert(msg->shortmsg);
1992 if (msg->shortmsg == NULL)
1997 decorate_message(msg, PEP_rating_undefined, NULL, true, true);
1999 msg->id = strdup(_src->id);
2001 if (msg->id == NULL)
2008 // ??? FIXME: Check to be sure we don't have references btw _src and msg.
2009 // I don't think we do.
2010 if (_src && _src != src)
2013 _cleanup_src(src, added_key_to_real_src);
2018 status = PEP_OUT_OF_MEMORY;
2021 free_stringlist(keys);
2023 if (_src && _src != src)
2026 _cleanup_src(src, added_key_to_real_src);
2031 DYNAMIC_API PEP_STATUS encrypt_message_and_add_priv_key(
2032 PEP_SESSION session,
2036 PEP_enc_format enc_format,
2037 PEP_encrypt_flags_t flags
2045 if (!session || !src || !dst || !to_fpr)
2046 return PEP_ILLEGAL_VALUE;
2048 if (enc_format == PEP_enc_none)
2049 return PEP_ILLEGAL_VALUE;
2051 if (src->cc || src->bcc)
2052 return PEP_ILLEGAL_VALUE;
2054 if (!src->to || src->to->next)
2055 return PEP_ILLEGAL_VALUE;
2057 if (!src->from->address || !src->to->ident || !src->to->ident->address)
2058 return PEP_ILLEGAL_VALUE;
2060 if (strcasecmp(src->from->address, src->to->ident->address) != 0)
2061 return PEP_ILLEGAL_VALUE;
2063 stringlist_t* keys = NULL;
2065 char* own_id = NULL;
2066 char* default_id = NULL;
2068 pEp_identity* own_identity = NULL;
2069 char* own_private_fpr = NULL;
2071 char* priv_key_data = NULL;
2073 PEP_STATUS status = get_default_own_userid(session, &own_id);
2076 return PEP_UNKNOWN_ERROR; // Probably a DB error at this point
2078 if (src->from->user_id) {
2079 if (strcmp(src->from->user_id, own_id) != 0) {
2080 status = get_userid_alias_default(session, src->from->user_id, &default_id);
2081 if (status != PEP_STATUS_OK || !default_id || strcmp(default_id, own_id) != 0) {
2082 status = PEP_ILLEGAL_VALUE;
2088 // Ok, we are at least marginally sure the initial stuff is ok.
2090 // Let's get our own, normal identity
2091 own_identity = identity_dup(src->from);
2092 status = myself(session, own_identity);
2094 if (status != PEP_STATUS_OK)
2097 // Ok, now we know the address is an own address. All good. Then...
2098 own_private_fpr = own_identity->fpr;
2099 own_identity->fpr = strdup(to_fpr);
2101 status = get_trust(session, own_identity);
2103 if (status != PEP_STATUS_OK) {
2104 if (status == PEP_CANNOT_FIND_IDENTITY)
2105 status = PEP_ILLEGAL_VALUE;
2109 if ((own_identity->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed) {
2110 status = PEP_ILLEGAL_VALUE;
2114 // Ok, so all the things are now allowed.
2115 // So let's get our own private key and roll with it.
2116 size_t priv_key_size = 0;
2118 status = export_secret_key(session, own_private_fpr, &priv_key_data,
2121 if (status != PEP_STATUS_OK)
2124 if (!priv_key_data) {
2125 status = PEP_CANNOT_EXPORT_KEY;
2129 // Ok, fine... let's encrypt yon blob
2130 keys = new_stringlist(own_private_fpr);
2132 status = PEP_OUT_OF_MEMORY;
2136 stringlist_add(keys, to_fpr);
2138 char* encrypted_key_text = NULL;
2139 size_t encrypted_key_size = 0;
2141 if (flags & PEP_encrypt_flag_force_unsigned)
2142 status = encrypt_only(session, keys, priv_key_data, priv_key_size,
2143 &encrypted_key_text, &encrypted_key_size);
2145 status = encrypt_and_sign(session, keys, priv_key_data, priv_key_size,
2146 &encrypted_key_text, &encrypted_key_size);
2148 if (!encrypted_key_text) {
2149 status = PEP_UNKNOWN_ERROR;
2153 // We will have to delete this before returning, as we allocated it.
2154 bloblist_t* created_bl = NULL;
2155 bloblist_t* created_predecessor = NULL;
2157 bloblist_t* old_head = NULL;
2159 if (!src->attachments || src->attachments->value == NULL) {
2160 if (src->attachments && src->attachments->value == NULL) {
2161 old_head = src->attachments;
2162 src->attachments = NULL;
2164 src->attachments = new_bloblist(encrypted_key_text, encrypted_key_size,
2165 "application/octet-stream",
2166 "file://pEpkey.asc.pgp");
2167 created_bl = src->attachments;
2170 bloblist_t* tmp = src->attachments;
2171 while (tmp && tmp->next) {
2174 created_predecessor = tmp;
2175 created_bl = bloblist_add(tmp,
2176 encrypted_key_text, encrypted_key_size,
2177 "application/octet-stream",
2178 "file://pEpkey.asc.pgp");
2182 status = PEP_OUT_OF_MEMORY;
2186 // Ok, it's in there. Let's do this.
2187 status = encrypt_message(session, src, keys, dst, enc_format, flags);
2189 // Delete what we added to src
2190 free_bloblist(created_bl);
2191 if (created_predecessor)
2192 created_predecessor->next = NULL;
2195 src->attachments = old_head;
2197 src->attachments = NULL;
2203 free(own_private_fpr);
2204 free(priv_key_data);
2205 free_identity(own_identity);
2206 free_stringlist(keys);
2211 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
2212 PEP_SESSION session,
2213 pEp_identity* target_id,
2215 stringlist_t* extra,
2217 PEP_enc_format enc_format,
2218 PEP_encrypt_flags_t flags
2221 PEP_STATUS status = PEP_STATUS_OK;
2222 message * msg = NULL;
2223 stringlist_t * keys = NULL;
2224 message* _src = src;
2230 assert(enc_format != PEP_enc_none);
2232 if (!(session && target_id && src && dst && enc_format != PEP_enc_none))
2233 return PEP_ILLEGAL_VALUE;
2235 // if (src->dir == PEP_dir_incoming)
2236 // return PEP_ILLEGAL_VALUE;
2238 determine_encryption_format(src);
2239 if (src->enc_format != PEP_enc_none)
2240 return PEP_ILLEGAL_VALUE;
2242 if (!target_id->user_id || target_id->user_id[0] == '\0') {
2243 char* own_id = NULL;
2244 status = get_default_own_userid(session, &own_id);
2246 free(target_id->user_id);
2247 target_id->user_id = own_id; // ownership transfer
2251 if (!target_id->user_id || target_id->user_id[0] == '\0')
2252 return PEP_CANNOT_FIND_IDENTITY;
2254 if (target_id->address) {
2255 status = myself(session, target_id);
2256 if (status != PEP_STATUS_OK)
2259 else if (!target_id->fpr) {
2260 return PEP_ILLEGAL_VALUE;
2265 // PEP_STATUS _status = update_identity(session, target_id);
2266 // if (_status != PEP_STATUS_OK) {
2267 // status = _status;
2271 char* target_fpr = target_id->fpr;
2273 return PEP_KEY_NOT_FOUND; // FIXME: Error condition
2275 keys = new_stringlist(target_fpr);
2277 stringlist_t *_k = keys;
2280 _k = stringlist_append(_k, extra);
2285 /* KG: did we ever do this??? */
2286 // if (!(flags & PEP_encrypt_flag_force_no_attached_key))
2287 // _attach_key(session, target_fpr, src);
2289 _src = wrap_message_as_attachment(NULL, src, PEP_message_default, false);
2293 msg = clone_to_empty_message(_src);
2297 switch (enc_format) {
2298 case PEP_enc_PGP_MIME:
2299 case PEP_enc_PEP: // BUG: should be implemented extra
2300 status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
2301 if (status == PEP_STATUS_OK || (src->longmsg && strstr(src->longmsg, "INNER")))
2302 _cleanup_src(src, false);
2305 case PEP_enc_inline:
2306 status = encrypt_PGP_inline(session, _src, keys, msg, flags);
2311 status = PEP_ILLEGAL_VALUE;
2315 if (status == PEP_OUT_OF_MEMORY)
2318 if (status != PEP_STATUS_OK)
2321 if (msg && msg->shortmsg == NULL) {
2322 msg->shortmsg = _pEp_subj_copy();
2323 assert(msg->shortmsg);
2324 if (msg->shortmsg == NULL)
2330 msg->id = strdup(_src->id);
2332 if (msg->id == NULL)
2335 decorate_message(msg, PEP_rating_undefined, NULL, true, true);
2346 status = PEP_OUT_OF_MEMORY;
2349 free_stringlist(keys);
2357 // static PEP_STATUS _update_identity_for_incoming_message(
2358 // PEP_SESSION session,
2359 // const message *src
2362 // PEP_STATUS status;
2364 // if (src->from && src->from->address) {
2365 // if (!is_me(session, src->from))
2366 // status = update_identity(session, src->from);
2368 // status = myself(session, src->from);
2369 // if (status == PEP_STATUS_OK
2370 // && is_a_pEpmessage(src)
2371 // && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
2372 // && src->from->comm_type != PEP_ct_pEp_unconfirmed
2373 // && src->from->comm_type != PEP_ct_pEp)
2375 // src->from->comm_type |= PEP_ct_pEp_unconfirmed;
2376 // status = set_identity(session, src->from);
2380 // return PEP_ILLEGAL_VALUE;
2384 static PEP_STATUS _get_detached_signature(message* msg,
2385 bloblist_t** signature_blob) {
2386 bloblist_t* attach_curr = msg->attachments;
2388 *signature_blob = NULL;
2390 while (attach_curr) {
2391 if (attach_curr->mime_type &&
2392 (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0)) {
2393 *signature_blob = attach_curr;
2396 attach_curr = attach_curr->next;
2399 return PEP_STATUS_OK;
2402 static PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
2403 char** stext, size_t* ssize) {
2405 char* signed_boundary = NULL;
2406 char* signpost = strstr(ptext, "Content-Type: multipart/signed");
2412 return PEP_UNKNOWN_ERROR;
2414 char* curr_line = signpost;
2415 // const char* end_text = ptext + psize;
2416 const char* boundary_key = "boundary=";
2417 const size_t BOUNDARY_KEY_SIZE = 9;
2419 char* start_boundary = strstr(curr_line, boundary_key);
2420 if (!start_boundary)
2421 return PEP_UNKNOWN_ERROR;
2423 start_boundary += BOUNDARY_KEY_SIZE;
2425 bool quoted = (*start_boundary == '"');
2430 char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
2433 return PEP_UNKNOWN_ERROR;
2435 // Add space for the "--"
2436 size_t boundary_strlen = (end_boundary - start_boundary) + 2;
2438 signed_boundary = calloc(boundary_strlen + 1, 1);
2439 assert(signed_boundary);
2440 if (!signed_boundary)
2441 return PEP_OUT_OF_MEMORY;
2443 strlcpy(signed_boundary, "--", boundary_strlen + 1);
2444 strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
2446 start_boundary = strstr(end_boundary, signed_boundary);
2448 if (!start_boundary)
2449 return PEP_UNKNOWN_ERROR;
2451 start_boundary += boundary_strlen;
2453 if (*start_boundary == '\r') {
2454 if (*(start_boundary + 1) == '\n')
2455 start_boundary += 2;
2457 else if (*start_boundary == '\n')
2460 end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
2463 return PEP_UNKNOWN_ERROR;
2465 // See RFC3156 section 5...
2467 if (*(end_boundary - 1) == '\r')
2470 *ssize = end_boundary - start_boundary;
2471 *stext = start_boundary;
2472 free(signed_boundary);
2474 return PEP_STATUS_OK;
2477 static PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in,
2478 stringlist_t** keylist_in_out,
2479 pEp_identity* from) {
2481 if (!verify_in || !(*verify_in)) // this isn't really a problem.
2482 return PEP_STATUS_OK;
2484 stringlist_t* orig_verify = *verify_in;
2486 stringlist_t* verify_curr = NULL;
2487 stringlist_t* from_keys = NULL;
2489 /* FIXME: what to do if head needs to be null */
2490 PEP_STATUS status = find_keys(session, from->address, &from_keys);
2492 stringlist_t* from_fpr_node = NULL;
2493 stringlist_t* from_curr;
2495 for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
2496 for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
2497 if (from_curr->value && verify_curr->value &&
2498 _same_fpr(from_curr->value, strlen(from_curr->value),
2499 verify_curr->value, strlen(verify_curr->value))) {
2500 from_fpr_node = from_curr;
2506 if (!from_fpr_node) {
2507 status = PEP_KEY_NOT_FOUND;
2511 verify_curr = orig_verify;
2513 /* put "from" signer at the beginning of the list */
2514 if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
2515 from_fpr_node->value, strlen(from_fpr_node->value))) {
2516 orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
2517 verify_curr = new_stringlist(from_fpr_node->value);
2518 verify_curr->next = orig_verify;
2521 if (keylist_in_out) {
2522 /* append keylist to signers */
2523 if (*keylist_in_out && (*keylist_in_out)->value) {
2524 stringlist_t** tail_pp = &verify_curr->next;
2527 tail_pp = &((*tail_pp)->next);
2529 stringlist_t* second_list = *keylist_in_out;
2531 char* listhead_val = second_list->value;
2532 if (!listhead_val || listhead_val[0] == '\0') {
2533 /* remove head, basically. This can happen when,
2534 for example, the signature is detached and
2535 verification is not seen directly after
2536 decryption, so no signer is presumed in
2537 the first construction of the keylist */
2538 *keylist_in_out = (*keylist_in_out)->next;
2539 second_list->next = NULL;
2540 free_stringlist(second_list);
2543 *tail_pp = *keylist_in_out;
2546 *keylist_in_out = verify_curr;
2549 status = PEP_STATUS_OK;
2552 free_stringlist(from_keys);
2556 static PEP_STATUS amend_rating_according_to_sender_and_recipients(
2557 PEP_SESSION session,
2559 pEp_identity *sender,
2560 stringlist_t *recipients) {
2562 PEP_STATUS status = PEP_STATUS_OK;
2564 if (*rating > PEP_rating_mistrust) {
2566 if (recipients == NULL) {
2567 *rating = PEP_rating_undefined;
2568 return PEP_STATUS_OK;
2571 char *fpr = recipients->value;
2573 if (!(sender && sender->user_id && sender->user_id[0] && fpr && fpr[0])) {
2574 *rating = PEP_rating_unreliable;
2577 pEp_identity *_sender = new_identity(sender->address, fpr,
2578 sender->user_id, sender->username);
2579 if (_sender == NULL)
2580 return PEP_OUT_OF_MEMORY;
2582 status = get_trust(session, _sender);
2583 if (_sender->comm_type == PEP_ct_unknown) {
2584 get_key_rating(session, fpr, &_sender->comm_type);
2586 if (_sender->comm_type != PEP_ct_unknown) {
2587 *rating = keylist_rating(session, recipients,
2588 fpr, _rating(_sender->comm_type));
2591 free_identity(_sender);
2592 if (status == PEP_CANNOT_FIND_IDENTITY)
2593 status = PEP_STATUS_OK;
2599 // FIXME: Do we need to remove the attachment? I think we do...
2600 static bool pull_up_attached_main_msg(message* src) {
2601 char* slong = src->longmsg;
2602 char* sform = src->longmsg_formatted;
2603 bloblist_t* satt = src->attachments;
2605 if ((!slong || slong[0] == '\0')
2606 && (!sform || sform[0] == '\0')) {
2608 const char* inner_mime_type = satt->mime_type;
2609 if (strcasecmp(inner_mime_type, "text/plain") == 0) {
2610 free(slong); /* in case of "" */
2611 src->longmsg = strndup(satt->value, satt->size);
2613 bloblist_t* next_node = satt->next;
2615 inner_mime_type = next_node->mime_type;
2616 if (strcasecmp(inner_mime_type, "text/html") == 0) {
2618 src->longmsg_formatted = strndup(next_node->value, next_node->size);
2622 else if (strcasecmp(inner_mime_type, "text/html") == 0) {
2624 src->longmsg_formatted = strndup(satt->value, satt->size);
2634 static PEP_STATUS unencapsulate_hidden_fields(message* src, message* msg,
2635 char** msg_wrap_info) {
2637 return PEP_ILLEGAL_VALUE;
2638 unsigned char pEpstr[] = PEP_SUBJ_STRING;
2639 PEP_STATUS status = PEP_STATUS_OK;
2641 bool change_source_in_place = (msg ? false : true);
2643 if (change_source_in_place)
2647 switch (src->enc_format) {
2648 case PEP_enc_PGP_MIME:
2649 case PEP_enc_inline:
2650 case PEP_enc_PGP_MIME_Outlook1:
2651 // case PEP_enc_none: // FIXME - this is wrong
2653 if (!change_source_in_place)
2654 status = copy_fields(msg, src);
2656 if (status != PEP_STATUS_OK)
2659 // FIXME: This is a mess. Talk with VB about how far we go to identify
2660 if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
2661 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0) ||
2662 (strcmp(src->shortmsg, "p=p") == 0))
2664 char * shortmsg = NULL;
2665 char * longmsg = NULL;
2668 int r = separate_short_and_long(msg->longmsg,
2674 return PEP_OUT_OF_MEMORY;
2677 // We only use the shortmsg in version 1.0 messages; if it occurs where we
2678 // didn't replace the subject, we ignore this all
2679 if (!(*msg_wrap_info || change_source_in_place)) {
2681 (src->shortmsg != NULL && strcmp(src->shortmsg, "pEp") != 0 &&
2682 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0 &&
2683 strcmp(src->shortmsg, "p=p") != 0)) {
2685 if (shortmsg != NULL)
2688 if (src->shortmsg == NULL) {
2689 shortmsg = strdup("");
2692 // FIXME: is msg->shortmsg always a copy of
2693 // src->shortmsg already?
2694 // if so, we need to change the logic so
2695 // that in this case, we don't free msg->shortmsg
2696 // and do this strdup, etc
2697 shortmsg = strdup(src->shortmsg);
2700 free(msg->shortmsg);
2701 msg->shortmsg = shortmsg;
2706 msg->longmsg = longmsg;
2709 if (!change_source_in_place) {
2710 msg->shortmsg = strdup(src->shortmsg);
2711 assert(msg->shortmsg);
2712 if (msg->shortmsg == NULL)
2713 return PEP_OUT_OF_MEMORY;
2718 // BUG: must implement more
2721 return PEP_STATUS_OK;
2725 static PEP_STATUS get_crypto_text(message* src, char** crypto_text, size_t* text_size) {
2727 // this is only here because of how NOT_IMPLEMENTED works
2728 PEP_STATUS status = PEP_STATUS_OK;
2730 switch (src->enc_format) {
2731 case PEP_enc_PGP_MIME:
2732 *crypto_text = src->attachments->next->value;
2733 *text_size = src->attachments->next->size;
2736 case PEP_enc_PGP_MIME_Outlook1:
2737 *crypto_text = src->attachments->value;
2738 *text_size = src->attachments->size;
2741 case PEP_enc_inline:
2742 *crypto_text = src->longmsg;
2743 *text_size = strlen(*crypto_text);
2754 static PEP_STATUS verify_decrypted(PEP_SESSION session,
2758 size_t plaintext_size,
2759 stringlist_t** keylist,
2760 PEP_STATUS* decrypt_status,
2761 PEP_cryptotech crypto) {
2763 assert(src && src->from);
2765 if (!src && !src->from)
2766 return PEP_ILLEGAL_VALUE;
2768 PEP_STATUS _cached_decrypt_status = *decrypt_status;
2770 pEp_identity* sender = src->from;
2772 bloblist_t* detached_sig = NULL;
2773 PEP_STATUS status = _get_detached_signature(msg, &detached_sig);
2774 stringlist_t *verify_keylist = NULL;
2778 char* dsig_text = detached_sig->value;
2779 size_t dsig_size = detached_sig->size;
2783 status = _get_signed_text(plaintext, plaintext_size, &stext, &ssize);
2785 if (ssize > 0 && stext) {
2786 status = cryptotech[crypto].verify_text(session, stext,
2787 ssize, dsig_text, dsig_size,
2791 if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
2793 *decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
2795 status = combine_keylists(session, &verify_keylist, keylist, sender);
2799 size_t csize, psize;
2802 get_crypto_text(src, &ctext, &csize);
2803 // reverify - we may have imported a key in the meantime
2804 // status = cryptotech[crypto].verify_text(session, ctext,
2806 // &verify_keylist);
2807 free_stringlist(*keylist);
2808 *decrypt_status = decrypt_and_verify(session, ctext, csize,
2810 &ptext, &psize, keylist,
2815 if (*decrypt_status != PEP_DECRYPTED_AND_VERIFIED)
2816 *decrypt_status = _cached_decrypt_status;
2818 return PEP_STATUS_OK;
2821 static PEP_STATUS _decrypt_in_pieces(PEP_SESSION session,
2827 PEP_STATUS status = PEP_STATUS_OK;
2829 *msg_ptr = clone_to_empty_message(src);
2831 if (*msg_ptr == NULL)
2832 return PEP_OUT_OF_MEMORY;
2834 message* msg = *msg_ptr;
2836 msg->longmsg = strdup(ptext);
2839 bloblist_t *_m = msg->attachments;
2840 if (_m == NULL && src->attachments && src->attachments->value) {
2841 msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
2842 _m = msg->attachments;
2846 for (_s = src->attachments; _s && _s->value; _s = _s->next) {
2847 if (_s->value == NULL && _s->size == 0){
2848 _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
2850 return PEP_OUT_OF_MEMORY;
2853 else if (is_encrypted_attachment(_s)) {
2854 stringlist_t *_keylist = NULL;
2855 char *attctext = _s->value;
2856 size_t attcsize = _s->size;
2861 char* pgp_filename = NULL;
2862 status = decrypt_and_verify(session, attctext, attcsize,
2864 &ptext, &psize, &_keylist,
2867 free_stringlist(_keylist);
2869 char* filename_uri = NULL;
2871 bool has_uri_prefix = (pgp_filename ? (is_file_uri(pgp_filename) || is_cid_uri(pgp_filename)) :
2872 (_s->filename ? (is_file_uri(_s->filename) || is_cid_uri(_s->filename)) :
2879 if (is_encrypted_html_attachment(_s)) {
2880 msg->longmsg_formatted = ptext;
2884 static const char * const mime_type = "application/octet-stream";
2886 if (!has_uri_prefix)
2887 filename_uri = build_uri("file", pgp_filename);
2889 _m = bloblist_add(_m, ptext, psize, mime_type,
2890 (filename_uri ? filename_uri : pgp_filename));
2895 return PEP_OUT_OF_MEMORY;
2898 char * const filename =
2899 without_double_ending(_s->filename);
2900 if (filename == NULL)
2901 return PEP_OUT_OF_MEMORY;
2903 if (!has_uri_prefix)
2904 filename_uri = build_uri("file", filename);
2906 _m = bloblist_add(_m, ptext, psize, mime_type,
2907 (filename_uri ? filename_uri : filename));
2911 return PEP_OUT_OF_MEMORY;
2915 if (msg->attachments == NULL)
2916 msg->attachments = _m;
2920 char *copy = malloc(_s->size);
2923 return PEP_OUT_OF_MEMORY;
2924 memcpy(copy, _s->value, _s->size);
2926 if (!has_uri_prefix && _s->filename)
2927 filename_uri = build_uri("file", _s->filename);
2929 _m = bloblist_add(_m, copy, _s->size, _s->mime_type,
2930 (filename_uri ? filename_uri : _s->filename));
2932 return PEP_OUT_OF_MEMORY;
2936 char *copy = malloc(_s->size);
2939 return PEP_OUT_OF_MEMORY;
2940 memcpy(copy, _s->value, _s->size);
2942 char* filename_uri = NULL;
2944 _m = bloblist_add(_m, copy, _s->size, _s->mime_type,
2945 ((_s->filename && !(is_file_uri(_s->filename) || is_cid_uri(_s->filename))) ?
2946 (filename_uri = build_uri("file", _s->filename)) : _s->filename));
2949 return PEP_OUT_OF_MEMORY;
2956 static PEP_STATUS import_priv_keys_from_decrypted_msg(PEP_SESSION session,
2958 bool* imported_keys,
2959 bool* imported_private,
2960 identity_list** private_il)
2962 assert(msg && imported_keys && imported_private);
2963 if (!(msg && imported_keys && imported_private))
2964 return PEP_ILLEGAL_VALUE;
2966 PEP_STATUS status = PEP_STATUS_OK;
2967 *imported_keys = NULL;
2968 *imported_private = false;
2972 // check for private key in decrypted message attachment while importing
2973 identity_list *_private_il = NULL;
2975 bool _imported_keys = import_attached_keys(session, msg, &_private_il);
2976 bool _imported_private = false;
2977 if (_private_il && _private_il->ident && _private_il->ident->address)
2978 _imported_private = true;
2980 if (private_il && _imported_private) {
2981 // the private identity list should NOT be subject to myself() or
2982 // update_identity() at this point.
2983 // If the receiving app wants them to be in the trust DB, it
2984 // should call set_own_key() on them upon return.
2985 // We do, however, prepare these so the app can use them
2986 // directly in a set_own_key() call by putting the own_id on it.
2987 char* own_id = NULL;
2988 status = get_default_own_userid(session, &own_id);
2990 for (identity_list* il = _private_il; il; il = il->next) {
2992 free(il->ident->user_id);
2993 il->ident->user_id = strdup(own_id);
2994 assert(il->ident->user_id);
2995 if (!il->ident->user_id) {
2996 status = PEP_OUT_OF_MEMORY;
3000 il->ident->me = true;
3004 *private_il = _private_il;
3007 free_identity_list(_private_il);
3011 *imported_keys = _imported_keys;
3012 *imported_private = _imported_private;
3018 // FIXME: myself ??????
3019 static PEP_STATUS update_sender_to_pEp_trust(
3020 PEP_SESSION session,
3021 pEp_identity* sender,
3022 stringlist_t* keylist)
3026 assert(keylist && !EMPTYSTR(keylist->value));
3028 if (!session || !sender || !keylist || EMPTYSTR(keylist->value))
3029 return PEP_ILLEGAL_VALUE;
3035 is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
3037 if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
3039 sender->fpr = strdup(keylist->value);
3041 return PEP_OUT_OF_MEMORY;
3042 status = set_pgp_keypair(session, sender->fpr);
3043 if (status != PEP_STATUS_OK)
3046 status = get_trust(session, sender);
3048 if (status == PEP_CANNOT_FIND_IDENTITY || sender->comm_type == PEP_ct_unknown) {
3049 PEP_comm_type ct = PEP_ct_unknown;
3050 status = get_key_rating(session, sender->fpr, &ct);
3051 if (status != PEP_STATUS_OK)
3054 sender->comm_type = ct;
3058 // Could be done elegantly, but we do this explicitly here for readability.
3059 // This file's code is difficult enough to parse. But change at will.
3060 switch (sender->comm_type) {
3061 case PEP_ct_OpenPGP_unconfirmed:
3062 case PEP_ct_OpenPGP:
3063 sender->comm_type = PEP_ct_pEp_unconfirmed | (sender->comm_type & PEP_ct_confirmed);
3064 status = set_trust(session, sender);
3067 status = PEP_CANNOT_SET_TRUST;
3074 static PEP_STATUS reconcile_identity(pEp_identity* srcid,
3075 pEp_identity* resultid) {
3079 if (!srcid || !resultid)
3080 return PEP_ILLEGAL_VALUE;
3082 if (!EMPTYSTR(srcid->user_id)) {
3083 if (EMPTYSTR(resultid->user_id) ||
3084 strcmp(srcid->user_id, resultid->user_id) != 0) {
3085 free(resultid->user_id);
3086 resultid->user_id = strdup(srcid->user_id);
3090 resultid->lang[0] = srcid->lang[0];
3091 resultid->lang[1] = srcid->lang[1];
3092 resultid->lang[2] = 0;
3093 resultid->me = srcid->me;
3094 resultid->flags = srcid->flags;
3096 return PEP_STATUS_OK;
3099 static PEP_STATUS reconcile_identity_lists(identity_list* src_ids,
3100 identity_list* result_ids) {
3102 identity_list* curr_id = result_ids;
3104 PEP_STATUS status = PEP_STATUS_OK;
3107 identity_list* curr_src_id = src_ids;
3108 pEp_identity* result_identity = curr_id->ident;
3110 while (curr_src_id) {
3111 pEp_identity* source_identity = curr_src_id->ident;
3113 if (EMPTYSTR(source_identity->address) || EMPTYSTR(result_identity->address))
3114 return PEP_ILLEGAL_VALUE; // something went badly wrong
3116 if (strcasecmp(source_identity->address, result_identity->address) == 0) {
3117 status = reconcile_identity(source_identity, result_identity);
3118 if (status != PEP_STATUS_OK)
3121 curr_src_id = curr_src_id->next;
3123 curr_id = curr_id->next;
3128 static PEP_STATUS reconcile_sent_and_recv_info(message* src, message* inner_message) {
3129 PEP_STATUS status = PEP_STATUS_OK;
3130 if (!src || !inner_message)
3131 return PEP_ILLEGAL_VALUE;
3133 if (!inner_message->sent)
3134 inner_message->sent = timestamp_dup(src->sent);
3136 // This will never be set otherwise, since it's a transport header on the outside
3137 inner_message->recv = timestamp_dup(src->recv);
3139 return PEP_STATUS_OK;
3142 static PEP_STATUS reconcile_src_and_inner_messages(message* src,
3143 message* inner_message) {
3145 PEP_STATUS status = PEP_STATUS_OK;
3147 if (strcasecmp(src->from->address, inner_message->from->address) == 0)
3148 status = reconcile_identity(src->from, inner_message->from);
3150 if (status == PEP_STATUS_OK && inner_message->to)
3151 status = reconcile_identity_lists(src->to, inner_message->to);
3153 if (status == PEP_STATUS_OK && inner_message->cc)
3154 status = reconcile_identity_lists(src->cc, inner_message->cc);
3156 if (status == PEP_STATUS_OK && inner_message->bcc)
3157 status = reconcile_identity_lists(src->bcc, inner_message->bcc);
3159 if (status == PEP_STATUS_OK)
3160 status = reconcile_sent_and_recv_info(src, inner_message);
3163 // FIXME - are there any flags or anything else we need to be sure are carried?
3166 static bool is_trusted_own_priv_fpr(PEP_SESSION session,
3171 bool retval = false;
3172 if (!EMPTYSTR(fpr)) {
3173 pEp_identity* test_identity = new_identity(NULL, fpr, own_id, NULL);
3174 if (test_identity) {
3175 PEP_STATUS status = get_trust(session, test_identity);
3176 if (status == PEP_STATUS_OK) {
3177 if (test_identity->comm_type & PEP_ct_confirmed) {
3178 bool has_priv = false;
3179 status = contains_priv_key(session, fpr, &has_priv);
3180 if (status == PEP_STATUS_OK && has_priv)
3184 free(test_identity);
3190 static bool reject_fpr(PEP_SESSION session, const char* fpr) {
3193 PEP_STATUS status = key_revoked(session, fpr, &reject);
3196 status = key_expired(session, fpr, time(NULL), &reject);
3198 timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
3199 status = renew_key(session, fpr, ts);
3201 if (status == PEP_STATUS_OK)
3208 static char* seek_good_trusted_private_fpr(PEP_SESSION session, char* own_id,
3209 stringlist_t* keylist) {
3210 if (!own_id || !keylist)
3213 stringlist_t* kl_curr = keylist;
3215 char* fpr = kl_curr->value;
3217 if (is_trusted_own_priv_fpr(session, own_id, fpr)) {
3218 if (!reject_fpr(session, fpr))
3222 kl_curr = kl_curr->next;
3225 char* target_own_fpr = NULL;
3228 PEP_STATUS status = get_user_default_key(session, own_id,
3231 if (status == PEP_STATUS_OK && !EMPTYSTR(target_own_fpr)) {
3232 if (is_trusted_own_priv_fpr(session, own_id, target_own_fpr)) {
3233 if (!reject_fpr(session, target_own_fpr))
3234 return target_own_fpr;
3238 // TODO: We can also go through all of the other available fprs for the
3239 // own identity, but then I submit this function requires a little refactoring
3244 static bool import_header_keys(PEP_SESSION session, message* src) {
3245 stringpair_list_t* header_keys = stringpair_list_find(src->opt_fields, "Autocrypt");
3246 if (!header_keys || !header_keys->value)
3248 const char* value = header_keys->value->value;
3251 const char* start_key = strstr(value, "keydata=");
3254 start_key += 8; // length of "keydata="
3255 int length = strlen(start_key);
3256 bloblist_t* the_key = base64_str_to_binary_blob(start_key, length);
3259 PEP_STATUS status = import_key(session, the_key->value, the_key->size, NULL);
3260 free_bloblist(the_key);
3261 if (status == PEP_STATUS_OK || status == PEP_KEY_IMPORTED)
3266 PEP_STATUS check_for_own_revoked_key(
3267 PEP_SESSION session,
3268 stringlist_t* keylist,
3269 stringpair_list_t** revoked_fpr_pairs
3272 if (!session || !revoked_fpr_pairs)
3273 return PEP_ILLEGAL_VALUE;
3275 *revoked_fpr_pairs = NULL;
3277 PEP_STATUS status = PEP_STATUS_OK;
3278 stringpair_list_t* _the_list = new_stringpair_list(NULL);
3280 stringlist_t* _k = keylist;
3281 for ( ; _k; _k = _k->next) {
3283 if (EMPTYSTR(_k->value))
3284 continue; // Maybe the right thing to do is choke.
3285 // But we can have NULL-valued empty list heads.
3287 const char* recip_fpr = _k->value;
3288 char* replace_fpr = NULL;
3289 uint64_t revoke_date = 0;
3290 status = get_replacement_fpr(session,
3295 bool own_key = false;
3298 case PEP_CANNOT_FIND_IDENTITY:
3299 status = PEP_STATUS_OK;
3303 status = is_own_key(session, recip_fpr, &own_key);
3305 if (status != PEP_STATUS_OK) {
3311 stringpair_list_add(_the_list, new_stringpair(recip_fpr, replace_fpr));
3321 if (_the_list && _the_list->value) {
3322 *revoked_fpr_pairs = _the_list;
3327 free_stringpair_list(_the_list);
3332 static PEP_STATUS _decrypt_message(
3333 PEP_SESSION session,
3336 stringlist_t **keylist,
3338 PEP_decrypt_flags_t *flags,
3339 identity_list **private_il
3349 if (!(session && src && dst && keylist && rating && flags))
3350 return PEP_ILLEGAL_VALUE;
3352 /*** Begin init ***/
3353 PEP_STATUS status = PEP_STATUS_OK;
3354 PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
3355 PEP_STATUS _decrypt_in_pieces_status = PEP_CANNOT_DECRYPT_UNKNOWN;
3356 message* msg = NULL;
3357 message* calculated_src = src;
3358 message* reset_msg = NULL;
3364 stringlist_t *_keylist = NULL;
3365 char* signer_fpr = NULL;
3366 bool is_pEp_msg = is_a_pEpmessage(src);
3367 bool myself_read_only = (src->dir == PEP_dir_incoming);
3370 bool reencrypt = (((*flags & PEP_decrypt_flag_untrusted_server) > 0) && *keylist && !EMPTYSTR((*keylist)->value));
3372 // We own this pointer, and we take control of *keylist if reencrypting.
3373 stringlist_t* extra = NULL;
3382 *rating = PEP_rating_undefined;
3387 // Ok, before we do anything, if it's a pEp message, regardless of whether it's
3388 // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
3390 if (src->from && !(is_me(session, src->from))) {
3392 pEp_identity* tmp_from = src->from;
3394 // Ensure there's a user id
3395 if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
3396 status = update_identity(session, tmp_from);
3397 if (status == PEP_CANNOT_FIND_IDENTITY) {
3398 tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
3399 if (!tmp_from->user_id)
3400 return PEP_OUT_OF_MEMORY;
3401 snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
3402 "TOFU_%s", tmp_from->address);
3403 status = PEP_STATUS_OK;
3406 if (status == PEP_STATUS_OK) {
3407 // Now set user as PEP (may also create an identity if none existed yet)
3408 status = set_as_pEp_user(session, tmp_from);
3412 // We really need key used in signing to do anything further on the pEp comm_type.
3413 // So we can't adjust the rating of the sender just yet.
3415 /*** Begin Import any attached public keys and update identities accordingly ***/
3416 // Private key in unencrypted mail are ignored -> NULL
3418 // This import is from the outermost message.
3419 // We don't do this for PGP_mime.
3420 bool imported_keys = false;
3421 if (!_has_PGP_MIME_format(src))
3422 imported_keys = import_attached_keys(session, src, NULL);
3424 import_header_keys(session, src);
3426 // FIXME: is this really necessary here?
3428 if (!is_me(session, src->from))
3429 status = update_identity(session, src->from);
3431 status = _myself(session, src->from, false, false, myself_read_only);
3433 // We absolutely should NOT be bailing here unless it's a serious error
3434 if (status == PEP_OUT_OF_MEMORY)
3438 /*** End Import any attached public keys and update identities accordingly ***/
3440 /*** Begin get detached signatures that are attached to the encrypted message ***/
3441 // Get detached signature, if any
3442 bloblist_t* detached_sig = NULL;
3443 char* dsig_text = NULL;
3444 size_t dsig_size = 0;
3445 status = _get_detached_signature(src, &detached_sig);
3447 dsig_text = detached_sig->value;
3448 dsig_size = detached_sig->size;
3450 /*** End get detached signatures that are attached to the encrypted message ***/
3452 /*** Determine encryption format ***/
3453 PEP_cryptotech crypto = determine_encryption_format(src);
3455 // Check for and deal with unencrypted messages
3456 if (src->enc_format == PEP_enc_none) {
3458 *rating = PEP_rating_unencrypted;
3460 // We remove these from the outermost source message
3461 // if (imported_keys)
3462 // remove_attached_keys(src);
3464 pull_up_attached_main_msg(src);
3466 return PEP_UNENCRYPTED;
3469 status = get_crypto_text(src, &ctext, &csize);
3470 if (status != PEP_STATUS_OK)
3473 /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
3474 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
3475 csize, dsig_text, dsig_size,
3476 &ptext, &psize, &_keylist,
3479 if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
3482 decrypt_status = status;
3484 bool imported_private_key_address = false;
3487 /* we got a plaintext from decryption */
3488 switch (src->enc_format) {
3490 case PEP_enc_PGP_MIME:
3491 case PEP_enc_PGP_MIME_Outlook1:
3493 status = mime_decode_message(ptext, psize, &msg);
3494 if (status != PEP_STATUS_OK)
3497 /* Ensure messages whose maintext is in the attachments
3498 move main text into message struct longmsg et al */
3499 /* KG: This IS a src modification of old - we're adding to it
3500 w/ memhole subject, but the question is whether or not
3501 this is OK overall... */
3502 pull_up_attached_main_msg(msg);
3503 if (msg->shortmsg) {
3504 free(src->shortmsg);
3505 src->shortmsg = strdup(msg->shortmsg);
3508 // check for private key in decrypted message attachment while importing
3509 // N.B. Apparently, we always import private keys into the keyring; however,
3510 // we do NOT always allow those to be used for encryption. THAT is controlled
3511 // by setting it as an own identity associated with the key in the DB.
3513 // We are importing from the decrypted outermost message now.
3515 status = import_priv_keys_from_decrypted_msg(session, msg,
3517 &imported_private_key_address,
3519 if (status != PEP_STATUS_OK)
3522 /* if decrypted, but not verified... */
3523 if (decrypt_status == PEP_DECRYPTED) {
3526 status = verify_decrypted(session,
3535 case PEP_enc_inline:
3536 status = PEP_STATUS_OK;
3538 _decrypt_in_pieces_status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
3540 switch (_decrypt_in_pieces_status) {
3542 case PEP_DECRYPTED_AND_VERIFIED:
3543 if (decrypt_status <= PEP_DECRYPTED_AND_VERIFIED)
3544 decrypt_status = MIN(decrypt_status, _decrypt_in_pieces_status);
3548 case PEP_OUT_OF_MEMORY:
3551 decrypt_status = _decrypt_in_pieces_status;
3556 // BUG: must implement more
3560 if (status == PEP_OUT_OF_MEMORY)
3563 if (status != PEP_STATUS_OK)
3566 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3567 char* wrap_info = NULL;
3569 status = unencapsulate_hidden_fields(src, msg, &wrap_info);
3571 // bool is_transport_wrapper = false;
3573 // FIXME: replace with enums, check status
3575 if (strcmp(wrap_info, "OUTER") == 0) {
3576 // this only occurs in with a direct outer wrapper
3577 // where the actual content is in the inner wrapper
3578 message* inner_message = NULL;
3579 bloblist_t* actual_message = msg->attachments;
3581 while (actual_message) {
3582 char* mime_type = actual_message->mime_type;
3585 // libetpan appears to change the mime_type on this one.
3587 if (strcmp("message/rfc822", mime_type) == 0 ||
3588 strcmp("text/rfc822", mime_type) == 0) {
3590 status = mime_decode_message(actual_message->value,
3591 actual_message->size,
3593 if (status != PEP_STATUS_OK)
3596 if (inner_message) {
3597 // Though this will strip any message info on the
3598 // attachment, this is safe, as we do not
3599 // produce more than one attachment-as-message,
3600 // and those are the only ones with such info.
3601 // Since we capture the information, this is ok.
3603 inner_message->enc_format = src->enc_format;
3605 status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);
3608 if (status != PEP_STATUS_OK) {
3609 free_message(inner_message);
3614 bool is_inner = (strcmp(wrap_info, "INNER") == 0);
3615 bool is_key_reset = (strcmp(wrap_info, "KEY_RESET") == 0);
3618 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3619 status = receive_key_reset(session,
3621 if (status != PEP_STATUS_OK) {
3622 free_message(inner_message);
3625 *flags |= PEP_decrypt_flag_consume;
3628 else if (is_inner) {
3630 // check for private key in decrypted message attachment while importing
3631 // N.B. Apparently, we always import private keys into the keyring; however,
3632 // we do NOT always allow those to be used for encryption. THAT is controlled
3633 // by setting it as an own identity associated with the key in the DB.
3635 // If we have a message 2.0 message, we are ONLY going to be ok with keys
3636 // we imported from THIS part of the message.
3637 imported_private_key_address = false;
3641 // import keys from decrypted INNER source
3642 status = import_priv_keys_from_decrypted_msg(session, inner_message,
3644 &imported_private_key_address,
3646 if (status != PEP_STATUS_OK)
3649 // THIS is our message
3650 // Now, let's make sure we've copied in
3651 // any information sent in by the app if
3653 reconcile_src_and_inner_messages(src, inner_message);
3656 // FIXME: free msg, but check references
3657 //src = msg = inner_message;
3658 calculated_src = msg = inner_message;
3660 // FIXME: should this be msg???
3662 if (!is_me(session, src->from))
3663 update_identity(session, (src->from));
3665 _myself(session, src->from, false, false, myself_read_only);
3669 else { // should never happen
3670 status = PEP_UNKNOWN_ERROR;
3671 free_message(inner_message);
3675 inner_message->enc_format = PEP_enc_none;
3677 else { // forwarded message, leave it alone
3678 free_message(inner_message);
3682 actual_message = actual_message->next;
3685 else if (strcmp(wrap_info, "TRANSPORT") == 0) {
3686 // FIXME: this gets even messier.
3687 // (TBI in ENGINE-278)
3689 else {} // shouldn't be anything to be done here
3693 *rating = decrypt_rating(decrypt_status);
3695 // Ok, so if it was signed and it's all verified, we can update
3696 // eligible signer comm_types to PEP_ct_pEp_*
3697 if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg && calculated_src->from)
3698 status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist);
3700 /* Ok, now we have a keylist used for decryption/verification.
3701 now we need to update the message rating with the
3702 sender and recipients in mind */
3703 status = amend_rating_according_to_sender_and_recipients(session,
3704 rating, calculated_src->from, _keylist);
3706 if (status != PEP_STATUS_OK)
3709 /* We decrypted ok, hallelujah. */
3710 msg->enc_format = PEP_enc_none;
3713 // We did not get a plaintext out of the decryption process.
3714 // Abort and return error.
3715 *rating = decrypt_rating(decrypt_status);
3720 Ok, at this point, we know we have a reliably decrypted message.
3721 Prepare the output message for return.
3724 // 1. Check to see if this message is to us and contains an own key imported
3725 // from own trusted message
3726 if (*rating >= PEP_rating_trusted && imported_private_key_address) {
3728 if (msg && msg->to && msg->to->ident) {
3729 // This will only happen rarely, so we can do this.
3730 PEP_STATUS _tmp_status = PEP_STATUS_OK;
3732 if (!is_me(session, msg->to->ident))
3733 _tmp_status = update_identity(session, msg->to->ident);
3735 if (_tmp_status == PEP_STATUS_OK && is_me(session, msg->to->ident)) {
3737 *flags |= PEP_decrypt_flag_own_private_key;
3742 // 2. Clean up message and prepare for return
3745 /* add pEp-related status flags to header */
3746 decorate_message(msg, *rating, _keylist, false, false);
3748 // Maybe unnecessary
3749 // if (imported_keys)
3750 // remove_attached_keys(msg);
3752 if (calculated_src->id && calculated_src != msg) {
3753 msg->id = strdup(calculated_src->id);
3755 if (msg->id == NULL)
3758 } // End prepare output message for return
3760 // 3. Check to see if the sender used any of our revoked keys
3761 stringpair_list_t* revoke_replace_pairs = NULL;
3762 status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
3764 //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN
3765 if (status != PEP_STATUS_OK) {
3766 // This should really never choke unless the DB is broken.
3767 status = PEP_UNKNOWN_DB_ERROR;
3772 stringpair_list_t* curr_pair_node;
3773 stringpair_t* curr_pair;
3775 for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
3776 curr_pair = curr_pair_node->value;
3779 continue; // Again, shouldn't occur
3781 if (curr_pair->key && curr_pair->value) {
3782 status = create_standalone_key_reset_message(session,
3788 // If we can't find the identity, this is someone we've never mailed, so we just
3789 // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
3790 if (status != PEP_CANNOT_FIND_IDENTITY) {
3791 if (status != PEP_STATUS_OK)
3795 status = PEP_OUT_OF_MEMORY;
3798 // insert into queue
3799 if (session->messageToSend)
3800 status = session->messageToSend(reset_msg);
3802 status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
3805 if (status == PEP_STATUS_OK) {
3806 // Put into notified DB
3807 status = set_reset_contact_notified(session, curr_pair->key, msg->from->user_id);
3808 if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
3812 // According to Volker, this would only be a fatal error, so...
3813 free_message(reset_msg); // ??
3814 reset_msg = NULL; // ??
3822 // 4. Set up return values
3824 *keylist = _keylist;
3826 // 5. Reencrypt if necessary
3828 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3829 message* reencrypt_msg = NULL;
3830 PEP_STATUS reencrypt_status = PEP_CANNOT_REENCRYPT;
3831 char* own_id = NULL;
3832 status = get_default_own_userid(session, &own_id);
3834 char* target_own_fpr = seek_good_trusted_private_fpr(session,
3837 if (target_own_fpr) {
3838 pEp_identity* target_id = new_identity(NULL, target_own_fpr,
3841 reencrypt_status = encrypt_message_for_self(session, target_id, msg,
3842 extra, &reencrypt_msg, PEP_enc_PGP_MIME,
3844 if (reencrypt_status != PEP_STATUS_OK)
3845 reencrypt_status = PEP_CANNOT_REENCRYPT;
3847 free_identity(target_id);
3849 free(target_own_fpr);
3853 free_stringlist(extra); // This was an input variable for us. Keylist is overwritten above.
3855 if (reencrypt_status != PEP_CANNOT_REENCRYPT && reencrypt_msg) {
3856 message_transfer(src, reencrypt_msg);
3857 *flags |= PEP_decrypt_flag_src_modified;
3858 free_message(reencrypt_msg);
3861 decrypt_status = PEP_CANNOT_REENCRYPT;
3865 if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
3866 return PEP_STATUS_OK;
3868 return decrypt_status;
3871 status = PEP_OUT_OF_MEMORY;
3877 free_message(reset_msg);
3878 free_stringlist(_keylist);
3883 DYNAMIC_API PEP_STATUS decrypt_message(
3884 PEP_SESSION session,
3887 stringlist_t **keylist,
3889 PEP_decrypt_flags_t *flags
3899 if (!(session && src && dst && keylist && rating && flags))
3900 return PEP_ILLEGAL_VALUE;
3902 if (!(*flags & PEP_decrypt_flag_untrusted_server))
3904 //*keylist = NULL; // NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!!!! This fucks up reencryption
3905 PEP_STATUS status = _decrypt_message(session, src, dst, keylist, rating, flags, NULL);
3907 message *msg = *dst ? *dst : src;
3909 if (session->inject_sync_event && msg && msg->from &&
3910 !(*flags & PEP_decrypt_flag_dont_trigger_sync)) {
3913 char *sender_fpr = NULL;
3914 PEP_STATUS tmpstatus = base_extract_message(session, msg, &size, &data, &sender_fpr);
3915 if (!tmpstatus && size && data) {
3917 signal_Sync_message(session, *rating, data, size, msg->from, sender_fpr);
3918 // FIXME: this must be changed to sender_fpr
3920 signal_Sync_message(session, *rating, data, size, msg->from, (*keylist)->value);
3928 DYNAMIC_API PEP_STATUS own_message_private_key_details(
3929 PEP_SESSION session,
3931 pEp_identity **ident
3938 if (!(session && msg && ident))
3939 return PEP_ILLEGAL_VALUE;
3941 message *dst = NULL;
3942 stringlist_t *keylist = NULL;
3944 PEP_decrypt_flags_t flags;
3948 identity_list *private_il = NULL;
3949 PEP_STATUS status = _decrypt_message(session, msg, &dst, &keylist, &rating, &flags, &private_il);
3951 free_stringlist(keylist);
3953 if (status == PEP_STATUS_OK &&
3954 flags & PEP_decrypt_flag_own_private_key &&
3957 *ident = identity_dup(private_il->ident);
3960 free_identity_list(private_il);
3965 // Note: if comm_type_determine is false, it generally means that
3966 // we were unable to get key information for anyone in the list,
3967 // likely because a key is missing.
3968 static void _max_comm_type_from_identity_list(
3969 identity_list *identities,
3970 PEP_SESSION session,
3971 PEP_comm_type *max_comm_type,
3972 bool *comm_type_determined
3976 for (il = identities; il != NULL; il = il->next)
3980 PEP_STATUS status = PEP_STATUS_OK;
3981 *max_comm_type = _get_comm_type(session, *max_comm_type,
3983 *comm_type_determined = true;
3985 bool is_blacklisted = false;
3986 if (il->ident->fpr && IS_PGP_CT(il->ident->comm_type)) {
3987 status = blacklist_is_listed(session, il->ident->fpr, &is_blacklisted);
3988 if (is_blacklisted) {
3989 bool user_default, ident_default, address_default;
3990 status = get_valid_pubkey(session, il->ident,
3991 &ident_default, &user_default,
3994 if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
3995 il->ident->comm_type = PEP_ct_key_not_found;
3996 if (*max_comm_type > PEP_ct_no_encryption)
3997 *max_comm_type = PEP_ct_no_encryption;
4002 // check for the return statuses which might not a representative
4003 // value in the comm_type
4004 if (status == PEP_ILLEGAL_VALUE || status == PEP_CANNOT_SET_PERSON ||
4005 status == PEP_CANNOT_FIND_IDENTITY) {
4006 // PEP_CANNOT_FIND_IDENTITY only comes back when we've really
4007 // got nothing from update_identity after applying the whole
4009 *max_comm_type = PEP_ct_no_encryption;
4010 *comm_type_determined = true;
4016 static void _max_comm_type_from_identity_list_preview(
4017 identity_list *identities,
4018 PEP_SESSION session,
4019 PEP_comm_type *max_comm_type
4023 for (il = identities; il != NULL; il = il->next)
4027 *max_comm_type = _get_comm_type_preview(session, *max_comm_type,
4033 DYNAMIC_API PEP_STATUS outgoing_message_rating(
4034 PEP_SESSION session,
4039 PEP_comm_type max_comm_type = PEP_ct_pEp;
4040 bool comm_type_determined = false;
4044 assert(msg->dir == PEP_dir_outgoing);
4047 if (!(session && msg && rating))
4048 return PEP_ILLEGAL_VALUE;
4050 if (msg->dir != PEP_dir_outgoing)
4051 return PEP_ILLEGAL_VALUE;
4053 *rating = PEP_rating_undefined;
4055 _max_comm_type_from_identity_list(msg->to, session,
4056 &max_comm_type, &comm_type_determined);
4058 _max_comm_type_from_identity_list(msg->cc, session,
4059 &max_comm_type, &comm_type_determined);
4061 _max_comm_type_from_identity_list(msg->bcc, session,
4062 &max_comm_type, &comm_type_determined);
4064 if (comm_type_determined == false) {
4065 // likely means there was a massive screwup with no sender or recipient
4067 *rating = PEP_rating_undefined;
4070 *rating = MAX(_rating(max_comm_type), PEP_rating_unencrypted);
4072 return PEP_STATUS_OK;
4075 DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
4076 PEP_SESSION session,
4081 PEP_comm_type max_comm_type = PEP_ct_pEp;
4085 assert(msg->dir == PEP_dir_outgoing);
4088 if (!(session && msg && rating))
4089 return PEP_ILLEGAL_VALUE;
4091 if (msg->dir != PEP_dir_outgoing)
4092 return PEP_ILLEGAL_VALUE;
4094 *rating = PEP_rating_undefined;
4096 _max_comm_type_from_identity_list_preview(msg->to, session,
4099 _max_comm_type_from_identity_list_preview(msg->cc, session,
4102 _max_comm_type_from_identity_list_preview(msg->bcc, session,
4105 *rating = _MAX(_rating(max_comm_type), PEP_rating_unencrypted);
4107 return PEP_STATUS_OK;
4110 DYNAMIC_API PEP_STATUS identity_rating(
4111 PEP_SESSION session,
4112 pEp_identity *ident,
4116 PEP_STATUS status = PEP_STATUS_OK;
4122 if (!(session && ident && rating))
4123 return PEP_ILLEGAL_VALUE;
4125 *rating = PEP_rating_undefined;
4128 status = _myself(session, ident, false, true, true);
4130 status = update_identity(session, ident);
4132 bool is_blacklisted = false;
4134 if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
4135 status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
4136 if (status != PEP_STATUS_OK) {
4137 return status; // DB ERROR
4139 if (is_blacklisted) {
4140 bool user_default, ident_default, address_default;
4141 status = get_valid_pubkey(session, ident,
4142 &ident_default, &user_default,
4145 if (status != PEP_STATUS_OK || ident->fpr == NULL) {
4146 ident->comm_type = PEP_ct_key_not_found;
4147 status = PEP_STATUS_OK;
4152 if (status == PEP_STATUS_OK)
4153 *rating = _rating(ident->comm_type);
4158 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
4160 PEP_STATUS status = PEP_STATUS_OK;
4164 return PEP_ILLEGAL_VALUE;
4166 if (cryptotech[tech].binary_path == NULL)
4169 status = cryptotech[tech].binary_path(path);
4175 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
4177 if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
4178 return PEP_color_no_color;
4180 if (rating < PEP_rating_undefined)
4181 return PEP_color_red;
4183 if (rating < PEP_rating_reliable)
4184 return PEP_color_no_color;
4186 if (rating < PEP_rating_trusted)
4187 return PEP_color_yellow;
4189 if (rating >= PEP_rating_trusted)
4190 return PEP_color_green;
4192 // this should never happen
4194 return PEP_color_no_color;
4197 /* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
4198 static short asciihex_to_num(char a) {
4199 short conv_num = -1;
4200 if (a >= 0x30 && a <= 0x39)
4201 conv_num = a - 0x30;
4203 // convert case, subtract offset, get number
4204 conv_num = ((a | 0x20) - 0x61) + 10;
4205 if (conv_num < 0xa || conv_num > 0xf)
4211 static char num_to_asciihex(short h) {
4212 if (h < 0 || h > 16)
4215 return (char)(h + 0x30);
4216 return (char)((h - 10) + 0x41); // for readability
4219 static char xor_hex_chars(char a, char b) {
4220 short a_num = asciihex_to_num(a);
4221 short b_num = asciihex_to_num(b);
4222 if (a_num < 0 || b_num < 0)
4224 short xor_num = a_num^b_num;
4225 return num_to_asciihex(xor_num);
4228 static const char* skip_separators(const char* current, const char* begin) {
4229 while (current >= begin) {
4230 /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
4231 char check_char = *current;
4232 switch (check_char) {
4250 PEP_STATUS check_for_zero_fpr(char* fpr) {
4251 PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
4255 status = PEP_STATUS_OK;
4265 DYNAMIC_API PEP_STATUS get_trustwords(
4266 PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
4267 const char* lang, char **words, size_t *wsize, bool full
4270 assert(session && id1 && id1->fpr && id2 && id2->fpr&& lang && words &&
4272 if (!(session && id1 && id1->fpr && id2 && id2->fpr&& lang && words &&
4274 return PEP_ILLEGAL_VALUE;
4276 return get_trustwords_for_fprs(session, id1->fpr, id2->fpr, lang, words,
4280 DYNAMIC_API PEP_STATUS get_trustwords_for_fprs(
4281 PEP_SESSION session, const char* fpr1, const char* fpr2,
4282 const char* lang, char **words, size_t *wsize, bool full
4285 assert(session && fpr1 && fpr2 && words && wsize);
4286 if (!(session && fpr1 && fpr2 && words && wsize))
4287 return PEP_ILLEGAL_VALUE;
4289 const int SHORT_NUM_TWORDS = 5;
4290 PEP_STATUS status = PEP_STATUS_OK;
4295 int fpr1_len = strlen(fpr1);
4296 int fpr2_len = strlen(fpr2);
4298 int max_len = (fpr1_len > fpr2_len ? fpr1_len : fpr2_len);
4300 char* XORed_fpr = (char*)(calloc(max_len + 1, 1));
4301 *(XORed_fpr + max_len) = '\0';
4302 char* result_curr = XORed_fpr + max_len - 1;
4303 const char* fpr1_curr = fpr1 + fpr1_len - 1;
4304 const char* fpr2_curr = fpr2 + fpr2_len - 1;
4306 while (fpr1 <= fpr1_curr && fpr2 <= fpr2_curr) {
4307 fpr1_curr = skip_separators(fpr1_curr, fpr1);
4308 fpr2_curr = skip_separators(fpr2_curr, fpr2);
4310 if (fpr1_curr < fpr1 || fpr2_curr < fpr2)
4313 char xor_hex = xor_hex_chars(*fpr1_curr, *fpr2_curr);
4314 if (xor_hex == '\0') {
4315 status = PEP_ILLEGAL_VALUE;
4319 *result_curr = xor_hex;
4320 result_curr--; fpr1_curr--; fpr2_curr--;
4323 const char* remainder_start = NULL;
4324 const char* remainder_curr = NULL;
4326 if (fpr1 <= fpr1_curr) {
4327 remainder_start = fpr1;
4328 remainder_curr = fpr1_curr;
4330 else if (fpr2 <= fpr2_curr) {
4331 remainder_start = fpr2;
4332 remainder_curr = fpr2_curr;
4334 if (remainder_curr) {
4335 while (remainder_start <= remainder_curr) {
4336 remainder_curr = skip_separators(remainder_curr, remainder_start);
4338 if (remainder_curr < remainder_start)
4341 char the_char = *remainder_curr;
4343 if (asciihex_to_num(the_char) < 0) {
4344 status = PEP_ILLEGAL_VALUE;
4348 *result_curr = the_char;
4356 if (result_curr > XORed_fpr) {
4357 char* tempstr = strdup(result_curr);
4359 XORed_fpr = tempstr;
4362 status = check_for_zero_fpr(XORed_fpr);
4364 if (status != PEP_STATUS_OK)
4367 size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
4369 char* the_words = NULL;
4370 size_t the_size = 0;
4372 status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
4373 if (status != PEP_STATUS_OK)
4379 status = PEP_STATUS_OK;
4390 DYNAMIC_API PEP_STATUS get_message_trustwords(
4391 PEP_SESSION session,
4393 stringlist_t *keylist,
4394 pEp_identity* received_by,
4395 const char* lang, char **words, bool full
4400 assert(received_by);
4401 assert(received_by->address);
4408 received_by->address &&
4411 return PEP_ILLEGAL_VALUE;
4413 pEp_identity* partner = NULL;
4415 PEP_STATUS status = PEP_STATUS_OK;
4419 // We want fingerprint of key that did sign the message
4421 if (keylist == NULL) {
4423 // Message is to be decrypted
4424 message *dst = NULL;
4425 stringlist_t *_keylist = keylist;
4427 PEP_decrypt_flags_t flags;
4428 status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
4430 if (status != PEP_STATUS_OK) {
4432 free_stringlist(_keylist);
4436 if (dst && dst->from && _keylist) {
4437 partner = identity_dup(dst->from);
4440 partner->fpr = strdup(_keylist->value);
4441 if (partner->fpr == NULL)
4442 status = PEP_OUT_OF_MEMORY;
4444 status = PEP_OUT_OF_MEMORY;
4447 status = PEP_UNKNOWN_ERROR;
4451 free_stringlist(_keylist);
4455 // Message already decrypted
4456 if (keylist->value) {
4457 partner = identity_dup(msg->from);
4460 partner->fpr = strdup(keylist->value);
4461 if (partner->fpr == NULL)
4462 status = PEP_OUT_OF_MEMORY;
4464 status = PEP_OUT_OF_MEMORY;
4467 status = PEP_ILLEGAL_VALUE;
4471 if (status != PEP_STATUS_OK) {
4472 free_identity(partner);
4476 // Find own identity corresponding to given account address.
4477 // In that case we want default key attached to own identity
4478 pEp_identity *stored_identity = NULL;
4480 char* own_id = NULL;
4481 status = get_default_own_userid(session, &own_id);
4483 if (!(status == PEP_STATUS_OK && own_id)) {
4485 return PEP_CANNOT_FIND_IDENTITY;
4488 status = get_identity(session,
4489 received_by->address,
4495 if (status != PEP_STATUS_OK) {
4496 free_identity(stored_identity);
4500 // get the trustwords
4502 status = get_trustwords(session,
4503 partner, received_by,
4504 lang, words, &wsize, full);
4509 static PEP_rating string_to_rating(const char * rating)
4512 return PEP_rating_undefined;
4513 if (strcmp(rating, "cannot_decrypt") == 0)
4514 return PEP_rating_cannot_decrypt;
4515 if (strcmp(rating, "have_no_key") == 0)
4516 return PEP_rating_have_no_key;
4517 if (strcmp(rating, "unencrypted") == 0)
4518 return PEP_rating_unencrypted;
4519 if (strcmp(rating, "unencrypted_for_some") == 0)
4520 return PEP_rating_undefined; // don't use this any more
4521 if (strcmp(rating, "unreliable") == 0)
4522 return PEP_rating_unreliable;
4523 if (strcmp(rating, "reliable") == 0)
4524 return PEP_rating_reliable;
4525 if (strcmp(rating, "trusted") == 0)
4526 return PEP_rating_trusted;
4527 if (strcmp(rating, "trusted_and_anonymized") == 0)
4528 return PEP_rating_trusted_and_anonymized;
4529 if (strcmp(rating, "fully_anonymous") == 0)
4530 return PEP_rating_fully_anonymous;
4531 if (strcmp(rating, "mistrust") == 0)
4532 return PEP_rating_mistrust;
4533 if (strcmp(rating, "b0rken") == 0)
4534 return PEP_rating_b0rken;
4535 if (strcmp(rating, "under_attack") == 0)
4536 return PEP_rating_under_attack;
4537 return PEP_rating_undefined;
4540 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
4542 if (skeylist == NULL || keylist == NULL)
4543 return PEP_ILLEGAL_VALUE;
4545 stringlist_t *rkeylist = NULL;
4546 stringlist_t *_kcurr = NULL;
4547 const char * fpr_begin = skeylist;
4548 const char * fpr_end = NULL;
4551 fpr_end = strstr(fpr_begin, ",");
4553 char * fpr = strndup(
4555 (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
4560 _kcurr = stringlist_add(_kcurr, fpr);
4561 if (_kcurr == NULL) {
4566 if (rkeylist == NULL)
4569 fpr_begin = fpr_end ? fpr_end + 1 : NULL;
4571 } while (fpr_begin);
4573 *keylist = rkeylist;
4574 return PEP_STATUS_OK;
4577 free_stringlist(rkeylist);
4578 return PEP_OUT_OF_MEMORY;
4581 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
4582 PEP_SESSION session,
4584 stringlist_t *x_keylist,
4585 PEP_rating x_enc_status,
4589 PEP_STATUS status = PEP_STATUS_OK;
4590 stringlist_t *_keylist = x_keylist;
4591 bool must_free_keylist = false;
4598 if (!(session && msg && rating))
4599 return PEP_ILLEGAL_VALUE;
4601 *rating = PEP_rating_undefined;
4603 if (x_enc_status == PEP_rating_undefined){
4604 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
4605 if (strcasecmp(i->value->key, "X-EncStatus") == 0){
4606 x_enc_status = string_to_rating(i->value->value);
4610 return PEP_ILLEGAL_VALUE;
4615 _rating = x_enc_status;
4617 if (_keylist == NULL){
4618 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
4619 if (strcasecmp(i->value->key, "X-KeyList") == 0){
4620 status = string_to_keylist(i->value->value, &_keylist);
4621 if (status != PEP_STATUS_OK)
4623 must_free_keylist = true;
4628 // there was no rcpt fpr, it could be an unencrypted mail
4629 if(_rating == PEP_rating_unencrypted) {
4631 return PEP_STATUS_OK;
4634 return PEP_ILLEGAL_VALUE;
4638 if (!is_me(session, msg->from))
4639 status = update_identity(session, msg->from);
4641 status = _myself(session, msg->from, false, false, true);
4644 case PEP_KEY_NOT_FOUND:
4645 case PEP_KEY_UNSUITABLE:
4646 case PEP_KEY_BLACKLISTED:
4647 case PEP_CANNOT_FIND_IDENTITY:
4648 case PEP_CANNOT_FIND_ALIAS:
4649 status = PEP_STATUS_OK;
4656 status = amend_rating_according_to_sender_and_recipients(session, &_rating,
4657 msg->from, _keylist);
4658 if (status == PEP_STATUS_OK)
4662 if (must_free_keylist)
4663 free_stringlist(_keylist);
4668 DYNAMIC_API PEP_STATUS get_key_rating_for_user(
4669 PEP_SESSION session,
4670 const char *user_id,
4675 assert(session && user_id && user_id[0] && fpr && fpr[0] && rating);
4676 if (!(session && user_id && user_id[0] && fpr && fpr[0] && rating))
4677 return PEP_ILLEGAL_VALUE;
4679 *rating = PEP_rating_undefined;
4681 pEp_identity *ident = new_identity(NULL, fpr, user_id, NULL);
4683 return PEP_OUT_OF_MEMORY;
4685 PEP_STATUS status = get_trust(session, ident);
4689 if (!ident->comm_type) {
4690 status = PEP_RECORD_NOT_FOUND;
4694 *rating = _rating(ident->comm_type);
4697 free_identity(ident);