aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog23
-rw-r--r--camel/camel-cipher-context.c127
-rw-r--r--camel/camel-cipher-context.h42
-rw-r--r--camel/camel-gpg-context.c90
-rw-r--r--camel/camel-multipart-encrypted.c14
-rw-r--r--camel/camel-multipart-signed.c5
-rw-r--r--camel/camel-smime-context.c245
-rw-r--r--camel/camel-smime-context.h7
8 files changed, 380 insertions, 173 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index faff76a429..a61c63cbcb 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,26 @@
+2003-11-10 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (sm_verify_cmsg): split out the CMSMessage
+ verification code so it can be used from enveloped or externally
+ signed data.
+
+ * camel-cipher-context.c (camel_cipher_verify): only take a
+ mimepart, internally handle multiparts and the hash.
+
+2003-11-07 Not Zed <NotZed@Ximian.com>
+
+ * camel-cipher-context.c: make ciphervalidity a public structure,
+ added encrypt status.
+ (camel_cipher_decrypt): changed to return a ciphervalidity. fixed
+ implementations.
+ (camel_cipher_validity_*): Fixed implementations to match new
+ structure, some of this is now redundant.
+
+2003-11-06 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.c (camel_smime_context_describe_part):
+ implement.
+
2003-11-05 Jeffrey Stedfast <fejj@ximian.com>
* providers/smtp/camel-smtp-transport.c (connect_to_server): Don't
diff --git a/camel/camel-cipher-context.c b/camel/camel-cipher-context.c
index dff60c25aa..9e741e4531 100644
--- a/camel/camel-cipher-context.c
+++ b/camel/camel-cipher-context.c
@@ -24,8 +24,10 @@
#include <config.h>
#endif
-#include <glib.h>
#include <pthread.h>
+#include <string.h>
+
+#include <glib.h>
#include "camel-cipher-context.h"
#include "camel-stream.h"
@@ -132,8 +134,7 @@ camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherH
}
static CamelCipherValidity *
-cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _CamelStream *istream,
- struct _CamelMimePart *sigpart, CamelException *ex)
+cipher_verify (CamelCipherContext *context, struct _CamelMimePart *sigpart, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Verifying is not supported by this cipher"));
@@ -143,8 +144,7 @@ cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _CamelS
/**
* camel_cipher_verify:
* @context: Cipher Context
- * @istream: input stream
- * @sigstream: optional detached-signature stream
+ * @ipart: part to verify
* @ex: exception
*
* Verifies the signature. If @istream is a clearsigned stream,
@@ -157,8 +157,7 @@ cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _CamelS
* execute at all.
**/
CamelCipherValidity *
-camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _CamelStream *istream,
- struct _CamelMimePart *sigpart, CamelException *ex)
+camel_cipher_verify (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex)
{
CamelCipherValidity *valid;
@@ -166,7 +165,7 @@ camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _
CIPHER_LOCK(context);
- valid = CCC_CLASS (context)->verify (context, hash, istream, sigpart, ex);
+ valid = CCC_CLASS (context)->verify (context, ipart, ex);
CIPHER_UNLOCK(context);
@@ -213,8 +212,8 @@ camel_cipher_encrypt (CamelCipherContext *context, const char *userid, GPtrArray
return retval;
}
-static struct _CamelMimePart *
-cipher_decrypt(CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex)
+static CamelCipherValidity *
+cipher_decrypt(CamelCipherContext *context, struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Decryption is not supported by this cipher"));
@@ -223,30 +222,29 @@ cipher_decrypt(CamelCipherContext *context, struct _CamelMimePart *ipart, CamelE
/**
* camel_cipher_decrypt:
- * @context: Cipher Context
- * @ciphertext: ciphertext stream (ie input stream)
- * @cleartext: cleartext stream (ie output stream)
- * @ex: exception
- *
- * Decrypts the ciphertext input stream and writes the resulting
- * cleartext to the output stream.
- *
- * Return value: 0 for success or -1 for failure.
+ * @context:
+ * @ipart:
+ * @opart:
+ * @ex:
+ *
+ * Decrypts @ipart into @opart.
+ *
+ * Return value: A validity/encryption status.
**/
-struct _CamelMimePart *
-camel_cipher_decrypt (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex)
+CamelCipherValidity *
+camel_cipher_decrypt(CamelCipherContext *context, struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
{
- struct _CamelMimePart *opart;
+ CamelCipherValidity *valid;
g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
CIPHER_LOCK(context);
- opart = CCC_CLASS (context)->decrypt (context, ipart, ex);
+ valid = CCC_CLASS (context)->decrypt (context, ipart, opart, ex);
CIPHER_UNLOCK(context);
- return opart;
+ return valid;
}
static int
@@ -341,20 +339,15 @@ camel_cipher_hash_to_id(CamelCipherContext *context, CamelCipherHash hash)
}
/* Cipher Validity stuff */
-struct _CamelCipherValidity {
- gboolean valid;
- gchar *description;
-};
CamelCipherValidity *
camel_cipher_validity_new (void)
{
CamelCipherValidity *validity;
- validity = g_new (CamelCipherValidity, 1);
- validity->valid = FALSE;
- validity->description = NULL;
-
+ validity = g_malloc(sizeof(*validity));
+ camel_cipher_validity_init(validity);
+
return validity;
}
@@ -362,18 +355,15 @@ void
camel_cipher_validity_init (CamelCipherValidity *validity)
{
g_assert (validity != NULL);
-
- validity->valid = FALSE;
- validity->description = NULL;
+
+ memset(validity, 0, sizeof(*validity));
}
gboolean
camel_cipher_validity_get_valid (CamelCipherValidity *validity)
{
- if (validity == NULL)
- return FALSE;
-
- return validity->valid;
+ return validity != NULL
+ && validity->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_GOOD;
}
void
@@ -381,7 +371,7 @@ camel_cipher_validity_set_valid (CamelCipherValidity *validity, gboolean valid)
{
g_assert (validity != NULL);
- validity->valid = valid;
+ validity->sign.status = CAMEL_CIPHER_VALIDITY_SIGN_GOOD;
}
gchar *
@@ -390,7 +380,7 @@ camel_cipher_validity_get_description (CamelCipherValidity *validity)
if (validity == NULL)
return NULL;
- return validity->description;
+ return validity->sign.description;
}
void
@@ -398,18 +388,47 @@ camel_cipher_validity_set_description (CamelCipherValidity *validity, const gcha
{
g_assert (validity != NULL);
- g_free (validity->description);
- validity->description = g_strdup (description);
+ g_free(validity->sign.description);
+ validity->sign.description = g_strdup(description);
}
void
camel_cipher_validity_clear (CamelCipherValidity *validity)
{
g_assert (validity != NULL);
-
- validity->valid = FALSE;
- g_free (validity->description);
- validity->description = NULL;
+
+ g_free(validity->sign.description);
+ g_free(validity->encrypt.description);
+ camel_cipher_validity_init(validity);
+}
+
+/**
+ * camel_cipher_validity_envelope:
+ * @validity:
+ * @outer:
+ *
+ * Calculate a conglomerate validity based on wrapping one secure part inside
+ * another one.
+ **/
+void
+camel_cipher_validity_envelope(CamelCipherValidity *valid, CamelCipherValidity *outer)
+{
+ if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE
+ && valid->encrypt.status == CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
+ && outer->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_NONE
+ && outer->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
+ /* case 1: only signed inside only encrypted -> merge both */
+ valid->encrypt.status = outer->encrypt.status;
+ valid->encrypt.description = g_strdup(outer->encrypt.description);
+ } else if (valid->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_NONE
+ && valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
+ && outer->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE
+ && outer->encrypt.status == CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
+ /* case 2: only encrypted inside only signed */
+ valid->sign.status = outer->sign.status;
+ valid->sign.description = g_strdup(outer->sign.description);
+ }
+ /* Otherwise, I dunno - what do you do? */
}
void
@@ -417,9 +436,9 @@ camel_cipher_validity_free (CamelCipherValidity *validity)
{
if (validity == NULL)
return;
-
- g_free (validity->description);
- g_free (validity);
+
+ camel_cipher_validity_clear(validity);
+ g_free(validity);
}
/* ********************************************************************** */
@@ -511,6 +530,7 @@ cc_prepare_sign(CamelMimePart *part)
/**
* camel_cipher_canonical_to_stream:
* @part: Part to write.
+ * @flags: flags for the canonicalisation filter (CamelMimeFilterCanon)
* @ostream: stream to write canonicalised output to.
*
* Writes a part to a stream in a canonicalised format, suitable for signing/encrypting.
@@ -520,16 +540,17 @@ cc_prepare_sign(CamelMimePart *part)
* Return value: -1 on error;
**/
int
-camel_cipher_canonical_to_stream(CamelMimePart *part, CamelStream *ostream)
+camel_cipher_canonical_to_stream(CamelMimePart *part, guint32 flags, CamelStream *ostream)
{
CamelStreamFilter *filter;
CamelMimeFilter *canon;
int res = -1;
- cc_prepare_sign(part);
+ if (flags & (CAMEL_MIME_FILTER_CANON_FROM|CAMEL_MIME_FILTER_CANON_STRIP))
+ cc_prepare_sign(part);
filter = camel_stream_filter_new_with_stream(ostream);
- canon = camel_mime_filter_canon_new(CAMEL_MIME_FILTER_CANON_STRIP|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_FROM);
+ canon = camel_mime_filter_canon_new(flags);
camel_stream_filter_add(filter, canon);
camel_object_unref(canon);
diff --git a/camel/camel-cipher-context.h b/camel/camel-cipher-context.h
index db83e92438..d3aea4c6b0 100644
--- a/camel/camel-cipher-context.h
+++ b/camel/camel-cipher-context.h
@@ -51,6 +51,31 @@ typedef enum {
CAMEL_CIPHER_HASH_HAVAL5160
} CamelCipherHash;
+enum _camel_cipher_validity_sign_t {
+ CAMEL_CIPHER_VALIDITY_SIGN_NONE,
+ CAMEL_CIPHER_VALIDITY_SIGN_GOOD,
+ CAMEL_CIPHER_VALIDITY_SIGN_BAD,
+ CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN,
+};
+
+enum _camel_cipher_validity_encrypt_t {
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE,
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_WEAK,
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED, /* encrypted, unknown strenght */
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG,
+};
+
+struct _CamelCipherValidity {
+ struct {
+ enum _camel_cipher_validity_sign_t status;
+ char *description;
+ } sign;
+ struct {
+ enum _camel_cipher_validity_encrypt_t status;
+ char *description;
+ } encrypt;
+};
+
typedef struct _CamelCipherContext {
CamelObject parent_object;
@@ -73,15 +98,14 @@ typedef struct _CamelCipherContextClass {
int (*sign) (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex);
- CamelCipherValidity * (*verify) (CamelCipherContext *context, CamelCipherHash hash,
- struct _CamelStream *istream, struct _CamelMimePart *sigpart,
- CamelException *ex);
+ CamelCipherValidity * (*verify) (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
int (*encrypt) (CamelCipherContext *context, const char *userid,
GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart,
CamelException *ex);
- struct _CamelMimePart *(*decrypt) (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
+ CamelCipherValidity *(*decrypt) (CamelCipherContext *context, struct _CamelMimePart *ipart, struct _CamelMimePart *opart,
+ CamelException *ex);
int (*import_keys) (CamelCipherContext *context, struct _CamelStream *istream,
CamelException *ex);
@@ -108,13 +132,12 @@ const char * camel_cipher_hash_to_id (CamelCipherContext *context, CamelCip
/* cipher routines */
int camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex);
-CamelCipherValidity *camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash,
- struct _CamelStream *istream, struct _CamelMimePart *sigpart,
- CamelException *ex);
+CamelCipherValidity *camel_cipher_verify (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
int camel_cipher_encrypt (CamelCipherContext *context, const char *userid,
GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart,
CamelException *ex);
-struct _CamelMimePart *camel_cipher_decrypt (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
+CamelCipherValidity *camel_cipher_decrypt (CamelCipherContext *context, struct _CamelMimePart *ipart, struct _CamelMimePart *opart,
+ CamelException *ex);
/* key/certificate routines */
int camel_cipher_import_keys (CamelCipherContext *context, struct _CamelStream *istream,
@@ -130,10 +153,11 @@ void camel_cipher_validity_set_valid (CamelCipherValidity *valid
char *camel_cipher_validity_get_description (CamelCipherValidity *validity);
void camel_cipher_validity_set_description (CamelCipherValidity *validity, const char *description);
void camel_cipher_validity_clear (CamelCipherValidity *validity);
+void camel_cipher_validity_envelope(CamelCipherValidity *valid, CamelCipherValidity *outer);
void camel_cipher_validity_free (CamelCipherValidity *validity);
/* utility functions */
-int camel_cipher_canonical_to_stream(CamelMimePart *part, CamelStream *ostream);
+int camel_cipher_canonical_to_stream(CamelMimePart *part, guint32 flags, CamelStream *ostream);
#ifdef __cplusplus
}
diff --git a/camel/camel-gpg-context.c b/camel/camel-gpg-context.c
index a3b158d943..71b9106e10 100644
--- a/camel/camel-gpg-context.c
+++ b/camel/camel-gpg-context.c
@@ -1225,9 +1225,9 @@ gpg_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
/* Note: see rfc2015 or rfc3156, section 5 */
/* FIXME: stream this, we stream output at least */
- /*prepare_sign(content);*/
istream = camel_stream_mem_new();
- if (camel_cipher_canonical_to_stream(ipart, istream) == -1) {
+ if (camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_STRIP|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_FROM,
+ istream) == -1) {
camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
_("Could not generate signing data: %s"), g_strerror(errno));
goto fail;
@@ -1346,32 +1346,54 @@ swrite (CamelMimePart *sigpart)
}
static CamelCipherValidity *
-gpg_verify (CamelCipherContext *context, CamelCipherHash hash,
- CamelStream *istream, CamelMimePart *sigpart,
- CamelException *ex)
+gpg_verify (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
{
CamelCipherValidity *validity;
- const char *diagnostics = NULL;
- struct _GpgCtx *gpg;
+ const char *diagnostics = NULL, *tmp;
+ struct _GpgCtx *gpg = NULL;
char *sigfile = NULL;
gboolean valid;
-
- if (sigpart != NULL) {
- /* We are going to verify a detached signature so save
- the signature to a temp file. */
- sigfile = swrite (sigpart);
- if (sigfile == NULL) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot verify message signature: "
- "could not create temp file: %s"),
- g_strerror (errno));
- return NULL;
- }
+ CamelContentType *ct;
+ CamelMimePart *sigpart, *datapart;
+ CamelStream *istream = NULL;
+ CamelMultipart *mps;
+
+ ct = camel_mime_part_get_content_type(ipart);
+ tmp = camel_content_type_param(ct, "protocol");
+ mps = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)ipart);
+ if (!camel_content_type_is(ct, "multipart", "signed")
+ || !CAMEL_IS_MULTIPART_SIGNED(mps)
+ || tmp == NULL
+ || g_ascii_strcasecmp(tmp, context->sign_protocol) != 0) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ return NULL;
+ }
+
+ datapart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_CONTENT);
+ sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
+
+ if (sigpart == NULL || datapart == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ goto exception;
+ }
+
+ sigfile = swrite (sigpart);
+ if (sigfile == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: could not create temp file: %s"),
+ g_strerror (errno));
+ goto exception;
}
+
+ istream = camel_stream_mem_new();
+ camel_cipher_canonical_to_stream(datapart, CAMEL_MIME_FILTER_CANON_CRLF, istream);
+ camel_stream_reset(istream);
gpg = gpg_ctx_new (context->session);
gpg_ctx_set_mode (gpg, GPG_CTX_MODE_VERIFY);
- gpg_ctx_set_hash (gpg, hash);
+ gpg_ctx_set_hash (gpg, camel_cipher_id_to_hash(context, camel_content_type_param(ct, "micalg")));
gpg_ctx_set_sigfile (gpg, sigfile);
gpg_ctx_set_istream (gpg, istream);
@@ -1413,7 +1435,10 @@ gpg_verify (CamelCipherContext *context, CamelCipherHash hash,
exception:
gpg_ctx_free (gpg);
-
+
+ if (istream)
+ camel_object_unref(istream);
+
if (sigfile) {
unlink (sigfile);
g_free (sigfile);
@@ -1436,7 +1461,7 @@ gpg_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipie
ostream = camel_stream_mem_new();
istream = camel_stream_mem_new();
- if (camel_cipher_canonical_to_stream(ipart, istream) == -1) {
+ if (camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_CRLF, istream) == -1) {
camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
_("Could not generate encrypting data: %s"), g_strerror(errno));
goto fail1;
@@ -1512,7 +1537,7 @@ gpg_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipie
mpe = camel_multipart_encrypted_new();
ct = camel_content_type_new("multipart", "encrypted");
- camel_content_type_set_param(ct, "protocol", context->sign_protocol);
+ camel_content_type_set_param(ct, "protocol", context->encrypt_protocol);
camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mpe, ct);
camel_content_type_unref(ct);
camel_multipart_set_boundary((CamelMultipart *)mpe, NULL);
@@ -1535,11 +1560,11 @@ fail1:
return res;
}
-static CamelMimePart *
-gpg_decrypt (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+static CamelCipherValidity *
+gpg_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
{
struct _GpgCtx *gpg;
- CamelMimePart *opart = NULL;
+ CamelCipherValidity *valid = NULL;
CamelStream *ostream, *istream;
istream = camel_stream_mem_new();
@@ -1588,20 +1613,21 @@ gpg_decrypt (CamelCipherContext *context, CamelMimePart *ipart, CamelException *
goto fail;
}
- opart = camel_mime_part_new();
camel_stream_reset(ostream);
- if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream) == -1) {
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream) != -1) {
+ valid = camel_cipher_validity_new();
+ valid->encrypt.description = g_strdup(_("Encrypted content"));
+ valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
+ } else {
camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
_("Unable to parse message content"));
- camel_object_unref(opart);
- opart = NULL;
}
fail:
camel_object_unref(ostream);
camel_object_unref(istream);
gpg_ctx_free (gpg);
-
- return opart;
+
+ return valid;
}
static int
diff --git a/camel/camel-multipart-encrypted.c b/camel/camel-multipart-encrypted.c
index 2dfe3b4914..aa036bec23 100644
--- a/camel/camel-multipart-encrypted.c
+++ b/camel/camel-multipart-encrypted.c
@@ -205,6 +205,7 @@ camel_multipart_encrypted_decrypt (CamelMultipartEncrypted *mpe,
{
CamelMimePart *version_part, *encrypted_part, *decrypted_part;
CamelContentType *mime_type;
+ CamelCipherValidity *valid;
CamelDataWrapper *wrapper;
const char *protocol;
char *content_type;
@@ -256,11 +257,16 @@ camel_multipart_encrypted_decrypt (CamelMultipartEncrypted *mpe,
_("Failed to decrypt MIME part: invalid structure"));
return NULL;
}
-
- decrypted_part = camel_cipher_decrypt(cipher, encrypted_part, ex);
- if (decrypted_part) {
- camel_object_ref (decrypted_part);
+
+ decrypted_part = camel_mime_part_new();
+ valid = camel_cipher_decrypt(cipher, encrypted_part, decrypted_part, ex);
+ if (valid) {
+ camel_object_ref(decrypted_part);
mpe->decrypted = decrypted_part;
+ camel_cipher_validity_free(valid);
+ } else {
+ camel_object_ref(decrypted_part);
+ decrypted_part = NULL;
}
return decrypted_part;
diff --git a/camel/camel-multipart-signed.c b/camel/camel-multipart-signed.c
index 2647ba6591..47d749ab73 100644
--- a/camel/camel-multipart-signed.c
+++ b/camel/camel-multipart-signed.c
@@ -670,6 +670,10 @@ camel_multipart_signed_sign(CamelMultipartSigned *mps, CamelCipherContext *conte
CamelCipherValidity *
camel_multipart_signed_verify(CamelMultipartSigned *mps, CamelCipherContext *context, CamelException *ex)
{
+ abort();
+
+ return NULL;
+#if 0
CamelCipherValidity *valid;
CamelMimePart *sigpart;
CamelStream *constream;
@@ -720,6 +724,7 @@ camel_multipart_signed_verify(CamelMultipartSigned *mps, CamelCipherContext *con
camel_object_unref(constream);
return valid;
+#endif
}
diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c
index 75cbba9e2b..e2af550db8 100644
--- a/camel/camel-smime-context.c
+++ b/camel/camel-smime-context.c
@@ -68,6 +68,41 @@ struct _CamelSMIMEContextPrivate {
static CamelCipherContextClass *parent_class = NULL;
+/* used for decode content callback, for streaming decode */
+static void
+sm_write_stream(void *arg, const char *buf, unsigned long len)
+{
+ camel_stream_write((CamelStream *)arg, buf, len);
+}
+
+static PK11SymKey *
+sm_decrypt_key(void *arg, SECAlgorithmID *algid)
+{
+ printf("Decrypt key called\n");
+ return (PK11SymKey *)arg;
+}
+
+static char *
+sm_get_passwd(PK11SlotInfo *info, PRBool retry, void *arg)
+{
+ CamelSMIMEContext *context = arg;
+ char *pass, *nsspass = NULL;
+ char *prompt;
+ CamelException *ex;
+
+ ex = camel_exception_new();
+ prompt = g_strdup_printf(_("Enter security pass-phrase for `%s'"), PK11_GetTokenName(info));
+ pass = camel_session_get_password(((CamelCipherContext *)context)->session, prompt, FALSE, TRUE, NULL, PK11_GetTokenName(info), ex);
+ camel_exception_free(ex);
+ g_free(prompt);
+ if (pass) {
+ nsspass = PORT_Strdup(pass);
+ g_free(pass);
+ }
+
+ return nsspass;
+}
+
/**
* camel_smime_context_new:
* @session: session
@@ -108,10 +143,62 @@ camel_smime_context_set_sign_mode(CamelSMIMEContext *context, camel_smime_sign_t
context->priv->sign_mode = type;
}
+/* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */
guint32
camel_smime_context_describe_part(CamelSMIMEContext *context, CamelMimePart *part)
{
- return 0;
+ guint32 flags = 0;
+ CamelContentType *ct;
+ const char *tmp;
+
+ ct = camel_mime_part_get_content_type(part);
+
+ if (camel_content_type_is(ct, "multipart", "signed")) {
+ tmp = camel_content_type_param(ct, "protocol");
+ if (tmp && g_ascii_strcasecmp(tmp, ((CamelCipherContext *)context)->sign_protocol))
+ flags = CAMEL_SMIME_SIGNED;
+ } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) {
+ CamelStreamMem *istream;
+ NSSCMSMessage *cmsg;
+ NSSCMSDecoderContext *dec;
+
+ /* FIXME: stream this to the decoder incrementally */
+ istream = (CamelStreamMem *)camel_stream_mem_new();
+ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)istream);
+ camel_stream_reset((CamelStream *)istream);
+
+ dec = NSS_CMSDecoder_Start(NULL,
+ NULL, NULL,
+ sm_get_passwd, context, /* password callback */
+ NULL, NULL); /* decrypt key callback */
+
+ NSS_CMSDecoder_Update(dec, istream->buffer->data, istream->buffer->len);
+ camel_object_unref(istream);
+
+ cmsg = NSS_CMSDecoder_Finish(dec);
+ if (cmsg) {
+ if (NSS_CMSMessage_IsSigned(cmsg)) {
+ printf("message is signed\n");
+ flags |= CAMEL_SMIME_SIGNED;
+ }
+
+ if (NSS_CMSMessage_IsEncrypted(cmsg)) {
+ printf("message is encrypted\n");
+ flags |= CAMEL_SMIME_ENCRYPTED;
+ }
+#if 0
+ if (NSS_CMSMessage_ContainsCertsOrCrls(cmsg)) {
+ printf("message contains certs or crls\n");
+ flags |= CAMEL_SMIME_CERTS;
+ }
+#endif
+ NSS_CMSMessage_Destroy(cmsg);
+ } else {
+ printf("Message could not be parsed\n");
+ }
+ }
+
+ return flags;
}
static const char *
@@ -141,41 +228,6 @@ sm_id_to_hash(CamelCipherContext *context, const char *id)
return CAMEL_CIPHER_HASH_DEFAULT;
}
-/* used for decode content callback, for streaming decode */
-static void
-sm_write_stream(void *arg, const char *buf, unsigned long len)
-{
- camel_stream_write((CamelStream *)arg, buf, len);
-}
-
-static PK11SymKey *
-sm_decrypt_key(void *arg, SECAlgorithmID *algid)
-{
- printf("Decrypt key called\n");
- return (PK11SymKey *)arg;
-}
-
-static char *
-sm_get_passwd(PK11SlotInfo *info, PRBool retry, void *arg)
-{
- CamelSMIMEContext *context = arg;
- char *pass, *nsspass = NULL;
- char *prompt;
- CamelException *ex;
-
- ex = camel_exception_new();
- prompt = g_strdup_printf(_("Enter security pass-phrase for `%s'"), PK11_GetTokenName(info));
- pass = camel_session_get_password(((CamelCipherContext *)context)->session, prompt, FALSE, TRUE, NULL, PK11_GetTokenName(info), ex);
- camel_exception_free(ex);
- g_free(prompt);
- if (pass) {
- nsspass = PORT_Strdup(pass);
- g_free(pass);
- }
-
- return nsspass;
-}
-
static NSSCMSMessage *
sm_signing_cmsmessage(CamelSMIMEContext *context, const char *nick, SECOidTag hash, int detached, CamelException *ex)
{
@@ -346,7 +398,10 @@ sm_sign(CamelCipherContext *context, const char *userid, CamelCipherHash hash, C
/* FIXME: stream this, we stream output at least */
istream = camel_stream_mem_new();
- if (camel_cipher_canonical_to_stream(ipart, istream) == -1) {
+ if (camel_cipher_canonical_to_stream(ipart,
+ CAMEL_MIME_FILTER_CANON_STRIP
+ |CAMEL_MIME_FILTER_CANON_CRLF
+ |CAMEL_MIME_FILTER_CANON_FROM, istream) == -1) {
camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
_("Could not generate signing data: %s"), g_strerror(errno));
goto fail;
@@ -466,11 +521,9 @@ sm_status_description(NSSCMSVerificationStatus status)
}
static CamelCipherValidity *
-sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream, CamelMimePart *sigpart, CamelException *ex)
+sm_verify_cmsg(CamelCipherContext *context, NSSCMSMessage *cmsg, CamelMimePart *extpart, CamelException *ex)
{
struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv;
- NSSCMSDecoderContext *dec;
- NSSCMSMessage *cmsg;
NSSCMSSignedData *sigd = NULL;
NSSCMSEnvelopedData *envd;
NSSCMSEncryptedData *encd;
@@ -484,22 +537,6 @@ sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istrea
CamelCipherValidity *valid;
GString *description;
- dec = NSS_CMSDecoder_Start(NULL,
- NULL, NULL, /* content callback */
- sm_get_passwd, context, /* password callback */
- NULL, NULL); /* decrypt key callback */
-
- /* FIXME: Stream? not worth it? sigs are small */
- mem = (CamelStreamMem *)camel_stream_mem_new();
- camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem);
- (void)NSS_CMSDecoder_Update(dec, mem->buffer->data, mem->buffer->len);
- camel_object_unref(mem);
- cmsg = NSS_CMSDecoder_Finish(dec);
- if (cmsg == NULL) {
- camel_exception_setv(ex, 1, "Decoder failed");
- return NULL;
- }
-
description = g_string_new("");
valid = camel_cipher_validity_new();
camel_cipher_validity_set_valid(valid, TRUE);
@@ -522,6 +559,11 @@ sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istrea
/* need to build digests of the content */
if (!NSS_CMSSignedData_HasDigests(sigd)) {
+ if (extpart == NULL) {
+ camel_exception_setv(ex, 1, "Digests missing from enveloped data");
+ goto fail;
+ }
+
if ((poolp = PORT_NewArena(1024)) == NULL) {
camel_exception_setv(ex, 1, "out of memory");
goto fail;
@@ -536,12 +578,12 @@ sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istrea
}
mem = (CamelStreamMem *)camel_stream_mem_new();
- camel_stream_write_to_stream(istream, (CamelStream *)mem);
+ camel_cipher_canonical_to_stream(extpart, CAMEL_MIME_FILTER_CANON_CRLF, (CamelStream *)mem);
NSS_CMSDigestContext_Update(digcx, mem->buffer->data, mem->buffer->len);
camel_object_unref(mem);
if (NSS_CMSDigestContext_FinishMultiple(digcx, poolp, &digests) != SECSuccess) {
- camel_exception_setv(ex, 1, "Can not calculate digests");
+ camel_exception_setv(ex, 1, "Cannot calculate digests");
goto fail;
}
@@ -572,7 +614,6 @@ sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istrea
g_string_printf(description, "Certficate only message, certificates imported and verified");
}
} else {
-
if (!NSS_CMSSignedData_HasDigests(sigd)) {
camel_exception_setv(ex, 1, "Can't find signature digests");
goto fail;
@@ -606,7 +647,6 @@ sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istrea
break;
case SEC_OID_PKCS7_ENVELOPED_DATA:
envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
- /* do we need to look into the enveloped data for signatures too?? */
break;
case SEC_OID_PKCS7_ENCRYPTED_DATA:
encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
@@ -622,20 +662,74 @@ sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istrea
camel_cipher_validity_set_description(valid, description->str);
g_string_free(description, TRUE);
- NSS_CMSMessage_Destroy(cmsg);
return valid;
fail:
- NSS_CMSMessage_Destroy(cmsg);
camel_cipher_validity_free(valid);
g_string_free(description, TRUE);
- if (poolp)
- PORT_FreeArena(poolp, PR_FALSE);
-
return NULL;
}
+static CamelCipherValidity *
+sm_verify(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+{
+ NSSCMSDecoderContext *dec;
+ NSSCMSMessage *cmsg;
+ CamelStreamMem *mem;
+ CamelCipherValidity *valid;
+ CamelContentType *ct;
+ const char *tmp;
+ CamelMimePart *extpart, *sigpart;
+
+ ct = camel_mime_part_get_content_type(ipart);
+ if (camel_content_type_is(ct, "multipart", "signed")) {
+ CamelMultipart *mps = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)ipart);
+
+ tmp = camel_content_type_param(ct, "protocol");
+ extpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_CONTENT);
+ sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
+ if (!CAMEL_IS_MULTIPART_SIGNED(mps)
+ || tmp == NULL
+ || g_ascii_strcasecmp(tmp, context->sign_protocol) != 0
+ || extpart == NULL
+ || sigpart == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ return NULL;
+ }
+ } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) {
+ extpart = NULL;
+ sigpart = ipart;
+ } else {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Cannot verify message signature: Incorrect message format"));
+ return NULL;
+ }
+
+ dec = NSS_CMSDecoder_Start(NULL,
+ NULL, NULL, /* content callback */
+ sm_get_passwd, context, /* password callback */
+ NULL, NULL); /* decrypt key callback */
+
+ /* FIXME: we should stream this to the decoder */
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem);
+ (void)NSS_CMSDecoder_Update(dec, mem->buffer->data, mem->buffer->len);
+ camel_object_unref(mem);
+ cmsg = NSS_CMSDecoder_Finish(dec);
+ if (cmsg == NULL) {
+ camel_exception_setv(ex, 1, "Decoder failed");
+ return NULL;
+ }
+
+ valid = sm_verify_cmsg(context, cmsg, extpart, ex);
+
+ NSS_CMSMessage_Destroy(cmsg);
+
+ return valid;
+}
+
static int
sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
{
@@ -812,14 +906,14 @@ fail:
return -1;
}
-static CamelMimePart *
-sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+static CamelCipherValidity *
+sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
{
NSSCMSDecoderContext *dec;
NSSCMSMessage *cmsg;
CamelStreamMem *istream;
CamelStream *ostream;
- CamelMimePart *opart = NULL;
+ CamelCipherValidity *valid = NULL;
/* FIXME: This assumes the content is only encrypted. Perhaps its ok for
this api to do this ... */
@@ -856,15 +950,22 @@ sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex
}
#endif
- NSS_CMSMessage_Destroy(cmsg);
-
- opart = camel_mime_part_new();
camel_stream_reset(ostream);
camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream);
+
+ if (NSS_CMSMessage_IsSigned(cmsg)) {
+ valid = sm_verify_cmsg(context, cmsg, NULL, ex);
+ } else {
+ valid = camel_cipher_validity_new();
+ valid->encrypt.description = g_strdup(_("Encrypted content"));
+ valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
+ }
+
+ NSS_CMSMessage_Destroy(cmsg);
fail:
camel_object_unref(ostream);
- return opart;
+ return valid;
}
static int
diff --git a/camel/camel-smime-context.h b/camel/camel-smime-context.h
index f0e8d45c3b..19f0e8464b 100644
--- a/camel/camel-smime-context.h
+++ b/camel/camel-smime-context.h
@@ -42,9 +42,10 @@ typedef enum _camel_smime_sign_t {
} camel_smime_sign_t;
typedef enum _camel_smime_describe_t {
- CAMEL_SMIME_SIGNED = 1,
- CAMEL_SMIME_ENCRYPTED = 2,
- CAMEL_SMIME_CERTS = 4,
+ CAMEL_SMIME_SIGNED = 1<<0,
+ CAMEL_SMIME_ENCRYPTED = 1<<1,
+ CAMEL_SMIME_CERTS = 1<<2,
+ CAMEL_SMIME_CRLS = 1<<3,
} camel_smime_describe_t;
typedef struct _CamelSMIMEContext CamelSMIMEContext;