1 // This file is under GNU General Public License 3.0
4 #include "pEp_internal.h"
5 #include "message_api.h"
17 #define _MIN(A, B) ((B) > (A) ? (A) : (B))
20 #define _MAX(A, B) ((B) > (A) ? (B) : (A))
23 static char* _get_resource_ptr_noown(char* uri) {
24 char* uri_delim = strstr(uri, "://");
31 static bool is_file_uri(char* str) {
32 return(strncmp(str, "file://", 7) == 0);
35 static bool is_cid_uri(const char* str) {
36 return(strncmp(str, "cid://", 6) == 0);
39 static bool string_equality(const char *s1, const char *s2)
41 if (s1 == NULL || s2 == NULL)
46 return strcmp(s1, s2) == 0;
49 static bool is_mime_type(const bloblist_t *bl, const char *mt)
53 return bl && string_equality(bl->mime_type, mt);
57 // This function presumes the file ending is a proper substring of the
58 // filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
59 // return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
60 // return false. This is desired behaviour.
62 static bool is_fileending(const bloblist_t *bl, const char *fe)
66 if (bl == NULL || bl->filename == NULL || fe == NULL || is_cid_uri(bl->filename))
69 assert(bl && bl->filename);
71 size_t fe_len = strlen(fe);
72 size_t fn_len = strlen(bl->filename);
77 assert(fn_len > fe_len);
79 return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
82 void add_opt_field(message *msg, const char *name, const char *value)
84 assert(msg && name && value);
86 if (msg && name && value) {
87 stringpair_t *pair = new_stringpair(name, value);
91 stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
94 free_stringpair(pair);
98 if (msg->opt_fields == NULL)
99 msg->opt_fields = field;
103 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
106 assert(strcmp(shortmsg, "pEp") != 0);
108 if (!shortmsg || strcmp(shortmsg, "pEp") == 0) {
113 char *result = strdup(longmsg);
122 const char * const subject = "Subject: ";
123 const size_t SUBJ_LEN = 9;
124 const char * const newlines = "\n\n";
125 const size_t NL_LEN = 2;
127 const size_t bufsize = SUBJ_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
128 char * ptext = calloc(1, bufsize);
133 strlcpy(ptext, subject, bufsize);
134 strlcat(ptext, shortmsg, bufsize);
135 strlcat(ptext, newlines, bufsize);
136 strlcat(ptext, longmsg, bufsize);
141 static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
143 char *_shortmsg = NULL;
144 char *_longmsg = NULL;
150 if (src == NULL || shortmsg == NULL || longmsg == NULL)
156 if (strncasecmp(src, "subject: ", 9) == 0) {
157 char *line_end = strchr(src, '\n');
159 if (line_end == NULL) {
160 _shortmsg = strdup(src + 9);
162 if (_shortmsg == NULL)
167 size_t n = line_end - src;
169 if (*(line_end - 1) == '\r')
170 _shortmsg = strndup(src + 9, n - 10);
172 _shortmsg = strndup(src + 9, n - 9);
174 if (_shortmsg == NULL)
177 while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
181 _longmsg = strdup(src + n);
183 if (_longmsg == NULL)
187 *shortmsg = _shortmsg;
190 // If there's no "Subject: " and the shortmsg is
191 // pEp (or anything else), then we shouldn't be replacing it.
192 // Chances are that the message wasn't encrypted
193 // using pEp and that the actually subject IS pEp. In any event,
194 // erasing the subject line when we don't have one in the plaintext
195 // isn't the right behaviour.
196 // _shortmsg = strdup("");
197 _longmsg = strdup(src);
199 if (_longmsg == NULL)
214 // static void remove_msg_version_field(message* msg) {
217 // stringpair_list_t* msg_opt_flds_curr = msg->opt_fields;
218 // stringpair_list_t** msg_opt_flds_prev_p = NULL;
220 // while (msg_opt_flds_curr) {
221 // char* fld_key = msg_opt_flds_curr->value->key;
223 // if (strcmp(fld_key, "X-pEp-Message-Version") == 0) {
224 // if (!msg_opt_flds_prev_p) {
225 // msg->opt_fields = msg_opt_flds_curr->next;
228 // (*msg_opt_flds_prev_p)->next = msg_opt_flds_curr->next;
230 // msg_opt_flds_curr->next = NULL;
231 // free_stringpair_list(msg_opt_flds_curr);
234 // *msg_opt_flds_prev_p = msg_opt_flds_curr;
235 // msg_opt_flds_curr = msg_opt_flds_curr->next;
240 static PEP_STATUS copy_fields(message *dst, const message *src)
246 return PEP_ILLEGAL_VALUE;
248 free_timestamp(dst->sent);
251 dst->sent = timestamp_dup(src->sent);
252 if (dst->sent == NULL)
253 return PEP_OUT_OF_MEMORY;
256 free_timestamp(dst->recv);
259 dst->recv = timestamp_dup(src->recv);
260 if (dst->recv == NULL)
261 return PEP_OUT_OF_MEMORY;
264 free_identity(dst->from);
267 dst->from = identity_dup(src->from);
268 if (dst->from == NULL)
269 return PEP_OUT_OF_MEMORY;
272 free_identity_list(dst->to);
274 if (src->to && src->to->ident) {
275 dst->to = identity_list_dup(src->to);
277 return PEP_OUT_OF_MEMORY;
280 free_identity(dst->recv_by);
283 dst->recv_by = identity_dup(src->recv_by);
284 if (dst->recv_by == NULL)
285 return PEP_OUT_OF_MEMORY;
288 free_identity_list(dst->cc);
290 if (src->cc && src->cc->ident) {
291 dst->cc = identity_list_dup(src->cc);
293 return PEP_OUT_OF_MEMORY;
296 free_identity_list(dst->bcc);
298 if (src->bcc && src->bcc->ident) {
299 dst->bcc = identity_list_dup(src->bcc);
300 if (dst->bcc == NULL)
301 return PEP_OUT_OF_MEMORY;
304 free_identity_list(dst->reply_to);
305 dst->reply_to = NULL;
306 if (src->reply_to && src->reply_to->ident) {
307 dst->reply_to = identity_list_dup(src->reply_to);
308 if (dst->reply_to == NULL)
309 return PEP_OUT_OF_MEMORY;
312 free_stringlist(dst->in_reply_to);
313 dst->in_reply_to = NULL;
314 if (src->in_reply_to && src->in_reply_to->value) {
315 dst->in_reply_to = stringlist_dup(src->in_reply_to);
316 if (dst->in_reply_to == NULL)
317 return PEP_OUT_OF_MEMORY;
320 free_stringlist(dst->references);
321 dst->references = NULL;
322 if (src->references) {
323 dst->references = stringlist_dup(src->references);
324 if (dst->references == NULL)
325 return PEP_OUT_OF_MEMORY;
328 free_stringlist(dst->keywords);
329 dst->keywords = NULL;
330 if (src->keywords && src->keywords->value) {
331 dst->keywords = stringlist_dup(src->keywords);
332 if (dst->keywords == NULL)
333 return PEP_OUT_OF_MEMORY;
337 dst->comments = NULL;
339 dst->comments = strdup(src->comments);
340 assert(dst->comments);
341 if (dst->comments == NULL)
342 return PEP_OUT_OF_MEMORY;
345 free_stringpair_list(dst->opt_fields);
346 dst->opt_fields = NULL;
347 if (src->opt_fields) {
348 dst->opt_fields = stringpair_list_dup(src->opt_fields);
349 if (dst->opt_fields == NULL)
350 return PEP_OUT_OF_MEMORY;
353 return PEP_STATUS_OK;
357 static message* extract_minimal_envelope(const message* src,
358 PEP_msg_direction direct) {
360 message* envelope = new_message(direct);
364 envelope->shortmsg = strdup("pEp");
365 if (!envelope->shortmsg)
369 envelope->from = identity_dup(src->from);
375 envelope->to = identity_list_dup(src->to);
381 envelope->cc = identity_list_dup(src->cc);
387 envelope->bcc = identity_list_dup(src->bcc);
392 /* DO WE WANT TO EXPOSE THIS??? */
394 envelope->reply_to = identity_list_dup(src->reply_to);
395 if (!envelope->reply_to)
399 envelope->enc_format = src->enc_format;
404 static void add_message_version(
412 char buf[8]; // xxx.xxx\0
413 if (major_version < 1000 && minor_version < 1000) {
414 int chars_set = sprintf(buf, "%d.%d", major_version, minor_version);
416 add_opt_field(msg, "X-pEp-Message-Version", buf);
420 static message* wrap_message_as_attachment(message* envelope,
421 const message* attachment) {
423 message* _envelope = NULL;
426 _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
428 return PEP_UNKNOWN_ERROR;
429 envelope = _envelope;
432 char* message_text = NULL;
433 /* Turn message into a MIME-blob */
434 PEP_STATUS status = mime_encode_message(attachment, false, &message_text);
436 if (status != PEP_STATUS_OK) {
441 size_t message_len = strlen(message_text);
443 bloblist_t* message_blob = new_bloblist(message_text, message_len,
444 "message/rfc822", NULL);
446 envelope->attachments = message_blob;
447 add_message_version(envelope, 2, 0);
452 static message * clone_to_empty_message(const message * src)
455 message * msg = NULL;
461 msg = calloc(1, sizeof(message));
468 status = copy_fields(msg, src);
469 if (status != PEP_STATUS_OK)
479 static PEP_STATUS encrypt_PGP_MIME(
484 PEP_encrypt_flags_t flags
487 PEP_STATUS status = PEP_STATUS_OK;
488 bool free_ptext = false;
491 char *mimetext = NULL;
493 assert(dst->longmsg == NULL);
494 dst->enc_format = PEP_enc_PGP_MIME;
496 if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
497 if (session->unencrypted_subject) {
498 dst->shortmsg = strdup(src->shortmsg);
499 assert(dst->shortmsg);
500 if (dst->shortmsg == NULL)
502 ptext = src->longmsg;
505 ptext = combine_short_and_long(src->shortmsg, src->longmsg);
511 else if (src->longmsg) {
512 ptext = src->longmsg;
518 message *_src = calloc(1, sizeof(message));
522 _src->longmsg = ptext;
523 _src->longmsg_formatted = src->longmsg_formatted;
524 _src->attachments = src->attachments;
525 _src->enc_format = PEP_enc_none;
526 status = mime_encode_message(_src, true, &mimetext);
527 assert(status == PEP_STATUS_OK);
528 if (status != PEP_STATUS_OK)
537 if (mimetext == NULL)
540 if (flags & PEP_encrypt_flag_force_unsigned)
541 status = encrypt_only(session, keys, mimetext, strlen(mimetext),
544 status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
550 dst->longmsg = strdup("this message was encrypted with p≡p "
551 "https://pEp-project.org");
552 assert(dst->longmsg);
553 if (dst->longmsg == NULL)
556 char *v = strdup("Version: 1");
561 bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
564 dst->attachments = _a;
566 _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
571 return PEP_STATUS_OK;
574 status = PEP_OUT_OF_MEMORY;
583 // N.B. TO BE MOVED TO READ-ONLY
584 // FIXME: Does this happen concurrent w/ message 2.0 merge?
585 static PEP_STATUS encrypt_PGP_in_pieces(
590 PEP_encrypt_flags_t flags
593 PEP_STATUS status = PEP_STATUS_OK;
597 bool free_ptext = false;
599 assert(dst->longmsg == NULL);
600 assert(dst->attachments == NULL);
602 dst->enc_format = PEP_enc_pieces;
604 bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
606 if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0) {
607 if (session->unencrypted_subject) {
608 dst->shortmsg = strdup(src->shortmsg);
609 assert(dst->shortmsg);
610 if (dst->shortmsg == NULL)
612 ptext = src->longmsg;
615 ptext = combine_short_and_long(src->shortmsg, src->longmsg);
622 status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
625 status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
631 dst->longmsg = ctext;
637 else if (src->longmsg && src->longmsg[0]) {
638 ptext = src->longmsg;
640 status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
643 status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
646 dst->longmsg = ctext;
653 dst->longmsg = strdup("");
654 assert(dst->longmsg);
655 if (dst->longmsg == NULL)
659 if (src->longmsg_formatted && src->longmsg_formatted[0]) {
660 ptext = src->longmsg_formatted;
662 status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
665 status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
669 bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
670 "application/octet-stream", "file://PGPexch.htm.pgp");
673 if (dst->attachments == NULL)
674 dst->attachments = _a;
681 if (src->attachments) {
682 if (dst->attachments == NULL) {
683 dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
684 if (dst->attachments == NULL)
688 bloblist_t *_s = src->attachments;
689 bloblist_t *_d = dst->attachments;
691 for (int n = 0; _s; _s = _s->next) {
692 if (_s->value == NULL && _s->size == 0) {
693 _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
698 size_t psize = _s->size;
701 status = encrypt_only(session, keys, ptext, psize, &ctext,
704 status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
707 char *filename = NULL;
709 char *attach_fn = _s->filename;
710 if (attach_fn && !is_cid_uri(attach_fn)) {
711 size_t len = strlen(_s->filename);
712 size_t bufsize = len + 5; // length of .pgp extension + NUL
713 bool already_uri = false;
714 if (is_file_uri(attach_fn))
717 bufsize += 7; // length of file://
719 filename = calloc(1, bufsize);
720 if (filename == NULL)
724 strlcpy(filename, "file://", bufsize);
725 // First char is NUL, so we're ok, even if not copying above. (calloc)
726 strlcat(filename, _s->filename, bufsize);
727 strlcat(filename, ".pgp", bufsize);
730 filename = calloc(1, 27);
731 if (filename == NULL)
736 snprintf(filename, 20, "file://Attachment%d.pgp", n);
739 _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
752 return PEP_STATUS_OK;
755 status = PEP_OUT_OF_MEMORY;
763 static char * keylist_to_string(const stringlist_t *keylist)
766 size_t size = stringlist_length(keylist);
768 const stringlist_t *_kl;
769 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
770 size += strlen(_kl->value);
773 char *result = calloc(1, size);
778 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
779 _r = stpcpy(_r, _kl->value);
780 if (_kl->next && _kl->next->value)
781 _r = stpcpy(_r, ",");
791 static const char * rating_to_string(PEP_rating rating)
794 case PEP_rating_cannot_decrypt:
795 return "cannot_decrypt";
796 case PEP_rating_have_no_key:
797 return "have_no_key";
798 case PEP_rating_unencrypted:
799 return "unencrypted";
800 case PEP_rating_unencrypted_for_some:
801 return "unencrypted_for_some";
802 case PEP_rating_unreliable:
804 case PEP_rating_reliable:
806 case PEP_rating_trusted:
808 case PEP_rating_trusted_and_anonymized:
809 return "trusted_and_anonymized";
810 case PEP_rating_fully_anonymous:
811 return "fully_anonymous";
812 case PEP_rating_mistrust:
814 case PEP_rating_b0rken:
816 case PEP_rating_under_attack:
817 return "under_attack";
823 static void decorate_message(
826 stringlist_t *keylist
831 add_opt_field(msg, "X-pEp-Version", PEP_VERSION);
833 if (rating != PEP_rating_undefined)
834 add_opt_field(msg, "X-EncStatus", rating_to_string(rating));
837 char *_keylist = keylist_to_string(keylist);
838 add_opt_field(msg, "X-KeyList", _keylist);
843 static PEP_rating _rating(PEP_comm_type ct, PEP_rating rating)
845 if (ct == PEP_ct_unknown)
846 return PEP_rating_undefined;
848 else if (ct == PEP_ct_key_not_found)
849 return PEP_rating_have_no_key;
851 else if (ct == PEP_ct_compromized)
852 return PEP_rating_under_attack;
854 else if (ct == PEP_ct_mistrusted)
855 return PEP_rating_mistrust;
857 if (rating == PEP_rating_unencrypted_for_some)
858 return PEP_rating_unencrypted_for_some;
860 if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
861 ct == PEP_ct_my_key_not_included) {
862 if (rating > PEP_rating_unencrypted_for_some)
863 return PEP_rating_unencrypted_for_some;
865 return PEP_rating_unencrypted;
868 if (rating == PEP_rating_unencrypted)
869 return PEP_rating_unencrypted_for_some;
871 if (ct >= PEP_ct_confirmed_enc_anon)
872 return PEP_rating_trusted_and_anonymized;
874 else if (ct >= PEP_ct_strong_encryption)
875 return PEP_rating_trusted;
877 else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
878 return PEP_rating_reliable;
881 return PEP_rating_unreliable;
884 static bool is_encrypted_attachment(const bloblist_t *blob)
888 if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
891 char *ext = strrchr(blob->filename, '.');
895 if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
896 if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
897 strcmp(ext, ".asc") == 0)
900 else if (strcmp(blob->mime_type, "text/plain") == 0) {
901 if (strcmp(ext, ".asc") == 0)
908 static bool is_encrypted_html_attachment(const bloblist_t *blob)
911 assert(blob->filename);
912 if (blob == NULL || blob->filename == NULL || is_cid_uri(blob->filename))
915 const char* bare_filename_ptr = _get_resource_ptr_noown(blob->filename);
916 if (strncmp(bare_filename_ptr, "PGPexch.htm.", 12) == 0) {
917 if (strcmp(bare_filename_ptr + 11, ".pgp") == 0 ||
918 strcmp(bare_filename_ptr + 11, ".asc") == 0)
925 static char * without_double_ending(const char *filename)
928 if (filename == NULL || is_cid_uri(filename))
931 char *ext = strrchr(filename, '.');
935 char *result = strndup(filename, ext - filename);
940 static PEP_rating decrypt_rating(PEP_STATUS status)
943 case PEP_UNENCRYPTED:
945 case PEP_VERIFY_NO_KEY:
946 case PEP_VERIFIED_AND_TRUSTED:
947 return PEP_rating_unencrypted;
950 case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
951 return PEP_rating_unreliable;
953 case PEP_DECRYPTED_AND_VERIFIED:
954 return PEP_rating_reliable;
956 case PEP_DECRYPT_NO_KEY:
957 return PEP_rating_have_no_key;
959 case PEP_DECRYPT_WRONG_FORMAT:
960 case PEP_CANNOT_DECRYPT_UNKNOWN:
961 return PEP_rating_cannot_decrypt;
964 return PEP_rating_undefined;
968 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
974 if (session == NULL || fpr == NULL)
975 return PEP_rating_undefined;
978 PEP_comm_type bare_comm_type = PEP_ct_unknown;
979 PEP_comm_type resulting_comm_type = PEP_ct_unknown;
980 PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
981 if (status != PEP_STATUS_OK)
982 return PEP_rating_undefined;
984 PEP_comm_type least_comm_type = PEP_ct_unknown;
985 least_trust(session, fpr, &least_comm_type);
987 if (least_comm_type == PEP_ct_unknown) {
988 resulting_comm_type = bare_comm_type;
989 } else if (least_comm_type < PEP_ct_strong_but_unconfirmed ||
990 bare_comm_type < PEP_ct_strong_but_unconfirmed) {
991 // take minimum if anything bad
992 resulting_comm_type = least_comm_type < bare_comm_type ?
996 resulting_comm_type = least_comm_type;
998 return _rating(resulting_comm_type, PEP_rating_undefined);
1001 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
1002 return ((rating1 < rating2) ? rating1 : rating2);
1005 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist, char* sender_fpr, PEP_rating sender_rating)
1007 PEP_rating rating = sender_rating;
1009 assert(keylist && keylist->value);
1010 if (keylist == NULL || keylist->value == NULL)
1011 return PEP_rating_undefined;
1014 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
1017 if(_same_fpr(sender_fpr, strlen(sender_fpr), _kl->value, strlen(_kl->value)))
1020 PEP_rating _rating_ = key_rating(session, _kl->value);
1022 if (_rating_ <= PEP_rating_mistrust)
1025 if (_rating_ == PEP_rating_unencrypted)
1027 if (rating > PEP_rating_unencrypted_for_some)
1028 rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
1032 rating = worst_rating(rating, _rating_);
1039 static PEP_comm_type _get_comm_type(
1040 PEP_SESSION session,
1041 PEP_comm_type max_comm_type,
1045 PEP_STATUS status = update_identity(session, ident);
1047 if (max_comm_type == PEP_ct_compromized)
1048 return PEP_ct_compromized;
1050 if (max_comm_type == PEP_ct_mistrusted)
1051 return PEP_ct_mistrusted;
1053 if (status == PEP_STATUS_OK) {
1054 if (ident->comm_type == PEP_ct_compromized)
1055 return PEP_ct_compromized;
1056 else if (ident->comm_type == PEP_ct_mistrusted)
1057 return PEP_ct_mistrusted;
1059 return _MIN(max_comm_type, ident->comm_type);
1062 return PEP_ct_unknown;
1066 static void free_bl_entry(bloblist_t *bl)
1070 free(bl->mime_type);
1076 static bool is_key(const bloblist_t *bl)
1078 return (// workaround for Apple Mail bugs
1079 (is_mime_type(bl, "application/x-apple-msg-attachment") &&
1080 is_fileending(bl, ".asc")) ||
1081 // as binary, by file name
1082 ((bl->mime_type == NULL ||
1083 is_mime_type(bl, "application/octet-stream")) &&
1084 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
1085 is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
1086 // explicit mime type
1087 is_mime_type(bl, "application/pgp-keys") ||
1088 // as text, by file name
1089 (is_mime_type(bl, "text/plain") &&
1090 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
1091 is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
1095 static void remove_attached_keys(message *msg)
1098 bloblist_t *last = NULL;
1099 for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
1100 bloblist_t *next = bl->next;
1107 msg->attachments = next;
1119 bool import_attached_keys(
1120 PEP_SESSION session,
1122 identity_list **private_idents
1128 if (session == NULL || msg == NULL)
1131 bool remove = false;
1134 for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
1137 if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
1140 identity_list *local_private_idents = NULL;
1141 import_key(session, bl->value, bl->size, &local_private_idents);
1143 if (private_idents && *private_idents == NULL && local_private_idents != NULL)
1144 *private_idents = local_private_idents;
1146 free_identity_list(local_private_idents);
1153 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
1155 char *keydata = NULL;
1158 PEP_STATUS status = export_key(session, fpr, &keydata, &size);
1159 assert(status == PEP_STATUS_OK);
1160 if (status != PEP_STATUS_OK)
1164 bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
1165 "file://pEpkey.asc");
1167 if (msg->attachments == NULL && bl)
1168 msg->attachments = bl;
1170 return PEP_STATUS_OK;
1173 #define ONE_WEEK (7*24*3600)
1175 void attach_own_key(PEP_SESSION session, message *msg)
1180 if (msg->dir == PEP_dir_incoming)
1183 assert(msg->from && msg->from->fpr);
1184 if (msg->from == NULL || msg->from->fpr == NULL)
1187 if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
1190 char *revoked_fpr = NULL;
1191 uint64_t revocation_date = 0;
1193 if(get_revoked(session, msg->from->fpr,
1194 &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
1195 revoked_fpr != NULL)
1197 time_t now = time(NULL);
1199 if (now < (time_t)revocation_date + ONE_WEEK)
1201 _attach_key(session, revoked_fpr, msg);
1207 PEP_cryptotech determine_encryption_format(message *msg)
1211 if (is_PGP_message_text(msg->longmsg)) {
1212 msg->enc_format = PEP_enc_pieces;
1213 return PEP_crypt_OpenPGP;
1215 else if (msg->attachments && msg->attachments->next &&
1216 is_mime_type(msg->attachments, "application/pgp-encrypted") &&
1217 is_PGP_message_text(msg->attachments->next->value)
1219 msg->enc_format = PEP_enc_PGP_MIME;
1220 return PEP_crypt_OpenPGP;
1222 else if (msg->attachments && msg->attachments->next &&
1223 is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
1224 is_PGP_message_text(msg->attachments->value)
1226 msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
1227 return PEP_crypt_OpenPGP;
1230 msg->enc_format = PEP_enc_none;
1231 return PEP_crypt_none;
1235 DYNAMIC_API PEP_STATUS encrypt_message(
1236 PEP_SESSION session,
1238 stringlist_t * extra,
1240 PEP_enc_format enc_format,
1241 PEP_encrypt_flags_t flags
1244 PEP_STATUS status = PEP_STATUS_OK;
1245 message * msg = NULL;
1246 stringlist_t * keys = NULL;
1247 message* _src = NULL;
1248 bool no_wrap_message = (flags & PEP_encrypt_flag_dont_raise_headers);
1253 assert(enc_format != PEP_enc_none);
1255 if (!(session && src && dst && enc_format != PEP_enc_none))
1256 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1258 if (src->dir == PEP_dir_incoming)
1259 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1261 determine_encryption_format(src);
1262 if (src->enc_format != PEP_enc_none)
1263 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1267 status = myself(session, src->from);
1268 if (status != PEP_STATUS_OK)
1271 keys = new_stringlist(src->from->fpr);
1275 stringlist_t *_k = keys;
1278 _k = stringlist_append(_k, extra);
1283 bool dest_keys_found = true;
1284 PEP_comm_type max_comm_type = PEP_ct_pEp;
1286 identity_list * _il;
1288 if ((_il = src->bcc) && _il->ident)
1290 // BCC limited support:
1291 // - App splits mails with BCC in multiple mails.
1292 // - Each email is encrypted separately
1294 if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
1296 // Only one Bcc with no other recipient allowed for now
1297 return PEP_ILLEGAL_VALUE;
1300 PEP_STATUS _status = update_identity(session, _il->ident);
1301 if (_status != PEP_STATUS_OK) {
1306 if (_il->ident->fpr && _il->ident->fpr[0]) {
1307 _k = stringlist_add(_k, _il->ident->fpr);
1310 max_comm_type = _get_comm_type(session, max_comm_type,
1314 dest_keys_found = false;
1315 status = PEP_KEY_NOT_FOUND;
1320 for (_il = src->to; _il && _il->ident; _il = _il->next) {
1321 PEP_STATUS _status = update_identity(session, _il->ident);
1322 if (_status != PEP_STATUS_OK) {
1327 if (_il->ident->fpr && _il->ident->fpr[0]) {
1328 _k = stringlist_add(_k, _il->ident->fpr);
1331 max_comm_type = _get_comm_type(session, max_comm_type,
1335 dest_keys_found = false;
1336 status = PEP_KEY_NOT_FOUND;
1340 for (_il = src->cc; _il && _il->ident; _il = _il->next) {
1341 PEP_STATUS _status = update_identity(session, _il->ident);
1342 if (_status != PEP_STATUS_OK)
1348 if (_il->ident->fpr && _il->ident->fpr[0]) {
1349 _k = stringlist_add(_k, _il->ident->fpr);
1352 max_comm_type = _get_comm_type(session, max_comm_type,
1356 dest_keys_found = false;
1357 status = PEP_KEY_NOT_FOUND;
1362 if (!dest_keys_found ||
1363 stringlist_length(keys) == 0 ||
1364 _rating(max_comm_type,
1365 PEP_rating_undefined) < PEP_rating_reliable)
1367 free_stringlist(keys);
1368 if (!session->passive_mode &&
1369 !(flags & PEP_encrypt_flag_force_no_attached_key)) {
1370 attach_own_key(session, src);
1371 decorate_message(src, PEP_rating_undefined, NULL);
1373 return ADD_TO_LOG(PEP_UNENCRYPTED);
1376 if (no_wrap_message) {
1377 msg = clone_to_empty_message(src);
1381 // encrypt inner message
1382 message* inner_message = NULL;
1383 status = encrypt_message(session, src, extra, &inner_message,
1384 enc_format, flags | PEP_encrypt_flag_dont_raise_headers);
1385 _src = wrap_message_as_attachment(NULL, inner_message);
1387 status = PEP_UNKNOWN_ERROR;
1390 msg = clone_to_empty_message(_src);
1395 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1396 attach_own_key(session, _src);
1398 switch (enc_format) {
1399 case PEP_enc_PGP_MIME:
1400 case PEP_enc_PEP: // BUG: should be implemented extra
1401 status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
1404 // This actually doesn't really make sense for message 2.0... See function comment below
1405 case PEP_enc_pieces:
1406 status = encrypt_PGP_in_pieces(session, _src, keys, msg, flags);
1409 /* case PEP_enc_PEP:
1415 status = PEP_ILLEGAL_VALUE;
1419 if (status == PEP_OUT_OF_MEMORY)
1422 if (status != PEP_STATUS_OK)
1426 free_stringlist(keys);
1428 if (msg && msg->shortmsg == NULL) {
1429 msg->shortmsg = strdup("pEp");
1430 assert(msg->shortmsg);
1431 if (msg->shortmsg == NULL)
1436 decorate_message(msg, PEP_rating_undefined, NULL);
1438 msg->id = strdup(_src->id);
1440 if (msg->id == NULL)
1446 // free_message(wrapped_msg);
1447 return ADD_TO_LOG(status);
1450 status = PEP_OUT_OF_MEMORY;
1453 free_stringlist(keys);
1455 if (!no_wrap_message)
1457 return ADD_TO_LOG(status);
1460 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
1461 PEP_SESSION session,
1462 pEp_identity* target_id,
1465 PEP_enc_format enc_format,
1466 PEP_encrypt_flags_t flags
1469 PEP_STATUS status = PEP_STATUS_OK;
1470 message * msg = NULL;
1471 stringlist_t * keys = NULL;
1476 assert(enc_format != PEP_enc_none);
1478 if (!(session && src && dst && enc_format != PEP_enc_none))
1479 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1481 if (src->dir == PEP_dir_incoming)
1482 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1484 determine_encryption_format(src);
1485 if (src->enc_format != PEP_enc_none)
1486 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1488 status = myself(session, target_id);
1489 if (status != PEP_STATUS_OK)
1495 PEP_STATUS _status = update_identity(session, target_id);
1496 if (_status != PEP_STATUS_OK) {
1501 char* target_fpr = target_id->fpr;
1503 return PEP_KEY_NOT_FOUND; // FIXME: Error condition
1505 keys = new_stringlist(target_fpr);
1507 /* KG: did we ever do this??? */
1508 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1509 _attach_key(session, target_fpr, src);
1511 msg = clone_to_empty_message(src);
1515 switch (enc_format) {
1516 case PEP_enc_PGP_MIME:
1517 case PEP_enc_PEP: // BUG: should be implemented extra
1518 // N.B. Don't raise headers, as we want to send a 1.0 message back.
1519 // If this is a draft, obviously that will change when it's reencrypted
1520 // for everybody else.
1521 status = encrypt_PGP_MIME(session, src, keys, msg,
1522 flags | PEP_encrypt_flag_dont_raise_headers);
1525 case PEP_enc_pieces:
1526 status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
1529 /* case PEP_enc_PEP:
1535 status = PEP_ILLEGAL_VALUE;
1539 if (status == PEP_OUT_OF_MEMORY)
1542 if (status != PEP_STATUS_OK)
1545 if (msg && msg->shortmsg == NULL) {
1546 msg->shortmsg = strdup("pEp");
1547 assert(msg->shortmsg);
1548 if (msg->shortmsg == NULL)
1554 msg->id = strdup(src->id);
1556 if (msg->id == NULL)
1565 status = PEP_OUT_OF_MEMORY;
1568 free_stringlist(keys);
1571 return ADD_TO_LOG(status);
1574 static bool is_a_pEpmessage(const message *msg)
1576 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
1577 if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
1583 static const char* pEpmessage_version_str(const message *msg)
1585 char* retval = NULL;
1586 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
1587 if (strcasecmp(i->value->key, "X-pEp-Message-Version") == 0) {
1588 retval = i->value->value;
1595 static int pEpmessage_major_version(const message *msg) {
1596 const char* version_string = pEpmessage_version_str(msg);
1597 if (!version_string)
1600 int ver_strlen = strlen(version_string);
1604 const short MAX_MAJ_VERSION_DIGITS = 4; // I certainly hope...
1605 char version_buf[MAX_MAJ_VERSION_DIGITS + 1];
1609 for ( ; i < MAX_MAJ_VERSION_DIGITS && i < ver_strlen; i++ ) {
1610 if (version_string[i] == '.') {
1611 version_buf[i] = '\0';
1614 version_buf[i] = version_string[i];
1617 if (version_string[i] != '.')
1620 // ok, this is some chars + \0, but not necessarily numeric.
1621 int retval = atoi(version_buf);
1622 if (retval == 0 && version_buf[0] != 0)
1628 // static bool verify_explicit_message_version(const char* desired_version,
1629 // const message* msg) {
1630 // if (!desired_version || !msg)
1632 // const char* msg_version_str = pEpmessage_version_str(msg);
1633 // return (msg_version_str && (strcmp(desired_version, msg_version_str) == 0));
1636 // update comm_type to pEp_ct_pEp if needed
1637 static PEP_STATUS _update_identity_for_incoming_message(
1638 PEP_SESSION session,
1643 if (src->from && src->from->address) {
1644 status = update_identity(session, src->from);
1645 if (status == PEP_STATUS_OK
1646 && is_a_pEpmessage(src)
1647 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
1648 && src->from->comm_type != PEP_ct_pEp_unconfirmed
1649 && src->from->comm_type != PEP_ct_pEp)
1651 src->from->comm_type |= PEP_ct_pEp_unconfirmed;
1652 status = set_identity(session, src->from);
1656 return PEP_ILLEGAL_VALUE;
1660 PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
1661 bloblist_t* attach_curr = msg->attachments;
1663 *signature_blob = NULL;
1665 while (attach_curr) {
1666 if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
1667 *signature_blob = attach_curr;
1670 attach_curr = attach_curr->next;
1673 return PEP_STATUS_OK;
1676 PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
1677 char** stext, size_t* ssize) {
1679 char* signed_boundary = NULL;
1680 char* signpost = strstr(ptext, "Content-Type: multipart/signed");
1686 return PEP_UNKNOWN_ERROR;
1688 char* curr_line = signpost;
1689 // const char* end_text = ptext + psize;
1690 const char* boundary_key = "boundary=";
1691 const size_t BOUNDARY_KEY_SIZE = 9;
1693 char* start_boundary = strstr(curr_line, boundary_key);
1694 if (!start_boundary)
1695 return PEP_UNKNOWN_ERROR;
1697 start_boundary += BOUNDARY_KEY_SIZE;
1699 bool quoted = (*start_boundary == '"');
1704 char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
1707 return PEP_UNKNOWN_ERROR;
1709 // Add space for the "--"
1710 size_t boundary_strlen = (end_boundary - start_boundary) + 2;
1712 signed_boundary = calloc(1, boundary_strlen + 1);
1713 strlcpy(signed_boundary, "--", boundary_strlen + 1);
1714 strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
1716 start_boundary = strstr(end_boundary, signed_boundary);
1718 if (!start_boundary)
1719 return PEP_UNKNOWN_ERROR;
1721 start_boundary += boundary_strlen;
1723 if (*start_boundary == '\r') {
1724 if (*(start_boundary + 1) == '\n')
1725 start_boundary += 2;
1727 else if (*start_boundary == '\n')
1730 end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
1733 return PEP_UNKNOWN_ERROR;
1735 // See RFC3156 section 5...
1737 if (*(end_boundary - 1) == '\r')
1740 *ssize = end_boundary - start_boundary;
1741 *stext = start_boundary;
1742 free(signed_boundary);
1744 return PEP_STATUS_OK;
1747 PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in,
1748 stringlist_t** keylist_in_out,
1749 pEp_identity* from) {
1751 if (!verify_in || !(*verify_in)) // this isn't really a problem.
1752 return PEP_STATUS_OK;
1754 stringlist_t* orig_verify = *verify_in;
1756 stringlist_t* verify_curr = NULL;
1757 stringlist_t* from_keys = NULL;
1759 /* FIXME: what to do if head needs to be null */
1760 PEP_STATUS status = find_keys(session, from->address, &from_keys);
1762 stringlist_t* from_fpr_node = NULL;
1763 stringlist_t* from_curr;
1765 for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
1766 for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
1767 if (from_curr->value && verify_curr->value &&
1768 _same_fpr(from_curr->value, strlen(from_curr->value),
1769 verify_curr->value, strlen(verify_curr->value))) {
1770 from_fpr_node = from_curr;
1776 if (!from_fpr_node) {
1777 status = PEP_KEY_NOT_FOUND;
1781 verify_curr = orig_verify;
1783 /* put "from" signer at the beginning of the list */
1784 if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
1785 from_fpr_node->value, strlen(from_fpr_node->value))) {
1786 orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
1787 verify_curr = new_stringlist(from_fpr_node->value);
1788 verify_curr->next = orig_verify;
1791 /* append keylist to signers */
1792 if (keylist_in_out && *keylist_in_out && (*keylist_in_out)->value) {
1793 stringlist_t** tail_pp = &verify_curr->next;
1796 tail_pp = &((*tail_pp)->next);
1798 stringlist_t* second_list = *keylist_in_out;
1800 char* listhead_val = second_list->value;
1801 if (!listhead_val || listhead_val[0] == '\0') {
1802 /* remove head, basically. This can happen when,
1803 for example, the signature is detached and
1804 verification is not seen directly after
1805 decryption, so no signer is presumed in
1806 the first construction of the keylist */
1807 *keylist_in_out = (*keylist_in_out)->next;
1808 second_list->next = NULL;
1809 free_stringlist(second_list);
1812 *tail_pp = *keylist_in_out;
1815 *keylist_in_out = verify_curr;
1817 status = PEP_STATUS_OK;
1820 free_stringlist(from_keys);
1824 PEP_STATUS amend_rating_according_to_sender_and_recipients(
1825 PEP_SESSION session,
1827 pEp_identity *sender,
1828 stringlist_t *recipients) {
1830 PEP_STATUS status = PEP_STATUS_OK;
1832 if (*rating > PEP_rating_mistrust) {
1834 if (recipients == NULL) {
1835 *rating = PEP_rating_undefined;
1836 return PEP_STATUS_OK;
1839 char *fpr = recipients->value;
1841 if (!(sender && sender->user_id && sender->user_id[0] && fpr && fpr[0])) {
1842 *rating = PEP_rating_unreliable;
1845 pEp_identity *_sender = new_identity(sender->address, fpr,
1846 sender->user_id, sender->username);
1847 if (_sender == NULL)
1848 return PEP_OUT_OF_MEMORY;
1850 status = get_trust(session, _sender);
1851 if (_sender->comm_type != PEP_ct_unknown) {
1852 *rating = keylist_rating(session, recipients,
1853 fpr, _rating(_sender->comm_type,
1854 PEP_rating_undefined));
1856 free_identity(_sender);
1857 if (status == PEP_CANNOT_FIND_IDENTITY)
1858 status = PEP_STATUS_OK;
1864 static void pull_up_longmsg_attachment(message* msg) {
1865 bloblist_t* matt = msg->attachments;
1867 const char* inner_mime_type = matt->mime_type;
1868 if (strcasecmp(inner_mime_type, "text/plain") == 0) {
1869 free(msg->longmsg); /* in case of "" */
1870 msg->longmsg = strndup(matt->value, matt->size);
1872 bloblist_t* next_node = matt->next;
1874 inner_mime_type = next_node->mime_type;
1875 if (strcasecmp(inner_mime_type, "text/html") == 0) {
1876 free(msg->longmsg_formatted);
1877 msg->longmsg_formatted = strndup(next_node->value, next_node->size);
1881 else if (strcasecmp(inner_mime_type, "text/html") == 0) {
1882 free(msg->longmsg_formatted);
1883 msg->longmsg_formatted = strndup(matt->value, matt->size);
1888 DYNAMIC_API PEP_STATUS _decrypt_message(
1889 PEP_SESSION session,
1892 stringlist_t **keylist,
1894 PEP_decrypt_flags_t *flags,
1895 identity_list **private_il
1898 PEP_STATUS status = PEP_STATUS_OK;
1899 PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
1900 message *msg = NULL;
1905 stringlist_t *_keylist = NULL;
1906 message *inner_message = NULL; // For version 2.0+ messages
1915 if (!(session && src && dst && keylist && rating && flags))
1916 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1920 // Private key in unencrypted mail are ignored -> NULL
1921 bool imported_keys = import_attached_keys(session, src, NULL);
1923 // Update src->from in case we just imported a key
1924 // we would need to check signature
1925 status = _update_identity_for_incoming_message(session, src);
1926 if(status != PEP_STATUS_OK)
1927 return ADD_TO_LOG(status);
1929 // Get detached signature, if any
1930 bloblist_t* detached_sig = NULL;
1931 char* dsig_text = NULL;
1932 size_t dsig_size = 0;
1933 status = _get_detached_signature(src, &detached_sig);
1935 dsig_text = detached_sig->value;
1936 dsig_size = detached_sig->size;
1939 PEP_cryptotech crypto = determine_encryption_format(src);
1943 *rating = PEP_rating_undefined;
1945 switch (src->enc_format) {
1947 *rating = PEP_rating_unencrypted;
1949 remove_attached_keys(src);
1950 if(session->sync_session->inject_sync_msg){
1951 status = receive_DeviceState_msg(session, src, *rating, *keylist);
1952 if (status == PEP_MESSAGE_CONSUME ||
1953 status == PEP_MESSAGE_IGNORE) {
1956 *flags |= (status == PEP_MESSAGE_IGNORE) ?
1957 PEP_decrypt_flag_ignore :
1958 PEP_decrypt_flag_consume;
1960 else if (status != PEP_STATUS_OK) {
1961 return ADD_TO_LOG(status);
1965 char* slong = src->longmsg;
1966 char* sform = src->longmsg_formatted;
1968 if ((!slong || slong[0] == '\0') && (!sform || sform[0] == '\0'))
1969 pull_up_longmsg_attachment(src);
1971 return ADD_TO_LOG(PEP_UNENCRYPTED);
1973 case PEP_enc_PGP_MIME:
1974 ctext = src->attachments->next->value;
1975 csize = src->attachments->next->size;
1978 case PEP_enc_PGP_MIME_Outlook1:
1979 ctext = src->attachments->value;
1980 csize = src->attachments->size;
1983 case PEP_enc_pieces:
1984 ctext = src->longmsg;
1985 csize = strlen(ctext);
1991 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
1992 csize, dsig_text, dsig_size,
1993 &ptext, &psize, &_keylist);
1994 if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
1998 decrypt_status = status;
2000 if (status == PEP_DECRYPT_NO_KEY){
2001 PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
2002 if (sync_status == PEP_OUT_OF_MEMORY){
2003 status = PEP_OUT_OF_MEMORY;
2008 bool imported_private_key_address = false;
2011 switch (src->enc_format) {
2012 case PEP_enc_PGP_MIME:
2013 case PEP_enc_PGP_MIME_Outlook1:
2014 status = mime_decode_message(ptext, psize, &msg);
2015 if (status != PEP_STATUS_OK)
2018 int msg_major_version = pEpmessage_major_version(src);
2020 if (msg_major_version > 1) {
2021 status = mime_decode_message(msg->attachments->value,
2022 msg->attachments->size,
2024 if (status != PEP_STATUS_OK)
2027 int inner_message_version = pEpmessage_major_version(inner_message);
2029 /* recurse one level if need be */
2030 if (inner_message_version < 2) {
2031 status = _decrypt_message(session, inner_message,
2032 dst, keylist, rating,
2035 free_message(inner_message);
2039 otherwise, we're just going to verify the outer
2040 message's keylist etc, and then pull up at the end.
2044 char* mlong = msg->longmsg;
2045 char* mform = msg->longmsg_formatted;
2047 /* Note: we don't do this for Version 2.0+ inner messages, as we want to
2048 return the whole message, not just the attachment, in that case.
2049 (N.B. Version 2.0+ inner messages are themselves compound messages,
2050 and the inner message is probably one that needs to be routed
2051 elsewhere by the transport)
2053 if (!inner_message && (!mlong || mlong[0] == '\0') && (!mform || mform[0] == '\0')) {
2054 pull_up_longmsg_attachment(msg);
2056 if (msg->shortmsg) {
2057 free(src->shortmsg);
2058 src->shortmsg = strdup(msg->shortmsg);
2062 if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
2063 status = _get_detached_signature(msg, &detached_sig);
2064 if (decrypt_status == PEP_DECRYPTED && detached_sig) {
2065 dsig_text = detached_sig->value;
2066 dsig_size = detached_sig->size;
2070 status = _get_signed_text(ptext, psize, &stext, &ssize);
2071 stringlist_t *_verify_keylist = NULL;
2073 if (ssize > 0 && stext) {
2074 status = cryptotech[crypto].verify_text(session, stext,
2075 ssize, dsig_text, dsig_size,
2078 if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
2079 decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
2081 status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
2087 case PEP_enc_pieces:
2088 msg = clone_to_empty_message(src);
2092 msg->longmsg = ptext;
2095 bloblist_t *_m = msg->attachments;
2096 if (_m == NULL && src->attachments && src->attachments->value) {
2097 msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
2098 _m = msg->attachments;
2102 for (_s = src->attachments; _s; _s = _s->next) {
2103 if (_s->value == NULL && _s->size == 0){
2104 _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
2109 else if (is_encrypted_attachment(_s)) {
2110 stringlist_t *_keylist = NULL;
2111 char *attctext = _s->value;
2112 size_t attcsize = _s->size;
2117 // FIXME: What about attachments with separate sigs???
2118 status = decrypt_and_verify(session, attctext, attcsize,
2120 &ptext, &psize, &_keylist);
2121 free_stringlist(_keylist); // FIXME: Why do we do this?
2124 if (is_encrypted_html_attachment(_s)) {
2125 msg->longmsg_formatted = ptext;
2129 static const char * const mime_type = "application/octet-stream";
2130 char * const filename =
2131 without_double_ending(_s->filename);
2132 if (filename == NULL)
2135 _m = bloblist_add(_m, ptext, psize, mime_type,
2143 if (msg->attachments == NULL)
2144 msg->attachments = _m;
2148 char *copy = malloc(_s->size);
2152 memcpy(copy, _s->value, _s->size);
2153 _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
2159 char *copy = malloc(_s->size);
2163 memcpy(copy, _s->value, _s->size);
2164 _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
2173 // BUG: must implement more
2177 switch (src->enc_format) {
2178 case PEP_enc_PGP_MIME:
2179 case PEP_enc_pieces:
2180 case PEP_enc_PGP_MIME_Outlook1:
2181 status = copy_fields(msg, src);
2182 if (status != PEP_STATUS_OK)
2187 if (!inner_message) {
2188 if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
2193 int r = separate_short_and_long(msg->longmsg, &shortmsg,
2199 if (shortmsg == NULL) {
2200 if (src->shortmsg == NULL)
2201 shortmsg = strdup("");
2203 // FIXME: is msg->shortmsg always a copy of
2204 // src->shortmsg already?
2205 // if so, we need to change the logic so
2206 // that in this case, we don't free msg->shortmsg
2207 // and do this strdup, etc.
2208 shortmsg = strdup(src->shortmsg);
2213 free(msg->shortmsg);
2216 msg->shortmsg = shortmsg;
2217 msg->longmsg = longmsg;
2220 msg->shortmsg = strdup(src->shortmsg);
2221 assert(msg->shortmsg);
2222 if (msg->shortmsg == NULL)
2228 // BUG: must implement more
2232 // check for private key in decrypted message attachement while inporting
2233 identity_list *_private_il = NULL;
2234 imported_keys = import_attached_keys(session, msg, &_private_il);
2236 identity_list_length(_private_il) == 1 &&
2237 _private_il->ident->address)
2239 imported_private_key_address = true;
2242 if(private_il && imported_private_key_address){
2243 *private_il = _private_il;
2245 free_identity_list(_private_il);
2248 if(decrypt_status == PEP_DECRYPTED){
2250 // TODO optimize if import_attached_keys didn't import any key
2252 // In case message did decrypt, but no valid signature could be found
2253 // then retry decrypt+verify after importing key.
2255 // Update msg->from in case we just imported a key
2256 // we would need to check signature
2258 status = _update_identity_for_incoming_message(session, src);
2259 if(status != PEP_STATUS_OK)
2264 char *re_ptext = NULL;
2267 free_stringlist(_keylist);
2270 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
2271 csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
2275 if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
2280 decrypt_status = status;
2283 *rating = decrypt_rating(decrypt_status);
2285 status = amend_rating_according_to_sender_and_recipients(session,
2290 if (status != PEP_STATUS_OK)
2295 *rating = decrypt_rating(decrypt_status);
2299 // Case of own key imported from own trusted message
2300 if (// Message have been reliably decrypted
2302 *rating >= PEP_rating_trusted &&
2303 imported_private_key_address &&
2305 msg->to->ident->user_id &&
2306 strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
2309 *flags |= PEP_decrypt_flag_own_private_key;
2312 // FIXME: To here, we're ok with the separate messages. We need to
2313 // specify what clients expect when this is a 2.0 message.
2314 // IMHO, we don't need the keylist at that point, just
2315 // the rating and move on.
2317 decorate_message(msg, *rating, _keylist);
2319 remove_attached_keys(msg);
2320 if (*rating >= PEP_rating_reliable &&
2321 session->sync_session->inject_sync_msg) {
2322 status = receive_DeviceState_msg(session, msg, *rating, _keylist);
2323 if (status == PEP_MESSAGE_CONSUME ||
2324 status == PEP_MESSAGE_IGNORE) {
2327 *flags |= (status == PEP_MESSAGE_IGNORE) ?
2328 PEP_decrypt_flag_ignore :
2329 PEP_decrypt_flag_consume;
2332 else if (status != PEP_STATUS_OK){
2339 msg->id = strdup(src->id);
2341 if (msg->id == NULL)
2347 *dst = inner_message;
2351 // I think we keep it this way for 2.0 inner messages.
2352 *keylist = _keylist;
2354 if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
2355 return ADD_TO_LOG(PEP_STATUS_OK);
2357 return ADD_TO_LOG(decrypt_status);
2360 status = PEP_OUT_OF_MEMORY;
2364 if (inner_message) // necessary? FIXME: check
2365 free_message(inner_message);
2367 free_stringlist(_keylist);
2369 return ADD_TO_LOG(status);
2372 DYNAMIC_API PEP_STATUS decrypt_message(
2373 PEP_SESSION session,
2376 stringlist_t **keylist,
2378 PEP_decrypt_flags_t *flags
2381 return _decrypt_message( session, src, dst, keylist, rating, flags, NULL );
2384 DYNAMIC_API PEP_STATUS own_message_private_key_details(
2385 PEP_SESSION session,
2387 pEp_identity **ident
2394 if (!(session && msg && ident))
2395 return PEP_ILLEGAL_VALUE;
2397 message *dst = NULL;
2398 stringlist_t *keylist = NULL;
2400 PEP_decrypt_flags_t flags;
2404 identity_list *private_il = NULL;
2405 PEP_STATUS status = _decrypt_message(session, msg, &dst, &keylist, &rating, &flags, &private_il);
2407 free_stringlist(keylist);
2409 if (status == PEP_STATUS_OK &&
2410 flags & PEP_decrypt_flag_own_private_key &&
2413 *ident = identity_dup(private_il->ident);
2416 free_identity_list(private_il);
2418 return ADD_TO_LOG(status);
2421 static void _max_comm_type_from_identity_list(
2422 identity_list *identities,
2423 PEP_SESSION session,
2424 PEP_comm_type *max_comm_type,
2425 bool *comm_type_determined
2429 for (il = identities; il != NULL; il = il->next)
2433 PEP_STATUS status = update_identity(session, il->ident);
2434 if (status == PEP_STATUS_OK)
2436 *max_comm_type = _get_comm_type(session, *max_comm_type,
2438 *comm_type_determined = true;
2444 DYNAMIC_API PEP_STATUS outgoing_message_rating(
2445 PEP_SESSION session,
2450 PEP_comm_type max_comm_type = PEP_ct_pEp;
2451 bool comm_type_determined = false;
2455 assert(msg->dir == PEP_dir_outgoing);
2458 if (!(session && msg && rating))
2459 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2461 if (msg->dir != PEP_dir_outgoing)
2462 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2464 *rating = PEP_rating_undefined;
2466 _max_comm_type_from_identity_list(msg->to, session,
2467 &max_comm_type, &comm_type_determined);
2469 _max_comm_type_from_identity_list(msg->cc, session,
2470 &max_comm_type, &comm_type_determined);
2472 _max_comm_type_from_identity_list(msg->bcc, session,
2473 &max_comm_type, &comm_type_determined);
2475 if (comm_type_determined == false)
2476 *rating = PEP_rating_undefined;
2478 *rating = _MAX(_rating(max_comm_type, PEP_rating_undefined),
2479 PEP_rating_unencrypted);
2481 return PEP_STATUS_OK;
2484 DYNAMIC_API PEP_STATUS identity_rating(
2485 PEP_SESSION session,
2486 pEp_identity *ident,
2490 PEP_STATUS status = PEP_STATUS_OK;
2496 if (!(session && ident && rating))
2497 return PEP_ILLEGAL_VALUE;
2499 if (_identity_me(ident))
2500 status = _myself(session, ident, false, true);
2502 status = update_identity(session, ident);
2504 if (status == PEP_STATUS_OK)
2505 *rating = _rating(ident->comm_type, PEP_rating_undefined);
2510 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
2512 PEP_STATUS status = PEP_STATUS_OK;
2516 return PEP_ILLEGAL_VALUE;
2518 if (cryptotech[tech].binary_path == NULL)
2521 status = cryptotech[tech].binary_path(path);
2527 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
2529 if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
2530 return PEP_color_no_color;
2532 if (rating < PEP_rating_undefined)
2533 return PEP_color_red;
2535 if (rating < PEP_rating_reliable)
2536 return PEP_color_no_color;
2538 if (rating < PEP_rating_trusted)
2539 return PEP_color_yellow;
2541 if (rating >= PEP_rating_trusted)
2542 return PEP_color_green;
2544 // this should never happen
2546 return PEP_color_no_color;
2549 /* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
2550 static short asciihex_to_num(char a) {
2551 short conv_num = -1;
2552 if (a >= 0x30 && a <= 0x39)
2553 conv_num = a - 0x30;
2555 // convert case, subtract offset, get number
2556 conv_num = ((a | 0x20) - 0x61) + 10;
2557 if (conv_num < 0xa || conv_num > 0xf)
2563 static char num_to_asciihex(short h) {
2564 if (h < 0 || h > 16)
2567 return (char)(h + 0x30);
2568 return (char)((h - 10) + 0x41); // for readability
2571 static char xor_hex_chars(char a, char b) {
2572 short a_num = asciihex_to_num(a);
2573 short b_num = asciihex_to_num(b);
2574 if (a_num < 0 || b_num < 0)
2576 short xor_num = a_num^b_num;
2577 return num_to_asciihex(xor_num);
2580 static char* skip_separators(char* current, char* begin) {
2581 while (current >= begin) {
2582 /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
2583 char check_char = *current;
2584 switch (check_char) {
2602 PEP_STATUS check_for_zero_fpr(char* fpr) {
2603 PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
2607 status = PEP_STATUS_OK;
2617 DYNAMIC_API PEP_STATUS get_trustwords(
2618 PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
2619 const char* lang, char **words, size_t *wsize, bool full
2630 int SHORT_NUM_TWORDS = 5;
2632 PEP_STATUS status = PEP_STATUS_OK;
2634 if (!(session && id1 && id2 && words && wsize) ||
2635 !(id1->fpr) || (!id2->fpr))
2636 return PEP_ILLEGAL_VALUE;
2638 char *source1 = id1->fpr;
2639 char *source2 = id2->fpr;
2641 int source1_len = strlen(source1);
2642 int source2_len = strlen(source2);
2648 max_len = (source1_len > source2_len ? source1_len : source2_len);
2650 char* XORed_fpr = (char*)(calloc(1,max_len + 1));
2651 *(XORed_fpr + max_len) = '\0';
2652 char* result_curr = XORed_fpr + max_len - 1;
2653 char* source1_curr = source1 + source1_len - 1;
2654 char* source2_curr = source2 + source2_len - 1;
2656 while (source1 <= source1_curr && source2 <= source2_curr) {
2657 source1_curr = skip_separators(source1_curr, source1);
2658 source2_curr = skip_separators(source2_curr, source2);
2660 if (source1_curr < source1 || source2_curr < source2)
2663 char xor_hex = xor_hex_chars(*source1_curr, *source2_curr);
2664 if (xor_hex == '\0') {
2665 status = PEP_ILLEGAL_VALUE;
2669 *result_curr = xor_hex;
2670 result_curr--; source1_curr--; source2_curr--;
2673 char* remainder_start = NULL;
2674 char* remainder_curr = NULL;
2676 if (source1 <= source1_curr) {
2677 remainder_start = source1;
2678 remainder_curr = source1_curr;
2680 else if (source2 <= source2_curr) {
2681 remainder_start = source2;
2682 remainder_curr = source2_curr;
2684 if (remainder_curr) {
2685 while (remainder_start <= remainder_curr) {
2686 remainder_curr = skip_separators(remainder_curr, remainder_start);
2688 if (remainder_curr < remainder_start)
2691 char the_char = *remainder_curr;
2693 if (asciihex_to_num(the_char) < 0) {
2694 status = PEP_ILLEGAL_VALUE;
2698 *result_curr = the_char;
2706 if (result_curr > XORed_fpr) {
2707 char* tempstr = strdup(result_curr);
2709 XORed_fpr = tempstr;
2712 status = check_for_zero_fpr(XORed_fpr);
2714 if (status != PEP_STATUS_OK)
2717 size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
2719 char* the_words = NULL;
2720 size_t the_size = 0;
2722 status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
2723 if (status != PEP_STATUS_OK)
2729 status = PEP_STATUS_OK;
2737 return ADD_TO_LOG(status);
2740 DYNAMIC_API PEP_STATUS get_message_trustwords(
2741 PEP_SESSION session,
2743 stringlist_t *keylist,
2744 pEp_identity* received_by,
2745 const char* lang, char **words, bool full
2750 assert(received_by);
2751 assert(received_by->address);
2758 received_by->address &&
2761 return PEP_ILLEGAL_VALUE;
2763 pEp_identity* partner = NULL;
2765 PEP_STATUS status = PEP_STATUS_OK;
2769 // We want fingerprint of key that did sign the message
2771 if (keylist == NULL) {
2773 // Message is to be decrypted
2774 message *dst = NULL;
2775 stringlist_t *_keylist = keylist;
2777 PEP_decrypt_flags_t flags;
2778 status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
2780 if (status != PEP_STATUS_OK) {
2782 free_stringlist(_keylist);
2786 if (dst && dst->from && _keylist) {
2787 partner = identity_dup(dst->from);
2790 partner->fpr = strdup(_keylist->value);
2791 if (partner->fpr == NULL)
2792 status = PEP_OUT_OF_MEMORY;
2794 status = PEP_OUT_OF_MEMORY;
2797 status = PEP_UNKNOWN_ERROR;
2801 free_stringlist(_keylist);
2805 // Message already decrypted
2806 if (keylist->value) {
2807 partner = identity_dup(msg->from);
2810 partner->fpr = strdup(keylist->value);
2811 if (partner->fpr == NULL)
2812 status = PEP_OUT_OF_MEMORY;
2814 status = PEP_OUT_OF_MEMORY;
2817 status = PEP_ILLEGAL_VALUE;
2821 if (status != PEP_STATUS_OK) {
2822 free_identity(partner);
2823 return ADD_TO_LOG(status);
2826 // Find own identity corresponding to given account address.
2827 // In that case we want default key attached to own identity
2828 pEp_identity *stored_identity = NULL;
2829 status = get_identity(session,
2830 received_by->address,
2834 if (status != PEP_STATUS_OK) {
2835 free_identity(stored_identity);
2836 return ADD_TO_LOG(status);
2839 // get the trustwords
2841 status = get_trustwords(session,
2842 partner, received_by,
2843 lang, words, &wsize, full);
2845 return ADD_TO_LOG(status);
2848 DYNAMIC_API PEP_STATUS MIME_decrypt_message(
2849 PEP_SESSION session,
2850 const char *mimetext,
2852 char** mime_plaintext,
2853 stringlist_t **keylist,
2855 PEP_decrypt_flags_t *flags
2859 assert(mime_plaintext);
2864 PEP_STATUS status = PEP_STATUS_OK;
2865 message* tmp_msg = NULL;
2866 message* dec_msg = NULL;
2867 *mime_plaintext = NULL;
2869 status = mime_decode_message(mimetext, size, &tmp_msg);
2870 if (status != PEP_STATUS_OK)
2873 PEP_STATUS decrypt_status = decrypt_message(session,
2880 if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
2881 dec_msg = message_dup(tmp_msg);
2884 if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN || !dec_msg)
2886 status = decrypt_status;
2890 status = mime_encode_message(dec_msg, false, mime_plaintext);
2892 if (status == PEP_STATUS_OK)
2896 return ADD_TO_LOG(decrypt_status);
2900 free_message(tmp_msg);
2901 free_message(dec_msg);
2903 return ADD_TO_LOG(status);
2907 DYNAMIC_API PEP_STATUS MIME_encrypt_message(
2908 PEP_SESSION session,
2909 const char *mimetext,
2911 stringlist_t* extra,
2912 char** mime_ciphertext,
2913 PEP_enc_format enc_format,
2914 PEP_encrypt_flags_t flags
2917 PEP_STATUS status = PEP_STATUS_OK;
2918 message* tmp_msg = NULL;
2919 message* enc_msg = NULL;
2921 status = mime_decode_message(mimetext, size, &tmp_msg);
2922 if (status != PEP_STATUS_OK)
2925 // This isn't incoming, though... so we need to reverse the direction
2926 tmp_msg->dir = PEP_dir_outgoing;
2927 status = encrypt_message(session,
2933 if (status != PEP_STATUS_OK)
2938 status = PEP_UNKNOWN_ERROR;
2942 status = mime_encode_message(enc_msg, false, mime_ciphertext);
2945 free_message(tmp_msg);
2946 free_message(enc_msg);
2948 return ADD_TO_LOG(status);
2952 DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
2953 PEP_SESSION session,
2954 pEp_identity* target_id,
2955 const char *mimetext,
2957 char** mime_ciphertext,
2958 PEP_enc_format enc_format,
2959 PEP_encrypt_flags_t flags
2962 PEP_STATUS status = PEP_STATUS_OK;
2963 message* tmp_msg = NULL;
2964 message* enc_msg = NULL;
2966 status = mime_decode_message(mimetext, size, &tmp_msg);
2967 if (status != PEP_STATUS_OK)
2970 // This isn't incoming, though... so we need to reverse the direction
2971 tmp_msg->dir = PEP_dir_outgoing;
2972 status = encrypt_message_for_self(session,
2978 if (status != PEP_STATUS_OK)
2982 status = PEP_UNKNOWN_ERROR;
2986 status = mime_encode_message(enc_msg, false, mime_ciphertext);
2989 free_message(tmp_msg);
2990 free_message(enc_msg);
2992 return ADD_TO_LOG(status);
2995 static PEP_rating string_to_rating(const char * rating)
2998 return PEP_rating_undefined;
2999 if (strcmp(rating, "cannot_decrypt") == 0)
3000 return PEP_rating_cannot_decrypt;
3001 if (strcmp(rating, "have_no_key") == 0)
3002 return PEP_rating_have_no_key;
3003 if (strcmp(rating, "unencrypted") == 0)
3004 return PEP_rating_unencrypted;
3005 if (strcmp(rating, "unencrypted_for_some") == 0)
3006 return PEP_rating_unencrypted_for_some;
3007 if (strcmp(rating, "unreliable") == 0)
3008 return PEP_rating_unreliable;
3009 if (strcmp(rating, "reliable") == 0)
3010 return PEP_rating_reliable;
3011 if (strcmp(rating, "trusted") == 0)
3012 return PEP_rating_trusted;
3013 if (strcmp(rating, "trusted_and_anonymized") == 0)
3014 return PEP_rating_trusted_and_anonymized;
3015 if (strcmp(rating, "fully_anonymous") == 0)
3016 return PEP_rating_fully_anonymous;
3017 if (strcmp(rating, "mistrust") == 0)
3018 return PEP_rating_mistrust;
3019 if (strcmp(rating, "b0rken") == 0)
3020 return PEP_rating_b0rken;
3021 if (strcmp(rating, "under_attack") == 0)
3022 return PEP_rating_under_attack;
3023 return PEP_rating_undefined;
3026 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
3028 if (skeylist == NULL || keylist == NULL)
3029 return PEP_ILLEGAL_VALUE;
3031 stringlist_t *rkeylist = NULL;
3032 stringlist_t *_kcurr = NULL;
3033 const char * fpr_begin = skeylist;
3034 const char * fpr_end = NULL;
3037 fpr_end = strstr(fpr_begin, ",");
3039 char * fpr = strndup(
3041 (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
3046 _kcurr = stringlist_add(_kcurr, fpr);
3047 if (_kcurr == NULL) {
3052 if (rkeylist == NULL)
3055 fpr_begin = fpr_end ? fpr_end + 1 : NULL;
3057 } while (fpr_begin);
3059 *keylist = rkeylist;
3060 return PEP_STATUS_OK;
3063 free_stringlist(rkeylist);
3064 return PEP_OUT_OF_MEMORY;
3067 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
3068 PEP_SESSION session,
3070 stringlist_t *x_keylist,
3071 PEP_rating x_enc_status,
3075 PEP_STATUS status = PEP_STATUS_OK;
3076 stringlist_t *_keylist = x_keylist;
3077 bool must_free_keylist = false;
3084 if (!(session && msg && rating))
3085 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
3087 *rating = PEP_rating_undefined;
3089 if (x_enc_status == PEP_rating_undefined){
3090 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
3091 if (strcasecmp(i->value->key, "X-EncStatus") == 0){
3092 x_enc_status = string_to_rating(i->value->value);
3096 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
3101 _rating = x_enc_status;
3103 if (_keylist == NULL){
3104 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
3105 if (strcasecmp(i->value->key, "X-KeyList") == 0){
3106 status = string_to_keylist(i->value->value, &_keylist);
3107 if (status != PEP_STATUS_OK)
3109 must_free_keylist = true;
3114 // there was no rcpt fpr, it could be an unencrypted mail
3115 if(_rating == PEP_rating_unencrypted) {
3117 return ADD_TO_LOG(PEP_STATUS_OK);
3120 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
3124 status = update_identity(session, msg->from);
3125 if (status != PEP_STATUS_OK)
3128 status = amend_rating_according_to_sender_and_recipients(session,
3132 if (status == PEP_STATUS_OK)
3136 if (must_free_keylist)
3137 free_stringlist(_keylist);
3139 return ADD_TO_LOG(status);