...
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_src_and_inner_messages(message* src,
3129 message* inner_message) {
3131 PEP_STATUS status = PEP_STATUS_OK;
3133 if (strcasecmp(src->from->address, inner_message->from->address) == 0)
3134 status = reconcile_identity(src->from, inner_message->from);
3136 if (status == PEP_STATUS_OK && inner_message->to)
3137 status = reconcile_identity_lists(src->to, inner_message->to);
3139 if (status == PEP_STATUS_OK && inner_message->cc)
3140 status = reconcile_identity_lists(src->cc, inner_message->cc);
3142 if (status == PEP_STATUS_OK && inner_message->bcc)
3143 status = reconcile_identity_lists(src->bcc, inner_message->bcc);
3146 // FIXME - are there any flags or anything else we need to be sure are carried?
3149 static bool is_trusted_own_priv_fpr(PEP_SESSION session,
3154 bool retval = false;
3155 if (!EMPTYSTR(fpr)) {
3156 pEp_identity* test_identity = new_identity(NULL, fpr, own_id, NULL);
3157 if (test_identity) {
3158 PEP_STATUS status = get_trust(session, test_identity);
3159 if (status == PEP_STATUS_OK) {
3160 if (test_identity->comm_type & PEP_ct_confirmed) {
3161 bool has_priv = false;
3162 status = contains_priv_key(session, fpr, &has_priv);
3163 if (status == PEP_STATUS_OK && has_priv)
3167 free(test_identity);
3173 static bool reject_fpr(PEP_SESSION session, const char* fpr) {
3176 PEP_STATUS status = key_revoked(session, fpr, &reject);
3179 status = key_expired(session, fpr, time(NULL), &reject);
3181 timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
3182 status = renew_key(session, fpr, ts);
3184 if (status == PEP_STATUS_OK)
3191 static char* seek_good_trusted_private_fpr(PEP_SESSION session, char* own_id,
3192 stringlist_t* keylist) {
3193 if (!own_id || !keylist)
3196 stringlist_t* kl_curr = keylist;
3198 char* fpr = kl_curr->value;
3200 if (is_trusted_own_priv_fpr(session, own_id, fpr)) {
3201 if (!reject_fpr(session, fpr))
3205 kl_curr = kl_curr->next;
3208 char* target_own_fpr = NULL;
3211 PEP_STATUS status = get_user_default_key(session, own_id,
3214 if (status == PEP_STATUS_OK && !EMPTYSTR(target_own_fpr)) {
3215 if (is_trusted_own_priv_fpr(session, own_id, target_own_fpr)) {
3216 if (!reject_fpr(session, target_own_fpr))
3217 return target_own_fpr;
3221 // TODO: We can also go through all of the other available fprs for the
3222 // own identity, but then I submit this function requires a little refactoring
3227 static bool import_header_keys(PEP_SESSION session, message* src) {
3228 stringpair_list_t* header_keys = stringpair_list_find(src->opt_fields, "Autocrypt");
3229 if (!header_keys || !header_keys->value)
3231 const char* value = header_keys->value->value;
3234 const char* start_key = strstr(value, "keydata=");
3237 start_key += 8; // length of "keydata="
3238 int length = strlen(start_key);
3239 bloblist_t* the_key = base64_str_to_binary_blob(start_key, length);
3242 PEP_STATUS status = import_key(session, the_key->value, the_key->size, NULL);
3243 free_bloblist(the_key);
3244 if (status == PEP_STATUS_OK || status == PEP_KEY_IMPORTED)
3249 PEP_STATUS check_for_own_revoked_key(
3250 PEP_SESSION session,
3251 stringlist_t* keylist,
3252 stringpair_list_t** revoked_fpr_pairs
3255 if (!session || !revoked_fpr_pairs)
3256 return PEP_ILLEGAL_VALUE;
3258 *revoked_fpr_pairs = NULL;
3260 PEP_STATUS status = PEP_STATUS_OK;
3261 stringpair_list_t* _the_list = new_stringpair_list(NULL);
3263 stringlist_t* _k = keylist;
3264 for ( ; _k; _k = _k->next) {
3266 if (EMPTYSTR(_k->value))
3267 continue; // Maybe the right thing to do is choke.
3268 // But we can have NULL-valued empty list heads.
3270 const char* recip_fpr = _k->value;
3271 char* replace_fpr = NULL;
3272 uint64_t revoke_date = 0;
3273 status = get_replacement_fpr(session,
3278 bool own_key = false;
3281 case PEP_CANNOT_FIND_IDENTITY:
3282 status = PEP_STATUS_OK;
3286 status = is_own_key(session, recip_fpr, &own_key);
3288 if (status != PEP_STATUS_OK) {
3294 stringpair_list_add(_the_list, new_stringpair(recip_fpr, replace_fpr));
3304 if (_the_list && _the_list->value) {
3305 *revoked_fpr_pairs = _the_list;
3310 free_stringpair_list(_the_list);
3315 static PEP_STATUS _decrypt_message(
3316 PEP_SESSION session,
3319 stringlist_t **keylist,
3321 PEP_decrypt_flags_t *flags,
3322 identity_list **private_il
3332 if (!(session && src && dst && keylist && rating && flags))
3333 return PEP_ILLEGAL_VALUE;
3335 /*** Begin init ***/
3336 PEP_STATUS status = PEP_STATUS_OK;
3337 PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
3338 PEP_STATUS _decrypt_in_pieces_status = PEP_CANNOT_DECRYPT_UNKNOWN;
3339 message* msg = NULL;
3340 message* calculated_src = src;
3341 message* reset_msg = NULL;
3347 stringlist_t *_keylist = NULL;
3348 char* signer_fpr = NULL;
3349 bool is_pEp_msg = is_a_pEpmessage(src);
3350 bool myself_read_only = (src->dir == PEP_dir_incoming);
3353 bool reencrypt = (((*flags & PEP_decrypt_flag_untrusted_server) > 0) && *keylist && !EMPTYSTR((*keylist)->value));
3355 // We own this pointer, and we take control of *keylist if reencrypting.
3356 stringlist_t* extra = NULL;
3365 *rating = PEP_rating_undefined;
3370 // Ok, before we do anything, if it's a pEp message, regardless of whether it's
3371 // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
3373 if (src->from && !(is_me(session, src->from))) {
3375 pEp_identity* tmp_from = src->from;
3377 // Ensure there's a user id
3378 if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
3379 status = update_identity(session, tmp_from);
3380 if (status == PEP_CANNOT_FIND_IDENTITY) {
3381 tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
3382 if (!tmp_from->user_id)
3383 return PEP_OUT_OF_MEMORY;
3384 snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
3385 "TOFU_%s", tmp_from->address);
3386 status = PEP_STATUS_OK;
3389 if (status == PEP_STATUS_OK) {
3390 // Now set user as PEP (may also create an identity if none existed yet)
3391 status = set_as_pEp_user(session, tmp_from);
3395 // We really need key used in signing to do anything further on the pEp comm_type.
3396 // So we can't adjust the rating of the sender just yet.
3398 /*** Begin Import any attached public keys and update identities accordingly ***/
3399 // Private key in unencrypted mail are ignored -> NULL
3401 // This import is from the outermost message.
3402 // We don't do this for PGP_mime.
3403 bool imported_keys = false;
3404 if (!_has_PGP_MIME_format(src))
3405 imported_keys = import_attached_keys(session, src, NULL);
3407 import_header_keys(session, src);
3409 // FIXME: is this really necessary here?
3411 if (!is_me(session, src->from))
3412 status = update_identity(session, src->from);
3414 status = _myself(session, src->from, false, false, myself_read_only);
3416 // We absolutely should NOT be bailing here unless it's a serious error
3417 if (status == PEP_OUT_OF_MEMORY)
3421 /*** End Import any attached public keys and update identities accordingly ***/
3423 /*** Begin get detached signatures that are attached to the encrypted message ***/
3424 // Get detached signature, if any
3425 bloblist_t* detached_sig = NULL;
3426 char* dsig_text = NULL;
3427 size_t dsig_size = 0;
3428 status = _get_detached_signature(src, &detached_sig);
3430 dsig_text = detached_sig->value;
3431 dsig_size = detached_sig->size;
3433 /*** End get detached signatures that are attached to the encrypted message ***/
3435 /*** Determine encryption format ***/
3436 PEP_cryptotech crypto = determine_encryption_format(src);
3438 // Check for and deal with unencrypted messages
3439 if (src->enc_format == PEP_enc_none) {
3441 *rating = PEP_rating_unencrypted;
3443 // We remove these from the outermost source message
3444 // if (imported_keys)
3445 // remove_attached_keys(src);
3447 pull_up_attached_main_msg(src);
3449 return PEP_UNENCRYPTED;
3452 status = get_crypto_text(src, &ctext, &csize);
3453 if (status != PEP_STATUS_OK)
3456 /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
3457 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
3458 csize, dsig_text, dsig_size,
3459 &ptext, &psize, &_keylist,
3462 if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
3465 decrypt_status = status;
3467 bool imported_private_key_address = false;
3470 /* we got a plaintext from decryption */
3471 switch (src->enc_format) {
3473 case PEP_enc_PGP_MIME:
3474 case PEP_enc_PGP_MIME_Outlook1:
3476 status = mime_decode_message(ptext, psize, &msg);
3477 if (status != PEP_STATUS_OK)
3480 /* Ensure messages whose maintext is in the attachments
3481 move main text into message struct longmsg et al */
3482 /* KG: This IS a src modification of old - we're adding to it
3483 w/ memhole subject, but the question is whether or not
3484 this is OK overall... */
3485 pull_up_attached_main_msg(msg);
3486 if (msg->shortmsg) {
3487 free(src->shortmsg);
3488 src->shortmsg = strdup(msg->shortmsg);
3491 // check for private key in decrypted message attachment while importing
3492 // N.B. Apparently, we always import private keys into the keyring; however,
3493 // we do NOT always allow those to be used for encryption. THAT is controlled
3494 // by setting it as an own identity associated with the key in the DB.
3496 // We are importing from the decrypted outermost message now.
3498 status = import_priv_keys_from_decrypted_msg(session, msg,
3500 &imported_private_key_address,
3502 if (status != PEP_STATUS_OK)
3505 /* if decrypted, but not verified... */
3506 if (decrypt_status == PEP_DECRYPTED) {
3509 status = verify_decrypted(session,
3518 case PEP_enc_inline:
3519 status = PEP_STATUS_OK;
3521 _decrypt_in_pieces_status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
3523 switch (_decrypt_in_pieces_status) {
3525 case PEP_DECRYPTED_AND_VERIFIED:
3526 if (decrypt_status <= PEP_DECRYPTED_AND_VERIFIED)
3527 decrypt_status = MIN(decrypt_status, _decrypt_in_pieces_status);
3531 case PEP_OUT_OF_MEMORY:
3534 decrypt_status = _decrypt_in_pieces_status;
3539 // BUG: must implement more
3543 if (status == PEP_OUT_OF_MEMORY)
3546 if (status != PEP_STATUS_OK)
3549 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3550 char* wrap_info = NULL;
3552 status = unencapsulate_hidden_fields(src, msg, &wrap_info);
3554 // bool is_transport_wrapper = false;
3556 // FIXME: replace with enums, check status
3558 if (strcmp(wrap_info, "OUTER") == 0) {
3559 // this only occurs in with a direct outer wrapper
3560 // where the actual content is in the inner wrapper
3561 message* inner_message = NULL;
3562 bloblist_t* actual_message = msg->attachments;
3564 while (actual_message) {
3565 char* mime_type = actual_message->mime_type;
3568 // libetpan appears to change the mime_type on this one.
3570 if (strcmp("message/rfc822", mime_type) == 0 ||
3571 strcmp("text/rfc822", mime_type) == 0) {
3573 status = mime_decode_message(actual_message->value,
3574 actual_message->size,
3576 if (status != PEP_STATUS_OK)
3579 if (inner_message) {
3580 // Though this will strip any message info on the
3581 // attachment, this is safe, as we do not
3582 // produce more than one attachment-as-message,
3583 // and those are the only ones with such info.
3584 // Since we capture the information, this is ok.
3586 inner_message->enc_format = src->enc_format;
3588 status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);
3591 if (status != PEP_STATUS_OK) {
3592 free_message(inner_message);
3597 bool is_inner = (strcmp(wrap_info, "INNER") == 0);
3598 bool is_key_reset = (strcmp(wrap_info, "KEY_RESET") == 0);
3601 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3602 status = receive_key_reset(session,
3604 if (status != PEP_STATUS_OK) {
3605 free_message(inner_message);
3608 *flags |= PEP_decrypt_flag_consume;
3611 else if (is_inner) {
3613 // check for private key in decrypted message attachment while importing
3614 // N.B. Apparently, we always import private keys into the keyring; however,
3615 // we do NOT always allow those to be used for encryption. THAT is controlled
3616 // by setting it as an own identity associated with the key in the DB.
3618 // If we have a message 2.0 message, we are ONLY going to be ok with keys
3619 // we imported from THIS part of the message.
3620 imported_private_key_address = false;
3624 // import keys from decrypted INNER source
3625 status = import_priv_keys_from_decrypted_msg(session, inner_message,
3627 &imported_private_key_address,
3629 if (status != PEP_STATUS_OK)
3632 // THIS is our message
3633 // Now, let's make sure we've copied in
3634 // any information sent in by the app if
3636 reconcile_src_and_inner_messages(src, inner_message);
3639 // FIXME: free msg, but check references
3640 //src = msg = inner_message;
3641 calculated_src = msg = inner_message;
3643 // FIXME: should this be msg???
3645 if (!is_me(session, src->from))
3646 update_identity(session, (src->from));
3648 _myself(session, src->from, false, false, myself_read_only);
3652 else { // should never happen
3653 status = PEP_UNKNOWN_ERROR;
3654 free_message(inner_message);
3658 inner_message->enc_format = PEP_enc_none;
3660 else { // forwarded message, leave it alone
3661 free_message(inner_message);
3665 actual_message = actual_message->next;
3668 else if (strcmp(wrap_info, "TRANSPORT") == 0) {
3669 // FIXME: this gets even messier.
3670 // (TBI in ENGINE-278)
3672 else {} // shouldn't be anything to be done here
3676 *rating = decrypt_rating(decrypt_status);
3678 // Ok, so if it was signed and it's all verified, we can update
3679 // eligible signer comm_types to PEP_ct_pEp_*
3680 if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg && calculated_src->from)
3681 status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist);
3683 /* Ok, now we have a keylist used for decryption/verification.
3684 now we need to update the message rating with the
3685 sender and recipients in mind */
3686 status = amend_rating_according_to_sender_and_recipients(session,
3687 rating, calculated_src->from, _keylist);
3689 if (status != PEP_STATUS_OK)
3692 /* We decrypted ok, hallelujah. */
3693 msg->enc_format = PEP_enc_none;
3696 // We did not get a plaintext out of the decryption process.
3697 // Abort and return error.
3698 *rating = decrypt_rating(decrypt_status);
3703 Ok, at this point, we know we have a reliably decrypted message.
3704 Prepare the output message for return.
3707 // 1. Check to see if this message is to us and contains an own key imported
3708 // from own trusted message
3709 if (*rating >= PEP_rating_trusted && imported_private_key_address) {
3711 if (msg && msg->to && msg->to->ident) {
3712 // This will only happen rarely, so we can do this.
3713 PEP_STATUS _tmp_status = PEP_STATUS_OK;
3715 if (!is_me(session, msg->to->ident))
3716 _tmp_status = update_identity(session, msg->to->ident);
3718 if (_tmp_status == PEP_STATUS_OK && is_me(session, msg->to->ident)) {
3720 *flags |= PEP_decrypt_flag_own_private_key;
3725 // 2. Clean up message and prepare for return
3728 /* add pEp-related status flags to header */
3729 decorate_message(msg, *rating, _keylist, false, false);
3731 // Maybe unnecessary
3732 // if (imported_keys)
3733 // remove_attached_keys(msg);
3735 if (calculated_src->id && calculated_src != msg) {
3736 msg->id = strdup(calculated_src->id);
3738 if (msg->id == NULL)
3741 } // End prepare output message for return
3743 // 3. Check to see if the sender used any of our revoked keys
3744 stringpair_list_t* revoke_replace_pairs = NULL;
3745 status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
3747 //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN
3748 if (status != PEP_STATUS_OK) {
3749 // This should really never choke unless the DB is broken.
3750 status = PEP_UNKNOWN_DB_ERROR;
3755 stringpair_list_t* curr_pair_node;
3756 stringpair_t* curr_pair;
3758 for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
3759 curr_pair = curr_pair_node->value;
3762 continue; // Again, shouldn't occur
3764 if (curr_pair->key && curr_pair->value) {
3765 status = create_standalone_key_reset_message(session,
3771 // If we can't find the identity, this is someone we've never mailed, so we just
3772 // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
3773 if (status != PEP_CANNOT_FIND_IDENTITY) {
3774 if (status != PEP_STATUS_OK)
3778 status = PEP_OUT_OF_MEMORY;
3781 // insert into queue
3782 if (session->messageToSend)
3783 status = session->messageToSend(reset_msg);
3785 status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
3788 if (status == PEP_STATUS_OK) {
3789 // Put into notified DB
3790 status = set_reset_contact_notified(session, curr_pair->key, msg->from->user_id);
3791 if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
3795 // According to Volker, this would only be a fatal error, so...
3796 free_message(reset_msg); // ??
3797 reset_msg = NULL; // ??
3805 // 4. Set up return values
3807 *keylist = _keylist;
3809 // 5. Reencrypt if necessary
3811 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3812 message* reencrypt_msg = NULL;
3813 PEP_STATUS reencrypt_status = PEP_CANNOT_REENCRYPT;
3814 char* own_id = NULL;
3815 status = get_default_own_userid(session, &own_id);
3817 char* target_own_fpr = seek_good_trusted_private_fpr(session,
3820 if (target_own_fpr) {
3821 pEp_identity* target_id = new_identity(NULL, target_own_fpr,
3824 reencrypt_status = encrypt_message_for_self(session, target_id, msg,
3825 extra, &reencrypt_msg, PEP_enc_PGP_MIME,
3827 if (reencrypt_status != PEP_STATUS_OK)
3828 reencrypt_status = PEP_CANNOT_REENCRYPT;
3830 free_identity(target_id);
3832 free(target_own_fpr);
3836 free_stringlist(extra); // This was an input variable for us. Keylist is overwritten above.
3838 if (reencrypt_status != PEP_CANNOT_REENCRYPT && reencrypt_msg) {
3839 message_transfer(src, reencrypt_msg);
3840 *flags |= PEP_decrypt_flag_src_modified;
3841 free_message(reencrypt_msg);
3844 decrypt_status = PEP_CANNOT_REENCRYPT;
3848 if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
3849 return PEP_STATUS_OK;
3851 return decrypt_status;
3854 status = PEP_OUT_OF_MEMORY;
3860 free_message(reset_msg);
3861 free_stringlist(_keylist);
3866 DYNAMIC_API PEP_STATUS decrypt_message(
3867 PEP_SESSION session,
3870 stringlist_t **keylist,
3872 PEP_decrypt_flags_t *flags
3882 if (!(session && src && dst && keylist && rating && flags))
3883 return PEP_ILLEGAL_VALUE;
3885 if (!(*flags & PEP_decrypt_flag_untrusted_server))
3887 //*keylist = NULL; // NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!!!! This fucks up reencryption
3888 PEP_STATUS status = _decrypt_message(session, src, dst, keylist, rating, flags, NULL);
3890 message *msg = *dst ? *dst : src;
3892 if (session->inject_sync_event && msg && msg->from &&
3893 !(*flags & PEP_decrypt_flag_dont_trigger_sync)) {
3896 char *sync_fpr = NULL;
3897 PEP_STATUS tmpstatus = base_extract_message(session, msg, &size, &data, &sync_fpr);
3898 if (!tmpstatus && size && data) {
3900 signal_Sync_message(session, *rating, data, size, msg->from, sync_fpr);
3902 signal_Sync_message(session, *rating, data, size, msg->from, (*keylist)->value);
3910 DYNAMIC_API PEP_STATUS own_message_private_key_details(
3911 PEP_SESSION session,
3913 pEp_identity **ident
3920 if (!(session && msg && ident))
3921 return PEP_ILLEGAL_VALUE;
3923 message *dst = NULL;
3924 stringlist_t *keylist = NULL;
3926 PEP_decrypt_flags_t flags;
3930 identity_list *private_il = NULL;
3931 PEP_STATUS status = _decrypt_message(session, msg, &dst, &keylist, &rating, &flags, &private_il);
3933 free_stringlist(keylist);
3935 if (status == PEP_STATUS_OK &&
3936 flags & PEP_decrypt_flag_own_private_key &&
3939 *ident = identity_dup(private_il->ident);
3942 free_identity_list(private_il);
3947 // Note: if comm_type_determine is false, it generally means that
3948 // we were unable to get key information for anyone in the list,
3949 // likely because a key is missing.
3950 static void _max_comm_type_from_identity_list(
3951 identity_list *identities,
3952 PEP_SESSION session,
3953 PEP_comm_type *max_comm_type,
3954 bool *comm_type_determined
3958 for (il = identities; il != NULL; il = il->next)
3962 PEP_STATUS status = PEP_STATUS_OK;
3963 *max_comm_type = _get_comm_type(session, *max_comm_type,
3965 *comm_type_determined = true;
3967 bool is_blacklisted = false;
3968 if (il->ident->fpr && IS_PGP_CT(il->ident->comm_type)) {
3969 status = blacklist_is_listed(session, il->ident->fpr, &is_blacklisted);
3970 if (is_blacklisted) {
3971 bool user_default, ident_default, address_default;
3972 status = get_valid_pubkey(session, il->ident,
3973 &ident_default, &user_default,
3976 if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
3977 il->ident->comm_type = PEP_ct_key_not_found;
3978 if (*max_comm_type > PEP_ct_no_encryption)
3979 *max_comm_type = PEP_ct_no_encryption;
3984 // check for the return statuses which might not a representative
3985 // value in the comm_type
3986 if (status == PEP_ILLEGAL_VALUE || status == PEP_CANNOT_SET_PERSON ||
3987 status == PEP_CANNOT_FIND_IDENTITY) {
3988 // PEP_CANNOT_FIND_IDENTITY only comes back when we've really
3989 // got nothing from update_identity after applying the whole
3991 *max_comm_type = PEP_ct_no_encryption;
3992 *comm_type_determined = true;
3998 static void _max_comm_type_from_identity_list_preview(
3999 identity_list *identities,
4000 PEP_SESSION session,
4001 PEP_comm_type *max_comm_type
4005 for (il = identities; il != NULL; il = il->next)
4009 *max_comm_type = _get_comm_type_preview(session, *max_comm_type,
4015 DYNAMIC_API PEP_STATUS outgoing_message_rating(
4016 PEP_SESSION session,
4021 PEP_comm_type max_comm_type = PEP_ct_pEp;
4022 bool comm_type_determined = false;
4026 assert(msg->dir == PEP_dir_outgoing);
4029 if (!(session && msg && rating))
4030 return PEP_ILLEGAL_VALUE;
4032 if (msg->dir != PEP_dir_outgoing)
4033 return PEP_ILLEGAL_VALUE;
4035 *rating = PEP_rating_undefined;
4037 _max_comm_type_from_identity_list(msg->to, session,
4038 &max_comm_type, &comm_type_determined);
4040 _max_comm_type_from_identity_list(msg->cc, session,
4041 &max_comm_type, &comm_type_determined);
4043 _max_comm_type_from_identity_list(msg->bcc, session,
4044 &max_comm_type, &comm_type_determined);
4046 if (comm_type_determined == false) {
4047 // likely means there was a massive screwup with no sender or recipient
4049 *rating = PEP_rating_undefined;
4052 *rating = MAX(_rating(max_comm_type), PEP_rating_unencrypted);
4054 return PEP_STATUS_OK;
4057 DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
4058 PEP_SESSION session,
4063 PEP_comm_type max_comm_type = PEP_ct_pEp;
4067 assert(msg->dir == PEP_dir_outgoing);
4070 if (!(session && msg && rating))
4071 return PEP_ILLEGAL_VALUE;
4073 if (msg->dir != PEP_dir_outgoing)
4074 return PEP_ILLEGAL_VALUE;
4076 *rating = PEP_rating_undefined;
4078 _max_comm_type_from_identity_list_preview(msg->to, session,
4081 _max_comm_type_from_identity_list_preview(msg->cc, session,
4084 _max_comm_type_from_identity_list_preview(msg->bcc, session,
4087 *rating = _MAX(_rating(max_comm_type), PEP_rating_unencrypted);
4089 return PEP_STATUS_OK;
4092 DYNAMIC_API PEP_STATUS identity_rating(
4093 PEP_SESSION session,
4094 pEp_identity *ident,
4098 PEP_STATUS status = PEP_STATUS_OK;
4104 if (!(session && ident && rating))
4105 return PEP_ILLEGAL_VALUE;
4107 *rating = PEP_rating_undefined;
4110 status = _myself(session, ident, false, true, true);
4112 status = update_identity(session, ident);
4114 bool is_blacklisted = false;
4116 if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
4117 status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
4118 if (status != PEP_STATUS_OK) {
4119 return status; // DB ERROR
4121 if (is_blacklisted) {
4122 bool user_default, ident_default, address_default;
4123 status = get_valid_pubkey(session, ident,
4124 &ident_default, &user_default,
4127 if (status != PEP_STATUS_OK || ident->fpr == NULL) {
4128 ident->comm_type = PEP_ct_key_not_found;
4129 status = PEP_STATUS_OK;
4134 if (status == PEP_STATUS_OK)
4135 *rating = _rating(ident->comm_type);
4140 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
4142 PEP_STATUS status = PEP_STATUS_OK;
4146 return PEP_ILLEGAL_VALUE;
4148 if (cryptotech[tech].binary_path == NULL)
4151 status = cryptotech[tech].binary_path(path);
4157 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
4159 if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
4160 return PEP_color_no_color;
4162 if (rating < PEP_rating_undefined)
4163 return PEP_color_red;
4165 if (rating < PEP_rating_reliable)
4166 return PEP_color_no_color;
4168 if (rating < PEP_rating_trusted)
4169 return PEP_color_yellow;
4171 if (rating >= PEP_rating_trusted)
4172 return PEP_color_green;
4174 // this should never happen
4176 return PEP_color_no_color;
4179 /* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
4180 static short asciihex_to_num(char a) {
4181 short conv_num = -1;
4182 if (a >= 0x30 && a <= 0x39)
4183 conv_num = a - 0x30;
4185 // convert case, subtract offset, get number
4186 conv_num = ((a | 0x20) - 0x61) + 10;
4187 if (conv_num < 0xa || conv_num > 0xf)
4193 static char num_to_asciihex(short h) {
4194 if (h < 0 || h > 16)
4197 return (char)(h + 0x30);
4198 return (char)((h - 10) + 0x41); // for readability
4201 static char xor_hex_chars(char a, char b) {
4202 short a_num = asciihex_to_num(a);
4203 short b_num = asciihex_to_num(b);
4204 if (a_num < 0 || b_num < 0)
4206 short xor_num = a_num^b_num;
4207 return num_to_asciihex(xor_num);
4210 static char* skip_separators(char* current, char* begin) {
4211 while (current >= begin) {
4212 /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
4213 char check_char = *current;
4214 switch (check_char) {
4232 PEP_STATUS check_for_zero_fpr(char* fpr) {
4233 PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
4237 status = PEP_STATUS_OK;
4247 DYNAMIC_API PEP_STATUS get_trustwords(
4248 PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
4249 const char* lang, char **words, size_t *wsize, bool full
4260 int SHORT_NUM_TWORDS = 5;
4262 PEP_STATUS status = PEP_STATUS_OK;
4264 if (!(session && id1 && id2 && words && wsize) ||
4265 !(id1->fpr) || (!id2->fpr))
4266 return PEP_ILLEGAL_VALUE;
4268 char *source1 = id1->fpr;
4269 char *source2 = id2->fpr;
4271 int source1_len = strlen(source1);
4272 int source2_len = strlen(source2);
4278 max_len = (source1_len > source2_len ? source1_len : source2_len);
4280 char* XORed_fpr = (char*)(calloc(max_len + 1, 1));
4281 *(XORed_fpr + max_len) = '\0';
4282 char* result_curr = XORed_fpr + max_len - 1;
4283 char* source1_curr = source1 + source1_len - 1;
4284 char* source2_curr = source2 + source2_len - 1;
4286 while (source1 <= source1_curr && source2 <= source2_curr) {
4287 source1_curr = skip_separators(source1_curr, source1);
4288 source2_curr = skip_separators(source2_curr, source2);
4290 if (source1_curr < source1 || source2_curr < source2)
4293 char xor_hex = xor_hex_chars(*source1_curr, *source2_curr);
4294 if (xor_hex == '\0') {
4295 status = PEP_ILLEGAL_VALUE;
4299 *result_curr = xor_hex;
4300 result_curr--; source1_curr--; source2_curr--;
4303 char* remainder_start = NULL;
4304 char* remainder_curr = NULL;
4306 if (source1 <= source1_curr) {
4307 remainder_start = source1;
4308 remainder_curr = source1_curr;
4310 else if (source2 <= source2_curr) {
4311 remainder_start = source2;
4312 remainder_curr = source2_curr;
4314 if (remainder_curr) {
4315 while (remainder_start <= remainder_curr) {
4316 remainder_curr = skip_separators(remainder_curr, remainder_start);
4318 if (remainder_curr < remainder_start)
4321 char the_char = *remainder_curr;
4323 if (asciihex_to_num(the_char) < 0) {
4324 status = PEP_ILLEGAL_VALUE;
4328 *result_curr = the_char;
4336 if (result_curr > XORed_fpr) {
4337 char* tempstr = strdup(result_curr);
4339 XORed_fpr = tempstr;
4342 status = check_for_zero_fpr(XORed_fpr);
4344 if (status != PEP_STATUS_OK)
4347 size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
4349 char* the_words = NULL;
4350 size_t the_size = 0;
4352 status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
4353 if (status != PEP_STATUS_OK)
4359 status = PEP_STATUS_OK;
4370 DYNAMIC_API PEP_STATUS get_message_trustwords(
4371 PEP_SESSION session,
4373 stringlist_t *keylist,
4374 pEp_identity* received_by,
4375 const char* lang, char **words, bool full
4380 assert(received_by);
4381 assert(received_by->address);
4388 received_by->address &&
4391 return PEP_ILLEGAL_VALUE;
4393 pEp_identity* partner = NULL;
4395 PEP_STATUS status = PEP_STATUS_OK;
4399 // We want fingerprint of key that did sign the message
4401 if (keylist == NULL) {
4403 // Message is to be decrypted
4404 message *dst = NULL;
4405 stringlist_t *_keylist = keylist;
4407 PEP_decrypt_flags_t flags;
4408 status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
4410 if (status != PEP_STATUS_OK) {
4412 free_stringlist(_keylist);
4416 if (dst && dst->from && _keylist) {
4417 partner = identity_dup(dst->from);
4420 partner->fpr = strdup(_keylist->value);
4421 if (partner->fpr == NULL)
4422 status = PEP_OUT_OF_MEMORY;
4424 status = PEP_OUT_OF_MEMORY;
4427 status = PEP_UNKNOWN_ERROR;
4431 free_stringlist(_keylist);
4435 // Message already decrypted
4436 if (keylist->value) {
4437 partner = identity_dup(msg->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_ILLEGAL_VALUE;
4451 if (status != PEP_STATUS_OK) {
4452 free_identity(partner);
4456 // Find own identity corresponding to given account address.
4457 // In that case we want default key attached to own identity
4458 pEp_identity *stored_identity = NULL;
4460 char* own_id = NULL;
4461 status = get_default_own_userid(session, &own_id);
4463 if (!(status == PEP_STATUS_OK && own_id)) {
4465 return PEP_CANNOT_FIND_IDENTITY;
4468 status = get_identity(session,
4469 received_by->address,
4475 if (status != PEP_STATUS_OK) {
4476 free_identity(stored_identity);
4480 // get the trustwords
4482 status = get_trustwords(session,
4483 partner, received_by,
4484 lang, words, &wsize, full);
4489 static PEP_rating string_to_rating(const char * rating)
4492 return PEP_rating_undefined;
4493 if (strcmp(rating, "cannot_decrypt") == 0)
4494 return PEP_rating_cannot_decrypt;
4495 if (strcmp(rating, "have_no_key") == 0)
4496 return PEP_rating_have_no_key;
4497 if (strcmp(rating, "unencrypted") == 0)
4498 return PEP_rating_unencrypted;
4499 if (strcmp(rating, "unencrypted_for_some") == 0)
4500 return PEP_rating_undefined; // don't use this any more
4501 if (strcmp(rating, "unreliable") == 0)
4502 return PEP_rating_unreliable;
4503 if (strcmp(rating, "reliable") == 0)
4504 return PEP_rating_reliable;
4505 if (strcmp(rating, "trusted") == 0)
4506 return PEP_rating_trusted;
4507 if (strcmp(rating, "trusted_and_anonymized") == 0)
4508 return PEP_rating_trusted_and_anonymized;
4509 if (strcmp(rating, "fully_anonymous") == 0)
4510 return PEP_rating_fully_anonymous;
4511 if (strcmp(rating, "mistrust") == 0)
4512 return PEP_rating_mistrust;
4513 if (strcmp(rating, "b0rken") == 0)
4514 return PEP_rating_b0rken;
4515 if (strcmp(rating, "under_attack") == 0)
4516 return PEP_rating_under_attack;
4517 return PEP_rating_undefined;
4520 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
4522 if (skeylist == NULL || keylist == NULL)
4523 return PEP_ILLEGAL_VALUE;
4525 stringlist_t *rkeylist = NULL;
4526 stringlist_t *_kcurr = NULL;
4527 const char * fpr_begin = skeylist;
4528 const char * fpr_end = NULL;
4531 fpr_end = strstr(fpr_begin, ",");
4533 char * fpr = strndup(
4535 (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
4540 _kcurr = stringlist_add(_kcurr, fpr);
4541 if (_kcurr == NULL) {
4546 if (rkeylist == NULL)
4549 fpr_begin = fpr_end ? fpr_end + 1 : NULL;
4551 } while (fpr_begin);
4553 *keylist = rkeylist;
4554 return PEP_STATUS_OK;
4557 free_stringlist(rkeylist);
4558 return PEP_OUT_OF_MEMORY;
4561 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
4562 PEP_SESSION session,
4564 stringlist_t *x_keylist,
4565 PEP_rating x_enc_status,
4569 PEP_STATUS status = PEP_STATUS_OK;
4570 stringlist_t *_keylist = x_keylist;
4571 bool must_free_keylist = false;
4578 if (!(session && msg && rating))
4579 return PEP_ILLEGAL_VALUE;
4581 *rating = PEP_rating_undefined;
4583 if (x_enc_status == PEP_rating_undefined){
4584 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
4585 if (strcasecmp(i->value->key, "X-EncStatus") == 0){
4586 x_enc_status = string_to_rating(i->value->value);
4590 return PEP_ILLEGAL_VALUE;
4595 _rating = x_enc_status;
4597 if (_keylist == NULL){
4598 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
4599 if (strcasecmp(i->value->key, "X-KeyList") == 0){
4600 status = string_to_keylist(i->value->value, &_keylist);
4601 if (status != PEP_STATUS_OK)
4603 must_free_keylist = true;
4608 // there was no rcpt fpr, it could be an unencrypted mail
4609 if(_rating == PEP_rating_unencrypted) {
4611 return PEP_STATUS_OK;
4614 return PEP_ILLEGAL_VALUE;
4618 if (!is_me(session, msg->from))
4619 status = update_identity(session, msg->from);
4621 status = _myself(session, msg->from, false, false, true);
4624 case PEP_KEY_NOT_FOUND:
4625 case PEP_KEY_UNSUITABLE:
4626 case PEP_KEY_BLACKLISTED:
4627 case PEP_CANNOT_FIND_IDENTITY:
4628 case PEP_CANNOT_FIND_ALIAS:
4629 status = PEP_STATUS_OK;
4636 status = amend_rating_according_to_sender_and_recipients(session, &_rating,
4637 msg->from, _keylist);
4638 if (status == PEP_STATUS_OK)
4642 if (must_free_keylist)
4643 free_stringlist(_keylist);
4648 DYNAMIC_API PEP_STATUS get_key_rating_for_user(
4649 PEP_SESSION session,
4650 const char *user_id,
4655 assert(session && user_id && user_id[0] && fpr && fpr[0] && rating);
4656 if (!(session && user_id && user_id[0] && fpr && fpr[0] && rating))
4657 return PEP_ILLEGAL_VALUE;
4659 *rating = PEP_rating_undefined;
4661 pEp_identity *ident = new_identity(NULL, fpr, user_id, NULL);
4663 return PEP_OUT_OF_MEMORY;
4665 PEP_STATUS status = get_trust(session, ident);
4669 if (!ident->comm_type) {
4670 status = PEP_RECORD_NOT_FOUND;
4674 *rating = _rating(ident->comm_type);
4677 free_identity(ident);