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 char * keylist_to_string(const stringlist_t *keylist)
39 size_t size = stringlist_length(keylist);
41 const stringlist_t *_kl;
42 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
43 size += strlen(_kl->value);
46 char *result = calloc(size, 1);
51 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
52 _r = stpcpy(_r, _kl->value);
53 if (_kl->next && _kl->next->value)
64 static const char * rating_to_string(PEP_rating rating)
67 case PEP_rating_cannot_decrypt:
68 return "cannot_decrypt";
69 case PEP_rating_have_no_key:
71 case PEP_rating_unencrypted:
73 case PEP_rating_unencrypted_for_some: // don't use this any more
75 case PEP_rating_unreliable:
77 case PEP_rating_reliable:
79 case PEP_rating_trusted:
81 case PEP_rating_trusted_and_anonymized:
82 return "trusted_and_anonymized";
83 case PEP_rating_fully_anonymous:
84 return "fully_anonymous";
85 case PEP_rating_mistrust:
87 case PEP_rating_b0rken:
89 case PEP_rating_under_attack:
90 return "under_attack";
96 bool _memnmemn(const char* needle,
101 if (needle_size > haystack_size) {
104 else if (needle_size == 0) {
109 const char* haystack_ptr = haystack;
111 size_t remaining_hay = haystack_size;
112 for (i = 0; i < haystack_size && (remaining_hay >= needle_size); i++, haystack_ptr++) {
114 const char* needle_ptr = needle;
115 if (*haystack_ptr == *needle) {
116 const char* haystack_tmp = haystack_ptr;
119 for (j = 0; j < needle_size; j++) {
120 if (*needle_ptr++ != *haystack_tmp++) {
133 void add_opt_field(message *msg, const char *name, const char *value)
135 assert(msg && name && value);
137 if (msg && name && value) {
138 stringpair_t *pair = new_stringpair(name, value);
142 stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
145 free_stringpair(pair);
149 if (msg->opt_fields == NULL)
150 msg->opt_fields = field;
154 void replace_opt_field(message *msg,
159 assert(msg && name && value);
161 if (msg && name && value) {
162 stringpair_list_t* opt_fields = msg->opt_fields;
163 stringpair_t* pair = NULL;
167 pair = opt_fields->value;
168 if (pair && (strcmp(name, pair->key) == 0))
172 opt_fields = opt_fields->next;
179 pair->value = strdup(value);
183 add_opt_field(msg, name, value);
188 void decorate_message(
191 stringlist_t *keylist,
199 replace_opt_field(msg, "X-pEp-Version", PEP_VERSION, clobber);
201 if (rating != PEP_rating_undefined)
202 replace_opt_field(msg, "X-EncStatus", rating_to_string(rating), clobber);
205 char *_keylist = keylist_to_string(keylist);
206 replace_opt_field(msg, "X-KeyList", _keylist, clobber);
211 static char* _get_resource_ptr_noown(char* uri) {
212 char* uri_delim = strstr(uri, "://");
219 static bool string_equality(const char *s1, const char *s2)
221 if (s1 == NULL || s2 == NULL)
226 return strcmp(s1, s2) == 0;
229 static bool is_mime_type(const bloblist_t *bl, const char *mt)
233 return bl && string_equality(bl->mime_type, mt);
237 // This function presumes the file ending is a proper substring of the
238 // filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
239 // return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
240 // return false. This is desired behaviour.
242 static bool is_fileending(const bloblist_t *bl, const char *fe)
246 if (bl == NULL || bl->filename == NULL || fe == NULL || is_cid_uri(bl->filename))
249 assert(bl && bl->filename);
251 size_t fe_len = strlen(fe);
252 size_t fn_len = strlen(bl->filename);
254 if (fn_len <= fe_len)
257 assert(fn_len > fe_len);
259 return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
262 char * encapsulate_message_wrap_info(const char *msg_wrap_info, const char *longmsg)
264 assert(msg_wrap_info);
266 if (!msg_wrap_info) {
270 char *result = strdup(longmsg);
279 const char * const newlines = "\n\n";
280 const size_t NL_LEN = 2;
282 const size_t bufsize = PEP_MSG_WRAP_KEY_LEN + strlen(msg_wrap_info) + NL_LEN + strlen(longmsg) + 1;
283 char * ptext = calloc(bufsize, 1);
288 strlcpy(ptext, PEP_MSG_WRAP_KEY, bufsize);
289 strlcat(ptext, msg_wrap_info, bufsize);
290 strlcat(ptext, newlines, bufsize);
291 strlcat(ptext, longmsg, bufsize);
296 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
300 unsigned char pEpstr[] = PEP_SUBJ_STRING;
301 assert(strcmp(shortmsg, "pEp") != 0 && _unsigned_signed_strcmp(pEpstr, shortmsg, PEP_SUBJ_BYTELEN) != 0);
303 if (!shortmsg || strcmp(shortmsg, "pEp") == 0 ||
304 _unsigned_signed_strcmp(pEpstr, shortmsg, PEP_SUBJ_BYTELEN) == 0) {
309 char *result = strdup(longmsg);
318 const char * const newlines = "\n\n";
319 const size_t NL_LEN = 2;
321 const size_t bufsize = PEP_SUBJ_KEY_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
322 char * ptext = calloc(bufsize, 1);
327 strlcpy(ptext, PEP_SUBJ_KEY, bufsize);
328 strlcat(ptext, shortmsg, bufsize);
329 strlcat(ptext, newlines, bufsize);
330 strlcat(ptext, longmsg, bufsize);
335 static PEP_STATUS replace_subject(message* msg) {
336 unsigned char pEpstr[] = PEP_SUBJ_STRING;
337 if (msg->shortmsg && *(msg->shortmsg) != '\0') {
338 char* longmsg = combine_short_and_long(msg->shortmsg, msg->longmsg);
340 return PEP_OUT_OF_MEMORY;
343 msg->longmsg = longmsg;
348 msg->shortmsg = strdup("pEp");
350 msg->shortmsg = strdup((char*)pEpstr);
354 return PEP_OUT_OF_MEMORY;
356 return PEP_STATUS_OK;
359 unsigned long long get_bitmask(int num_bits) {
363 unsigned long long bitmask = 0;
365 for (i = 1; i < num_bits; i++) {
366 bitmask = bitmask << 1;
372 static char* get_base_36_rep(unsigned long long value, int num_sig_bits) {
374 int bufsize = ((int) ceil((double) num_sig_bits / _pEp_log2_36)) + 1;
377 // https://en.wikipedia.org/wiki/Base36#C_implementation
378 // ok, we supposedly have a 64-bit kinda sorta random blob
379 const char base_36_symbols[37] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
381 char* retbuf = calloc(bufsize, 1);
386 int i = bufsize - 1; // (end index)
389 retbuf[--i] = base_36_symbols[value % 36];
397 static char* message_id_prand_part(void) {
399 int num_bits = _pEp_rand_max_bits;
404 const int DESIRED_BITS = 64;
406 num_bits = MIN(num_bits, DESIRED_BITS);
411 unsigned long long bitmask = get_bitmask(num_bits);
413 unsigned long long output_value = 0;
419 int randval = rand();
420 unsigned long long temp_val = randval & bitmask;
422 output_value |= temp_val;
424 i -= MIN(num_bits, i);
426 bitshift = MIN(num_bits, i);
427 output_value <<= bitshift;
428 bitmask = get_bitmask(bitshift);
431 return get_base_36_rep(output_value, DESIRED_BITS);
434 static PEP_STATUS generate_message_id(message* msg) {
436 if (!msg || !msg->from || !msg->from->address)
437 return PEP_ILLEGAL_VALUE;
439 char* time_prefix = NULL;
440 char* random_id = NULL;
443 size_t buf_len = 2; // NUL + @
445 char* from_addr = msg->from->address;
446 char* domain_ptr = strstr(from_addr, "@");
447 if (!domain_ptr || *(domain_ptr + 1) == '\0')
448 domain_ptr = "localhost";
452 buf_len += strlen(domain_ptr);
459 time_t curr_time = time(NULL);
461 time_prefix = get_base_36_rep(curr_time, (int) ceil(log2((double) curr_time)));
466 buf_len += strlen(time_prefix);
468 random_id = message_id_prand_part();
474 buf_len += strlen(random_id);
476 // make a new uuid - depending on rand() impl, time precision, etc,
477 // we may still not be unique. We'd better make sure. So.
480 uuid_generate_random(uuid);
481 uuid_unparse_upper(uuid, new_uuid);
483 buf_len += strlen(new_uuid);
485 buf_len += 6; // "pEp" and 3 '.' chars
487 retval = calloc(buf_len, 1);
492 strlcpy(retval, "pEp.", buf_len);
493 strlcat(retval, time_prefix, buf_len);
494 strlcat(retval, ".", buf_len);
495 strlcat(retval, random_id, buf_len);
496 strlcat(retval, ".", buf_len);
497 strlcat(retval, new_uuid, buf_len);
498 strlcat(retval, "@", buf_len);
499 strlcat(retval, domain_ptr, buf_len);
506 return PEP_STATUS_OK;
511 return PEP_OUT_OF_MEMORY;
515 WARNING: For the moment, this only works for the first line of decrypted
516 plaintext because we don't need more. IF WE DO, THIS MUST BE EXPANDED, or
517 we need a delineated section to parse separately
519 Does case-insensitive compare of keys, so sending in a lower-cased
520 string constant saves a bit of computation
522 static PEP_STATUS get_data_from_encapsulated_line(const char* plaintext, const char* key,
523 const size_t keylen, char** data,
524 char** modified_msg) {
526 char* _modified = NULL;
528 if (strncasecmp(plaintext, key, keylen) == 0) {
529 const char *line_end = strchr(plaintext, '\n');
531 if (line_end == NULL) {
532 _data = strdup(plaintext + keylen);
535 return PEP_OUT_OF_MEMORY;
538 size_t n = line_end - plaintext;
540 if (*(line_end - 1) == '\r')
541 _data = strndup(plaintext + keylen, n - (keylen + 1));
543 _data = strndup(plaintext + keylen, n - keylen);
546 return PEP_OUT_OF_MEMORY;
548 while (*(plaintext + n) && (*(plaintext + n) == '\n' || *(plaintext + n) == '\r'))
551 if (*(plaintext + n)) {
552 _modified = strdup(plaintext + n);
554 if (_modified == NULL)
555 return PEP_OUT_OF_MEMORY;
560 *modified_msg = _modified;
561 return PEP_STATUS_OK;
565 static int separate_short_and_long(const char *src, char **shortmsg, char** msg_wrap_info, char **longmsg)
567 char *_shortmsg = NULL;
568 char *_msg_wrap_info = NULL;
569 char *_longmsg = NULL;
573 assert(msg_wrap_info);
576 if (src == NULL || shortmsg == NULL || msg_wrap_info == NULL || longmsg == NULL)
581 *msg_wrap_info = NULL;
583 // We generated the input here. If we ever need more than one header value to be
584 // encapsulated and hidden in the encrypted text, we will have to modify this.
585 // As is, we're either doing this with a version 1.0 client, in which case
586 // the only encapsulated header value is subject, or 2.0+, in which the
587 // message wrap info is the only encapsulated header value. If we need this
588 // to be more complex, we're going to have to do something more elegant
590 PEP_STATUS status = get_data_from_encapsulated_line(src, PEP_SUBJ_KEY_LC,
592 &_shortmsg, &_longmsg);
595 if (status == PEP_STATUS_OK)
596 *shortmsg = _shortmsg;
601 status = get_data_from_encapsulated_line(src, PEP_MSG_WRAP_KEY_LC,
602 PEP_MSG_WRAP_KEY_LEN,
603 &_msg_wrap_info, &_longmsg);
604 if (_msg_wrap_info) {
605 if (status == PEP_STATUS_OK)
606 *msg_wrap_info = _msg_wrap_info;
612 // If there was no secret data hiding in the first line...
613 if (!_shortmsg && !_msg_wrap_info) {
614 _longmsg = strdup(src);
616 if (_longmsg == NULL)
626 free(_msg_wrap_info);
632 static PEP_STATUS copy_fields(message *dst, const message *src)
638 return PEP_ILLEGAL_VALUE;
640 free_timestamp(dst->sent);
643 dst->sent = timestamp_dup(src->sent);
644 if (dst->sent == NULL)
645 return PEP_OUT_OF_MEMORY;
648 free_timestamp(dst->recv);
651 dst->recv = timestamp_dup(src->recv);
652 if (dst->recv == NULL)
653 return PEP_OUT_OF_MEMORY;
656 free_identity(dst->from);
659 dst->from = identity_dup(src->from);
660 if (dst->from == NULL)
661 return PEP_OUT_OF_MEMORY;
664 free_identity_list(dst->to);
666 if (src->to && src->to->ident) {
667 dst->to = identity_list_dup(src->to);
669 return PEP_OUT_OF_MEMORY;
672 free_identity(dst->recv_by);
675 dst->recv_by = identity_dup(src->recv_by);
676 if (dst->recv_by == NULL)
677 return PEP_OUT_OF_MEMORY;
680 free_identity_list(dst->cc);
682 if (src->cc && src->cc->ident) {
683 dst->cc = identity_list_dup(src->cc);
685 return PEP_OUT_OF_MEMORY;
688 free_identity_list(dst->bcc);
690 if (src->bcc && src->bcc->ident) {
691 dst->bcc = identity_list_dup(src->bcc);
692 if (dst->bcc == NULL)
693 return PEP_OUT_OF_MEMORY;
696 free_identity_list(dst->reply_to);
697 dst->reply_to = NULL;
698 if (src->reply_to && src->reply_to->ident) {
699 dst->reply_to = identity_list_dup(src->reply_to);
700 if (dst->reply_to == NULL)
701 return PEP_OUT_OF_MEMORY;
704 free_stringlist(dst->in_reply_to);
705 dst->in_reply_to = NULL;
706 if (src->in_reply_to && src->in_reply_to->value) {
707 dst->in_reply_to = stringlist_dup(src->in_reply_to);
708 if (dst->in_reply_to == NULL)
709 return PEP_OUT_OF_MEMORY;
712 free_stringlist(dst->references);
713 dst->references = NULL;
714 if (src->references) {
715 dst->references = stringlist_dup(src->references);
716 if (dst->references == NULL)
717 return PEP_OUT_OF_MEMORY;
720 free_stringlist(dst->keywords);
721 dst->keywords = NULL;
722 if (src->keywords && src->keywords->value) {
723 dst->keywords = stringlist_dup(src->keywords);
724 if (dst->keywords == NULL)
725 return PEP_OUT_OF_MEMORY;
729 dst->comments = NULL;
731 dst->comments = strdup(src->comments);
732 assert(dst->comments);
733 if (dst->comments == NULL)
734 return PEP_OUT_OF_MEMORY;
737 free_stringpair_list(dst->opt_fields);
738 dst->opt_fields = NULL;
739 if (src->opt_fields) {
740 dst->opt_fields = stringpair_list_dup(src->opt_fields);
741 if (dst->opt_fields == NULL)
742 return PEP_OUT_OF_MEMORY;
745 return PEP_STATUS_OK;
748 // FIXME: error mem leakage
749 static message* extract_minimal_envelope(const message* src,
750 PEP_msg_direction direct) {
752 message* envelope = new_message(direct);
756 envelope->shortmsg = _pEp_subj_copy();
757 if (!envelope->shortmsg)
761 envelope->from = identity_dup(src->from);
767 envelope->to = identity_list_dup(src->to);
773 envelope->cc = identity_list_dup(src->cc);
779 envelope->bcc = identity_list_dup(src->bcc);
784 // For Outlook Force-Encryption
785 // const char* pull_keys[] = {"pEp-auto-consume",
786 // "pEp-force-protection",
787 // "X-pEp-Never-Unsecure"};
788 // int pull_keys_len = 3; // UPDATE WHEN MORE ADDED ABOVE
791 // stringpair_t* opt_add = NULL;
792 // for( ; i < pull_keys_len; i++) {
793 // opt_add = search_optfields(src, pull_keys[i]);
794 // stringpair_list_t* add_ptr = NULL;
796 // add_ptr = stringpair_list_add(src->opt_fields, stringpair_dup(opt_add));
804 envelope->enc_format = src->enc_format;
813 static message * clone_to_empty_message(const message * src)
816 message * msg = NULL;
822 msg = calloc(1, sizeof(message));
829 status = copy_fields(msg, src);
830 if (status != PEP_STATUS_OK)
840 static message* wrap_message_as_attachment(message* envelope,
841 message* attachment, message_wrap_type wrap_type, bool keep_orig_subject, unsigned int max_major, unsigned int max_minor) {
846 message* _envelope = envelope;
848 PEP_STATUS status = PEP_STATUS_OK;
850 replace_opt_field(attachment, "X-pEp-Version", PEP_VERSION, true);
852 if (!_envelope && (wrap_type != PEP_message_transport)) {
853 _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
854 status = generate_message_id(_envelope);
856 if (status != PEP_STATUS_OK)
859 const char* inner_type_string = "";
861 case PEP_message_key_reset:
862 inner_type_string = "KEY_RESET";
865 inner_type_string = "INNER";
867 if (max_major < 2 || (max_major == 2 && max_minor == 0)) {
868 attachment->longmsg = encapsulate_message_wrap_info(inner_type_string, attachment->longmsg);
869 _envelope->longmsg = encapsulate_message_wrap_info("OUTER", _envelope->longmsg);
872 _envelope->longmsg = strdup(
873 "This message was encrypted with p≡p (https://pep.software). If you are seeing this message,\n"
874 "your client does not support raising message attachments. Please click on the message attachment to\n"
875 "to view it, or better yet, consider using p≡p!\n"
878 // 2.1, to replace the above
879 add_opt_field(attachment, X_PEP_MSG_WRAP_KEY, inner_type_string);
881 else if (_envelope) {
882 // 2.1 - how do we peel this particular union when we get there?
883 _envelope->longmsg = encapsulate_message_wrap_info("TRANSPORT", _envelope->longmsg);
889 if (!attachment->id || attachment->id[0] == '\0') {
890 free(attachment->id);
891 if (!_envelope->id) {
892 status = generate_message_id(_envelope);
894 if (status != PEP_STATUS_OK)
898 attachment->id = strdup(_envelope->id);
901 char* message_text = NULL;
903 /* prevent introduction of pEp in inner message */
905 if (!attachment->shortmsg) {
906 attachment->shortmsg = strdup("");
907 if (!attachment->shortmsg)
911 /* add sender fpr to inner message */
912 add_opt_field(attachment,
914 (attachment->_sender_fpr ? attachment->_sender_fpr : "")
917 /* Turn message into a MIME-blob */
918 status = _mime_encode_message_internal(attachment, false, &message_text, true, false);
920 if (status != PEP_STATUS_OK)
923 size_t message_len = strlen(message_text);
925 bloblist_t* message_blob = new_bloblist(message_text, message_len,
926 "message/rfc822", NULL);
928 _envelope->attachments = message_blob;
929 if (keep_orig_subject && attachment->shortmsg)
930 _envelope->shortmsg = strdup(attachment->shortmsg);
935 free_message(_envelope);
940 static PEP_STATUS encrypt_PGP_inline(
945 PEP_encrypt_flags_t flags
951 PEP_STATUS status = encrypt_and_sign(session, keys, src->longmsg,
952 strlen(src->longmsg), &ctext, &csize);
956 dst->enc_format = PEP_enc_inline;
958 // shortmsg is being copied
960 dst->shortmsg = strdup(src->shortmsg);
961 assert(dst->shortmsg);
963 return PEP_OUT_OF_MEMORY;
966 // id is staying the same
968 dst->id = strdup(src->id);
971 return PEP_OUT_OF_MEMORY;
974 char *_ctext = realloc(ctext, csize + 1);
977 return PEP_OUT_OF_MEMORY;
980 dst->longmsg = _ctext;
982 // longmsg_formatted is unsupported
984 // attachments are going unencrypted
985 bloblist_t *bl = bloblist_dup(src->attachments);
987 return PEP_OUT_OF_MEMORY;
988 dst->attachments = bl;
990 return PEP_STATUS_OK;
993 static PEP_STATUS encrypt_PGP_MIME(
998 PEP_encrypt_flags_t flags,
999 message_wrap_type wrap_type
1002 PEP_STATUS status = PEP_STATUS_OK;
1003 bool free_ptext = false;
1006 char *mimetext = NULL;
1008 assert(dst->longmsg == NULL);
1009 dst->enc_format = PEP_enc_PGP_MIME;
1012 dst->shortmsg = strdup(src->shortmsg);
1014 message *_src = calloc(1, sizeof(message));
1018 // _src->longmsg = ptext;
1019 _src->longmsg = src->longmsg;
1020 _src->longmsg_formatted = src->longmsg_formatted;
1021 _src->attachments = src->attachments;
1022 _src->enc_format = PEP_enc_none;
1024 // These vars are here to be clear, and because I don't know how this may change in the near future.
1025 bool wrapped = (wrap_type != PEP_message_unwrapped);
1026 bool mime_encode = !wrapped;
1027 status = _mime_encode_message_internal(_src, true, &mimetext, mime_encode, wrapped);
1028 assert(status == PEP_STATUS_OK);
1029 if (status != PEP_STATUS_OK)
1039 if (mimetext == NULL)
1042 if (flags & PEP_encrypt_flag_force_unsigned)
1043 status = encrypt_only(session, keys, mimetext, strlen(mimetext),
1046 status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
1052 dst->longmsg = strdup("this message was encrypted with p≡p "
1053 "https://pEp-project.org");
1054 assert(dst->longmsg);
1055 if (dst->longmsg == NULL)
1058 char *v = strdup("Version: 1");
1063 bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
1066 dst->attachments = _a;
1068 _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
1073 return PEP_STATUS_OK;
1076 status = PEP_OUT_OF_MEMORY;
1087 static bool _has_PGP_MIME_format(message* msg) {
1088 if (!msg || !msg->attachments || !msg->attachments->next)
1090 if (msg->attachments->next->next)
1092 if (!msg->attachments->mime_type)
1094 if (strcmp(msg->attachments->mime_type, "application/pgp-encrypted") != 0)
1096 if (!msg->attachments->next->mime_type ||
1097 strcmp(msg->attachments->next->mime_type, "application/octet-stream") != 0)
1103 static inline PEP_rating _rating(PEP_comm_type ct)
1105 if (ct == PEP_ct_unknown)
1106 return PEP_rating_undefined;
1108 else if (ct == PEP_ct_key_not_found)
1109 return PEP_rating_have_no_key;
1111 else if (ct == PEP_ct_compromised)
1112 return PEP_rating_under_attack;
1114 else if (ct == PEP_ct_mistrusted)
1115 return PEP_rating_mistrust;
1117 if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
1118 ct == PEP_ct_my_key_not_included)
1119 return PEP_rating_unencrypted;
1121 if (ct >= PEP_ct_confirmed_enc_anon)
1122 return PEP_rating_trusted_and_anonymized;
1124 else if (ct >= PEP_ct_strong_encryption)
1125 return PEP_rating_trusted;
1127 else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
1128 return PEP_rating_reliable;
1131 return PEP_rating_unreliable;
1134 DYNAMIC_API PEP_rating rating_from_comm_type(PEP_comm_type ct)
1139 static bool is_encrypted_attachment(const bloblist_t *blob)
1143 if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
1146 char *ext = strrchr(blob->filename, '.');
1150 if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
1151 if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0)
1154 if (strcmp(ext, ".asc") == 0 && blob->size > 0) {
1155 const char* pubk_needle = "BEGIN PGP PUBLIC KEY";
1156 size_t pubk_needle_size = strlen(pubk_needle);
1157 const char* privk_needle = "BEGIN PGP PRIVATE KEY";
1158 size_t privk_needle_size = strlen(privk_needle);
1160 if (!(_memnmemn(pubk_needle, pubk_needle_size, blob->value, blob->size)) &&
1161 !(_memnmemn(privk_needle, privk_needle_size, blob->value, blob->size)))
1168 static bool is_encrypted_html_attachment(const bloblist_t *blob)
1171 assert(blob->filename);
1172 if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
1175 const char* bare_filename_ptr = _get_resource_ptr_noown(blob->filename);
1176 bare_filename_ptr += strlen(bare_filename_ptr) - 15;
1177 if (strncmp(bare_filename_ptr, "PGPexch.htm.", 12) == 0) {
1178 if (strcmp(bare_filename_ptr + 11, ".pgp") == 0 ||
1179 strcmp(bare_filename_ptr + 11, ".asc") == 0)
1186 static char * without_double_ending(const char *filename)
1189 if (filename == NULL || is_cid_uri(filename))
1192 char *ext = strrchr(filename, '.');
1196 char *result = strndup(filename, ext - filename);
1201 static PEP_rating decrypt_rating(PEP_STATUS status)
1204 case PEP_UNENCRYPTED:
1206 case PEP_VERIFY_NO_KEY:
1207 case PEP_VERIFIED_AND_TRUSTED:
1208 return PEP_rating_unencrypted;
1211 case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
1212 return PEP_rating_unreliable;
1214 case PEP_DECRYPTED_AND_VERIFIED:
1215 return PEP_rating_reliable;
1217 case PEP_DECRYPT_NO_KEY:
1218 return PEP_rating_have_no_key;
1220 case PEP_DECRYPT_WRONG_FORMAT:
1221 case PEP_CANNOT_DECRYPT_UNKNOWN:
1222 return PEP_rating_cannot_decrypt;
1225 return PEP_rating_undefined;
1229 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
1235 if (session == NULL || fpr == NULL)
1236 return PEP_rating_undefined;
1239 PEP_comm_type bare_comm_type = PEP_ct_unknown;
1240 PEP_comm_type resulting_comm_type = PEP_ct_unknown;
1241 PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
1242 if (status != PEP_STATUS_OK)
1243 return PEP_rating_undefined;
1245 PEP_comm_type least_comm_type = PEP_ct_unknown;
1246 least_trust(session, fpr, &least_comm_type);
1248 if (least_comm_type == PEP_ct_unknown) {
1249 resulting_comm_type = bare_comm_type;
1250 } else if (least_comm_type < PEP_ct_strong_but_unconfirmed ||
1251 bare_comm_type < PEP_ct_strong_but_unconfirmed) {
1252 // take minimum if anything bad
1253 resulting_comm_type = least_comm_type < bare_comm_type ?
1257 resulting_comm_type = least_comm_type;
1259 return _rating(resulting_comm_type);
1262 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
1263 return ((rating1 < rating2) ? rating1 : rating2);
1266 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, char* sender_fpr, PEP_rating sender_rating)
1268 PEP_rating rating = sender_rating;
1270 assert(keylist && keylist->value);
1271 if (keylist == NULL || keylist->value == NULL)
1272 return PEP_rating_undefined;
1275 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
1278 if(_same_fpr(sender_fpr, strlen(sender_fpr), _kl->value, strlen(_kl->value)))
1281 PEP_rating _rating_ = key_rating(session, _kl->value);
1283 if (_rating_ <= PEP_rating_mistrust)
1286 rating = worst_rating(rating, _rating_);
1292 // Internal function WARNING:
1293 // Only call this on an ident that might have its FPR set from retrieval!
1294 // (or on one without an fpr)
1295 // We do not want myself() setting the fpr here.
1296 static PEP_comm_type _get_comm_type(
1297 PEP_SESSION session,
1298 PEP_comm_type max_comm_type,
1302 PEP_STATUS status = PEP_STATUS_OK;
1304 if (max_comm_type == PEP_ct_compromised)
1305 return PEP_ct_compromised;
1307 if (max_comm_type == PEP_ct_mistrusted)
1308 return PEP_ct_mistrusted;
1310 if (!is_me(session, ident))
1311 status = update_identity(session, ident);
1314 status = _myself(session, ident, false, false, true);
1316 if (status == PEP_STATUS_OK) {
1317 if (ident->comm_type == PEP_ct_compromised)
1318 return PEP_ct_compromised;
1319 else if (ident->comm_type == PEP_ct_mistrusted)
1320 return PEP_ct_mistrusted;
1322 return MIN(max_comm_type, ident->comm_type);
1325 return PEP_ct_unknown;
1329 static PEP_comm_type _get_comm_type_preview(
1330 PEP_SESSION session,
1331 PEP_comm_type max_comm_type,
1338 PEP_STATUS status = PEP_STATUS_OK;
1340 if (max_comm_type == PEP_ct_compromised)
1341 return PEP_ct_compromised;
1343 if (max_comm_type == PEP_ct_mistrusted)
1344 return PEP_ct_mistrusted;
1346 PEP_comm_type comm_type = PEP_ct_unknown;
1347 if (ident && !EMPTYSTR(ident->address) && !EMPTYSTR(ident->user_id)) {
1348 pEp_identity *ident2;
1349 status = get_identity(session, ident->address, ident->user_id, &ident2);
1350 comm_type = ident2 ? ident2->comm_type : PEP_ct_unknown;
1351 free_identity(ident2);
1353 if (status == PEP_STATUS_OK) {
1354 if (comm_type == PEP_ct_compromised)
1355 comm_type = PEP_ct_compromised;
1356 else if (comm_type == PEP_ct_mistrusted)
1357 comm_type = PEP_ct_mistrusted;
1359 comm_type = _MIN(max_comm_type, comm_type);
1362 comm_type = PEP_ct_unknown;
1368 // static void free_bl_entry(bloblist_t *bl)
1372 // free(bl->mime_type);
1373 // free(bl->filename);
1378 static bool is_key(const bloblist_t *bl)
1380 return (// workaround for Apple Mail bugs
1381 (is_mime_type(bl, "application/x-apple-msg-attachment") &&
1382 is_fileending(bl, ".asc")) ||
1383 // as binary, by file name
1384 ((bl->mime_type == NULL ||
1385 is_mime_type(bl, "application/octet-stream")) &&
1386 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
1387 is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
1388 // explicit mime type
1389 is_mime_type(bl, "application/pgp-keys") ||
1390 // as text, by file name
1391 (is_mime_type(bl, "text/plain") &&
1392 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
1393 is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
1397 // static void remove_attached_keys(message *msg)
1400 // bloblist_t *last = NULL;
1401 // for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
1402 // bloblist_t *next = bl->next;
1404 // if (is_key(bl)) {
1406 // last->next = next;
1409 // msg->attachments = next;
1411 // free_bl_entry(bl);
1421 static bool compare_first_n_bytes(const char* first, const char* second, size_t n) {
1423 for (i = 0; i < n; i++) {
1425 char num2 = *second;
1440 bool import_attached_keys(
1441 PEP_SESSION session,
1443 identity_list **private_idents
1449 if (session == NULL || msg == NULL)
1452 bool remove = false;
1456 bloblist_t* prev = NULL;
1458 bool do_not_advance = false;
1459 const char* pubkey_header = "-----BEGIN PGP PUBLIC KEY BLOCK-----";
1460 const char* privkey_header = "-----BEGIN PGP PRIVATE KEY BLOCK-----";
1461 // Hate my magic numbers at your peril, but I don't want a strlen each time
1462 const size_t PUBKEY_HSIZE = 36;
1463 const size_t PRIVKEY_HSIZE = 37;
1465 for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
1468 do_not_advance = false;
1469 if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
1472 char* blob_value = bl->value;
1473 size_t blob_size = bl->size;
1474 bool free_blobval = false;
1476 if (is_encrypted_attachment(bl)) {
1478 char* bl_ptext = NULL;
1479 size_t bl_psize = 0;
1480 stringlist_t* bl_keylist = NULL;
1481 PEP_STATUS _status = decrypt_and_verify(session,
1482 blob_value, blob_size,
1484 &bl_ptext, &bl_psize,
1487 free_stringlist(bl_keylist); // we don't care about key encryption as long as we decrypt
1488 if (_status == PEP_DECRYPTED || _status == PEP_DECRYPTED_AND_VERIFIED) {
1489 free_blobval = true;
1490 blob_value = bl_ptext;
1491 blob_size = bl_psize;
1494 // This is an encrypted attachment we can do nothing with.
1495 // We shouldn't delete it or import it, because we can't
1503 identity_list *local_private_idents = NULL;
1504 PEP_STATUS import_status = import_key(session, blob_value, blob_size, &local_private_idents);
1505 bloblist_t* to_delete = NULL;
1506 switch (import_status) {
1507 case PEP_NO_KEY_IMPORTED:
1509 case PEP_KEY_IMPORT_STATUS_UNKNOWN:
1510 // We'll delete armoured stuff, at least
1511 if (blob_size <= PUBKEY_HSIZE)
1513 if ((!compare_first_n_bytes(pubkey_header, (const char*)blob_value, PUBKEY_HSIZE)) &&
1514 (!compare_first_n_bytes(privkey_header, (const char*)blob_value, PRIVKEY_HSIZE)))
1516 // else fall through and delete
1517 case PEP_KEY_IMPORTED:
1521 prev->next = bl->next;
1523 msg->attachments = bl->next;
1525 to_delete->next = NULL;
1526 free_bloblist(to_delete);
1527 do_not_advance = true;
1531 // bad stuff, but ok.
1534 if (private_idents && *private_idents == NULL && local_private_idents != NULL)
1535 *private_idents = local_private_idents;
1537 free_identity_list(local_private_idents);
1541 if (!do_not_advance) {
1550 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
1552 char *keydata = NULL;
1555 PEP_STATUS status = export_key(session, fpr, &keydata, &size);
1556 assert(status == PEP_STATUS_OK);
1557 if (status != PEP_STATUS_OK)
1561 bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
1562 "file://pEpkey.asc");
1564 if (msg->attachments == NULL && bl)
1565 msg->attachments = bl;
1567 return PEP_STATUS_OK;
1570 #define ONE_WEEK (7*24*3600)
1572 void attach_own_key(PEP_SESSION session, message *msg)
1577 if (msg->dir == PEP_dir_incoming)
1580 assert(msg->from && msg->from->fpr);
1581 if (msg->from == NULL || msg->from->fpr == NULL)
1584 if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
1587 char *revoked_fpr = NULL;
1588 uint64_t revocation_date = 0;
1590 if(get_revoked(session, msg->from->fpr,
1591 &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
1592 revoked_fpr != NULL)
1594 time_t now = time(NULL);
1596 if (now < (time_t)revocation_date + ONE_WEEK)
1598 _attach_key(session, revoked_fpr, msg);
1604 PEP_cryptotech determine_encryption_format(message *msg)
1608 if (is_PGP_message_text(msg->longmsg)) {
1609 msg->enc_format = PEP_enc_inline;
1610 return PEP_crypt_OpenPGP;
1612 else if (msg->attachments && msg->attachments->next &&
1613 is_mime_type(msg->attachments, "application/pgp-encrypted") &&
1614 is_PGP_message_text(msg->attachments->next->value)
1616 msg->enc_format = PEP_enc_PGP_MIME;
1617 return PEP_crypt_OpenPGP;
1619 else if (msg->attachments && msg->attachments->next &&
1620 is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
1621 is_PGP_message_text(msg->attachments->value)
1623 msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
1624 return PEP_crypt_OpenPGP;
1627 msg->enc_format = PEP_enc_none;
1628 return PEP_crypt_none;
1632 static void _cleanup_src(message* src, bool remove_attached_key) {
1638 char* longmsg = NULL;
1639 char* shortmsg = NULL;
1640 char* msg_wrap_info = NULL;
1642 separate_short_and_long(src->longmsg, &shortmsg, &msg_wrap_info,
1647 free(msg_wrap_info);
1648 src->longmsg = longmsg;
1650 if (remove_attached_key) {
1651 // End of the attachment list
1652 if (src->attachments) {
1653 bloblist_t* tmp = src->attachments;
1654 while (tmp->next && tmp->next->next) {
1657 free_bloblist(tmp->next);
1663 DYNAMIC_API PEP_STATUS encrypt_message(
1664 PEP_SESSION session,
1666 stringlist_t * extra,
1668 PEP_enc_format enc_format,
1669 PEP_encrypt_flags_t flags
1672 PEP_STATUS status = PEP_STATUS_OK;
1673 message * msg = NULL;
1674 stringlist_t * keys = NULL;
1675 message* _src = src;
1677 bool added_key_to_real_src = false;
1680 assert(src && src->from);
1683 if (!(session && src && src->from && dst))
1684 return PEP_ILLEGAL_VALUE;
1686 if (src->dir == PEP_dir_incoming)
1687 return PEP_ILLEGAL_VALUE;
1689 determine_encryption_format(src);
1690 // TODO: change this for multi-encryption in message format 2.0
1691 if (src->enc_format != PEP_enc_none)
1692 return PEP_ILLEGAL_VALUE;
1694 bool force_v_1 = flags & PEP_encrypt_flag_force_version_1;
1698 if (!src->from->user_id || src->from->user_id[0] == '\0') {
1699 char* own_id = NULL;
1700 status = get_default_own_userid(session, &own_id);
1702 free(src->from->user_id);
1703 src->from->user_id = own_id; // ownership transfer
1707 status = myself(session, src->from);
1708 if (status != PEP_STATUS_OK)
1711 char* send_fpr = strdup(src->from->fpr ? src->from->fpr : "");
1712 src->_sender_fpr = send_fpr;
1714 keys = new_stringlist(send_fpr);
1718 stringlist_t *_k = keys;
1721 _k = stringlist_append(_k, extra);
1726 bool dest_keys_found = true;
1727 bool has_pEp_user = false;
1729 PEP_comm_type max_comm_type = PEP_ct_pEp;
1730 unsigned int max_version_major = 0;
1731 unsigned int max_version_minor = 0;
1732 pEp_version_major_minor(PEP_VERSION, &max_version_major, &max_version_minor);
1734 identity_list * _il = NULL;
1736 if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
1737 // BCC limited support:
1739 // - App splits mails with BCC in multiple mails.
1740 // - Each email is encrypted separately
1741 if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
1743 // Only one Bcc with no other recipient allowed for now
1744 return PEP_ILLEGAL_VALUE;
1747 PEP_STATUS _status = PEP_STATUS_OK;
1748 if (!is_me(session, _il->ident)) {
1749 _status = update_identity(session, _il->ident);
1750 if (_status == PEP_CANNOT_FIND_IDENTITY) {
1751 _il->ident->comm_type = PEP_ct_key_not_found;
1752 _status = PEP_STATUS_OK;
1754 // 0 unless set, so safe.
1756 set_min_version( _il->ident->major_ver, _il->ident->minor_ver,
1757 max_version_major, max_version_minor,
1758 &max_version_major, &max_version_minor);
1760 bool is_blacklisted = false;
1761 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
1762 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
1763 if (_status != PEP_STATUS_OK) {
1765 status = PEP_UNENCRYPTED;
1768 if (is_blacklisted) {
1769 bool user_default, ident_default, address_default;
1770 _status = get_valid_pubkey(session, _il->ident,
1771 &ident_default, &user_default,
1774 if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
1775 _il->ident->comm_type = PEP_ct_key_not_found;
1776 _status = PEP_STATUS_OK;
1780 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
1781 is_pEp_user(session, _il->ident, &has_pEp_user);
1784 _status = myself(session, _il->ident);
1786 if (_status != PEP_STATUS_OK) {
1787 status = PEP_UNENCRYPTED;
1791 if (_il->ident->fpr && _il->ident->fpr[0]) {
1792 _k = stringlist_add(_k, _il->ident->fpr);
1795 max_comm_type = _get_comm_type(session, max_comm_type,
1799 dest_keys_found = false;
1800 status = PEP_KEY_NOT_FOUND;
1805 for (_il = src->to; _il && _il->ident; _il = _il->next) {
1806 PEP_STATUS _status = PEP_STATUS_OK;
1807 if (!is_me(session, _il->ident)) {
1808 _status = update_identity(session, _il->ident);
1809 if (_status == PEP_CANNOT_FIND_IDENTITY) {
1810 _il->ident->comm_type = PEP_ct_key_not_found;
1811 _status = PEP_STATUS_OK;
1813 // 0 unless set, so safe.
1814 set_min_version( _il->ident->major_ver, _il->ident->minor_ver,
1815 max_version_major, max_version_minor,
1816 &max_version_major, &max_version_minor);
1818 bool is_blacklisted = false;
1819 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
1820 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
1821 if (_status != PEP_STATUS_OK) {
1823 status = PEP_UNENCRYPTED;
1826 if (is_blacklisted) {
1827 bool user_default, ident_default, address_default;
1828 _status = get_valid_pubkey(session, _il->ident,
1829 &ident_default, &user_default,
1832 if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
1833 _il->ident->comm_type = PEP_ct_key_not_found;
1834 _status = PEP_STATUS_OK;
1838 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
1839 is_pEp_user(session, _il->ident, &has_pEp_user);
1841 _status = bind_own_ident_with_contact_ident(session, src->from, _il->ident);
1842 if (_status != PEP_STATUS_OK) {
1843 status = PEP_UNKNOWN_DB_ERROR;
1849 _status = myself(session, _il->ident);
1851 if (_status != PEP_STATUS_OK) {
1852 status = PEP_UNENCRYPTED;
1856 if (_il->ident->fpr && _il->ident->fpr[0]) {
1857 _k = stringlist_add(_k, _il->ident->fpr);
1860 max_comm_type = _get_comm_type(session, max_comm_type,
1864 dest_keys_found = false;
1865 status = PEP_KEY_NOT_FOUND;
1869 for (_il = src->cc; _il && _il->ident; _il = _il->next) {
1870 PEP_STATUS _status = PEP_STATUS_OK;
1871 if (!is_me(session, _il->ident)) {
1872 _status = update_identity(session, _il->ident);
1873 if (_status == PEP_CANNOT_FIND_IDENTITY) {
1874 _il->ident->comm_type = PEP_ct_key_not_found;
1875 _status = PEP_STATUS_OK;
1877 bool is_blacklisted = false;
1878 if (_il->ident->fpr && IS_PGP_CT(_il->ident->comm_type)) {
1879 _status = blacklist_is_listed(session, _il->ident->fpr, &is_blacklisted);
1880 if (_status != PEP_STATUS_OK) {
1882 status = PEP_UNENCRYPTED;
1885 if (is_blacklisted) {
1886 bool user_default, ident_default, address_default;
1887 _status = get_valid_pubkey(session, _il->ident,
1888 &ident_default, &user_default,
1891 if (_status != PEP_STATUS_OK || _il->ident->fpr == NULL) {
1892 _il->ident->comm_type = PEP_ct_key_not_found;
1893 _status = PEP_STATUS_OK;
1897 if (!has_pEp_user && !EMPTYSTR(_il->ident->user_id))
1898 is_pEp_user(session, _il->ident, &has_pEp_user);
1901 _status = myself(session, _il->ident);
1902 if (_status != PEP_STATUS_OK)
1904 status = PEP_UNENCRYPTED;
1908 if (_il->ident->fpr && _il->ident->fpr[0]) {
1909 _k = stringlist_add(_k, _il->ident->fpr);
1912 max_comm_type = _get_comm_type(session, max_comm_type,
1916 dest_keys_found = false;
1921 if (max_version_major == 1)
1924 if (enc_format == PEP_enc_none || !dest_keys_found ||
1925 stringlist_length(keys) == 0 ||
1926 _rating(max_comm_type) < PEP_rating_reliable)
1928 free_stringlist(keys);
1929 if ((has_pEp_user || !session->passive_mode) &&
1930 !(flags & PEP_encrypt_flag_force_no_attached_key)) {
1931 attach_own_key(session, src);
1932 added_key_to_real_src = true;
1934 decorate_message(src, PEP_rating_undefined, NULL, true, true);
1935 return PEP_UNENCRYPTED;
1938 // First, dedup the keylist
1939 if (keys && keys->next)
1940 dedup_stringlist(keys->next);
1942 // FIXME - we need to deal with transport types (via flag)
1943 message_wrap_type wrap_type = PEP_message_unwrapped;
1944 if ((enc_format != PEP_enc_inline) && (!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
1945 wrap_type = ((flags & PEP_encrypt_flag_key_reset_only) ? PEP_message_key_reset : PEP_message_default);
1946 _src = wrap_message_as_attachment(NULL, src, wrap_type, false, max_version_major, max_version_minor);
1952 if (enc_format != PEP_enc_inline) {
1953 status = replace_subject(_src);
1954 if (status == PEP_OUT_OF_MEMORY)
1957 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1958 added_key_to_real_src = true;
1960 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1961 attach_own_key(session, _src);
1963 msg = clone_to_empty_message(_src);
1967 switch (enc_format) {
1968 case PEP_enc_PGP_MIME:
1969 case PEP_enc_PEP: // BUG: should be implemented extra
1970 status = encrypt_PGP_MIME(session, _src, keys, msg, flags, wrap_type);
1973 case PEP_enc_inline:
1974 status = encrypt_PGP_inline(session, _src, keys, msg, flags);
1979 status = PEP_ILLEGAL_VALUE;
1983 if (status == PEP_OUT_OF_MEMORY)
1986 if (status != PEP_STATUS_OK)
1990 free_stringlist(keys);
1992 if (msg && msg->shortmsg == NULL) {
1993 msg->shortmsg = strdup("");
1994 assert(msg->shortmsg);
1995 if (msg->shortmsg == NULL)
2000 decorate_message(msg, PEP_rating_undefined, NULL, true, true);
2002 msg->id = strdup(_src->id);
2004 if (msg->id == NULL)
2011 // ??? FIXME: Check to be sure we don't have references btw _src and msg.
2012 // I don't think we do.
2013 if (_src && _src != src)
2016 _cleanup_src(src, added_key_to_real_src);
2021 status = PEP_OUT_OF_MEMORY;
2024 free_stringlist(keys);
2026 if (_src && _src != src)
2029 _cleanup_src(src, added_key_to_real_src);
2034 DYNAMIC_API PEP_STATUS encrypt_message_and_add_priv_key(
2035 PEP_SESSION session,
2039 PEP_enc_format enc_format,
2040 PEP_encrypt_flags_t flags
2048 if (!session || !src || !dst || !to_fpr)
2049 return PEP_ILLEGAL_VALUE;
2051 if (enc_format == PEP_enc_none)
2052 return PEP_ILLEGAL_VALUE;
2054 if (src->cc || src->bcc)
2055 return PEP_ILLEGAL_VALUE;
2057 if (!src->to || src->to->next)
2058 return PEP_ILLEGAL_VALUE;
2060 if (!src->from->address || !src->to->ident || !src->to->ident->address)
2061 return PEP_ILLEGAL_VALUE;
2063 if (strcasecmp(src->from->address, src->to->ident->address) != 0)
2064 return PEP_ILLEGAL_VALUE;
2066 stringlist_t* keys = NULL;
2068 char* own_id = NULL;
2069 char* default_id = NULL;
2071 pEp_identity* own_identity = NULL;
2072 char* own_private_fpr = NULL;
2074 char* priv_key_data = NULL;
2076 PEP_STATUS status = get_default_own_userid(session, &own_id);
2079 return PEP_UNKNOWN_ERROR; // Probably a DB error at this point
2081 if (src->from->user_id) {
2082 if (strcmp(src->from->user_id, own_id) != 0) {
2083 status = get_userid_alias_default(session, src->from->user_id, &default_id);
2084 if (status != PEP_STATUS_OK || !default_id || strcmp(default_id, own_id) != 0) {
2085 status = PEP_ILLEGAL_VALUE;
2091 // Ok, we are at least marginally sure the initial stuff is ok.
2093 // Let's get our own, normal identity
2094 own_identity = identity_dup(src->from);
2095 status = myself(session, own_identity);
2097 if (status != PEP_STATUS_OK)
2100 // Ok, now we know the address is an own address. All good. Then...
2101 own_private_fpr = own_identity->fpr;
2102 own_identity->fpr = strdup(to_fpr);
2104 status = get_trust(session, own_identity);
2106 if (status != PEP_STATUS_OK) {
2107 if (status == PEP_CANNOT_FIND_IDENTITY)
2108 status = PEP_ILLEGAL_VALUE;
2112 if ((own_identity->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed) {
2113 status = PEP_ILLEGAL_VALUE;
2117 // Ok, so all the things are now allowed.
2118 // So let's get our own private key and roll with it.
2119 size_t priv_key_size = 0;
2121 status = export_secret_key(session, own_private_fpr, &priv_key_data,
2124 if (status != PEP_STATUS_OK)
2127 if (!priv_key_data) {
2128 status = PEP_CANNOT_EXPORT_KEY;
2132 // Ok, fine... let's encrypt yon blob
2133 keys = new_stringlist(own_private_fpr);
2135 status = PEP_OUT_OF_MEMORY;
2139 stringlist_add(keys, to_fpr);
2141 char* encrypted_key_text = NULL;
2142 size_t encrypted_key_size = 0;
2144 if (flags & PEP_encrypt_flag_force_unsigned)
2145 status = encrypt_only(session, keys, priv_key_data, priv_key_size,
2146 &encrypted_key_text, &encrypted_key_size);
2148 status = encrypt_and_sign(session, keys, priv_key_data, priv_key_size,
2149 &encrypted_key_text, &encrypted_key_size);
2151 if (!encrypted_key_text) {
2152 status = PEP_UNKNOWN_ERROR;
2156 // We will have to delete this before returning, as we allocated it.
2157 bloblist_t* created_bl = NULL;
2158 bloblist_t* created_predecessor = NULL;
2160 bloblist_t* old_head = NULL;
2162 if (!src->attachments || src->attachments->value == NULL) {
2163 if (src->attachments && src->attachments->value == NULL) {
2164 old_head = src->attachments;
2165 src->attachments = NULL;
2167 src->attachments = new_bloblist(encrypted_key_text, encrypted_key_size,
2168 "application/octet-stream",
2169 "file://pEpkey.asc.pgp");
2170 created_bl = src->attachments;
2173 bloblist_t* tmp = src->attachments;
2174 while (tmp && tmp->next) {
2177 created_predecessor = tmp;
2178 created_bl = bloblist_add(tmp,
2179 encrypted_key_text, encrypted_key_size,
2180 "application/octet-stream",
2181 "file://pEpkey.asc.pgp");
2185 status = PEP_OUT_OF_MEMORY;
2189 // Ok, it's in there. Let's do this.
2190 status = encrypt_message(session, src, keys, dst, enc_format, flags);
2192 // Delete what we added to src
2193 free_bloblist(created_bl);
2194 if (created_predecessor)
2195 created_predecessor->next = NULL;
2198 src->attachments = old_head;
2200 src->attachments = NULL;
2206 free(own_private_fpr);
2207 free(priv_key_data);
2208 free_identity(own_identity);
2209 free_stringlist(keys);
2214 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
2215 PEP_SESSION session,
2216 pEp_identity* target_id,
2218 stringlist_t* extra,
2220 PEP_enc_format enc_format,
2221 PEP_encrypt_flags_t flags
2224 PEP_STATUS status = PEP_STATUS_OK;
2225 message * msg = NULL;
2226 stringlist_t * keys = NULL;
2227 message* _src = src;
2233 assert(enc_format != PEP_enc_none);
2235 if (!(session && target_id && src && dst && enc_format != PEP_enc_none))
2236 return PEP_ILLEGAL_VALUE;
2238 // if (src->dir == PEP_dir_incoming)
2239 // return PEP_ILLEGAL_VALUE;
2241 determine_encryption_format(src);
2242 if (src->enc_format != PEP_enc_none)
2243 return PEP_ILLEGAL_VALUE;
2245 if (!target_id->user_id || target_id->user_id[0] == '\0') {
2246 char* own_id = NULL;
2247 status = get_default_own_userid(session, &own_id);
2249 free(target_id->user_id);
2250 target_id->user_id = own_id; // ownership transfer
2254 if (!target_id->user_id || target_id->user_id[0] == '\0')
2255 return PEP_CANNOT_FIND_IDENTITY;
2257 if (target_id->address) {
2258 status = myself(session, target_id);
2259 if (status != PEP_STATUS_OK)
2262 else if (!target_id->fpr) {
2263 return PEP_ILLEGAL_VALUE;
2268 // PEP_STATUS _status = update_identity(session, target_id);
2269 // if (_status != PEP_STATUS_OK) {
2270 // status = _status;
2274 char* target_fpr = target_id->fpr;
2276 return PEP_KEY_NOT_FOUND; // FIXME: Error condition
2278 keys = new_stringlist(target_fpr);
2280 stringlist_t *_k = keys;
2283 _k = stringlist_append(_k, extra);
2288 /* KG: did we ever do this??? */
2289 // if (!(flags & PEP_encrypt_flag_force_no_attached_key))
2290 // _attach_key(session, target_fpr, src);
2292 unsigned int major_ver, minor_ver;
2293 pEp_version_major_minor(PEP_VERSION, &major_ver, &minor_ver);
2294 _src = wrap_message_as_attachment(NULL, src, PEP_message_default, false, major_ver, minor_ver);
2298 msg = clone_to_empty_message(_src);
2302 switch (enc_format) {
2303 case PEP_enc_PGP_MIME:
2304 case PEP_enc_PEP: // BUG: should be implemented extra
2305 status = encrypt_PGP_MIME(session, _src, keys, msg, flags, PEP_message_default);
2306 if (status == PEP_STATUS_OK || (src->longmsg && strstr(src->longmsg, "INNER")))
2307 _cleanup_src(src, false);
2310 case PEP_enc_inline:
2311 status = encrypt_PGP_inline(session, _src, keys, msg, flags);
2316 status = PEP_ILLEGAL_VALUE;
2320 if (status == PEP_OUT_OF_MEMORY)
2323 if (status != PEP_STATUS_OK)
2327 if (!src->shortmsg) {
2328 free(msg->shortmsg);
2329 msg->shortmsg = _pEp_subj_copy();
2330 assert(msg->shortmsg);
2331 if (msg->shortmsg == NULL)
2335 if (session->unencrypted_subject && (flags & PEP_encrypt_reencrypt)) {
2336 free(msg->shortmsg);
2337 msg->shortmsg = strdup(src->shortmsg);
2342 msg->id = strdup(_src->id);
2344 if (msg->id == NULL)
2347 decorate_message(msg, PEP_rating_undefined, NULL, true, true);
2358 status = PEP_OUT_OF_MEMORY;
2361 free_stringlist(keys);
2369 // static PEP_STATUS _update_identity_for_incoming_message(
2370 // PEP_SESSION session,
2371 // const message *src
2374 // PEP_STATUS status;
2376 // if (src->from && src->from->address) {
2377 // if (!is_me(session, src->from))
2378 // status = update_identity(session, src->from);
2380 // status = myself(session, src->from);
2381 // if (status == PEP_STATUS_OK
2382 // && is_a_pEpmessage(src)
2383 // && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
2384 // && src->from->comm_type != PEP_ct_pEp_unconfirmed
2385 // && src->from->comm_type != PEP_ct_pEp)
2387 // src->from->comm_type |= PEP_ct_pEp_unconfirmed;
2388 // status = set_identity(session, src->from);
2392 // return PEP_ILLEGAL_VALUE;
2396 static PEP_STATUS _get_detached_signature(message* msg,
2397 bloblist_t** signature_blob) {
2398 bloblist_t* attach_curr = msg->attachments;
2400 *signature_blob = NULL;
2402 while (attach_curr) {
2403 if (attach_curr->mime_type &&
2404 (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0)) {
2405 *signature_blob = attach_curr;
2408 attach_curr = attach_curr->next;
2411 return PEP_STATUS_OK;
2414 static PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
2415 char** stext, size_t* ssize) {
2417 char* signed_boundary = NULL;
2418 char* signpost = strstr(ptext, "Content-Type: multipart/signed");
2424 return PEP_UNKNOWN_ERROR;
2426 char* curr_line = signpost;
2427 // const char* end_text = ptext + psize;
2428 const char* boundary_key = "boundary=";
2429 const size_t BOUNDARY_KEY_SIZE = 9;
2431 char* start_boundary = strstr(curr_line, boundary_key);
2432 if (!start_boundary)
2433 return PEP_UNKNOWN_ERROR;
2435 start_boundary += BOUNDARY_KEY_SIZE;
2437 bool quoted = (*start_boundary == '"');
2442 char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
2445 return PEP_UNKNOWN_ERROR;
2447 // Add space for the "--"
2448 size_t boundary_strlen = (end_boundary - start_boundary) + 2;
2450 signed_boundary = calloc(boundary_strlen + 1, 1);
2451 assert(signed_boundary);
2452 if (!signed_boundary)
2453 return PEP_OUT_OF_MEMORY;
2455 strlcpy(signed_boundary, "--", boundary_strlen + 1);
2456 strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
2458 start_boundary = strstr(end_boundary, signed_boundary);
2460 if (!start_boundary)
2461 return PEP_UNKNOWN_ERROR;
2463 start_boundary += boundary_strlen;
2465 if (*start_boundary == '\r') {
2466 if (*(start_boundary + 1) == '\n')
2467 start_boundary += 2;
2469 else if (*start_boundary == '\n')
2472 end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
2475 return PEP_UNKNOWN_ERROR;
2477 // See RFC3156 section 5...
2479 if (*(end_boundary - 1) == '\r')
2482 *ssize = end_boundary - start_boundary;
2483 *stext = start_boundary;
2484 free(signed_boundary);
2486 return PEP_STATUS_OK;
2489 static PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in,
2490 stringlist_t** keylist_in_out,
2491 pEp_identity* from) {
2493 if (!verify_in || !(*verify_in)) // this isn't really a problem.
2494 return PEP_STATUS_OK;
2496 stringlist_t* orig_verify = *verify_in;
2498 stringlist_t* verify_curr = NULL;
2499 stringlist_t* from_keys = NULL;
2501 /* FIXME: what to do if head needs to be null */
2502 PEP_STATUS status = find_keys(session, from->address, &from_keys);
2504 stringlist_t* from_fpr_node = NULL;
2505 stringlist_t* from_curr;
2507 for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
2508 for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
2509 if (from_curr->value && verify_curr->value &&
2510 _same_fpr(from_curr->value, strlen(from_curr->value),
2511 verify_curr->value, strlen(verify_curr->value))) {
2512 from_fpr_node = from_curr;
2518 if (!from_fpr_node) {
2519 status = PEP_KEY_NOT_FOUND;
2523 verify_curr = orig_verify;
2525 /* put "from" signer at the beginning of the list */
2526 if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
2527 from_fpr_node->value, strlen(from_fpr_node->value))) {
2528 orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
2529 verify_curr = new_stringlist(from_fpr_node->value);
2530 verify_curr->next = orig_verify;
2533 if (keylist_in_out) {
2534 /* append keylist to signers */
2535 if (*keylist_in_out && (*keylist_in_out)->value) {
2536 stringlist_t** tail_pp = &verify_curr->next;
2539 tail_pp = &((*tail_pp)->next);
2541 stringlist_t* second_list = *keylist_in_out;
2543 char* listhead_val = second_list->value;
2544 if (!listhead_val || listhead_val[0] == '\0') {
2545 /* remove head, basically. This can happen when,
2546 for example, the signature is detached and
2547 verification is not seen directly after
2548 decryption, so no signer is presumed in
2549 the first construction of the keylist */
2550 *keylist_in_out = (*keylist_in_out)->next;
2551 second_list->next = NULL;
2552 free_stringlist(second_list);
2555 *tail_pp = *keylist_in_out;
2558 *keylist_in_out = verify_curr;
2561 status = PEP_STATUS_OK;
2564 free_stringlist(from_keys);
2568 static PEP_STATUS amend_rating_according_to_sender_and_recipients(
2569 PEP_SESSION session,
2571 pEp_identity *sender,
2572 stringlist_t *recipients) {
2574 PEP_STATUS status = PEP_STATUS_OK;
2576 if (*rating > PEP_rating_mistrust) {
2578 if (recipients == NULL) {
2579 *rating = PEP_rating_undefined;
2580 return PEP_STATUS_OK;
2583 char *fpr = recipients->value;
2585 if (!(sender && sender->user_id && sender->user_id[0] && fpr && fpr[0])) {
2586 *rating = PEP_rating_unreliable;
2589 pEp_identity *_sender = new_identity(sender->address, fpr,
2590 sender->user_id, sender->username);
2591 if (_sender == NULL)
2592 return PEP_OUT_OF_MEMORY;
2594 status = get_trust(session, _sender);
2595 if (_sender->comm_type == PEP_ct_unknown) {
2596 get_key_rating(session, fpr, &_sender->comm_type);
2598 if (_sender->comm_type != PEP_ct_unknown) {
2599 *rating = keylist_rating(session, recipients,
2600 fpr, _rating(_sender->comm_type));
2603 free_identity(_sender);
2604 if (status == PEP_CANNOT_FIND_IDENTITY)
2605 status = PEP_STATUS_OK;
2611 // FIXME: Do we need to remove the attachment? I think we do...
2612 static bool pull_up_attached_main_msg(message* src) {
2613 char* slong = src->longmsg;
2614 char* sform = src->longmsg_formatted;
2615 bloblist_t* satt = src->attachments;
2617 if ((!slong || slong[0] == '\0')
2618 && (!sform || sform[0] == '\0')) {
2619 const char* inner_mime_type = (satt ? satt->mime_type : NULL);
2620 if (inner_mime_type) {
2621 if (strcasecmp(inner_mime_type, "text/plain") == 0) {
2622 free(slong); /* in case of "" */
2623 src->longmsg = strndup(satt->value, satt->size);
2625 bloblist_t* next_node = satt->next;
2627 inner_mime_type = next_node->mime_type;
2628 if (strcasecmp(inner_mime_type, "text/html") == 0) {
2630 src->longmsg_formatted = strndup(next_node->value, next_node->size);
2634 else if (strcasecmp(inner_mime_type, "text/html") == 0) {
2636 src->longmsg_formatted = strndup(satt->value, satt->size);
2646 static PEP_STATUS unencapsulate_hidden_fields(message* src, message* msg,
2647 char** msg_wrap_info) {
2649 return PEP_ILLEGAL_VALUE;
2650 unsigned char pEpstr[] = PEP_SUBJ_STRING;
2651 PEP_STATUS status = PEP_STATUS_OK;
2653 bool change_source_in_place = (msg ? false : true);
2655 if (change_source_in_place)
2659 switch (src->enc_format) {
2660 case PEP_enc_PGP_MIME:
2661 case PEP_enc_inline:
2662 case PEP_enc_PGP_MIME_Outlook1:
2663 // case PEP_enc_none: // FIXME - this is wrong
2665 if (!change_source_in_place)
2666 status = copy_fields(msg, src);
2668 if (status != PEP_STATUS_OK)
2671 // FIXME: This is a mess. Talk with VB about how far we go to identify
2672 if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
2673 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0) ||
2674 (strcmp(src->shortmsg, "p=p") == 0))
2676 char * shortmsg = NULL;
2677 char * longmsg = NULL;
2680 int r = separate_short_and_long(msg->longmsg,
2686 return PEP_OUT_OF_MEMORY;
2689 // We only use the shortmsg in version 1.0 messages; if it occurs where we
2690 // didn't replace the subject, we ignore this all
2691 if (!(*msg_wrap_info || change_source_in_place)) {
2693 (src->shortmsg != NULL && strcmp(src->shortmsg, "pEp") != 0 &&
2694 _unsigned_signed_strcmp(pEpstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0 &&
2695 strcmp(src->shortmsg, "p=p") != 0)) {
2697 if (shortmsg != NULL)
2700 if (src->shortmsg == NULL) {
2701 shortmsg = strdup("");
2704 // FIXME: is msg->shortmsg always a copy of
2705 // src->shortmsg already?
2706 // if so, we need to change the logic so
2707 // that in this case, we don't free msg->shortmsg
2708 // and do this strdup, etc
2709 shortmsg = strdup(src->shortmsg);
2712 free(msg->shortmsg);
2713 msg->shortmsg = shortmsg;
2718 msg->longmsg = longmsg;
2721 if (!change_source_in_place) {
2722 msg->shortmsg = strdup(src->shortmsg);
2723 assert(msg->shortmsg);
2724 if (msg->shortmsg == NULL)
2725 return PEP_OUT_OF_MEMORY;
2730 // BUG: must implement more
2733 return PEP_STATUS_OK;
2737 static PEP_STATUS get_crypto_text(message* src, char** crypto_text, size_t* text_size) {
2739 // this is only here because of how NOT_IMPLEMENTED works
2740 PEP_STATUS status = PEP_STATUS_OK;
2742 switch (src->enc_format) {
2743 case PEP_enc_PGP_MIME:
2744 case PEP_enc_PGP_MIME_Outlook1:
2745 *crypto_text = src->attachments->next->value;
2746 if (src->attachments->next->value[src->attachments->next->size - 1]) {
2747 // if the attachment is not ending with a trailing 0
2748 // then it is containing the crypto text directly
2749 *text_size = src->attachments->next->size;
2752 // if the attachment is ending with trailing 0
2753 // then it is containting a string
2754 *text_size = strlen(src->attachments->next->value);
2758 case PEP_enc_inline:
2759 *crypto_text = src->longmsg;
2760 *text_size = strlen(*crypto_text);
2771 static PEP_STATUS verify_decrypted(PEP_SESSION session,
2775 size_t plaintext_size,
2776 stringlist_t** keylist,
2777 PEP_STATUS* decrypt_status,
2778 PEP_cryptotech crypto) {
2780 assert(src && src->from);
2782 if (!src && !src->from)
2783 return PEP_ILLEGAL_VALUE;
2785 PEP_STATUS _cached_decrypt_status = *decrypt_status;
2787 pEp_identity* sender = src->from;
2789 bloblist_t* detached_sig = NULL;
2790 PEP_STATUS status = _get_detached_signature(msg, &detached_sig);
2791 stringlist_t *verify_keylist = NULL;
2795 char* dsig_text = detached_sig->value;
2796 size_t dsig_size = detached_sig->size;
2800 status = _get_signed_text(plaintext, plaintext_size, &stext, &ssize);
2802 if (ssize > 0 && stext) {
2803 status = cryptotech[crypto].verify_text(session, stext,
2804 ssize, dsig_text, dsig_size,
2808 if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
2810 *decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
2812 status = combine_keylists(session, &verify_keylist, keylist, sender);
2816 size_t csize, psize;
2819 get_crypto_text(src, &ctext, &csize);
2820 // reverify - we may have imported a key in the meantime
2821 // status = cryptotech[crypto].verify_text(session, ctext,
2823 // &verify_keylist);
2824 free_stringlist(*keylist);
2825 *decrypt_status = decrypt_and_verify(session, ctext, csize,
2827 &ptext, &psize, keylist,
2832 if (*decrypt_status != PEP_DECRYPTED_AND_VERIFIED)
2833 *decrypt_status = _cached_decrypt_status;
2835 return PEP_STATUS_OK;
2838 static PEP_STATUS _decrypt_in_pieces(PEP_SESSION session,
2844 PEP_STATUS status = PEP_STATUS_OK;
2846 *msg_ptr = clone_to_empty_message(src);
2848 if (*msg_ptr == NULL)
2849 return PEP_OUT_OF_MEMORY;
2851 message* msg = *msg_ptr;
2853 msg->longmsg = strdup(ptext);
2856 bloblist_t *_m = msg->attachments;
2857 if (_m == NULL && src->attachments && src->attachments->value) {
2858 msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
2859 _m = msg->attachments;
2863 for (_s = src->attachments; _s && _s->value; _s = _s->next) {
2864 if (_s->value == NULL && _s->size == 0){
2865 _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
2867 return PEP_OUT_OF_MEMORY;
2870 else if (is_encrypted_attachment(_s)) {
2871 stringlist_t *_keylist = NULL;
2872 char *attctext = _s->value;
2873 size_t attcsize = _s->size;
2878 char* pgp_filename = NULL;
2879 status = decrypt_and_verify(session, attctext, attcsize,
2881 &ptext, &psize, &_keylist,
2884 free_stringlist(_keylist);
2886 char* filename_uri = NULL;
2888 bool has_uri_prefix = (pgp_filename ? (is_file_uri(pgp_filename) || is_cid_uri(pgp_filename)) :
2889 (_s->filename ? (is_file_uri(_s->filename) || is_cid_uri(_s->filename)) :
2896 if (is_encrypted_html_attachment(_s)) {
2897 msg->longmsg_formatted = ptext;
2901 static const char * const mime_type = "application/octet-stream";
2903 if (!has_uri_prefix)
2904 filename_uri = build_uri("file", pgp_filename);
2906 _m = bloblist_add(_m, ptext, psize, mime_type,
2907 (filename_uri ? filename_uri : pgp_filename));
2912 return PEP_OUT_OF_MEMORY;
2915 char * const filename =
2916 without_double_ending(_s->filename);
2917 if (filename == NULL)
2918 return PEP_OUT_OF_MEMORY;
2920 if (!has_uri_prefix)
2921 filename_uri = build_uri("file", filename);
2923 _m = bloblist_add(_m, ptext, psize, mime_type,
2924 (filename_uri ? filename_uri : filename));
2928 return PEP_OUT_OF_MEMORY;
2932 if (msg->attachments == NULL)
2933 msg->attachments = _m;
2937 char *copy = malloc(_s->size);
2940 return PEP_OUT_OF_MEMORY;
2941 memcpy(copy, _s->value, _s->size);
2943 if (!has_uri_prefix && _s->filename)
2944 filename_uri = build_uri("file", _s->filename);
2946 _m = bloblist_add(_m, copy, _s->size, _s->mime_type,
2947 (filename_uri ? filename_uri : _s->filename));
2949 return PEP_OUT_OF_MEMORY;
2953 char *copy = malloc(_s->size);
2956 return PEP_OUT_OF_MEMORY;
2957 memcpy(copy, _s->value, _s->size);
2959 char* filename_uri = NULL;
2961 _m = bloblist_add(_m, copy, _s->size, _s->mime_type,
2962 ((_s->filename && !(is_file_uri(_s->filename) || is_cid_uri(_s->filename))) ?
2963 (filename_uri = build_uri("file", _s->filename)) : _s->filename));
2966 return PEP_OUT_OF_MEMORY;
2973 static PEP_STATUS import_priv_keys_from_decrypted_msg(PEP_SESSION session,
2975 bool* imported_keys,
2976 bool* imported_private,
2977 identity_list** private_il)
2979 assert(msg && imported_keys && imported_private);
2980 if (!(msg && imported_keys && imported_private))
2981 return PEP_ILLEGAL_VALUE;
2983 PEP_STATUS status = PEP_STATUS_OK;
2984 *imported_keys = NULL;
2985 *imported_private = false;
2989 // check for private key in decrypted message attachment while importing
2990 identity_list *_private_il = NULL;
2992 bool _imported_keys = import_attached_keys(session, msg, &_private_il);
2993 bool _imported_private = false;
2994 if (_private_il && _private_il->ident && _private_il->ident->address)
2995 _imported_private = true;
2997 if (private_il && _imported_private) {
2998 // the private identity list should NOT be subject to myself() or
2999 // update_identity() at this point.
3000 // If the receiving app wants them to be in the trust DB, it
3001 // should call set_own_key() on them upon return.
3002 // We do, however, prepare these so the app can use them
3003 // directly in a set_own_key() call by putting the own_id on it.
3004 char* own_id = NULL;
3005 status = get_default_own_userid(session, &own_id);
3007 for (identity_list* il = _private_il; il; il = il->next) {
3009 free(il->ident->user_id);
3010 il->ident->user_id = strdup(own_id);
3011 assert(il->ident->user_id);
3012 if (!il->ident->user_id) {
3013 status = PEP_OUT_OF_MEMORY;
3017 il->ident->me = true;
3021 *private_il = _private_il;
3024 free_identity_list(_private_il);
3028 *imported_keys = _imported_keys;
3029 *imported_private = _imported_private;
3035 // ident is in_only and should have been updated
3036 static PEP_STATUS pEp_version_upgrade_or_ignore(
3037 PEP_SESSION session,
3038 pEp_identity* ident,
3040 unsigned int minor) {
3042 PEP_STATUS status = PEP_STATUS_OK;
3043 int ver_compare = compare_versions(major, minor, ident->major_ver, ident->minor_ver);
3044 if (ver_compare > 0)
3045 status = set_pEp_version(session, ident, major, minor);
3050 // FIXME: myself ??????
3051 static PEP_STATUS update_sender_to_pEp_trust(
3052 PEP_SESSION session,
3053 pEp_identity* sender,
3054 stringlist_t* keylist,
3060 assert(keylist && !EMPTYSTR(keylist->value));
3062 if (!session || !sender || !keylist || EMPTYSTR(keylist->value))
3063 return PEP_ILLEGAL_VALUE;
3068 PEP_STATUS status = PEP_STATUS_OK;
3070 // Seems status doesn't matter
3071 is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
3073 if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
3075 sender->fpr = strdup(keylist->value);
3077 return PEP_OUT_OF_MEMORY;
3078 status = set_pgp_keypair(session, sender->fpr);
3079 if (status != PEP_STATUS_OK)
3082 status = get_trust(session, sender);
3084 if (status == PEP_CANNOT_FIND_IDENTITY || sender->comm_type == PEP_ct_unknown) {
3085 PEP_comm_type ct = PEP_ct_unknown;
3086 status = get_key_rating(session, sender->fpr, &ct);
3087 if (status != PEP_STATUS_OK)
3090 sender->comm_type = ct;
3094 // Could be done elegantly, but we do this explicitly here for readability.
3095 // This file's code is difficult enough to parse. But change at will.
3096 switch (sender->comm_type) {
3097 case PEP_ct_OpenPGP_unconfirmed:
3098 case PEP_ct_OpenPGP:
3099 sender->comm_type = PEP_ct_pEp_unconfirmed | (sender->comm_type & PEP_ct_confirmed);
3100 status = set_trust(session, sender);
3101 if (status != PEP_STATUS_OK)
3104 case PEP_ct_pEp_unconfirmed:
3110 status = pEp_version_upgrade_or_ignore(session, sender, major, minor);
3113 status = PEP_CANNOT_SET_TRUST;
3120 static PEP_STATUS reconcile_identity(pEp_identity* srcid,
3121 pEp_identity* resultid) {
3125 if (!srcid || !resultid)
3126 return PEP_ILLEGAL_VALUE;
3128 if (!EMPTYSTR(srcid->user_id)) {
3129 if (EMPTYSTR(resultid->user_id) ||
3130 strcmp(srcid->user_id, resultid->user_id) != 0) {
3131 free(resultid->user_id);
3132 resultid->user_id = strdup(srcid->user_id);
3136 resultid->lang[0] = srcid->lang[0];
3137 resultid->lang[1] = srcid->lang[1];
3138 resultid->lang[2] = 0;
3139 resultid->me = srcid->me;
3140 resultid->flags = srcid->flags;
3142 return PEP_STATUS_OK;
3145 static PEP_STATUS reconcile_identity_lists(identity_list* src_ids,
3146 identity_list* result_ids) {
3148 identity_list* curr_id = result_ids;
3150 PEP_STATUS status = PEP_STATUS_OK;
3153 identity_list* curr_src_id = src_ids;
3154 pEp_identity* result_identity = curr_id->ident;
3156 while (curr_src_id) {
3157 pEp_identity* source_identity = curr_src_id->ident;
3159 if (EMPTYSTR(source_identity->address) || EMPTYSTR(result_identity->address))
3160 return PEP_ILLEGAL_VALUE; // something went badly wrong
3162 if (strcasecmp(source_identity->address, result_identity->address) == 0) {
3163 status = reconcile_identity(source_identity, result_identity);
3164 if (status != PEP_STATUS_OK)
3167 curr_src_id = curr_src_id->next;
3169 curr_id = curr_id->next;
3174 static PEP_STATUS reconcile_sent_and_recv_info(message* src, message* inner_message) {
3175 if (!src || !inner_message)
3176 return PEP_ILLEGAL_VALUE;
3178 if (!inner_message->sent)
3179 inner_message->sent = timestamp_dup(src->sent);
3181 // This will never be set otherwise, since it's a transport header on the outside
3182 inner_message->recv = timestamp_dup(src->recv);
3184 return PEP_STATUS_OK;
3187 static PEP_STATUS reconcile_src_and_inner_messages(message* src,
3188 message* inner_message) {
3190 PEP_STATUS status = PEP_STATUS_OK;
3192 if (strcasecmp(src->from->address, inner_message->from->address) == 0)
3193 status = reconcile_identity(src->from, inner_message->from);
3195 if (status == PEP_STATUS_OK && inner_message->to)
3196 status = reconcile_identity_lists(src->to, inner_message->to);
3198 if (status == PEP_STATUS_OK && inner_message->cc)
3199 status = reconcile_identity_lists(src->cc, inner_message->cc);
3201 if (status == PEP_STATUS_OK && inner_message->bcc)
3202 status = reconcile_identity_lists(src->bcc, inner_message->bcc);
3204 if (status == PEP_STATUS_OK)
3205 status = reconcile_sent_and_recv_info(src, inner_message);
3208 // FIXME - are there any flags or anything else we need to be sure are carried?
3211 static bool is_trusted_own_priv_fpr(PEP_SESSION session,
3216 bool retval = false;
3217 if (!EMPTYSTR(fpr)) {
3218 pEp_identity* test_identity = new_identity(NULL, fpr, own_id, NULL);
3219 if (test_identity) {
3220 PEP_STATUS status = get_trust(session, test_identity);
3221 if (status == PEP_STATUS_OK) {
3222 if (test_identity->comm_type & PEP_ct_confirmed) {
3223 bool has_priv = false;
3224 status = contains_priv_key(session, fpr, &has_priv);
3225 if (status == PEP_STATUS_OK && has_priv)
3229 free(test_identity);
3235 static bool reject_fpr(PEP_SESSION session, const char* fpr) {
3238 PEP_STATUS status = key_revoked(session, fpr, &reject);
3241 status = key_expired(session, fpr, time(NULL), &reject);
3243 timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
3244 status = renew_key(session, fpr, ts);
3246 if (status == PEP_STATUS_OK)
3253 static char* seek_good_trusted_private_fpr(PEP_SESSION session, char* own_id,
3254 stringlist_t* keylist) {
3255 if (!own_id || !keylist)
3258 stringlist_t* kl_curr = keylist;
3260 char* fpr = kl_curr->value;
3262 if (is_trusted_own_priv_fpr(session, own_id, fpr)) {
3263 if (!reject_fpr(session, fpr))
3267 kl_curr = kl_curr->next;
3270 char* target_own_fpr = NULL;
3273 PEP_STATUS status = get_user_default_key(session, own_id,
3276 if (status == PEP_STATUS_OK && !EMPTYSTR(target_own_fpr)) {
3277 if (is_trusted_own_priv_fpr(session, own_id, target_own_fpr)) {
3278 if (!reject_fpr(session, target_own_fpr))
3279 return target_own_fpr;
3283 // TODO: We can also go through all of the other available fprs for the
3284 // own identity, but then I submit this function requires a little refactoring
3289 static bool import_header_keys(PEP_SESSION session, message* src) {
3290 stringpair_list_t* header_keys = stringpair_list_find(src->opt_fields, "Autocrypt");
3291 if (!header_keys || !header_keys->value)
3293 const char* value = header_keys->value->value;
3296 const char* start_key = strstr(value, "keydata=");
3299 start_key += 8; // length of "keydata="
3300 int length = strlen(start_key);
3301 bloblist_t* the_key = base64_str_to_binary_blob(start_key, length);
3304 PEP_STATUS status = import_key(session, the_key->value, the_key->size, NULL);
3305 free_bloblist(the_key);
3306 if (status == PEP_STATUS_OK || status == PEP_KEY_IMPORTED)
3311 PEP_STATUS check_for_own_revoked_key(
3312 PEP_SESSION session,
3313 stringlist_t* keylist,
3314 stringpair_list_t** revoked_fpr_pairs
3317 if (!session || !revoked_fpr_pairs)
3318 return PEP_ILLEGAL_VALUE;
3320 *revoked_fpr_pairs = NULL;
3322 PEP_STATUS status = PEP_STATUS_OK;
3323 stringpair_list_t* _the_list = new_stringpair_list(NULL);
3325 stringlist_t* _k = keylist;
3326 for ( ; _k; _k = _k->next) {
3328 if (EMPTYSTR(_k->value))
3329 continue; // Maybe the right thing to do is choke.
3330 // But we can have NULL-valued empty list heads.
3332 const char* recip_fpr = _k->value;
3333 char* replace_fpr = NULL;
3334 uint64_t revoke_date = 0;
3335 status = get_replacement_fpr(session,
3340 bool own_key = false;
3343 case PEP_CANNOT_FIND_IDENTITY:
3344 status = PEP_STATUS_OK;
3348 status = is_own_key(session, recip_fpr, &own_key);
3350 if (status != PEP_STATUS_OK) {
3356 stringpair_list_add(_the_list, new_stringpair(recip_fpr, replace_fpr));
3366 if (_the_list && _the_list->value) {
3367 *revoked_fpr_pairs = _the_list;
3372 free_stringpair_list(_the_list);
3377 static bool _have_extrakeys(stringlist_t *keylist)
3381 && keylist->value[0];
3384 static PEP_STATUS _decrypt_message(
3385 PEP_SESSION session,
3388 stringlist_t **keylist,
3390 PEP_decrypt_flags_t *flags,
3391 identity_list **private_il
3401 if (!(session && src && dst && keylist && rating && flags))
3402 return PEP_ILLEGAL_VALUE;
3404 /*** Begin init ***/
3405 PEP_STATUS status = PEP_STATUS_OK;
3406 PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
3407 PEP_STATUS _decrypt_in_pieces_status = PEP_CANNOT_DECRYPT_UNKNOWN;
3408 message* msg = NULL;
3409 message* calculated_src = src;
3410 message* reset_msg = NULL;
3416 stringlist_t *_keylist = NULL;
3417 bool is_pEp_msg = is_a_pEpmessage(src);
3418 bool myself_read_only = (src->dir == PEP_dir_incoming);
3419 unsigned int major_ver = 0;
3420 unsigned int minor_ver = 0;
3423 bool reencrypt = ((*flags & PEP_decrypt_flag_untrusted_server) &&
3424 (_have_extrakeys(*keylist) || session->unencrypted_subject));
3426 // We own this pointer, and we take control of *keylist if reencrypting.
3427 stringlist_t* extra = NULL;
3433 *rating = PEP_rating_undefined;
3438 // Ok, before we do anything, if it's a pEp message, regardless of whether it's
3439 // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
3441 if (src->from && !(is_me(session, src->from))) {
3443 pEp_identity* tmp_from = src->from;
3445 // Ensure there's a user id
3446 if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
3447 status = update_identity(session, tmp_from);
3448 if (status == PEP_CANNOT_FIND_IDENTITY) {
3449 tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
3450 if (!tmp_from->user_id)
3451 return PEP_OUT_OF_MEMORY;
3452 snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
3453 "TOFU_%s", tmp_from->address);
3454 status = PEP_STATUS_OK;
3457 if (status == PEP_STATUS_OK) {
3458 // Now set user as PEP (may also create an identity if none existed yet)
3459 status = set_as_pEp_user(session, tmp_from);
3463 // We really need key used in signing to do anything further on the pEp comm_type.
3464 // So we can't adjust the rating of the sender just yet.
3466 /*** Begin Import any attached public keys and update identities accordingly ***/
3467 // Private key in unencrypted mail are ignored -> NULL
3469 // This import is from the outermost message.
3470 // We don't do this for PGP_mime.
3471 bool imported_keys = false;
3472 PEP_cryptotech enc_type = determine_encryption_format(src);
3473 if (enc_type != PEP_crypt_OpenPGP || !(src->enc_format == PEP_enc_PGP_MIME || src->enc_format == PEP_enc_PGP_MIME_Outlook1))
3474 imported_keys = import_attached_keys(session, src, NULL);
3476 import_header_keys(session, src);
3478 // FIXME: is this really necessary here?
3480 // if (!is_me(session, src->from))
3481 // status = update_identity(session, src->from);
3483 // status = _myself(session, src->from, false, false, myself_read_only);
3485 // // We absolutely should NOT be bailing here unless it's a serious error
3486 // if (status == PEP_OUT_OF_MEMORY)
3490 /*** End Import any attached public keys and update identities accordingly ***/
3492 /*** Begin get detached signatures that are attached to the encrypted message ***/
3493 // Get detached signature, if any
3494 bloblist_t* detached_sig = NULL;
3495 char* dsig_text = NULL;
3496 size_t dsig_size = 0;
3497 status = _get_detached_signature(src, &detached_sig);
3499 dsig_text = detached_sig->value;
3500 dsig_size = detached_sig->size;
3502 /*** End get detached signatures that are attached to the encrypted message ***/
3504 /*** Determine encryption format ***/
3505 PEP_cryptotech crypto = determine_encryption_format(src);
3507 // Check for and deal with unencrypted messages
3508 if (src->enc_format == PEP_enc_none) {
3510 *rating = PEP_rating_unencrypted;
3512 // We remove these from the outermost source message
3513 // if (imported_keys)
3514 // remove_attached_keys(src);
3516 pull_up_attached_main_msg(src);
3518 return PEP_UNENCRYPTED;
3521 status = get_crypto_text(src, &ctext, &csize);
3522 if (status != PEP_STATUS_OK)
3525 /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
3526 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
3527 csize, dsig_text, dsig_size,
3528 &ptext, &psize, &_keylist,
3531 if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
3534 decrypt_status = status;
3536 bool imported_private_key_address = false;
3537 bool has_inner = false;
3540 /* we got a plaintext from decryption */
3541 switch (src->enc_format) {
3543 case PEP_enc_PGP_MIME:
3544 case PEP_enc_PGP_MIME_Outlook1:
3546 status = _mime_decode_message_internal(ptext, psize, &msg, &has_inner);
3547 if (status != PEP_STATUS_OK)
3550 /* Ensure messages whose maintext is in the attachments
3551 move main text into message struct longmsg et al */
3552 /* KG: This IS a src modification of old - we're adding to it
3553 w/ memhole subject, but the question is whether or not
3554 this is OK overall... */
3555 pull_up_attached_main_msg(msg);
3556 if (msg->shortmsg) {
3557 free(src->shortmsg);
3558 src->shortmsg = strdup(msg->shortmsg);
3561 // check for private key in decrypted message attachment while importing
3562 // N.B. Apparently, we always import private keys into the keyring; however,
3563 // we do NOT always allow those to be used for encryption. THAT is controlled
3564 // by setting it as an own identity associated with the key in the DB.
3566 // We are importing from the decrypted outermost message now.
3568 status = import_priv_keys_from_decrypted_msg(session, msg,
3570 &imported_private_key_address,
3572 if (status != PEP_STATUS_OK)
3575 /* if decrypted, but not verified... */
3576 if (decrypt_status == PEP_DECRYPTED) {
3579 status = verify_decrypted(session,
3588 case PEP_enc_inline:
3589 status = PEP_STATUS_OK;
3591 _decrypt_in_pieces_status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
3593 switch (_decrypt_in_pieces_status) {
3595 case PEP_DECRYPTED_AND_VERIFIED:
3596 if (decrypt_status <= PEP_DECRYPTED_AND_VERIFIED)
3597 decrypt_status = MIN(decrypt_status, _decrypt_in_pieces_status);
3601 case PEP_OUT_OF_MEMORY:
3604 decrypt_status = _decrypt_in_pieces_status;
3609 // BUG: must implement more
3613 if (status == PEP_OUT_OF_MEMORY)
3616 if (status != PEP_STATUS_OK)
3619 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3620 char* wrap_info = NULL;
3623 status = unencapsulate_hidden_fields(src, msg, &wrap_info);
3624 if (status == PEP_OUT_OF_MEMORY)
3626 if (status != PEP_STATUS_OK)
3630 // bool is_transport_wrapper = false;
3633 // FIXME: replace with enums, check status
3634 if (has_inner || wrap_info) { // Given that only wrap_info OUTER happens as of the end of wrap_info use, we don't need to strcmp it
3635 // if (strcmp(wrap_info, "OUTER") == 0) {
3636 // // this only occurs in with a direct outer wrapper
3637 // // where the actual content is in the inner wrapper
3638 message* inner_message = NULL;
3640 // For a wrapped message, this is ALWAYS the second attachment; the
3644 // |----- text/plain
3645 // |----- message/rfc822
3648 // We leave this in below, but once we're rid of 2.0 format,
3649 // we can dispense with the loop, as has_inner -> 1st message struct attachment is message/rfc822
3652 bloblist_t* message_blob = msg->attachments;
3654 if (msg->attachments) {
3655 message_blob = msg->attachments;
3656 if (!has_inner && strcmp(message_blob->mime_type, "message/rfc822") != 0
3657 && strcmp(message_blob->mime_type, "text/rfc822") != 0)
3658 message_blob = NULL;
3661 if (!message_blob) {
3662 bloblist_t* actual_message = msg->attachments;
3664 while (actual_message) {
3665 char* mime_type = actual_message->mime_type;
3668 // libetpan appears to change the mime_type on this one.
3670 if (strcmp("message/rfc822", mime_type) == 0 ||
3671 strcmp("text/rfc822", mime_type) == 0) {
3672 message_blob = actual_message;
3676 actual_message = actual_message->next;
3680 status = mime_decode_message(message_blob->value,
3683 if (status != PEP_STATUS_OK)
3686 if (inner_message) {
3687 is_pEp_msg = is_a_pEpmessage(inner_message);
3689 // Though this will strip any message info on the
3690 // attachment, this is safe, as we do not
3691 // produce more than one attachment-as-message,
3692 // and those are the only ones with such info.
3693 // Since we capture the information, this is ok.
3695 inner_message->enc_format = src->enc_format;
3697 const stringpair_list_t* pEp_protocol_version = NULL;
3698 pEp_protocol_version = stringpair_list_find(inner_message->opt_fields, "X-pEp-Version");
3700 if (pEp_protocol_version && pEp_protocol_version->value)
3701 pEp_version_major_minor(pEp_protocol_version->value->value, &major_ver, &minor_ver);
3703 // Sort out pEp user status and version number based on INNER message.
3705 bool is_inner = false;
3706 bool is_key_reset = false;
3708 // Deal with plaintext modification in 1.0 and 2.0 messages
3709 status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);
3711 if (status == PEP_OUT_OF_MEMORY)
3713 if (status != PEP_STATUS_OK)
3716 if (major_ver > 2 || (major_ver == 2 && minor_ver > 0)) {
3717 stringpair_list_t* searched = stringpair_list_find(inner_message->opt_fields, "X-pEp-Sender-FPR");
3718 inner_message->_sender_fpr = ((searched && searched->value && searched->value->value) ? strdup(searched->value->value) : NULL);
3719 searched = stringpair_list_find(inner_message->opt_fields, X_PEP_MSG_WRAP_KEY);
3720 if (searched && searched->value && searched->value->value) {
3721 is_inner = (strcmp(searched->value->value, "INNER") == 0);
3723 is_key_reset = (strcmp(searched->value->value, "KEY_RESET") == 0);
3724 if (is_inner || is_key_reset)
3725 inner_message->opt_fields = stringpair_list_delete_by_key(inner_message->opt_fields, X_PEP_MSG_WRAP_KEY);
3729 is_inner = (strcmp(wrap_info, "INNER") == 0);
3731 is_key_reset = (strcmp(wrap_info, "KEY_RESET") == 0);
3736 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3737 status = receive_key_reset(session,
3739 if (status != PEP_STATUS_OK) {
3740 free_message(inner_message);
3743 *flags |= PEP_decrypt_flag_consume;
3746 else if (is_inner) {
3748 // check for private key in decrypted message attachment while importing
3749 // N.B. Apparently, we always import private keys into the keyring; however,
3750 // we do NOT always allow those to be used for encryption. THAT is controlled
3751 // by setting it as an own identity associated with the key in the DB.
3753 // If we have a message 2.0 message, we are ONLY going to be ok with keys
3754 // we imported from THIS part of the message.
3755 imported_private_key_address = false;
3759 // import keys from decrypted INNER source
3760 status = import_priv_keys_from_decrypted_msg(session, inner_message,
3762 &imported_private_key_address,
3764 if (status != PEP_STATUS_OK)
3767 // THIS is our message
3768 // Now, let's make sure we've copied in
3769 // any information sent in by the app if
3771 reconcile_src_and_inner_messages(src, inner_message);
3774 // FIXME: free msg, but check references
3775 //src = msg = inner_message;
3776 calculated_src = msg = inner_message;
3779 else { // should never happen
3780 status = PEP_UNKNOWN_ERROR;
3781 free_message(inner_message);
3784 inner_message->enc_format = PEP_enc_none;
3786 else { // forwarded message, leave it alone
3787 free_message(inner_message);
3789 } // end if (message_blob)
3791 // else if (strcmp(wrap_info, "TRANSPORT") == 0) {
3792 // // FIXME: this gets even messier.
3793 // // (TBI in ENGINE-278)
3795 // else {} // shouldn't be anything to be done here
3797 } // end if (has_inner || wrap_info)
3800 } // this we do if this isn't an inner message
3802 pEp_identity* cs_from = calculated_src->from;
3803 if (cs_from && !EMPTYSTR(cs_from->address)) {
3804 if (!is_me(session, cs_from)) {
3805 status = update_identity(session, cs_from);
3806 if (status == PEP_CANNOT_FIND_IDENTITY) {
3807 cs_from->user_id = calloc(1, strlen(cs_from->address) + 6);
3808 if (!cs_from->user_id)
3809 return PEP_OUT_OF_MEMORY;
3810 snprintf(cs_from->user_id, strlen(cs_from->address) + 6,
3811 "TOFU_%s", cs_from->address);
3812 status = PEP_STATUS_OK;
3816 status = _myself(session, cs_from, false, false, myself_read_only);
3818 } // end if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
3820 *rating = decrypt_rating(decrypt_status);
3822 // Ok, so if it was signed and it's all verified, we can update
3823 // eligible signer comm_types to PEP_ct_pEp_*
3824 // This also sets and upgrades pEp version
3825 if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pEp_msg && calculated_src->from)
3826 status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist, major_ver, minor_ver);
3828 /* Ok, now we have a keylist used for decryption/verification.
3829 now we need to update the message rating with the
3830 sender and recipients in mind */
3831 status = amend_rating_according_to_sender_and_recipients(session,
3832 rating, calculated_src->from, _keylist);
3834 if (status != PEP_STATUS_OK)
3837 /* We decrypted ok, hallelujah. */
3838 msg->enc_format = PEP_enc_none;
3841 // We did not get a plaintext out of the decryption process.
3842 // Abort and return error.
3843 *rating = decrypt_rating(decrypt_status);
3848 Ok, at this point, we know we have a reliably decrypted message.
3849 Prepare the output message for return.
3852 // 1. Check to see if this message is to us and contains an own key imported
3853 // from own trusted message
3854 if (*rating >= PEP_rating_trusted && imported_private_key_address) {
3856 if (msg && msg->to && msg->to->ident) {
3857 // This will only happen rarely, so we can do this.
3858 PEP_STATUS _tmp_status = PEP_STATUS_OK;
3860 if (!is_me(session, msg->to->ident))
3861 _tmp_status = update_identity(session, msg->to->ident);
3863 if (_tmp_status == PEP_STATUS_OK && is_me(session, msg->to->ident)) {
3865 *flags |= PEP_decrypt_flag_own_private_key;
3870 // 2. Clean up message and prepare for return
3872 if (_keylist && _keylist->next)
3873 dedup_stringlist(_keylist->next);
3875 /* add pEp-related status flags to header */
3876 decorate_message(msg, *rating, _keylist, false, false);
3878 // Maybe unnecessary
3879 // if (imported_keys)
3880 // remove_attached_keys(msg);
3882 if (calculated_src->id && calculated_src != msg) {
3883 msg->id = strdup(calculated_src->id);
3885 if (msg->id == NULL)
3888 } // End prepare output message for return
3890 // 3. Check to see if the sender used any of our revoked keys
3891 stringpair_list_t* revoke_replace_pairs = NULL;
3892 status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
3894 //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN
3895 if (status != PEP_STATUS_OK) {
3896 // This should really never choke unless the DB is broken.
3897 status = PEP_UNKNOWN_DB_ERROR;
3902 stringpair_list_t* curr_pair_node;
3903 stringpair_t* curr_pair;
3905 for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
3906 curr_pair = curr_pair_node->value;
3909 continue; // Again, shouldn't occur
3911 if (curr_pair->key && curr_pair->value) {
3912 status = create_standalone_key_reset_message(session,
3918 // If we can't find the identity, this is someone we've never mailed, so we just
3919 // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
3920 if (status != PEP_CANNOT_FIND_IDENTITY) {
3921 if (status != PEP_STATUS_OK)
3925 status = PEP_OUT_OF_MEMORY;
3928 // insert into queue
3929 if (session->messageToSend)
3930 status = session->messageToSend(reset_msg);
3932 status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
3935 if (status == PEP_STATUS_OK) {
3936 // Put into notified DB
3937 status = set_reset_contact_notified(session, curr_pair->key, msg->from->user_id);
3938 if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
3942 // According to Volker, this would only be a fatal error, so...
3943 free_message(reset_msg); // ??
3944 reset_msg = NULL; // ??
3953 bool reenc_signer_key_is_own_key = false; // only matters for reencrypted messages
3955 // 4. Reencrypt if necessary
3956 bool has_extra_keys = _have_extrakeys(extra);
3957 if (reencrypt && session->unencrypted_subject && !has_extra_keys) {
3958 if (src->shortmsg && msg->shortmsg) {
3959 if (strcmp(src->shortmsg, msg->shortmsg) == 0)
3962 else if (src->shortmsg == NULL && msg->shortmsg == NULL)
3967 if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3968 const char* sfpr = NULL;
3970 sfpr = _keylist->value;
3972 if (sfpr && decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
3973 own_key_is_listed(session, sfpr, &reenc_signer_key_is_own_key);
3975 if (!reenc_signer_key_is_own_key) {
3976 message* reencrypt_msg = NULL;
3977 PEP_STATUS reencrypt_status = PEP_CANNOT_REENCRYPT;
3978 char* own_id = NULL;
3979 status = get_default_own_userid(session, &own_id);
3981 char* target_own_fpr = seek_good_trusted_private_fpr(session,
3984 if (target_own_fpr) {
3985 pEp_identity* target_id = new_identity(NULL, target_own_fpr,
3988 reencrypt_status = encrypt_message_for_self(session, target_id, msg,
3989 extra, &reencrypt_msg, PEP_enc_PGP_MIME,
3990 PEP_encrypt_reencrypt);
3991 if (reencrypt_status != PEP_STATUS_OK)
3992 reencrypt_status = PEP_CANNOT_REENCRYPT;
3994 free_identity(target_id);
3996 free(target_own_fpr);
4000 free_stringlist(extra); // This was an input variable for us. Keylist is overwritten above.
4002 if (reencrypt_status != PEP_CANNOT_REENCRYPT && reencrypt_msg) {
4003 message_transfer(src, reencrypt_msg);
4004 *flags |= PEP_decrypt_flag_src_modified;
4005 free_message(reencrypt_msg);
4008 decrypt_status = PEP_CANNOT_REENCRYPT;
4011 else if (!has_extra_keys && session->unencrypted_subject) {
4012 free(src->shortmsg);
4013 src->shortmsg = strdup(msg->shortmsg);
4014 assert(src->shortmsg);
4017 *flags |= PEP_decrypt_flag_src_modified;
4022 // 5. Set up return values
4024 *keylist = _keylist;
4026 // Double-check for message 2.1: (note, we don't do this for already-reencrypted-messages)
4027 if (!(reencrypt && reenc_signer_key_is_own_key)) {
4028 if (major_ver > 2 || (major_ver == 2 && minor_ver > 0)) {
4029 if (EMPTYSTR((*dst)->_sender_fpr) ||
4030 (!EMPTYSTR(_keylist->value) && (strcasecmp((*dst)->_sender_fpr, _keylist->value) != 0))) {
4031 if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
4032 decrypt_status = PEP_DECRYPTED;
4033 if (*rating > PEP_rating_unreliable)
4034 *rating = PEP_rating_unreliable;
4039 if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
4040 return PEP_STATUS_OK;
4042 return decrypt_status;
4045 status = PEP_OUT_OF_MEMORY;
4050 free_message(reset_msg);
4051 free_stringlist(_keylist);
4056 DYNAMIC_API PEP_STATUS decrypt_message(
4057 PEP_SESSION session,
4060 stringlist_t **keylist,
4062 PEP_decrypt_flags_t *flags
4072 if (!(session && src && dst && keylist && rating && flags))
4073 return PEP_ILLEGAL_VALUE;
4075 if (!(*flags & PEP_decrypt_flag_untrusted_server))
4077 //*keylist = NULL; // NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!!!! This fucks up reencryption
4078 PEP_STATUS status = _decrypt_message(session, src, dst, keylist, rating, flags, NULL);
4080 message *msg = *dst ? *dst : src;
4082 if (session->inject_sync_event && msg && msg->from &&
4083 !(*flags & PEP_decrypt_flag_dont_trigger_sync)) {
4086 char *sender_fpr = NULL;
4087 PEP_STATUS tmpstatus = base_extract_message(session, msg, &size, &data, &sender_fpr);
4088 if (!tmpstatus && size && data) {
4090 signal_Sync_message(session, *rating, data, size, msg->from, sender_fpr);
4091 // FIXME: this must be changed to sender_fpr
4093 signal_Sync_message(session, *rating, data, size, msg->from, (*keylist)->value);
4099 // Removed for now - partial fix in ENGINE-647, but we have sync issues. Need to
4100 // fix testing issue.
4102 // if (status == PEP_UNENCRYPTED || status == PEP_DECRYPTED_AND_VERIFIED) {
4103 // if (session->inject_sync_event && msg && msg->from &&
4104 // !(*flags & PEP_decrypt_flag_dont_trigger_sync)) {
4106 // const char *data;
4107 // char *sender_fpr = NULL;
4109 // PEP_STATUS tmpstatus = base_extract_message(session, msg, &size, &data, &sender_fpr);
4110 // if (!tmpstatus && size && data) {
4111 // bool use_extracted_fpr = (status != PEP_DECRYPTED_AND_VERIFIED) ||
4112 // !dst || !(*dst) || !((*dst)->_sender_fpr);
4114 // const char* event_sender_fpr = (use_extracted_fpr ? sender_fpr : (*dst)->_sender_fpr);
4115 // // FIXME - I don't think this is OK anymore. We either have a signed beacon or a properly encrypted/signed 2.1 message
4116 // // if ((!event_sender_fpr) && *keylist)
4117 // // event_sender_fpr = (*keylist)->value;
4118 // if (event_sender_fpr)
4119 // signal_Sync_message(session, *rating, data, size, msg->from, event_sender_fpr);
4121 // free(sender_fpr);
4127 DYNAMIC_API PEP_STATUS own_message_private_key_details(
4128 PEP_SESSION session,
4130 pEp_identity **ident
4137 if (!(session && msg && ident))
4138 return PEP_ILLEGAL_VALUE;
4140 message *dst = NULL;
4141 stringlist_t *keylist = NULL;
4143 PEP_decrypt_flags_t flags;
4147 identity_list *private_il = NULL;
4148 PEP_STATUS status = _decrypt_message(session, msg, &dst, &keylist, &rating, &flags, &private_il);
4150 free_stringlist(keylist);
4152 if (status == PEP_STATUS_OK &&
4153 flags & PEP_decrypt_flag_own_private_key &&
4156 *ident = identity_dup(private_il->ident);
4159 free_identity_list(private_il);
4164 // Note: if comm_type_determine is false, it generally means that
4165 // we were unable to get key information for anyone in the list,
4166 // likely because a key is missing.
4167 static void _max_comm_type_from_identity_list(
4168 identity_list *identities,
4169 PEP_SESSION session,
4170 PEP_comm_type *max_comm_type,
4171 bool *comm_type_determined
4175 for (il = identities; il != NULL; il = il->next)
4179 PEP_STATUS status = PEP_STATUS_OK;
4180 *max_comm_type = _get_comm_type(session, *max_comm_type,
4182 *comm_type_determined = true;
4184 bool is_blacklisted = false;
4185 if (il->ident->fpr && IS_PGP_CT(il->ident->comm_type)) {
4186 status = blacklist_is_listed(session, il->ident->fpr, &is_blacklisted);
4187 if (is_blacklisted) {
4188 bool user_default, ident_default, address_default;
4189 status = get_valid_pubkey(session, il->ident,
4190 &ident_default, &user_default,
4193 if (status != PEP_STATUS_OK || il->ident->fpr == NULL) {
4194 il->ident->comm_type = PEP_ct_key_not_found;
4195 if (*max_comm_type > PEP_ct_no_encryption)
4196 *max_comm_type = PEP_ct_no_encryption;
4201 // check for the return statuses which might not a representative
4202 // value in the comm_type
4203 if (status == PEP_ILLEGAL_VALUE || status == PEP_CANNOT_SET_PERSON ||
4204 status == PEP_CANNOT_FIND_IDENTITY) {
4205 // PEP_CANNOT_FIND_IDENTITY only comes back when we've really
4206 // got nothing from update_identity after applying the whole
4208 *max_comm_type = PEP_ct_no_encryption;
4209 *comm_type_determined = true;
4215 static void _max_comm_type_from_identity_list_preview(
4216 identity_list *identities,
4217 PEP_SESSION session,
4218 PEP_comm_type *max_comm_type
4222 for (il = identities; il != NULL; il = il->next)
4226 *max_comm_type = _get_comm_type_preview(session, *max_comm_type,
4232 DYNAMIC_API PEP_STATUS outgoing_message_rating(
4233 PEP_SESSION session,
4238 PEP_comm_type max_comm_type = PEP_ct_pEp;
4239 bool comm_type_determined = false;
4243 assert(msg->dir == PEP_dir_outgoing);
4246 if (!(session && msg && rating))
4247 return PEP_ILLEGAL_VALUE;
4249 if (msg->dir != PEP_dir_outgoing)
4250 return PEP_ILLEGAL_VALUE;
4252 *rating = PEP_rating_undefined;
4254 _max_comm_type_from_identity_list(msg->to, session,
4255 &max_comm_type, &comm_type_determined);
4257 _max_comm_type_from_identity_list(msg->cc, session,
4258 &max_comm_type, &comm_type_determined);
4260 _max_comm_type_from_identity_list(msg->bcc, session,
4261 &max_comm_type, &comm_type_determined);
4263 if (comm_type_determined == false) {
4264 // likely means there was a massive screwup with no sender or recipient
4266 *rating = PEP_rating_undefined;
4269 *rating = _MAX(_rating(max_comm_type), PEP_rating_unencrypted);
4271 return PEP_STATUS_OK;
4274 DYNAMIC_API PEP_STATUS outgoing_message_rating_preview(
4275 PEP_SESSION session,
4280 PEP_comm_type max_comm_type = PEP_ct_pEp;
4284 assert(msg->dir == PEP_dir_outgoing);
4287 if (!(session && msg && rating))
4288 return PEP_ILLEGAL_VALUE;
4290 if (msg->dir != PEP_dir_outgoing)
4291 return PEP_ILLEGAL_VALUE;
4293 *rating = PEP_rating_undefined;
4295 _max_comm_type_from_identity_list_preview(msg->to, session,
4298 _max_comm_type_from_identity_list_preview(msg->cc, session,
4301 _max_comm_type_from_identity_list_preview(msg->bcc, session,
4304 *rating = _MAX(_rating(max_comm_type), PEP_rating_unencrypted);
4306 return PEP_STATUS_OK;
4309 DYNAMIC_API PEP_STATUS identity_rating(
4310 PEP_SESSION session,
4311 pEp_identity *ident,
4315 PEP_STATUS status = PEP_STATUS_OK;
4321 if (!(session && ident && rating))
4322 return PEP_ILLEGAL_VALUE;
4324 *rating = PEP_rating_undefined;
4327 status = _myself(session, ident, false, true, true);
4329 status = update_identity(session, ident);
4331 bool is_blacklisted = false;
4333 if (ident->fpr && IS_PGP_CT(ident->comm_type)) {
4334 status = blacklist_is_listed(session, ident->fpr, &is_blacklisted);
4335 if (status != PEP_STATUS_OK) {
4336 return status; // DB ERROR
4338 if (is_blacklisted) {
4339 bool user_default, ident_default, address_default;
4340 status = get_valid_pubkey(session, ident,
4341 &ident_default, &user_default,
4344 if (status != PEP_STATUS_OK || ident->fpr == NULL) {
4345 ident->comm_type = PEP_ct_key_not_found;
4346 status = PEP_STATUS_OK;
4351 if (status == PEP_STATUS_OK)
4352 *rating = _rating(ident->comm_type);
4357 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
4359 PEP_STATUS status = PEP_STATUS_OK;
4363 return PEP_ILLEGAL_VALUE;
4365 if (cryptotech[tech].binary_path == NULL)
4368 status = cryptotech[tech].binary_path(path);
4374 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
4376 if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
4377 return PEP_color_no_color;
4379 if (rating < PEP_rating_undefined)
4380 return PEP_color_red;
4382 if (rating < PEP_rating_reliable)
4383 return PEP_color_no_color;
4385 if (rating < PEP_rating_trusted)
4386 return PEP_color_yellow;
4388 if (rating >= PEP_rating_trusted)
4389 return PEP_color_green;
4391 // this should never happen
4393 return PEP_color_no_color;
4396 /* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
4397 static short asciihex_to_num(char a) {
4398 short conv_num = -1;
4399 if (a >= 0x30 && a <= 0x39)
4400 conv_num = a - 0x30;
4402 // convert case, subtract offset, get number
4403 conv_num = ((a | 0x20) - 0x61) + 10;
4404 if (conv_num < 0xa || conv_num > 0xf)
4410 static char num_to_asciihex(short h) {
4411 if (h < 0 || h > 16)
4414 return (char)(h + 0x30);
4415 return (char)((h - 10) + 0x41); // for readability
4418 static char xor_hex_chars(char a, char b) {
4419 short a_num = asciihex_to_num(a);
4420 short b_num = asciihex_to_num(b);
4421 if (a_num < 0 || b_num < 0)
4423 short xor_num = a_num^b_num;
4424 return num_to_asciihex(xor_num);
4427 static const char* skip_separators(const char* current, const char* begin) {
4428 while (current >= begin) {
4429 /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
4430 char check_char = *current;
4431 switch (check_char) {
4449 PEP_STATUS check_for_zero_fpr(char* fpr) {
4450 PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
4454 status = PEP_STATUS_OK;
4464 DYNAMIC_API PEP_STATUS get_trustwords(
4465 PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
4466 const char* lang, char **words, size_t *wsize, bool full
4469 assert(session && id1 && id1->fpr && id2 && id2->fpr&& lang && words &&
4471 if (!(session && id1 && id1->fpr && id2 && id2->fpr&& lang && words &&
4473 return PEP_ILLEGAL_VALUE;
4475 return get_trustwords_for_fprs(session, id1->fpr, id2->fpr, lang, words,
4479 DYNAMIC_API PEP_STATUS get_trustwords_for_fprs(
4480 PEP_SESSION session, const char* fpr1, const char* fpr2,
4481 const char* lang, char **words, size_t *wsize, bool full
4484 assert(session && fpr1 && fpr2 && words && wsize);
4485 if (!(session && fpr1 && fpr2 && words && wsize))
4486 return PEP_ILLEGAL_VALUE;
4488 const int SHORT_NUM_TWORDS = 5;
4489 PEP_STATUS status = PEP_STATUS_OK;
4494 int fpr1_len = strlen(fpr1);
4495 int fpr2_len = strlen(fpr2);
4497 int max_len = (fpr1_len > fpr2_len ? fpr1_len : fpr2_len);
4499 char* XORed_fpr = (char*)(calloc(max_len + 1, 1));
4500 *(XORed_fpr + max_len) = '\0';
4501 char* result_curr = XORed_fpr + max_len - 1;
4502 const char* fpr1_curr = fpr1 + fpr1_len - 1;
4503 const char* fpr2_curr = fpr2 + fpr2_len - 1;
4505 while (fpr1 <= fpr1_curr && fpr2 <= fpr2_curr) {
4506 fpr1_curr = skip_separators(fpr1_curr, fpr1);
4507 fpr2_curr = skip_separators(fpr2_curr, fpr2);
4509 if (fpr1_curr < fpr1 || fpr2_curr < fpr2)
4512 char xor_hex = xor_hex_chars(*fpr1_curr, *fpr2_curr);
4513 if (xor_hex == '\0') {
4514 status = PEP_ILLEGAL_VALUE;
4518 *result_curr = xor_hex;
4519 result_curr--; fpr1_curr--; fpr2_curr--;
4522 const char* remainder_start = NULL;
4523 const char* remainder_curr = NULL;
4525 if (fpr1 <= fpr1_curr) {
4526 remainder_start = fpr1;
4527 remainder_curr = fpr1_curr;
4529 else if (fpr2 <= fpr2_curr) {
4530 remainder_start = fpr2;
4531 remainder_curr = fpr2_curr;
4533 if (remainder_curr) {
4534 while (remainder_start <= remainder_curr) {
4535 remainder_curr = skip_separators(remainder_curr, remainder_start);
4537 if (remainder_curr < remainder_start)
4540 char the_char = *remainder_curr;
4542 if (asciihex_to_num(the_char) < 0) {
4543 status = PEP_ILLEGAL_VALUE;
4547 *result_curr = the_char;
4555 if (result_curr > XORed_fpr) {
4556 char* tempstr = strdup(result_curr);
4558 XORed_fpr = tempstr;
4561 status = check_for_zero_fpr(XORed_fpr);
4563 if (status != PEP_STATUS_OK)
4566 size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
4568 char* the_words = NULL;
4569 size_t the_size = 0;
4571 status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
4572 if (status != PEP_STATUS_OK)
4578 status = PEP_STATUS_OK;
4589 DYNAMIC_API PEP_STATUS get_message_trustwords(
4590 PEP_SESSION session,
4592 stringlist_t *keylist,
4593 pEp_identity* received_by,
4594 const char* lang, char **words, bool full
4599 assert(received_by);
4600 assert(received_by->address);
4607 received_by->address &&
4610 return PEP_ILLEGAL_VALUE;
4612 pEp_identity* partner = NULL;
4614 PEP_STATUS status = PEP_STATUS_OK;
4618 // We want fingerprint of key that did sign the message
4620 if (keylist == NULL) {
4622 // Message is to be decrypted
4623 message *dst = NULL;
4624 stringlist_t *_keylist = keylist;
4626 PEP_decrypt_flags_t flags;
4627 status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
4629 if (status != PEP_STATUS_OK) {
4631 free_stringlist(_keylist);
4635 if (dst && dst->from && _keylist) {
4636 partner = identity_dup(dst->from);
4639 partner->fpr = strdup(_keylist->value);
4640 if (partner->fpr == NULL)
4641 status = PEP_OUT_OF_MEMORY;
4643 status = PEP_OUT_OF_MEMORY;
4646 status = PEP_UNKNOWN_ERROR;
4650 free_stringlist(_keylist);
4654 // Message already decrypted
4655 if (keylist->value) {
4656 partner = identity_dup(msg->from);
4659 partner->fpr = strdup(keylist->value);
4660 if (partner->fpr == NULL)
4661 status = PEP_OUT_OF_MEMORY;
4663 status = PEP_OUT_OF_MEMORY;
4666 status = PEP_ILLEGAL_VALUE;
4670 if (status != PEP_STATUS_OK) {
4671 free_identity(partner);
4675 // Find own identity corresponding to given account address.
4676 // In that case we want default key attached to own identity
4677 pEp_identity *stored_identity = NULL;
4679 char* own_id = NULL;
4680 status = get_default_own_userid(session, &own_id);
4682 if (!(status == PEP_STATUS_OK && own_id)) {
4684 return PEP_CANNOT_FIND_IDENTITY;
4687 status = get_identity(session,
4688 received_by->address,
4694 if (status != PEP_STATUS_OK) {
4695 free_identity(stored_identity);
4699 // get the trustwords
4701 status = get_trustwords(session,
4702 partner, received_by,
4703 lang, words, &wsize, full);
4708 static PEP_rating string_to_rating(const char * rating)
4711 return PEP_rating_undefined;
4712 if (strcmp(rating, "cannot_decrypt") == 0)
4713 return PEP_rating_cannot_decrypt;
4714 if (strcmp(rating, "have_no_key") == 0)
4715 return PEP_rating_have_no_key;
4716 if (strcmp(rating, "unencrypted") == 0)
4717 return PEP_rating_unencrypted;
4718 if (strcmp(rating, "unencrypted_for_some") == 0)
4719 return PEP_rating_undefined; // don't use this any more
4720 if (strcmp(rating, "unreliable") == 0)
4721 return PEP_rating_unreliable;
4722 if (strcmp(rating, "reliable") == 0)
4723 return PEP_rating_reliable;
4724 if (strcmp(rating, "trusted") == 0)
4725 return PEP_rating_trusted;
4726 if (strcmp(rating, "trusted_and_anonymized") == 0)
4727 return PEP_rating_trusted_and_anonymized;
4728 if (strcmp(rating, "fully_anonymous") == 0)
4729 return PEP_rating_fully_anonymous;
4730 if (strcmp(rating, "mistrust") == 0)
4731 return PEP_rating_mistrust;
4732 if (strcmp(rating, "b0rken") == 0)
4733 return PEP_rating_b0rken;
4734 if (strcmp(rating, "under_attack") == 0)
4735 return PEP_rating_under_attack;
4736 return PEP_rating_undefined;
4739 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
4741 if (skeylist == NULL || keylist == NULL)
4742 return PEP_ILLEGAL_VALUE;
4744 stringlist_t *rkeylist = NULL;
4745 stringlist_t *_kcurr = NULL;
4746 const char * fpr_begin = skeylist;
4747 const char * fpr_end = NULL;
4750 fpr_end = strstr(fpr_begin, ",");
4752 char * fpr = strndup(
4754 (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
4759 _kcurr = stringlist_add(_kcurr, fpr);
4760 if (_kcurr == NULL) {
4765 if (rkeylist == NULL)
4768 fpr_begin = fpr_end ? fpr_end + 1 : NULL;
4770 } while (fpr_begin);
4772 *keylist = rkeylist;
4773 return PEP_STATUS_OK;
4776 free_stringlist(rkeylist);
4777 return PEP_OUT_OF_MEMORY;
4780 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
4781 PEP_SESSION session,
4783 stringlist_t *x_keylist,
4784 PEP_rating x_enc_status,
4788 PEP_STATUS status = PEP_STATUS_OK;
4789 stringlist_t *_keylist = x_keylist;
4790 bool must_free_keylist = false;
4797 if (!(session && msg && rating))
4798 return PEP_ILLEGAL_VALUE;
4800 *rating = PEP_rating_undefined;
4802 if (x_enc_status == PEP_rating_undefined){
4803 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
4804 if (strcasecmp(i->value->key, "X-EncStatus") == 0){
4805 x_enc_status = string_to_rating(i->value->value);
4809 return PEP_ILLEGAL_VALUE;
4814 _rating = x_enc_status;
4816 if (_keylist == NULL){
4817 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
4818 if (strcasecmp(i->value->key, "X-KeyList") == 0){
4819 status = string_to_keylist(i->value->value, &_keylist);
4820 if (status != PEP_STATUS_OK)
4822 must_free_keylist = true;
4827 // there was no rcpt fpr, it could be an unencrypted mail
4828 if(_rating == PEP_rating_unencrypted) {
4830 return PEP_STATUS_OK;
4833 return PEP_ILLEGAL_VALUE;
4837 if (!is_me(session, msg->from))
4838 status = update_identity(session, msg->from);
4840 status = _myself(session, msg->from, false, false, true);
4843 case PEP_KEY_NOT_FOUND:
4844 case PEP_KEY_UNSUITABLE:
4845 case PEP_KEY_BLACKLISTED:
4846 case PEP_CANNOT_FIND_IDENTITY:
4847 case PEP_CANNOT_FIND_ALIAS:
4848 status = PEP_STATUS_OK;
4855 status = amend_rating_according_to_sender_and_recipients(session, &_rating,
4856 msg->from, _keylist);
4857 if (status == PEP_STATUS_OK)
4861 if (must_free_keylist)
4862 free_stringlist(_keylist);
4867 DYNAMIC_API PEP_STATUS get_key_rating_for_user(
4868 PEP_SESSION session,
4869 const char *user_id,
4874 assert(session && user_id && user_id[0] && fpr && fpr[0] && rating);
4875 if (!(session && user_id && user_id[0] && fpr && fpr[0] && rating))
4876 return PEP_ILLEGAL_VALUE;
4878 *rating = PEP_rating_undefined;
4880 pEp_identity *ident = new_identity(NULL, fpr, user_id, NULL);
4882 return PEP_OUT_OF_MEMORY;
4884 PEP_STATUS status = get_trust(session, ident);
4888 if (!ident->comm_type) {
4889 status = PEP_RECORD_NOT_FOUND;
4893 *rating = _rating(ident->comm_type);
4896 free_identity(ident);