static gboolean empe_inlinepgp_encrypted_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelCipherContext *cipher; CamelCipherValidity *valid; CamelMimePart *opart; CamelDataWrapper *dw; gchar *mime_type; gint len; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; GError *local_error = NULL; if (g_cancellable_is_cancelled (cancellable)) return FALSE; cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); opart = camel_mime_part_new (); /* Decrypt the message */ valid = camel_cipher_context_decrypt_sync ( cipher, part, opart, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse PGP message: %s"), local_error->message); g_error_free (local_error); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); g_object_unref (cipher); g_object_unref (opart); return TRUE; } dw = camel_medium_get_content ((CamelMedium *) opart); mime_type = camel_data_wrapper_get_mime_type (dw); /* this ensures to show the 'opart' as inlined, if possible */ if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) { const gchar *snoop; snoop = e_mail_part_snoop_type (opart); if (snoop != NULL) { camel_data_wrapper_set_mime_type (dw, snoop); /* Set the MIME type on the 'opart' itself as well. * If it's "text/plain", then we want the TextPlain * parser extension to treat it as "text/plain" and * NOT wrap it as an attachment. */ camel_data_wrapper_set_mime_type ( CAMEL_DATA_WRAPPER (opart), snoop); } } e_mail_part_preserve_charset_in_content_type (part, opart); g_free (mime_type); /* Pass it off to the real formatter */ len = part_id->len; g_string_append (part_id, ".inlinepgp_encrypted"); g_warn_if_fail (e_mail_parser_parse_part_as ( parser, opart, part_id, camel_data_wrapper_get_mime_type (dw), cancellable, &work_queue)); g_string_truncate (part_id, len); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".inlinepgp_encrypted.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } /* Clean Up */ camel_cipher_validity_free (valid); g_object_unref (opart); g_object_unref (cipher); return TRUE; }
gint main (gint argc, gchar **argv) { CamelSession *session; CamelCipherContext *ctx; GError **error; CamelCipherValidity *valid; CamelMimePart *mime_part; CamelMultipartSigned *mps; CamelMultipartEncrypted *mpe; GPtrArray *recipients; gint ret; camel_test_init (argc, argv); /* clear out any camel-test data */ system ("/bin/rm -rf /tmp/camel-test"); system ("/bin/mkdir /tmp/camel-test"); setenv ("GNUPGHOME", "/tmp/camel-test/.gnupg", 1); /* import the gpg keys */ if ((ret = system ("gpg < /dev/null > /dev/null 2>&1")) == -1) return 77; else if (WEXITSTATUS (ret) == 127) return 77; system ("gpg --import ../data/camel-test.gpg.pub > /dev/null 2>&1"); system ("gpg --import ../data/camel-test.gpg.sec > /dev/null 2>&1"); session = camel_pgp_session_new ("/tmp/camel-test"); ex = camel_exception_new (); ctx = camel_gpg_context_new (session); camel_gpg_context_set_always_trust (CAMEL_GPG_CONTEXT (ctx), TRUE); camel_test_start ("Test of PGP/MIME functions"); mime_part = camel_mime_part_new (); camel_mime_part_set_content (mime_part, test_msg, strlen (test_msg), "text/plain"); camel_mime_part_set_description (mime_part, "Test of PGP/MIME multipart/signed stuff"); camel_test_push ("PGP/MIME signing"); mps = camel_multipart_signed_new (); camel_multipart_signed_sign (mps, ctx, mime_part, "*****@*****.**", CAMEL_CIPHER_HASH_SHA1, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); camel_test_pull (); g_object_unref (mime_part); camel_exception_clear (ex); camel_test_push ("PGP/MIME verify"); valid = camel_multipart_signed_verify (mps, ctx, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); check_msg (camel_cipher_validity_get_valid (valid), "%s", camel_cipher_validity_get_description (valid)); camel_cipher_validity_free (valid); camel_test_pull (); g_object_unref (mps); camel_exception_clear (ex); mime_part = camel_mime_part_new (); camel_mime_part_set_content (mime_part, test_msg, strlen (test_msg), "text/plain"); camel_mime_part_set_description (mime_part, "Test of PGP/MIME multipart/encrypted stuff"); camel_test_push ("PGP/MIME encrypt"); recipients = g_ptr_array_new (); g_ptr_array_add (recipients, "*****@*****.**"); mpe = camel_multipart_encrypted_new (); camel_multipart_encrypted_encrypt (mpe, mime_part, ctx, "*****@*****.**", recipients, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); g_ptr_array_free (recipients, TRUE); camel_test_pull (); camel_exception_clear (ex); g_object_unref (mime_part); camel_test_push ("PGP/MIME decrypt"); mime_part = camel_multipart_encrypted_decrypt (mpe, ctx, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); g_object_unref (mime_part); g_object_unref (mpe); camel_test_pull (); g_object_unref (ctx); g_object_unref (session); camel_test_end (); return 0; }
static gboolean empe_mp_signed_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelMimePart *cpart = NULL; CamelMultipart *multipart; CamelCipherContext *cipher = NULL; CamelContentType *content_type; CamelSession *session; guint32 validity_type; CamelCipherValidity *valid; const gchar *protocol = NULL; GError *local_error = NULL; gint i, nparts, len; gboolean secured; /* If the part is application/pgp-signature sub-part then skip it. */ if (!CAMEL_IS_MULTIPART (part)) { content_type = camel_mime_part_get_content_type (part); if (camel_content_type_is ( content_type, "application", "pgp-signature")) { return TRUE; } } multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); if (CAMEL_IS_MULTIPART_SIGNED (multipart)) { cpart = camel_multipart_get_part ( multipart, CAMEL_MULTIPART_SIGNED_CONTENT); } if (cpart == NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse MIME message. " "Displaying as source.")); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); return TRUE; } content_type = camel_data_wrapper_get_mime_type_field ( CAMEL_DATA_WRAPPER (multipart)); if (content_type != NULL) protocol = camel_content_type_param (content_type, "protocol"); session = e_mail_parser_get_session (parser); /* FIXME: Should be done via a plugin interface */ /* FIXME: duplicated in em-format-html-display.c */ if (protocol != NULL) { #ifdef ENABLE_SMIME if (g_ascii_strcasecmp ("application/x-pkcs7-signature", protocol) == 0 || g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0) { cipher = camel_smime_context_new (session); validity_type = E_MAIL_PART_VALIDITY_SMIME; } else { #endif if (g_ascii_strcasecmp ("application/pgp-signature", protocol) == 0) { cipher = camel_gpg_context_new (session); validity_type = E_MAIL_PART_VALIDITY_PGP; } #ifdef ENABLE_SMIME } #endif } if (cipher == NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Unsupported signature format")); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); return TRUE; } valid = camel_cipher_context_verify_sync ( cipher, part, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Error verifying signature: %s"), local_error->message); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); g_object_unref (cipher); g_error_free (local_error); return TRUE; } nparts = camel_multipart_get_number (multipart); secured = FALSE; len = part_id->len; for (i = 0; i < nparts; i++) { GQueue work_queue = G_QUEUE_INIT; GList *head, *link; CamelMimePart *subpart; subpart = camel_multipart_get_part (multipart, i); g_string_append_printf (part_id, ".signed.%d", i); g_warn_if_fail (e_mail_parser_parse_part ( parser, subpart, part_id, cancellable, &work_queue)); g_string_truncate (part_id, len); if (!secured) secured = e_mail_part_is_secured (subpart); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); } e_queue_transfer (&work_queue, out_mail_parts); } /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself. */ if (!secured) { GQueue work_queue = G_QUEUE_INIT; EMailPart *mail_part; g_string_append (part_id, ".signed.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } camel_cipher_validity_free (valid); g_object_unref (cipher); return TRUE; }
static gboolean empe_mp_encrypted_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelCipherContext *context; const gchar *protocol; CamelMimePart *opart; CamelCipherValidity *valid; CamelMultipartEncrypted *mpe; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; GError *local_error = NULL; gint len; mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part); if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse MIME message. " "Displaying as source.")); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution/source", cancellable, out_mail_parts); return TRUE; } /* Currently we only handle RFC2015-style PGP encryption. */ protocol = camel_content_type_param ( ((CamelDataWrapper *) mpe)->mime_type, "protocol"); if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) { e_mail_parser_error ( parser, out_mail_parts, _("Unsupported encryption type for multipart/encrypted")); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); return TRUE; } context = camel_gpg_context_new (e_mail_parser_get_session (parser)); opart = camel_mime_part_new (); valid = camel_cipher_context_decrypt_sync ( context, part, opart, cancellable, &local_error); e_mail_part_preserve_charset_in_content_type (part, opart); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse PGP/MIME message: %s"), local_error->message); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); g_object_unref (opart); g_object_unref (context); g_error_free (local_error); return TRUE; } len = part_id->len; g_string_append (part_id, ".encrypted"); g_warn_if_fail (e_mail_parser_parse_part ( parser, opart, part_id, cancellable, &work_queue)); g_string_truncate (part_id, len); head = g_queue_peek_head_link (&work_queue); /* Update validity of all encrypted sub-parts */ for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); /* Add a widget with details about the encryption, but only when * the decrypted part isn't itself secured, in that case it has * created the button itself. */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".encrypted.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } camel_cipher_validity_free (valid); /* TODO: Make sure when we finalize this part, it is zero'd out */ g_object_unref (opart); g_object_unref (context); return TRUE; }
static gboolean empe_inlinepgp_signed_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelStream *filtered_stream; CamelMimeFilterPgp *pgp_filter; CamelContentType *content_type; CamelCipherContext *cipher; CamelCipherValidity *valid; CamelDataWrapper *dw; CamelMimePart *opart; CamelStream *ostream; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; gchar *type; gint len; GError *local_error = NULL; GByteArray *ba; if (g_cancellable_is_cancelled (cancellable) || /* avoid recursion */ (part_id->str && part_id->len > 17 && g_str_has_suffix (part_id->str, ".inlinepgp_signed"))) return FALSE; cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); /* Verify the signature of the message */ valid = camel_cipher_context_verify_sync ( cipher, part, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Error verifying signature: %s"), local_error->message); g_error_free (local_error); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); g_object_unref (cipher); return TRUE; } /* Setup output stream */ ostream = camel_stream_mem_new (); filtered_stream = camel_stream_filter_new (ostream); /* Add PGP header / footer filter */ pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new (); camel_stream_filter_add ( CAMEL_STREAM_FILTER (filtered_stream), CAMEL_MIME_FILTER (pgp_filter)); g_object_unref (pgp_filter); /* Pass through the filters that have been setup */ dw = camel_medium_get_content ((CamelMedium *) part); camel_data_wrapper_decode_to_stream_sync ( dw, (CamelStream *) filtered_stream, cancellable, NULL); camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL); g_object_unref (filtered_stream); /* Create a new text/plain MIME part containing the signed * content preserving the original part's Content-Type params. */ content_type = camel_mime_part_get_content_type (part); type = camel_content_type_format (content_type); content_type = camel_content_type_decode (type); g_free (type); g_free (content_type->type); content_type->type = g_strdup ("text"); g_free (content_type->subtype); content_type->subtype = g_strdup ("plain"); type = camel_content_type_format (content_type); camel_content_type_unref (content_type); ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream); opart = camel_mime_part_new (); camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type); g_free (type); len = part_id->len; g_string_append (part_id, ".inlinepgp_signed"); e_mail_parser_parse_part ( parser, opart, part_id, cancellable, &work_queue); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".inlinepgp_signed.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } /* Clean Up */ camel_cipher_validity_free (valid); g_object_unref (opart); g_object_unref (ostream); g_object_unref (cipher); return TRUE; }
int main (int argc, char **argv) { CamelSession *session; CamelCipherContext *ctx; CamelException *ex; CamelCipherValidity *valid; CamelStream *stream1, *stream2; struct _CamelMimePart *sigpart, *conpart, *encpart, *outpart; CamelDataWrapper *dw; GPtrArray *recipients; GByteArray *buf; char *before, *after; int ret; if (getenv("CAMEL_TEST_GPG") == NULL) return 77; camel_test_init (argc, argv); /* clear out any camel-test data */ system ("/bin/rm -rf /tmp/camel-test"); system ("/bin/mkdir /tmp/camel-test"); setenv ("GNUPGHOME", "/tmp/camel-test/.gnupg", 1); /* import the gpg keys */ if ((ret = system ("gpg < /dev/null > /dev/null 2>&1")) == -1) return 77; else if (WEXITSTATUS (ret) == 127) return 77; g_message ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.pub > /dev/null 2>&1"); system ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.pub > /dev/null 2>&1"); g_message ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.sec > /dev/null 2>&1"); system ("gpg --import " TEST_DATA_DIR "/camel-test.gpg.sec > /dev/null 2>&1"); session = camel_pgp_session_new ("/tmp/camel-test"); ex = camel_exception_new (); ctx = camel_gpg_context_new (session); camel_gpg_context_set_always_trust (CAMEL_GPG_CONTEXT (ctx), TRUE); camel_test_start ("Test of PGP functions"); stream1 = camel_stream_mem_new (); camel_stream_write (stream1, "Hello, I am a test stream.\n", 27); camel_stream_reset (stream1); conpart = camel_mime_part_new(); dw = camel_data_wrapper_new(); camel_data_wrapper_construct_from_stream(dw, stream1); camel_medium_set_content_object((CamelMedium *)conpart, dw); camel_object_unref(stream1); camel_object_unref(dw); sigpart = camel_mime_part_new(); camel_test_push ("PGP signing"); camel_cipher_sign (ctx, "*****@*****.**", CAMEL_CIPHER_HASH_SHA1, conpart, sigpart, ex); if (camel_exception_is_set(ex)) { printf("PGP signing failed assuming non-functional environment\n%s", camel_exception_get_description (ex)); camel_test_pull(); return 77; } camel_test_pull (); camel_exception_clear (ex); camel_test_push ("PGP verify"); valid = camel_cipher_verify (ctx, sigpart, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); check_msg (camel_cipher_validity_get_valid (valid), "%s", camel_cipher_validity_get_description (valid)); camel_cipher_validity_free (valid); camel_test_pull (); camel_object_unref(conpart); camel_object_unref(sigpart); stream1 = camel_stream_mem_new (); camel_stream_write (stream1, "Hello, I am a test of encryption/decryption.", 44); camel_stream_reset (stream1); conpart = camel_mime_part_new(); dw = camel_data_wrapper_new(); camel_stream_reset(stream1); camel_data_wrapper_construct_from_stream(dw, stream1); camel_medium_set_content_object((CamelMedium *)conpart, dw); camel_object_unref(stream1); camel_object_unref(dw); encpart = camel_mime_part_new(); camel_exception_clear (ex); camel_test_push ("PGP encrypt"); recipients = g_ptr_array_new (); g_ptr_array_add (recipients, "*****@*****.**"); camel_cipher_encrypt (ctx, "*****@*****.**", recipients, conpart, encpart, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); g_ptr_array_free (recipients, TRUE); camel_test_pull (); camel_exception_clear (ex); camel_test_push ("PGP decrypt"); outpart = camel_mime_part_new(); valid = camel_cipher_decrypt (ctx, encpart, outpart, ex); check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex)); check_msg (valid->encrypt.status == CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED, "%s", valid->encrypt.description); stream1 = camel_stream_mem_new(); stream2 = camel_stream_mem_new(); camel_data_wrapper_write_to_stream((CamelDataWrapper *)conpart, stream1); camel_data_wrapper_write_to_stream((CamelDataWrapper *)outpart, stream2); buf = CAMEL_STREAM_MEM (stream1)->buffer; before = g_strndup (buf->data, buf->len); buf = CAMEL_STREAM_MEM (stream2)->buffer; after = g_strndup (buf->data, buf->len); check_msg (string_equal (before, after), "before = '%s', after = '%s'", before, after); g_free (before); g_free (after); camel_object_unref(stream1); camel_object_unref(stream2); camel_object_unref(conpart); camel_object_unref(encpart); camel_object_unref(outpart); camel_test_pull (); camel_object_unref (CAMEL_OBJECT (ctx)); camel_object_unref (CAMEL_OBJECT (session)); camel_test_end (); return 0; }