Example #1
0
static gboolean
handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent,
		    MuMsgOptions opts, unsigned *index, gboolean decrypted,
		    MuMsgPartForeachFunc func, gpointer user_data)
{
	if (GMIME_IS_PART (mobj))
		return handle_part
			(msg, GMIME_PART(mobj), parent,
			 opts, index, decrypted, func, user_data);
	else if (GMIME_IS_MESSAGE_PART (mobj))
		return handle_message_part
			(msg, GMIME_MESSAGE_PART(mobj),
			 parent, opts, index, decrypted, func, user_data);
	else if ((opts & MU_MSG_OPTION_VERIFY) &&
	         GMIME_IS_MULTIPART_SIGNED (mobj)) {
		check_signature
			(msg, GMIME_MULTIPART_SIGNED (mobj), opts);
		return handle_multipart
			(msg, GMIME_MULTIPART (mobj), mobj, opts,
			 index, decrypted, func, user_data);
	} else if ((opts & MU_MSG_OPTION_DECRYPT) &&
	           GMIME_IS_MULTIPART_ENCRYPTED (mobj))
		return handle_encrypted_part
			(msg, GMIME_MULTIPART_ENCRYPTED (mobj),
			 opts, index, func, user_data);
	else if (GMIME_IS_MULTIPART (mobj))
		return handle_multipart
			(msg, GMIME_MULTIPART (mobj), parent, opts,
			 index, decrypted, func, user_data);
	return TRUE;
}
Example #2
0
GMimeObject* /* this is declared in mu-msg-priv.h */
mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts,
			    MuMsgPartPasswordFunc func, gpointer user_data,
			    GError **err)
{
	GMimeObject *dec;
	GMimeCryptoContext *ctx;

	g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED(enc), NULL);

	ctx = get_crypto_context (opts, func, user_data, err);
	if (!ctx) {
		mu_util_g_set_error (err, MU_ERROR_CRYPTO,
				     "failed to get crypto context");
		return NULL;
	}

	dec = g_mime_multipart_encrypted_decrypt (enc, ctx, NULL, err);
	g_object_unref (ctx);
	if (!dec) {
		if (err && !*err)
			mu_util_g_set_error (err, MU_ERROR_CRYPTO,
					     "decryption failed");
		return NULL;
	}

	return dec;
}
Example #3
0
/**
 * sign_prepare:
 * @mime_part: MIME part
 *
 * Prepare a part (and all subparts) to be signed. To do this we need
 * to set the encoding of all parts (that are not already encoded to
 * either QP or Base64 or 7-bit) to QP.
 *
 * Ref: RFC 3156, sect. 3.
 **/
static void
sign_prepare(GMimeObject * mime_part)
{
    GMimeContentEncoding encoding;
    GMimeObject *subpart;

    if (GMIME_IS_MULTIPART(mime_part)) {
        GMimeMultipart *multipart;
        int i, n;

	multipart = (GMimeMultipart *) mime_part;

	if (GMIME_IS_MULTIPART_SIGNED(multipart) ||
	    GMIME_IS_MULTIPART_ENCRYPTED(multipart)) {
	    /* must not modify these parts as they must be treated as opaque */
	    return;
	}

	n = g_mime_multipart_get_count(multipart);
	for (i = 0; i < n; i++) {
	    subpart = g_mime_multipart_get_part(multipart, i);
	    sign_prepare(subpart);
	}
    } else if (GMIME_IS_MESSAGE_PART(mime_part)) {
	subpart = GMIME_MESSAGE_PART(mime_part)->message->mime_part;
	sign_prepare(subpart);
    } else {
	encoding = g_mime_part_get_content_encoding(GMIME_PART(mime_part));
	if ((encoding != GMIME_CONTENT_ENCODING_BASE64) && (encoding != GMIME_CONTENT_ENCODING_7BIT))
	    g_mime_part_set_content_encoding(GMIME_PART(mime_part),
					     GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
    }
}
Example #4
0
/* call 'func' with information about this MIME-part */
static gboolean
handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent,
	     MuMsgOptions opts, unsigned *index, gboolean decrypted,
	     MuMsgPartForeachFunc func, gpointer user_data)
{
	GMimeContentType *ct;
	MuMsgPart msgpart;

	memset (&msgpart, 0, sizeof(MuMsgPart));

	msgpart.size        = get_part_size (part);
	msgpart.part_type   = MU_MSG_PART_TYPE_LEAF;
	msgpart.part_type  |= get_disposition ((GMimeObject*)part);
	if (decrypted)
		msgpart.part_type |= MU_MSG_PART_TYPE_DECRYPTED;
	else if ((opts & MU_MSG_OPTION_DECRYPT) &&
	         GMIME_IS_MULTIPART_ENCRYPTED (parent))
		msgpart.part_type |= MU_MSG_PART_TYPE_ENCRYPTED;


	ct = g_mime_object_get_content_type ((GMimeObject*)part);
	if (GMIME_IS_CONTENT_TYPE(ct)) {
		msgpart.type    = g_mime_content_type_get_media_type (ct);
		msgpart.subtype = g_mime_content_type_get_media_subtype (ct);
		/* store as in the part_type as well, for quick
		 * checking */
		if (g_mime_content_type_is_type (ct, "text", "plain"))
			msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_PLAIN;
		else if (g_mime_content_type_is_type (ct, "text", "html"))
			msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_HTML;
	}

	/* put the verification info in the pgp-signature and every
	 * descendent of a pgp-encrypted part */
	msgpart.sig_status_report = NULL;
	if (g_ascii_strcasecmp (msgpart.subtype, "pgp-signature") == 0 ||
	    decrypted) {
		msgpart.sig_status_report =
			(MuMsgPartSigStatusReport*)
			g_object_get_data (G_OBJECT(parent),
					   SIG_STATUS_REPORT);

		if (msgpart.sig_status_report)
			msgpart.part_type |= MU_MSG_PART_TYPE_SIGNED;
	}

	msgpart.data    = (gpointer)part;
	msgpart.index   = (*index)++;

	func (msg, &msgpart, user_data);

	return TRUE;
}
Example #5
0
GMimeObject* /* this is declared in mu-msg-priv.h */
mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts,
			    MuMsgPartPasswordFunc func, gpointer user_data,
			    GError **err)
{
	GMimeObject *dec;
	GMimeCryptoContext *ctx;
	GMimeDecryptResult *res;

	g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED(enc), NULL);

	ctx = get_crypto_context (opts, func, user_data, err);
	if (!ctx) {
		mu_util_g_set_error (err, MU_ERROR_CRYPTO,
				     "failed to get crypto context");
		return NULL;
	}

	/* at the time of writing, there is a small leak in
	 * g_mime_multipart_encrypted_decrypt; I've notified its
	 * author and it has been fixed 2012-09-12:
	 *   http://git.gnome.org/browse/gmime/commit/
	 *   ?id=1bacd43b50d91bd03a4ae1dc9f46f5783dee61b1
	 * (or GMime > 2.6.10)
	 *   */
	res = NULL;
	dec = g_mime_multipart_encrypted_decrypt (enc, ctx, &res, err);
	g_object_unref (ctx);

	/* we don't use the 3rd param 'res' * (GMimeDecryptResult),
	 * but we must unref it. */
	if (res)
		g_object_unref (res);

	if (!dec) {
		if (err && !*err)
			mu_util_g_set_error (err, MU_ERROR_CRYPTO,
					     "decryption failed");
		return NULL;
	}

	return dec;
}
Example #6
0
static gboolean
handle_mime_object (MuMsg *msg,
		    GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts,
		    unsigned index, MuMsgPartForeachFunc func, gpointer user_data)
{
	if (GMIME_IS_PART (mobj))
		return handle_part
			(msg, GMIME_PART(mobj), parent,
			 opts, index, func, user_data);
	else if (GMIME_IS_MESSAGE_PART (mobj))
		return handle_message_part
			(msg, GMIME_MESSAGE_PART(mobj),
			 parent, opts, index, func, user_data);
	else if (GMIME_IS_MULTIPART_SIGNED (mobj))
		return handle_signed_part
				(msg, GMIME_MULTIPART_SIGNED (mobj),
				 parent, opts, index, func, user_data);
	else if (GMIME_IS_MULTIPART_ENCRYPTED (mobj))
		return handle_encrypted_part
			(msg, GMIME_MULTIPART_ENCRYPTED (mobj),
			 parent, opts, index, func, user_data);

	return TRUE;
}
Example #7
0
notmuch_status_t
_notmuch_message_crypto_potential_payload (_notmuch_message_crypto_t *msg_crypto, GMimeObject *payload, GMimeObject *parent, int childnum)
{
    const char *protected_headers = NULL;
    const char *forwarded = NULL;
    const char *subject = NULL;

    if (!msg_crypto || !payload)
	return NOTMUCH_STATUS_NULL_POINTER;

    /* only fire on the first payload part encountered */
    if (msg_crypto->payload_encountered)
	return NOTMUCH_STATUS_SUCCESS;

    /* the first child of multipart/encrypted that matches the
     * encryption protocol should be "control information" metadata,
     * not payload.  So we skip it. (see
     * https://tools.ietf.org/html/rfc1847#page-8) */
    if (parent && GMIME_IS_MULTIPART_ENCRYPTED (parent) && childnum == GMIME_MULTIPART_ENCRYPTED_VERSION) {
	const char *enc_type = g_mime_object_get_content_type_parameter (parent, "protocol");
	GMimeContentType *ct = g_mime_object_get_content_type (payload);
	if (ct && enc_type) {
	    const char *part_type = g_mime_content_type_get_mime_type (ct);
	    if (part_type && strcmp (part_type, enc_type) == 0)
		return NOTMUCH_STATUS_SUCCESS;
	}
    }

    msg_crypto->payload_encountered = true;

    /* don't bother recording anything if there is no cryptographic
     * envelope: */
    if ((msg_crypto->decryption_status != NOTMUCH_MESSAGE_DECRYPTED_FULL) &&
	(msg_crypto->sig_list == NULL))
	return NOTMUCH_STATUS_SUCCESS;

    /* Verify that this payload has headers that are intended to be
     * exported to the larger message: */

    /* Consider a payload that uses Alexei Melinkov's forwarded="no" for
     * message/global or message/rfc822:
     * https://tools.ietf.org/html/draft-melnikov-smime-header-signing-05#section-4 */
    forwarded = g_mime_object_get_content_type_parameter (payload, "forwarded");
    if (GMIME_IS_MESSAGE_PART (payload) && forwarded && strcmp (forwarded, "no") == 0) {
	GMimeMessage *message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (payload));
	subject = g_mime_message_get_subject (message);
	/* FIXME: handle more than just Subject: at some point */
    } else {
	/* Consider "memoryhole"-style protected headers as practiced by Enigmail and K-9 */
	protected_headers = g_mime_object_get_content_type_parameter (payload, "protected-headers");
	if (protected_headers && strcasecmp("v1", protected_headers) == 0)
	    subject = g_mime_object_get_header (payload, "Subject");
	/* FIXME: handle more than just Subject: at some point */
    }

    if (subject) {
	if (msg_crypto->payload_subject)
	    talloc_free (msg_crypto->payload_subject);
	msg_crypto->payload_subject = talloc_strdup (msg_crypto, subject);
    }

    return NOTMUCH_STATUS_SUCCESS;
}
Example #8
0
GMimeObject *
g_mime_gpgme_mpe_decrypt(GMimeMultipartEncrypted * mpe,
			 GMimeGpgmeSigstat ** signature,
			 GtkWindow * parent, GError ** err)
{
    GMimeObject *decrypted, *version, *encrypted;
    GMimeStream *stream, *ciphertext;
    GMimeStream *filtered_stream;
    GMimeContentType *mime_type;
    GMimeGpgmeSigstat *sigstat;
    GMimeDataWrapper *wrapper;
    GMimeFilter *crlf_filter;
    GMimeParser *parser;
    const char *protocol;
    char *content_type;

    g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), NULL);

    if (signature && *signature) {
	g_object_unref(G_OBJECT(*signature));
	*signature = NULL;
    }

    protocol =
	g_mime_object_get_content_type_parameter(GMIME_OBJECT(mpe),
						 "protocol");

    /* make sure the protocol is present and matches the cipher encrypt protocol */
    if (!protocol
	|| g_ascii_strcasecmp("application/pgp-encrypted",
			      protocol) != 0) {
	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
		    _
		    ("Cannot decrypt multipart/encrypted part: unsupported encryption protocol ā€œ%sā€."),
		    protocol ? protocol : _("(none)"));
	return NULL;
    }

    version =
	g_mime_multipart_get_part(GMIME_MULTIPART(mpe),
				  GMIME_MULTIPART_ENCRYPTED_VERSION);

    /* make sure the protocol matches the version part's content-type */
    content_type = g_mime_content_type_to_string(version->content_type);
    if (g_ascii_strcasecmp(content_type, protocol) != 0) {
	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s",
		    _
		    ("Cannot decrypt multipart/encrypted part: content-type does not match protocol."));
	g_free(content_type);
	return NULL;
    }
    g_free(content_type);

    /* get the encrypted part and check that it is of type application/octet-stream */
    encrypted =
	g_mime_multipart_get_part(GMIME_MULTIPART(mpe),
				  GMIME_MULTIPART_ENCRYPTED_CONTENT);
    mime_type = g_mime_object_get_content_type(encrypted);
    if (!g_mime_content_type_is_type
	(mime_type, "application", "octet-stream")) {
	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s",
		    _
		    ("Cannot decrypt multipart/encrypted part: unexpected content type"));
	return NULL;
    }

    /* get the ciphertext stream */
    wrapper = g_mime_part_get_content_object(GMIME_PART(encrypted));
    ciphertext = g_mime_data_wrapper_get_decoded_stream(wrapper);
    g_mime_stream_reset(ciphertext);

    stream = g_mime_stream_mem_new();
    filtered_stream = g_mime_stream_filter_new(stream);
    crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE);
    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
			     crlf_filter);
    g_object_unref(crlf_filter);

    /* get the cleartext */
    sigstat =
	libbalsa_gpgme_decrypt(ciphertext, filtered_stream,
			       GPGME_PROTOCOL_OpenPGP, parent, err);
    if (!sigstat) {
	g_object_unref(filtered_stream);
	g_object_unref(ciphertext);
	g_object_unref(stream);
	return NULL;
    }

    g_mime_stream_flush(filtered_stream);
    g_object_unref(filtered_stream);
    g_object_unref(ciphertext);

    g_mime_stream_reset(stream);
    parser = g_mime_parser_new();
    g_mime_parser_init_with_stream(parser, stream);
    g_object_unref(stream);

    decrypted = g_mime_parser_construct_part(parser);
    g_object_unref(parser);

    if (!decrypted) {
	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s",
		    _
		    ("Cannot decrypt multipart/encrypted part: failed to parse decrypted content"));
	g_object_unref(G_OBJECT(sigstat));
	return NULL;
    }


    /* cache the decrypted part */
    if (signature) {
	if (sigstat->status != GPG_ERR_NOT_SIGNED)
	    *signature = sigstat;
	else
	    g_object_unref(G_OBJECT(sigstat));
    }

    return decrypted;
}
Example #9
0
gboolean
g_mime_gpgme_mpe_encrypt(GMimeMultipartEncrypted * mpe,
			 GMimeObject * content, GPtrArray * recipients,
			 gboolean trust_all, GtkWindow * parent,
			 GError ** err)
{
    GMimeStream *filtered_stream;
    GMimeStream *ciphertext;
    GMimeStream *stream;
    GMimePart *version_part;
    GMimePart *encrypted_part;
    GMimeDataWrapper *wrapper;
    GMimeFilter *crlf_filter;

    g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), FALSE);
    g_return_val_if_fail(GMIME_IS_OBJECT(content), FALSE);

    /* get the cleartext */
    stream = g_mime_stream_mem_new();
    filtered_stream = g_mime_stream_filter_new(stream);

    crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE);
    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
			     crlf_filter);
    g_object_unref(crlf_filter);

    g_mime_object_write_to_stream(content, filtered_stream);
    g_mime_stream_flush(filtered_stream);
    g_object_unref(filtered_stream);

    /* reset the content stream */
    g_mime_stream_reset(stream);

    /* encrypt the content stream */
    ciphertext = g_mime_stream_mem_new();
    if (!libbalsa_gpgme_encrypt
	(recipients, NULL, stream, ciphertext, GPGME_PROTOCOL_OpenPGP,
	 FALSE, trust_all, parent, err)) {
	g_object_unref(ciphertext);
	g_object_unref(stream);
	return FALSE;
    }

    g_object_unref(stream);
    g_mime_stream_reset(ciphertext);

    /* construct the version part */
    version_part =
	g_mime_part_new_with_type("application", "pgp-encrypted");
    g_mime_part_set_content_encoding(version_part,
				     GMIME_CONTENT_ENCODING_7BIT);
    stream =
	g_mime_stream_mem_new_with_buffer("Version: 1\n",
					  strlen("Version: 1\n"));
    wrapper =
	g_mime_data_wrapper_new_with_stream(stream,
					    GMIME_CONTENT_ENCODING_7BIT);
    g_mime_part_set_content_object(version_part, wrapper);
    g_object_unref(wrapper);
    g_object_unref(stream);

    /* construct the encrypted mime part */
    encrypted_part =
	g_mime_part_new_with_type("application", "octet-stream");
    g_mime_part_set_content_encoding(encrypted_part,
				     GMIME_CONTENT_ENCODING_7BIT);
    wrapper =
	g_mime_data_wrapper_new_with_stream(ciphertext,
					    GMIME_CONTENT_ENCODING_7BIT);
    g_mime_part_set_content_object(encrypted_part, wrapper);
    g_object_unref(ciphertext);
    g_object_unref(wrapper);

    /* save the version and encrypted parts */
    /* FIXME: make sure there aren't any other parts?? */
    g_mime_multipart_add(GMIME_MULTIPART(mpe), GMIME_OBJECT(version_part));
    g_mime_multipart_add(GMIME_MULTIPART(mpe),
			 GMIME_OBJECT(encrypted_part));
    g_object_unref(encrypted_part);
    g_object_unref(version_part);

    /* set the content-type params for this multipart/encrypted part */
    g_mime_object_set_content_type_parameter(GMIME_OBJECT(mpe), "protocol",
					     "application/pgp-encrypted");
    g_mime_multipart_set_boundary(GMIME_MULTIPART(mpe), NULL);

    return TRUE;
}