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))
24 static bool string_equality(const char *s1, const char *s2)
26 if (s1 == NULL || s2 == NULL)
31 return strcmp(s1, s2) == 0;
34 static bool is_mime_type(const bloblist_t *bl, const char *mt)
38 return bl && string_equality(bl->mime_type, mt);
42 // This function presumes the file ending is a proper substring of the
43 // filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
44 // return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
45 // return false. This is desired behaviour.
47 static bool is_fileending(const bloblist_t *bl, const char *fe)
51 if (bl == NULL || bl->filename == NULL || fe == NULL)
54 assert(bl && bl->filename);
56 size_t fe_len = strlen(fe);
57 size_t fn_len = strlen(bl->filename);
62 assert(fn_len > fe_len);
64 return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
67 void add_opt_field(message *msg, const char *name, const char *value)
69 assert(msg && name && value);
71 if (msg && name && value) {
72 stringpair_t *pair = new_stringpair(name, value);
76 stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
79 free_stringpair(pair);
83 if (msg->opt_fields == NULL)
84 msg->opt_fields = field;
88 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
91 assert(strcmp(shortmsg, "pEp") != 0);
93 if (!shortmsg || strcmp(shortmsg, "pEp") == 0) {
98 char *result = strdup(longmsg);
107 const char * const subject = "Subject: ";
108 const size_t SUBJ_LEN = 9;
109 const char * const newlines = "\n\n";
110 const size_t NL_LEN = 2;
112 const size_t bufsize = SUBJ_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
113 char * ptext = calloc(1, bufsize);
118 strlcpy(ptext, subject, bufsize);
119 strlcat(ptext, shortmsg, bufsize);
120 strlcat(ptext, newlines, bufsize);
121 strlcat(ptext, longmsg, bufsize);
126 static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
128 char *_shortmsg = NULL;
129 char *_longmsg = NULL;
135 if (src == NULL || shortmsg == NULL || longmsg == NULL)
141 if (strncasecmp(src, "subject: ", 9) == 0) {
142 char *line_end = strchr(src, '\n');
144 if (line_end == NULL) {
145 _shortmsg = strdup(src + 9);
147 if (_shortmsg == NULL)
152 size_t n = line_end - src;
154 if (*(line_end - 1) == '\r')
155 _shortmsg = strndup(src + 9, n - 10);
157 _shortmsg = strndup(src + 9, n - 9);
159 if (_shortmsg == NULL)
162 while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
166 _longmsg = strdup(src + n);
168 if (_longmsg == NULL)
172 *shortmsg = _shortmsg;
175 // If there's no "Subject: " and the shortmsg is
176 // pEp (or anything else), then we shouldn't be replacing it.
177 // Chances are that the message wasn't encrypted
178 // using pEp and that the actually subject IS pEp. In any event,
179 // erasing the subject line when we don't have one in the plaintext
180 // isn't the right behaviour.
181 // _shortmsg = strdup("");
182 _longmsg = strdup(src);
184 if (_longmsg == NULL)
199 static PEP_STATUS copy_fields(message *dst, const message *src)
205 return PEP_ILLEGAL_VALUE;
207 free_timestamp(dst->sent);
210 dst->sent = timestamp_dup(src->sent);
211 if (dst->sent == NULL)
212 return PEP_OUT_OF_MEMORY;
215 free_timestamp(dst->recv);
218 dst->recv = timestamp_dup(src->recv);
219 if (dst->recv == NULL)
220 return PEP_OUT_OF_MEMORY;
223 free_identity(dst->from);
226 dst->from = identity_dup(src->from);
227 if (dst->from == NULL)
228 return PEP_OUT_OF_MEMORY;
231 free_identity_list(dst->to);
233 if (src->to && src->to->ident) {
234 dst->to = identity_list_dup(src->to);
236 return PEP_OUT_OF_MEMORY;
239 free_identity(dst->recv_by);
242 dst->recv_by = identity_dup(src->recv_by);
243 if (dst->recv_by == NULL)
244 return PEP_OUT_OF_MEMORY;
247 free_identity_list(dst->cc);
249 if (src->cc && src->cc->ident) {
250 dst->cc = identity_list_dup(src->cc);
252 return PEP_OUT_OF_MEMORY;
255 free_identity_list(dst->bcc);
257 if (src->bcc && src->bcc->ident) {
258 dst->bcc = identity_list_dup(src->bcc);
259 if (dst->bcc == NULL)
260 return PEP_OUT_OF_MEMORY;
263 free_identity_list(dst->reply_to);
264 dst->reply_to = NULL;
265 if (src->reply_to && src->reply_to->ident) {
266 dst->reply_to = identity_list_dup(src->reply_to);
267 if (dst->reply_to == NULL)
268 return PEP_OUT_OF_MEMORY;
271 free_stringlist(dst->in_reply_to);
272 dst->in_reply_to = NULL;
273 if (src->in_reply_to && src->in_reply_to->value) {
274 dst->in_reply_to = stringlist_dup(src->in_reply_to);
275 if (dst->in_reply_to == NULL)
276 return PEP_OUT_OF_MEMORY;
279 free_stringlist(dst->references);
280 dst->references = NULL;
281 if (src->references) {
282 dst->references = stringlist_dup(src->references);
283 if (dst->references == NULL)
284 return PEP_OUT_OF_MEMORY;
287 free_stringlist(dst->keywords);
288 dst->keywords = NULL;
289 if (src->keywords && src->keywords->value) {
290 dst->keywords = stringlist_dup(src->keywords);
291 if (dst->keywords == NULL)
292 return PEP_OUT_OF_MEMORY;
296 dst->comments = NULL;
298 dst->comments = strdup(src->comments);
299 assert(dst->comments);
300 if (dst->comments == NULL)
301 return PEP_OUT_OF_MEMORY;
304 free_stringpair_list(dst->opt_fields);
305 dst->opt_fields = NULL;
306 if (src->opt_fields) {
307 dst->opt_fields = stringpair_list_dup(src->opt_fields);
308 if (dst->opt_fields == NULL)
309 return PEP_OUT_OF_MEMORY;
312 return PEP_STATUS_OK;
315 static message * clone_to_empty_message(const message * src)
318 message * msg = NULL;
324 msg = calloc(1, sizeof(message));
331 status = copy_fields(msg, src);
332 if (status != PEP_STATUS_OK)
342 static PEP_STATUS encrypt_PGP_MIME(
347 PEP_encrypt_flags_t flags
350 PEP_STATUS status = PEP_STATUS_OK;
351 bool free_ptext = false;
354 char *mimetext = NULL;
356 assert(dst->longmsg == NULL);
357 dst->enc_format = PEP_enc_PGP_MIME;
359 if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
360 if (session->unencrypted_subject) {
361 dst->shortmsg = strdup(src->shortmsg);
362 assert(dst->shortmsg);
363 if (dst->shortmsg == NULL)
365 ptext = src->longmsg;
368 ptext = combine_short_and_long(src->shortmsg, src->longmsg);
374 else if (src->longmsg) {
375 ptext = src->longmsg;
381 message *_src = calloc(1, sizeof(message));
385 _src->longmsg = ptext;
386 _src->longmsg_formatted = src->longmsg_formatted;
387 _src->attachments = src->attachments;
388 _src->enc_format = PEP_enc_none;
389 status = mime_encode_message(_src, true, &mimetext);
390 assert(status == PEP_STATUS_OK);
391 if (status != PEP_STATUS_OK)
400 if (mimetext == NULL)
403 if (flags & PEP_encrypt_flag_force_unsigned)
404 status = encrypt_only(session, keys, mimetext, strlen(mimetext),
407 status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
413 dst->longmsg = strdup("this message was encrypted with p≡p "
414 "https://pEp-project.org");
415 assert(dst->longmsg);
416 if (dst->longmsg == NULL)
419 char *v = strdup("Version: 1");
424 bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
427 dst->attachments = _a;
429 _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
434 return PEP_STATUS_OK;
437 status = PEP_OUT_OF_MEMORY;
446 static PEP_STATUS encrypt_PGP_in_pieces(
451 PEP_encrypt_flags_t flags
454 PEP_STATUS status = PEP_STATUS_OK;
458 bool free_ptext = false;
460 assert(dst->longmsg == NULL);
461 assert(dst->attachments == NULL);
463 dst->enc_format = PEP_enc_pieces;
465 bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
467 if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0) {
468 if (session->unencrypted_subject) {
469 dst->shortmsg = strdup(src->shortmsg);
470 assert(dst->shortmsg);
471 if (dst->shortmsg == NULL)
473 ptext = src->longmsg;
476 ptext = combine_short_and_long(src->shortmsg, src->longmsg);
483 status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
486 status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
492 dst->longmsg = ctext;
498 else if (src->longmsg && src->longmsg[0]) {
499 ptext = src->longmsg;
501 status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
504 status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
507 dst->longmsg = ctext;
514 dst->longmsg = strdup("");
515 assert(dst->longmsg);
516 if (dst->longmsg == NULL)
520 if (src->longmsg_formatted && src->longmsg_formatted[0]) {
521 ptext = src->longmsg_formatted;
523 status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
526 status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
530 bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
531 "application/octet-stream", "PGPexch.htm.pgp");
534 if (dst->attachments == NULL)
535 dst->attachments = _a;
542 if (src->attachments) {
543 if (dst->attachments == NULL) {
544 dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
545 if (dst->attachments == NULL)
549 bloblist_t *_s = src->attachments;
550 bloblist_t *_d = dst->attachments;
552 for (int n = 0; _s; _s = _s->next) {
553 if (_s->value == NULL && _s->size == 0) {
554 _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
559 size_t psize = _s->size;
562 status = encrypt_only(session, keys, ptext, psize, &ctext,
565 status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
568 char *filename = NULL;
571 size_t len = strlen(_s->filename);
572 size_t bufsize = len + 5; // length of .pgp extension + NUL
573 filename = calloc(1, bufsize);
574 if (filename == NULL)
577 strlcpy(filename, _s->filename, bufsize);
578 strlcat(filename, ".pgp", bufsize);
581 filename = calloc(1, 20);
582 if (filename == NULL)
587 snprintf(filename, 20, "Attachment%d.pgp", n);
590 _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
603 return PEP_STATUS_OK;
606 status = PEP_OUT_OF_MEMORY;
614 static char * keylist_to_string(const stringlist_t *keylist)
617 size_t size = stringlist_length(keylist);
619 const stringlist_t *_kl;
620 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
621 size += strlen(_kl->value);
624 char *result = calloc(1, size);
629 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
630 _r = stpcpy(_r, _kl->value);
631 if (_kl->next && _kl->next->value)
632 _r = stpcpy(_r, ",");
642 static const char * rating_to_string(PEP_rating rating)
645 case PEP_rating_cannot_decrypt:
646 return "cannot_decrypt";
647 case PEP_rating_have_no_key:
648 return "have_no_key";
649 case PEP_rating_unencrypted:
650 return "unencrypted";
651 case PEP_rating_unencrypted_for_some:
652 return "unencrypted_for_some";
653 case PEP_rating_unreliable:
655 case PEP_rating_reliable:
657 case PEP_rating_trusted:
659 case PEP_rating_trusted_and_anonymized:
660 return "trusted_and_anonymized";
661 case PEP_rating_fully_anonymous:
662 return "fully_anonymous";
663 case PEP_rating_mistrust:
665 case PEP_rating_b0rken:
667 case PEP_rating_under_attack:
668 return "under_attack";
674 static void decorate_message(
677 stringlist_t *keylist
682 add_opt_field(msg, "X-pEp-Version", PEP_VERSION);
684 if (rating != PEP_rating_undefined)
685 add_opt_field(msg, "X-EncStatus", rating_to_string(rating));
688 char *_keylist = keylist_to_string(keylist);
689 add_opt_field(msg, "X-KeyList", _keylist);
694 static PEP_rating _rating(PEP_comm_type ct, PEP_rating rating)
696 if (ct == PEP_ct_unknown)
697 return PEP_rating_undefined;
699 else if (ct == PEP_ct_key_not_found)
700 return PEP_rating_have_no_key;
702 else if (ct == PEP_ct_compromized)
703 return PEP_rating_under_attack;
705 else if (ct == PEP_ct_mistrusted)
706 return PEP_rating_mistrust;
708 if (rating == PEP_rating_unencrypted_for_some)
709 return PEP_rating_unencrypted_for_some;
711 if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
712 ct == PEP_ct_my_key_not_included) {
713 if (rating > PEP_rating_unencrypted_for_some)
714 return PEP_rating_unencrypted_for_some;
716 return PEP_rating_unencrypted;
719 if (rating == PEP_rating_unencrypted)
720 return PEP_rating_unencrypted_for_some;
722 if (ct >= PEP_ct_confirmed_enc_anon)
723 return PEP_rating_trusted_and_anonymized;
725 else if (ct >= PEP_ct_strong_encryption)
726 return PEP_rating_trusted;
728 else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
729 return PEP_rating_reliable;
732 return PEP_rating_unreliable;
735 static bool is_encrypted_attachment(const bloblist_t *blob)
739 if (blob == NULL || blob->filename == NULL)
742 char *ext = strrchr(blob->filename, '.');
746 if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
747 if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
748 strcmp(ext, ".asc") == 0)
751 else if (strcmp(blob->mime_type, "text/plain") == 0) {
752 if (strcmp(ext, ".asc") == 0)
759 static bool is_encrypted_html_attachment(const bloblist_t *blob)
762 assert(blob->filename);
763 if (blob == NULL || blob->filename == NULL)
766 if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
767 if (strcmp(blob->filename + 11, ".pgp") == 0 ||
768 strcmp(blob->filename + 11, ".asc") == 0)
775 static char * without_double_ending(const char *filename)
778 if (filename == NULL)
781 char *ext = strrchr(filename, '.');
785 char *result = strndup(filename, ext - filename);
790 static PEP_rating decrypt_rating(PEP_STATUS status)
793 case PEP_UNENCRYPTED:
795 case PEP_VERIFY_NO_KEY:
796 case PEP_VERIFIED_AND_TRUSTED:
797 return PEP_rating_unencrypted;
800 case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
801 return PEP_rating_unreliable;
803 case PEP_DECRYPTED_AND_VERIFIED:
804 return PEP_rating_reliable;
806 case PEP_DECRYPT_NO_KEY:
807 return PEP_rating_have_no_key;
809 case PEP_DECRYPT_WRONG_FORMAT:
810 case PEP_CANNOT_DECRYPT_UNKNOWN:
811 return PEP_rating_cannot_decrypt;
814 return PEP_rating_undefined;
818 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
824 if (session == NULL || fpr == NULL)
825 return PEP_rating_undefined;
828 PEP_comm_type bare_comm_type = PEP_ct_unknown;
829 PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
830 if (status != PEP_STATUS_OK)
831 return PEP_rating_undefined;
833 PEP_comm_type least_trust_type = PEP_ct_unknown;
834 least_trust(session, fpr, &least_trust_type);
836 if (least_trust_type == PEP_ct_unknown) {
837 return _rating(bare_comm_type, PEP_rating_undefined);
839 return _rating(least_trust_type, PEP_rating_undefined);
843 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
844 return ((rating1 < rating2) ? rating1 : rating2);
847 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist)
849 PEP_rating rating = PEP_rating_undefined;
851 assert(keylist && keylist->value);
852 if (keylist == NULL || keylist->value == NULL)
853 return PEP_rating_undefined;
857 for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
861 PEP_rating _rating_ = key_rating(session, _kl->value);
863 if (_rating_ <= PEP_rating_mistrust)
870 else if (rating == PEP_rating_undefined)
871 rating = worst_rating(rating, _rating_);
873 if (_rating_ >= PEP_rating_reliable) {
874 status = least_trust(session, _kl->value, &ct);
875 if (status != PEP_STATUS_OK)
876 return PEP_rating_undefined;
877 if (ct == PEP_ct_unknown){
878 /* per edouard, we reduce reliable+ ratings to reliable because
880 if (rating >= PEP_rating_reliable){
881 rating = PEP_rating_reliable;
885 rating = worst_rating(rating, _rating(ct, rating));
888 else if (_rating_ == PEP_rating_unencrypted) {
889 if (rating > PEP_rating_unencrypted_for_some)
890 rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
897 static PEP_comm_type _get_comm_type(
899 PEP_comm_type max_comm_type,
903 PEP_STATUS status = update_identity(session, ident);
905 if (max_comm_type == PEP_ct_compromized)
906 return PEP_ct_compromized;
908 if (max_comm_type == PEP_ct_mistrusted)
909 return PEP_ct_mistrusted;
911 if (status == PEP_STATUS_OK) {
912 if (ident->comm_type == PEP_ct_compromized)
913 return PEP_ct_compromized;
914 else if (ident->comm_type == PEP_ct_mistrusted)
915 return PEP_ct_mistrusted;
917 return _MIN(max_comm_type, ident->comm_type);
920 return PEP_ct_unknown;
924 static void free_bl_entry(bloblist_t *bl)
934 static bool is_key(const bloblist_t *bl)
936 return (// workaround for Apple Mail bugs
937 (is_mime_type(bl, "application/x-apple-msg-attachment") &&
938 is_fileending(bl, ".asc")) ||
939 // as binary, by file name
940 ((bl->mime_type == NULL ||
941 is_mime_type(bl, "application/octet-stream")) &&
942 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
943 is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
944 // explicit mime type
945 is_mime_type(bl, "application/pgp-keys") ||
946 // as text, by file name
947 (is_mime_type(bl, "text/plain") &&
948 (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
949 is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
953 static void remove_attached_keys(message *msg)
956 bloblist_t *last = NULL;
957 for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
958 bloblist_t *next = bl->next;
965 msg->attachments = next;
977 bool import_attached_keys(
980 identity_list **private_idents
986 if (session == NULL || msg == NULL)
992 for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
995 if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
998 import_key(session, bl->value, bl->size, private_idents);
1006 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
1008 char *keydata = NULL;
1011 PEP_STATUS status = export_key(session, fpr, &keydata, &size);
1012 assert(status == PEP_STATUS_OK);
1013 if (status != PEP_STATUS_OK)
1017 bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
1020 if (msg->attachments == NULL && bl)
1021 msg->attachments = bl;
1023 return PEP_STATUS_OK;
1026 #define ONE_WEEK (7*24*3600)
1028 void attach_own_key(PEP_SESSION session, message *msg)
1033 if (msg->dir == PEP_dir_incoming)
1036 assert(msg->from && msg->from->fpr);
1037 if (msg->from == NULL || msg->from->fpr == NULL)
1040 if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
1043 char *revoked_fpr = NULL;
1044 uint64_t revocation_date = 0;
1046 if(get_revoked(session, msg->from->fpr,
1047 &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
1048 revoked_fpr != NULL)
1050 time_t now = time(NULL);
1052 if (now < (time_t)revocation_date + ONE_WEEK)
1054 _attach_key(session, revoked_fpr, msg);
1060 PEP_cryptotech determine_encryption_format(message *msg)
1064 if (is_PGP_message_text(msg->longmsg)) {
1065 msg->enc_format = PEP_enc_pieces;
1066 return PEP_crypt_OpenPGP;
1068 else if (msg->attachments && msg->attachments->next &&
1069 is_mime_type(msg->attachments, "application/pgp-encrypted") &&
1070 is_PGP_message_text(msg->attachments->next->value)
1072 msg->enc_format = PEP_enc_PGP_MIME;
1073 return PEP_crypt_OpenPGP;
1075 else if (msg->attachments && msg->attachments->next &&
1076 is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
1077 is_PGP_message_text(msg->attachments->value)
1079 msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
1080 return PEP_crypt_OpenPGP;
1083 msg->enc_format = PEP_enc_none;
1084 return PEP_crypt_none;
1088 DYNAMIC_API PEP_STATUS encrypt_message(
1089 PEP_SESSION session,
1091 stringlist_t * extra,
1093 PEP_enc_format enc_format,
1094 PEP_encrypt_flags_t flags
1097 PEP_STATUS status = PEP_STATUS_OK;
1098 message * msg = NULL;
1099 stringlist_t * keys = NULL;
1104 assert(enc_format != PEP_enc_none);
1106 if (!(session && src && dst && enc_format != PEP_enc_none))
1107 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1109 if (src->dir == PEP_dir_incoming)
1110 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1112 determine_encryption_format(src);
1113 if (src->enc_format != PEP_enc_none)
1114 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1118 status = myself(session, src->from);
1119 if (status != PEP_STATUS_OK)
1122 keys = new_stringlist(src->from->fpr);
1126 stringlist_t *_k = keys;
1129 _k = stringlist_append(_k, extra);
1134 bool dest_keys_found = true;
1135 PEP_comm_type max_comm_type = PEP_ct_pEp;
1137 identity_list * _il;
1139 if ((_il = src->bcc) && _il->ident)
1141 // BCC limited support:
1142 // - App splits mails with BCC in multiple mails.
1143 // - Each email is encrypted separately
1145 if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
1147 // Only one Bcc with no other recipient allowed for now
1148 return PEP_ILLEGAL_VALUE;
1151 PEP_STATUS _status = update_identity(session, _il->ident);
1152 if (_status != PEP_STATUS_OK) {
1157 if (_il->ident->fpr && _il->ident->fpr[0]) {
1158 _k = stringlist_add(_k, _il->ident->fpr);
1161 max_comm_type = _get_comm_type(session, max_comm_type,
1165 dest_keys_found = false;
1166 status = PEP_KEY_NOT_FOUND;
1171 for (_il = src->to; _il && _il->ident; _il = _il->next) {
1172 PEP_STATUS _status = update_identity(session, _il->ident);
1173 if (_status != PEP_STATUS_OK) {
1178 if (_il->ident->fpr && _il->ident->fpr[0]) {
1179 _k = stringlist_add(_k, _il->ident->fpr);
1182 max_comm_type = _get_comm_type(session, max_comm_type,
1186 dest_keys_found = false;
1187 status = PEP_KEY_NOT_FOUND;
1191 for (_il = src->cc; _il && _il->ident; _il = _il->next) {
1192 PEP_STATUS _status = update_identity(session, _il->ident);
1193 if (_status != PEP_STATUS_OK)
1199 if (_il->ident->fpr && _il->ident->fpr[0]) {
1200 _k = stringlist_add(_k, _il->ident->fpr);
1203 max_comm_type = _get_comm_type(session, max_comm_type,
1207 dest_keys_found = false;
1208 status = PEP_KEY_NOT_FOUND;
1213 if (!dest_keys_found ||
1214 stringlist_length(keys) == 0 ||
1215 _rating(max_comm_type,
1216 PEP_rating_undefined) < PEP_rating_reliable)
1218 free_stringlist(keys);
1219 if (!session->passive_mode && !(flags & PEP_encrypt_flag_force_no_attached_key))
1220 attach_own_key(session, src);
1221 return ADD_TO_LOG(PEP_UNENCRYPTED);
1224 msg = clone_to_empty_message(src);
1228 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1229 attach_own_key(session, src);
1231 switch (enc_format) {
1232 case PEP_enc_PGP_MIME:
1233 case PEP_enc_PEP: // BUG: should be implemented extra
1234 status = encrypt_PGP_MIME(session, src, keys, msg, flags);
1237 case PEP_enc_pieces:
1238 status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
1241 /* case PEP_enc_PEP:
1247 status = PEP_ILLEGAL_VALUE;
1251 if (status == PEP_OUT_OF_MEMORY)
1254 if (status != PEP_STATUS_OK)
1258 free_stringlist(keys);
1260 if (msg && msg->shortmsg == NULL) {
1261 msg->shortmsg = strdup("pEp");
1262 assert(msg->shortmsg);
1263 if (msg->shortmsg == NULL)
1268 decorate_message(msg, PEP_rating_undefined, NULL);
1270 msg->id = strdup(src->id);
1272 if (msg->id == NULL)
1278 return ADD_TO_LOG(status);
1281 status = PEP_OUT_OF_MEMORY;
1284 free_stringlist(keys);
1287 return ADD_TO_LOG(status);
1290 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
1291 PEP_SESSION session,
1292 pEp_identity* target_id,
1295 PEP_enc_format enc_format,
1296 PEP_encrypt_flags_t flags
1299 PEP_STATUS status = PEP_STATUS_OK;
1300 message * msg = NULL;
1301 stringlist_t * keys = NULL;
1306 assert(enc_format != PEP_enc_none);
1308 if (!(session && src && dst && enc_format != PEP_enc_none))
1309 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1311 if (src->dir == PEP_dir_incoming)
1312 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1314 determine_encryption_format(src);
1315 if (src->enc_format != PEP_enc_none)
1316 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1318 status = myself(session, target_id);
1319 if (status != PEP_STATUS_OK)
1325 PEP_STATUS _status = update_identity(session, target_id);
1326 if (_status != PEP_STATUS_OK) {
1331 char* target_fpr = target_id->fpr;
1333 return PEP_KEY_NOT_FOUND; // FIXME: Error condition
1335 keys = new_stringlist(target_fpr);
1337 /* KG: did we ever do this??? */
1338 if (!(flags & PEP_encrypt_flag_force_no_attached_key))
1339 _attach_key(session, target_fpr, src);
1341 msg = clone_to_empty_message(src);
1345 switch (enc_format) {
1346 case PEP_enc_PGP_MIME:
1347 case PEP_enc_PEP: // BUG: should be implemented extra
1348 status = encrypt_PGP_MIME(session, src, keys, msg, flags);
1351 case PEP_enc_pieces:
1352 status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
1355 /* case PEP_enc_PEP:
1361 status = PEP_ILLEGAL_VALUE;
1365 if (status == PEP_OUT_OF_MEMORY)
1368 if (status != PEP_STATUS_OK)
1371 if (msg && msg->shortmsg == NULL) {
1372 msg->shortmsg = strdup("pEp");
1373 assert(msg->shortmsg);
1374 if (msg->shortmsg == NULL)
1380 msg->id = strdup(src->id);
1382 if (msg->id == NULL)
1391 status = PEP_OUT_OF_MEMORY;
1394 free_stringlist(keys);
1397 return ADD_TO_LOG(status);
1400 static bool is_a_pEpmessage(const message *msg)
1402 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
1403 if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
1409 // update comm_type to pEp_ct_pEp if needed
1411 static PEP_STATUS _update_identity_for_incoming_message(
1412 PEP_SESSION session,
1417 if (src->from && src->from->address) {
1418 status = update_identity(session, src->from);
1419 if (status == PEP_STATUS_OK
1420 && is_a_pEpmessage(src)
1421 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
1422 && src->from->comm_type != PEP_ct_pEp_unconfirmed
1423 && src->from->comm_type != PEP_ct_pEp)
1425 src->from->comm_type |= PEP_ct_pEp_unconfirmed;
1426 status = set_identity(session, src->from);
1430 return PEP_ILLEGAL_VALUE;
1434 PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
1435 bloblist_t* attach_curr = msg->attachments;
1437 *signature_blob = NULL;
1439 while (attach_curr) {
1440 if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
1441 *signature_blob = attach_curr;
1444 attach_curr = attach_curr->next;
1447 return PEP_STATUS_OK;
1450 PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
1451 char** stext, size_t* ssize) {
1453 char* signed_boundary = NULL;
1454 char* signpost = strstr(ptext, "Content-Type: multipart/signed");
1460 return PEP_UNKNOWN_ERROR;
1462 char* curr_line = signpost;
1463 // const char* end_text = ptext + psize;
1464 const char* boundary_key = "boundary=";
1465 const size_t BOUNDARY_KEY_SIZE = 9;
1467 char* start_boundary = strstr(curr_line, boundary_key);
1468 if (!start_boundary)
1469 return PEP_UNKNOWN_ERROR;
1471 start_boundary += BOUNDARY_KEY_SIZE;
1473 bool quoted = (*start_boundary == '"');
1478 char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
1481 return PEP_UNKNOWN_ERROR;
1483 // Add space for the "--"
1484 size_t boundary_strlen = (end_boundary - start_boundary) + 2;
1486 signed_boundary = calloc(1, boundary_strlen + 1);
1487 strlcpy(signed_boundary, "--", boundary_strlen + 1);
1488 strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
1490 start_boundary = strstr(end_boundary, signed_boundary);
1492 if (!start_boundary)
1493 return PEP_UNKNOWN_ERROR;
1495 start_boundary += boundary_strlen;
1497 if (*start_boundary == '\r') {
1498 if (*(start_boundary + 1) == '\n')
1499 start_boundary += 2;
1501 else if (*start_boundary == '\n')
1504 end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
1507 return PEP_UNKNOWN_ERROR;
1509 // See RFC3156 section 5...
1511 if (*(end_boundary - 1) == '\r')
1514 *ssize = end_boundary - start_boundary;
1515 *stext = start_boundary;
1516 free(signed_boundary);
1518 return PEP_STATUS_OK;
1521 PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in,
1522 stringlist_t** keylist_in_out,
1523 pEp_identity* from) {
1525 if (!verify_in || !(*verify_in)) // this isn't really a problem.
1526 return PEP_STATUS_OK;
1528 stringlist_t* orig_verify = *verify_in;
1530 stringlist_t* verify_curr = NULL;
1531 stringlist_t* from_keys = NULL;
1533 /* FIXME: what to do if head needs to be null */
1534 PEP_STATUS status = find_keys(session, from->address, &from_keys);
1536 stringlist_t* from_fpr_node = NULL;
1537 stringlist_t* from_curr;
1539 for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
1540 for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
1541 if (from_curr->value && verify_curr->value &&
1542 _same_fpr(from_curr->value, strlen(from_curr->value),
1543 verify_curr->value, strlen(verify_curr->value))) {
1544 from_fpr_node = from_curr;
1550 if (!from_fpr_node) {
1551 status = PEP_KEY_NOT_FOUND;
1555 verify_curr = orig_verify;
1557 /* put "from" signer at the beginning of the list */
1558 if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
1559 from_fpr_node->value, strlen(from_fpr_node->value))) {
1560 orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
1561 verify_curr = new_stringlist(from_fpr_node->value);
1562 verify_curr->next = orig_verify;
1565 /* append keylist to signers */
1566 if (keylist_in_out && *keylist_in_out && (*keylist_in_out)->value) {
1567 stringlist_t** tail_pp = &verify_curr->next;
1570 tail_pp = &((*tail_pp)->next);
1572 stringlist_t* second_list = *keylist_in_out;
1574 char* listhead_val = second_list->value;
1575 if (!listhead_val || listhead_val[0] == '\0') {
1576 /* remove head, basically. This can happen when,
1577 for example, the signature is detached and
1578 verification is not seen directly after
1579 decryption, so no signer is presumed in
1580 the first construction of the keylist */
1581 *keylist_in_out = (*keylist_in_out)->next;
1582 second_list->next = NULL;
1583 free_stringlist(second_list);
1586 *tail_pp = *keylist_in_out;
1589 *keylist_in_out = verify_curr;
1591 status = PEP_STATUS_OK;
1594 free_stringlist(from_keys);
1598 PEP_STATUS amend_rating_according_to_sender_and_recipients(
1599 PEP_SESSION session,
1601 pEp_identity *sender,
1602 stringlist_t *recipients) {
1604 PEP_STATUS status = PEP_STATUS_OK;
1606 if (*rating > PEP_rating_mistrust) {
1607 PEP_rating kl_rating = PEP_rating_undefined;
1610 kl_rating = keylist_rating(session, recipients);
1612 if (kl_rating <= PEP_rating_mistrust) {
1613 *rating = kl_rating;
1615 else if (*rating >= PEP_rating_reliable &&
1616 kl_rating < PEP_rating_reliable) {
1617 *rating = PEP_rating_unreliable;
1619 else if (*rating >= PEP_rating_reliable &&
1620 kl_rating >= PEP_rating_reliable) {
1621 if (!(sender && sender->user_id && sender->user_id[0])) {
1622 *rating = PEP_rating_unreliable;
1625 char *fpr = recipients->value;
1626 pEp_identity *_sender = new_identity(sender->address, fpr,
1627 sender->user_id, sender->username);
1628 if (_sender == NULL)
1629 return PEP_OUT_OF_MEMORY;
1630 status = get_trust(session, _sender);
1631 if (_sender->comm_type != PEP_ct_unknown) {
1632 *rating = worst_rating(_rating(_sender->comm_type, PEP_rating_undefined),
1635 free_identity(_sender);
1636 if (status == PEP_CANNOT_FIND_IDENTITY)
1637 status = PEP_STATUS_OK;
1645 DYNAMIC_API PEP_STATUS _decrypt_message(
1646 PEP_SESSION session,
1649 stringlist_t **keylist,
1651 PEP_decrypt_flags_t *flags,
1652 identity_list **private_il
1655 PEP_STATUS status = PEP_STATUS_OK;
1656 PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
1657 message *msg = NULL;
1662 stringlist_t *_keylist = NULL;
1671 if (!(session && src && dst && keylist && rating && flags))
1672 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
1676 // Private key in unencrypted mail are ignored -> NULL
1677 bool imported_keys = import_attached_keys(session, src, NULL);
1679 // Update src->from in case we just imported a key
1680 // we would need to check signature
1681 status = _update_identity_for_incoming_message(session, src);
1682 if(status != PEP_STATUS_OK)
1683 return ADD_TO_LOG(status);
1685 // Get detached signature, if any
1686 bloblist_t* detached_sig = NULL;
1687 char* dsig_text = NULL;
1688 size_t dsig_size = 0;
1689 status = _get_detached_signature(src, &detached_sig);
1691 dsig_text = detached_sig->value;
1692 dsig_size = detached_sig->size;
1695 PEP_cryptotech crypto = determine_encryption_format(src);
1699 *rating = PEP_rating_undefined;
1701 switch (src->enc_format) {
1703 *rating = PEP_rating_unencrypted;
1705 remove_attached_keys(src);
1706 if(session->sync_session->inject_sync_msg){
1707 status = receive_DeviceState_msg(session, src, *rating, *keylist);
1708 if (status == PEP_MESSAGE_CONSUME ||
1709 status == PEP_MESSAGE_IGNORE) {
1712 *flags |= (status == PEP_MESSAGE_IGNORE) ?
1713 PEP_decrypt_flag_ignore :
1714 PEP_decrypt_flag_consume;
1716 else if (status != PEP_STATUS_OK) {
1717 return ADD_TO_LOG(status);
1721 char* slong = src->longmsg;
1722 char* sform = src->longmsg_formatted;
1723 bloblist_t* satt = src->attachments;
1725 if ((!slong || slong[0] == '\0')
1726 && (!sform || sform[0] == '\0')) {
1728 const char* inner_mime_type = satt->mime_type;
1729 if (strcasecmp(inner_mime_type, "text/plain") == 0) {
1730 free(slong); /* in case of "" */
1731 src->longmsg = strndup(satt->value, satt->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
1733 bloblist_t* next_node = satt->next;
1735 inner_mime_type = next_node->mime_type;
1736 if (strcasecmp(inner_mime_type, "text/html") == 0) {
1738 src->longmsg_formatted = strndup(next_node->value, next_node->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
1742 else if (strcasecmp(inner_mime_type, "text/html") == 0) {
1744 src->longmsg_formatted = strndup(satt->value, satt->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
1749 return ADD_TO_LOG(PEP_UNENCRYPTED);
1751 case PEP_enc_PGP_MIME:
1752 ctext = src->attachments->next->value;
1753 csize = src->attachments->next->size;
1756 case PEP_enc_PGP_MIME_Outlook1:
1757 ctext = src->attachments->value;
1758 csize = src->attachments->size;
1761 case PEP_enc_pieces:
1762 ctext = src->longmsg;
1763 csize = strlen(ctext);
1769 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
1770 csize, dsig_text, dsig_size,
1771 &ptext, &psize, &_keylist);
1772 if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
1776 decrypt_status = status;
1778 if (status == PEP_DECRYPT_NO_KEY){
1779 PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
1780 if (sync_status == PEP_OUT_OF_MEMORY){
1781 status = PEP_OUT_OF_MEMORY;
1786 bool imported_private_key_address = false;
1789 switch (src->enc_format) {
1790 case PEP_enc_PGP_MIME:
1791 case PEP_enc_PGP_MIME_Outlook1:
1792 status = mime_decode_message(ptext, psize, &msg);
1793 if (status != PEP_STATUS_OK)
1796 char* mlong = msg->longmsg;
1797 char* mform = msg->longmsg_formatted;
1798 bloblist_t* matt = msg->attachments;
1800 if ((!mlong || mlong[0] == '\0')
1801 && (!mform || mform[0] == '\0')) {
1803 const char* inner_mime_type = matt->mime_type;
1804 if (strcasecmp(inner_mime_type, "text/plain") == 0) {
1805 free(mlong); /* in case of "" */
1806 msg->longmsg = strndup(matt->value, matt->size);
1808 bloblist_t* next_node = matt->next;
1810 inner_mime_type = next_node->mime_type;
1811 if (strcasecmp(inner_mime_type, "text/html") == 0) {
1813 msg->longmsg_formatted = strndup(next_node->value, next_node->size);
1817 else if (strcasecmp(inner_mime_type, "text/html") == 0) {
1819 msg->longmsg_formatted = strndup(matt->value, matt->size);
1822 if (msg->shortmsg) {
1823 free(src->shortmsg);
1824 src->shortmsg = strdup(msg->shortmsg);
1828 if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
1829 status = _get_detached_signature(msg, &detached_sig);
1830 if (decrypt_status == PEP_DECRYPTED && detached_sig) {
1831 dsig_text = detached_sig->value;
1832 dsig_size = detached_sig->size;
1836 status = _get_signed_text(ptext, psize, &stext, &ssize);
1837 stringlist_t *_verify_keylist = NULL;
1839 if (ssize > 0 && stext) {
1840 status = cryptotech[crypto].verify_text(session, stext,
1841 ssize, dsig_text, dsig_size,
1844 if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
1845 decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
1847 status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
1853 case PEP_enc_pieces:
1854 msg = clone_to_empty_message(src);
1858 msg->longmsg = ptext;
1861 bloblist_t *_m = msg->attachments;
1862 if (_m == NULL && src->attachments && src->attachments->value) {
1863 msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
1864 _m = msg->attachments;
1868 for (_s = src->attachments; _s; _s = _s->next) {
1869 if (_s->value == NULL && _s->size == 0){
1870 _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
1875 else if (is_encrypted_attachment(_s)) {
1876 stringlist_t *_keylist = NULL;
1877 char *attctext = _s->value;
1878 size_t attcsize = _s->size;
1883 // FIXME: What about attachments with separate sigs???
1884 status = decrypt_and_verify(session, attctext, attcsize,
1886 &ptext, &psize, &_keylist);
1887 free_stringlist(_keylist); // FIXME: Why do we do this?
1890 if (is_encrypted_html_attachment(_s)) {
1891 msg->longmsg_formatted = ptext;
1895 static const char * const mime_type = "application/octet-stream";
1896 char * const filename =
1897 without_double_ending(_s->filename);
1898 if (filename == NULL)
1901 _m = bloblist_add(_m, ptext, psize, mime_type,
1909 if (msg->attachments == NULL)
1910 msg->attachments = _m;
1914 char *copy = malloc(_s->size);
1918 memcpy(copy, _s->value, _s->size);
1919 _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
1925 char *copy = malloc(_s->size);
1929 memcpy(copy, _s->value, _s->size);
1930 _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
1939 // BUG: must implement more
1943 switch (src->enc_format) {
1944 case PEP_enc_PGP_MIME:
1945 case PEP_enc_pieces:
1946 case PEP_enc_PGP_MIME_Outlook1:
1947 status = copy_fields(msg, src);
1948 if (status != PEP_STATUS_OK)
1953 if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
1958 int r = separate_short_and_long(msg->longmsg, &shortmsg,
1964 if (shortmsg == NULL) {
1965 if (src->shortmsg == NULL)
1966 shortmsg = strdup("");
1968 // FIXME: is msg->shortmsg always a copy of
1969 // src->shortmsg already?
1970 // if so, we need to change the logic so
1971 // that in this case, we don't free msg->shortmsg
1972 // and do this strdup, etc.
1973 shortmsg = strdup(src->shortmsg);
1978 free(msg->shortmsg);
1981 msg->shortmsg = shortmsg;
1982 msg->longmsg = longmsg;
1985 msg->shortmsg = strdup(src->shortmsg);
1986 assert(msg->shortmsg);
1987 if (msg->shortmsg == NULL)
1992 // BUG: must implement more
1996 // check for private key in decrypted message attachement while inporting
1997 identity_list *_private_il = NULL;
1998 imported_keys = import_attached_keys(session, msg, &_private_il);
2000 identity_list_length(_private_il) == 1 &&
2001 _private_il->ident->address)
2003 imported_private_key_address = true;
2006 if(private_il && imported_private_key_address){
2007 *private_il = _private_il;
2009 free_identity_list(_private_il);
2012 if(decrypt_status == PEP_DECRYPTED){
2014 // TODO optimize if import_attached_keys didn't import any key
2016 // In case message did decrypt, but no valid signature could be found
2017 // then retry decrypt+verify after importing key.
2019 // Update msg->from in case we just imported a key
2020 // we would need to check signature
2022 status = _update_identity_for_incoming_message(session, src);
2023 if(status != PEP_STATUS_OK)
2028 char *re_ptext = NULL;
2031 free_stringlist(_keylist);
2034 status = cryptotech[crypto].decrypt_and_verify(session, ctext,
2035 csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
2039 if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
2044 decrypt_status = status;
2047 *rating = decrypt_rating(decrypt_status);
2049 status = amend_rating_according_to_sender_and_recipients(session,
2054 if (status != PEP_STATUS_OK)
2059 *rating = decrypt_rating(decrypt_status);
2063 // Case of own key imported from own trusted message
2064 if (// Message have been reliably decrypted
2066 *rating >= PEP_rating_trusted &&
2067 imported_private_key_address &&
2069 msg->to->ident->user_id &&
2070 strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
2073 *flags |= PEP_decrypt_flag_own_private_key;
2077 decorate_message(msg, *rating, _keylist);
2079 remove_attached_keys(msg);
2080 if (*rating >= PEP_rating_reliable &&
2081 session->sync_session->inject_sync_msg) {
2082 status = receive_DeviceState_msg(session, msg, *rating, _keylist);
2083 if (status == PEP_MESSAGE_CONSUME ||
2084 status == PEP_MESSAGE_IGNORE) {
2087 *flags |= (status == PEP_MESSAGE_IGNORE) ?
2088 PEP_decrypt_flag_ignore :
2089 PEP_decrypt_flag_consume;
2092 else if (status != PEP_STATUS_OK){
2099 msg->id = strdup(src->id);
2101 if (msg->id == NULL)
2107 *keylist = _keylist;
2109 if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
2110 return ADD_TO_LOG(PEP_STATUS_OK);
2112 return ADD_TO_LOG(decrypt_status);
2115 status = PEP_OUT_OF_MEMORY;
2120 free_stringlist(_keylist);
2122 return ADD_TO_LOG(status);
2125 DYNAMIC_API PEP_STATUS decrypt_message(
2126 PEP_SESSION session,
2129 stringlist_t **keylist,
2131 PEP_decrypt_flags_t *flags
2134 return _decrypt_message( session, src, dst, keylist, rating, flags, NULL );
2137 DYNAMIC_API PEP_STATUS own_message_private_key_details(
2138 PEP_SESSION session,
2140 pEp_identity **ident
2147 if (!(session && msg && ident))
2148 return PEP_ILLEGAL_VALUE;
2150 message *dst = NULL;
2151 stringlist_t *keylist = NULL;
2153 PEP_decrypt_flags_t flags;
2157 identity_list *private_il = NULL;
2158 PEP_STATUS status = _decrypt_message(session, msg, &dst, &keylist, &rating, &flags, &private_il);
2160 free_stringlist(keylist);
2162 if (status == PEP_STATUS_OK &&
2163 flags & PEP_decrypt_flag_own_private_key &&
2166 *ident = identity_dup(private_il->ident);
2169 free_identity_list(private_il);
2171 return ADD_TO_LOG(status);
2174 static void _max_comm_type_from_identity_list(
2175 identity_list *identities,
2176 PEP_SESSION session,
2177 PEP_comm_type *max_comm_type,
2178 bool *comm_type_determined
2182 for (il = identities; il != NULL; il = il->next)
2186 PEP_STATUS status = update_identity(session, il->ident);
2187 if (status == PEP_STATUS_OK)
2189 *max_comm_type = _get_comm_type(session, *max_comm_type,
2191 *comm_type_determined = true;
2197 DYNAMIC_API PEP_STATUS outgoing_message_rating(
2198 PEP_SESSION session,
2203 PEP_comm_type max_comm_type = PEP_ct_pEp;
2204 bool comm_type_determined = false;
2208 assert(msg->dir == PEP_dir_outgoing);
2211 if (!(session && msg && rating))
2212 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2214 if (msg->dir != PEP_dir_outgoing)
2215 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2217 *rating = PEP_rating_undefined;
2219 _max_comm_type_from_identity_list(msg->to, session,
2220 &max_comm_type, &comm_type_determined);
2222 _max_comm_type_from_identity_list(msg->cc, session,
2223 &max_comm_type, &comm_type_determined);
2225 _max_comm_type_from_identity_list(msg->bcc, session,
2226 &max_comm_type, &comm_type_determined);
2228 if (comm_type_determined == false)
2229 *rating = PEP_rating_undefined;
2231 *rating = _MAX(_rating(max_comm_type, PEP_rating_undefined),
2232 PEP_rating_unencrypted);
2234 return PEP_STATUS_OK;
2237 DYNAMIC_API PEP_STATUS identity_rating(
2238 PEP_SESSION session,
2239 pEp_identity *ident,
2243 PEP_STATUS status = PEP_STATUS_OK;
2249 if (!(session && ident && rating))
2250 return PEP_ILLEGAL_VALUE;
2253 status = _myself(session, ident, false, true);
2255 status = update_identity(session, ident);
2257 if (status == PEP_STATUS_OK)
2258 *rating = _rating(ident->comm_type, PEP_rating_undefined);
2263 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
2265 PEP_STATUS status = PEP_STATUS_OK;
2269 return PEP_ILLEGAL_VALUE;
2271 if (cryptotech[tech].binary_path == NULL)
2274 status = cryptotech[tech].binary_path(path);
2280 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
2282 if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
2283 return PEP_color_no_color;
2285 if (rating < PEP_rating_undefined)
2286 return PEP_color_red;
2288 if (rating < PEP_rating_reliable)
2289 return PEP_color_no_color;
2291 if (rating < PEP_rating_trusted)
2292 return PEP_color_yellow;
2294 if (rating >= PEP_rating_trusted)
2295 return PEP_color_green;
2297 // this should never happen
2299 return PEP_color_no_color;
2302 DYNAMIC_API PEP_STATUS get_trustwords(
2303 PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
2304 const char* lang, char **words, size_t *wsize, bool full
2315 if (!(session && id1 && id2 && words && wsize) ||
2316 !(id1->fpr) || (!id2->fpr))
2317 return PEP_ILLEGAL_VALUE;
2319 const char *source1 = id1->fpr;
2320 const char *source2 = id2->fpr;
2325 const size_t SHORT_NUM_TWORDS = 5;
2327 // N.B. THIS will have to be changed once we start checking trustword entropy.
2328 // For now, full is ALL, and otherwise it's 5-per-id.
2329 size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
2331 char* first_set = NULL;
2332 char* second_set = NULL;
2333 size_t first_wsize = 0;
2334 size_t second_wsize = 0;
2336 int fpr_comparison = -255;
2337 PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
2338 if (status != PEP_STATUS_OK)
2341 char* _retstr = NULL;
2343 switch (fpr_comparison) {
2344 case 1: // source1 > source2
2345 status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
2346 if (status != PEP_STATUS_OK)
2348 status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
2349 if (status != PEP_STATUS_OK)
2353 case -1: // source1 <= source2
2354 status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
2355 if (status != PEP_STATUS_OK)
2357 status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
2358 if (status != PEP_STATUS_OK)
2362 return ADD_TO_LOG(PEP_UNKNOWN_ERROR); // shouldn't be possible
2365 size_t _wsize = first_wsize + second_wsize;
2367 bool needs_space = (first_set[first_wsize - 1] != ' ');
2372 _retstr = calloc(1, _wsize + 1);
2374 size_t len = strlcpy(_retstr, first_set, _wsize);
2375 if (len >= _wsize) {
2376 status = PEP_UNKNOWN_ERROR;
2380 strlcat(_retstr, " ", _wsize);
2381 if (len >= _wsize) {
2382 status = PEP_UNKNOWN_ERROR;
2386 strlcat(_retstr, second_set, _wsize);
2388 status = PEP_UNKNOWN_ERROR;
2394 status = PEP_STATUS_OK;
2404 return ADD_TO_LOG(status);
2407 DYNAMIC_API PEP_STATUS get_message_trustwords(
2408 PEP_SESSION session,
2410 stringlist_t *keylist,
2411 pEp_identity* received_by,
2412 const char* lang, char **words, bool full
2417 assert(received_by);
2418 assert(received_by->address);
2425 received_by->address &&
2428 return PEP_ILLEGAL_VALUE;
2430 pEp_identity* partner = NULL;
2432 PEP_STATUS status = PEP_STATUS_OK;
2436 // We want fingerprint of key that did sign the message
2438 if (keylist == NULL) {
2440 // Message is to be decrypted
2441 message *dst = NULL;
2442 stringlist_t *_keylist = keylist;
2444 PEP_decrypt_flags_t flags;
2445 status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
2447 if (status != PEP_STATUS_OK) {
2449 free_stringlist(_keylist);
2453 if (dst && dst->from && _keylist) {
2454 partner = identity_dup(dst->from);
2457 partner->fpr = strdup(_keylist->value);
2458 if (partner->fpr == NULL)
2459 status = PEP_OUT_OF_MEMORY;
2461 status = PEP_OUT_OF_MEMORY;
2464 status = PEP_UNKNOWN_ERROR;
2468 free_stringlist(_keylist);
2472 // Message already decrypted
2473 if (keylist->value) {
2474 partner = identity_dup(msg->from);
2477 partner->fpr = strdup(keylist->value);
2478 if (partner->fpr == NULL)
2479 status = PEP_OUT_OF_MEMORY;
2481 status = PEP_OUT_OF_MEMORY;
2484 status = PEP_ILLEGAL_VALUE;
2488 if (status != PEP_STATUS_OK) {
2489 free_identity(partner);
2490 return ADD_TO_LOG(status);
2493 // Find own identity corresponding to given account address.
2494 // In that case we want default key attached to own identity
2495 pEp_identity *stored_identity = NULL;
2496 status = get_identity(session,
2497 received_by->address,
2501 if (status != PEP_STATUS_OK) {
2502 free_identity(stored_identity);
2503 return ADD_TO_LOG(status);
2506 // get the trustwords
2508 status = get_trustwords(session,
2509 partner, received_by,
2510 lang, words, &wsize, full);
2512 return ADD_TO_LOG(status);
2515 DYNAMIC_API PEP_STATUS MIME_decrypt_message(
2516 PEP_SESSION session,
2517 const char *mimetext,
2519 char** mime_plaintext,
2520 stringlist_t **keylist,
2522 PEP_decrypt_flags_t *flags
2526 assert(mime_plaintext);
2531 PEP_STATUS status = PEP_STATUS_OK;
2532 message* tmp_msg = NULL;
2533 message* dec_msg = NULL;
2534 *mime_plaintext = NULL;
2536 status = mime_decode_message(mimetext, size, &tmp_msg);
2537 if (status != PEP_STATUS_OK)
2540 PEP_STATUS decrypt_status = decrypt_message(session,
2547 if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
2548 dec_msg = message_dup(tmp_msg);
2551 if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN || !dec_msg)
2553 status = decrypt_status;
2557 status = mime_encode_message(dec_msg, false, mime_plaintext);
2559 if (status == PEP_STATUS_OK)
2563 return ADD_TO_LOG(decrypt_status);
2567 free_message(tmp_msg);
2568 free_message(dec_msg);
2570 return ADD_TO_LOG(status);
2574 DYNAMIC_API PEP_STATUS MIME_encrypt_message(
2575 PEP_SESSION session,
2576 const char *mimetext,
2578 stringlist_t* extra,
2579 char** mime_ciphertext,
2580 PEP_enc_format enc_format,
2581 PEP_encrypt_flags_t flags
2584 PEP_STATUS status = PEP_STATUS_OK;
2585 message* tmp_msg = NULL;
2586 message* enc_msg = NULL;
2588 status = mime_decode_message(mimetext, size, &tmp_msg);
2589 if (status != PEP_STATUS_OK)
2592 // This isn't incoming, though... so we need to reverse the direction
2593 tmp_msg->dir = PEP_dir_outgoing;
2594 status = encrypt_message(session,
2600 if (status != PEP_STATUS_OK)
2605 status = PEP_UNKNOWN_ERROR;
2609 status = mime_encode_message(enc_msg, false, mime_ciphertext);
2612 free_message(tmp_msg);
2613 free_message(enc_msg);
2615 return ADD_TO_LOG(status);
2619 DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
2620 PEP_SESSION session,
2621 pEp_identity* target_id,
2622 const char *mimetext,
2624 char** mime_ciphertext,
2625 PEP_enc_format enc_format,
2626 PEP_encrypt_flags_t flags
2629 PEP_STATUS status = PEP_STATUS_OK;
2630 message* tmp_msg = NULL;
2631 message* enc_msg = NULL;
2633 status = mime_decode_message(mimetext, size, &tmp_msg);
2634 if (status != PEP_STATUS_OK)
2637 // This isn't incoming, though... so we need to reverse the direction
2638 tmp_msg->dir = PEP_dir_outgoing;
2639 status = encrypt_message_for_self(session,
2645 if (status != PEP_STATUS_OK)
2649 status = PEP_UNKNOWN_ERROR;
2653 status = mime_encode_message(enc_msg, false, mime_ciphertext);
2656 free_message(tmp_msg);
2657 free_message(enc_msg);
2659 return ADD_TO_LOG(status);
2662 static PEP_rating string_to_rating(const char * rating)
2665 return PEP_rating_undefined;
2666 if (strcmp(rating, "cannot_decrypt") == 0)
2667 return PEP_rating_cannot_decrypt;
2668 if (strcmp(rating, "have_no_key") == 0)
2669 return PEP_rating_have_no_key;
2670 if (strcmp(rating, "unencrypted") == 0)
2671 return PEP_rating_unencrypted;
2672 if (strcmp(rating, "unencrypted_for_some") == 0)
2673 return PEP_rating_unencrypted_for_some;
2674 if (strcmp(rating, "unreliable") == 0)
2675 return PEP_rating_unreliable;
2676 if (strcmp(rating, "reliable") == 0)
2677 return PEP_rating_reliable;
2678 if (strcmp(rating, "trusted") == 0)
2679 return PEP_rating_trusted;
2680 if (strcmp(rating, "trusted_and_anonymized") == 0)
2681 return PEP_rating_trusted_and_anonymized;
2682 if (strcmp(rating, "fully_anonymous") == 0)
2683 return PEP_rating_fully_anonymous;
2684 if (strcmp(rating, "mistrust") == 0)
2685 return PEP_rating_mistrust;
2686 if (strcmp(rating, "b0rken") == 0)
2687 return PEP_rating_b0rken;
2688 if (strcmp(rating, "under_attack") == 0)
2689 return PEP_rating_under_attack;
2690 return PEP_rating_undefined;
2693 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
2695 if (skeylist == NULL || keylist == NULL)
2696 return PEP_ILLEGAL_VALUE;
2698 stringlist_t *rkeylist = NULL;
2699 stringlist_t *_kcurr = NULL;
2700 const char * fpr_begin = skeylist;
2701 const char * fpr_end = NULL;
2704 fpr_end = strstr(fpr_begin, ",");
2706 char * fpr = strndup(
2708 (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
2713 _kcurr = stringlist_add(_kcurr, fpr);
2714 if (_kcurr == NULL) {
2719 if (rkeylist == NULL)
2722 fpr_begin = fpr_end ? fpr_end + 1 : NULL;
2724 } while (fpr_begin);
2726 *keylist = rkeylist;
2727 return PEP_STATUS_OK;
2730 free_stringlist(rkeylist);
2731 return PEP_OUT_OF_MEMORY;
2734 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
2735 PEP_SESSION session,
2737 stringlist_t *x_keylist,
2738 PEP_rating x_enc_status,
2742 PEP_STATUS status = PEP_STATUS_OK;
2743 stringlist_t *_keylist = x_keylist;
2744 bool must_free_keylist = false;
2751 if (!(session && msg && rating))
2752 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2754 *rating = PEP_rating_undefined;
2756 if (x_enc_status == PEP_rating_undefined){
2757 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
2758 if (strcasecmp(i->value->key, "X-EncStatus") == 0){
2759 x_enc_status = string_to_rating(i->value->value);
2763 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2768 _rating = x_enc_status;
2770 if (_keylist == NULL){
2771 for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
2772 if (strcasecmp(i->value->key, "X-KeyList") == 0){
2773 status = string_to_keylist(i->value->value, &_keylist);
2774 if (status != PEP_STATUS_OK)
2776 must_free_keylist = true;
2780 return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
2784 status = update_identity(session, msg->from);
2785 if (status != PEP_STATUS_OK)
2788 status = amend_rating_according_to_sender_and_recipients(session,
2792 if (status == PEP_STATUS_OK)
2796 if (must_free_keylist)
2797 free_stringlist(_keylist);
2799 return ADD_TO_LOG(status);