aboutsummaryrefslogtreecommitdiffstats
path: root/camel
diff options
context:
space:
mode:
authorNot Zed <NotZed@Ximian.com>2003-10-30 12:58:33 +0800
committerMichael Zucci <zucchi@src.gnome.org>2003-10-30 12:58:33 +0800
commit52759f2d4018b8ff0ce173aa1237b08783f1424c (patch)
treec6b392bea311df4d965b3e234cb769d6bf78e7e0 /camel
parent4c9e3c871c301e92711b91f0df0aca2521567db1 (diff)
downloadgsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar
gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar.gz
gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar.bz2
gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar.lz
gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar.xz
gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar.zst
gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.zip
Added a note about api inconsistencies.
2003-10-30 Not Zed <NotZed@Ximian.com> * camel-cipher-context.h: Added a note about api inconsistencies. 2003-10-30 Not Zed <NotZed@Ximian.com> * camel-multipart-encrypted.c (camel_multipart_encrypted_decrypt): fix for cipher_decrypt changes. * camel-gpg-context.c, camel-cipher-context.c: moved all the init code to the end to save having to keep forward declarations around. (camel_cipher_decrypt): changed to take mimepart input and return a mimepart. (gpg_decrypt): fix for changed args. 2003-10-29 Not Zed <NotZed@Ximian.com> * camel-smime-context.[ch]: replaced entirely with a new implementation which inherits from camel-cipher-context, and add to build. * camel-multipart-encrypted.c (camel_multipart_encrypted_encrypt): fix for cipher_encrypt api changes. (camel_multipart_encrypted_decrypt): use g_ascii_strcasecmp. * camel-gpg-context.c (gpg_encrypt): Fix to handle input/output as parts not streams * camel-cipher-context.c (camel_cipher_encrypt): change to take mimeparts rather than streams as input/output. And remove the 'sign' argument, it is implied if userid is supplied. 2003-10-28 Not Zed <NotZed@Ximian.com> * tests/smime/pgp.c (main): fix for ciphercontext api changes. * camel-multipart-signed.c (camel_multipart_signed_verify): pass in the part to cipher_verify directly. (camel_multipart_signed_sign): let the cipher context setup the part details. * camel-gpg-context.c (gpg_sign): put the signature stream into a mimepart, with appropriate headers/encoding. (swrite): write out a mimepart rather than a stream. (gpg_verify): handle changed args. * camel-cipher-context.c (camel_cipher_sign): write the signature to a mimepart rather than a simple stream. (camel_cipher_verify): take the signature as a mimepart not a stream. 2003-10-22 Not Zed <NotZed@Ximian.com> * camel-utf8.c (camel_ucs2_utf8, camel_utf8_ucs2): helpers for ucs2 stuff. ucs2 is 16 bit truncated unicode. svn path=/trunk/; revision=23127
Diffstat (limited to 'camel')
-rw-r--r--camel/ChangeLog57
-rw-r--r--camel/Makefile.am2
-rw-r--r--camel/camel-cipher-context.c204
-rw-r--r--camel/camel-cipher-context.h50
-rw-r--r--camel/camel-gpg-context.c343
-rw-r--r--camel/camel-multipart-encrypted.c86
-rw-r--r--camel/camel-multipart-signed.c39
-rw-r--r--camel/camel-smime-context.c1613
-rw-r--r--camel/camel-smime-context.h80
-rw-r--r--camel/camel-utf8.c60
-rw-r--r--camel/camel-utf8.h4
-rw-r--r--camel/tests/smime/pgp.c16
12 files changed, 1253 insertions, 1301 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 1fd44c08d5..6d6b16e35c 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,60 @@
+2003-10-30 Not Zed <NotZed@Ximian.com>
+
+ * camel-cipher-context.h: Added a note about api inconsistencies.
+
+2003-10-30 Not Zed <NotZed@Ximian.com>
+
+ * camel-multipart-encrypted.c (camel_multipart_encrypted_decrypt):
+ fix for cipher_decrypt changes.
+
+ * camel-gpg-context.c, camel-cipher-context.c: moved all the init
+ code to the end to save having to keep forward declarations
+ around.
+ (camel_cipher_decrypt): changed to take mimepart input and return
+ a mimepart.
+ (gpg_decrypt): fix for changed args.
+
+2003-10-29 Not Zed <NotZed@Ximian.com>
+
+ * camel-smime-context.[ch]: replaced entirely with a new
+ implementation which inherits from camel-cipher-context, and add
+ to build.
+
+ * camel-multipart-encrypted.c (camel_multipart_encrypted_encrypt):
+ fix for cipher_encrypt api changes.
+ (camel_multipart_encrypted_decrypt): use g_ascii_strcasecmp.
+
+ * camel-gpg-context.c (gpg_encrypt): Fix to handle input/output as
+ parts not streams
+
+ * camel-cipher-context.c (camel_cipher_encrypt): change to take
+ mimeparts rather than streams as input/output. And remove the
+ 'sign' argument, it is implied if userid is supplied.
+
+2003-10-28 Not Zed <NotZed@Ximian.com>
+
+ * tests/smime/pgp.c (main): fix for ciphercontext api changes.
+
+ * camel-multipart-signed.c (camel_multipart_signed_verify): pass
+ in the part to cipher_verify directly.
+ (camel_multipart_signed_sign): let the cipher context setup the
+ part details.
+
+ * camel-gpg-context.c (gpg_sign): put the signature stream into a
+ mimepart, with appropriate headers/encoding.
+ (swrite): write out a mimepart rather than a stream.
+ (gpg_verify): handle changed args.
+
+ * camel-cipher-context.c (camel_cipher_sign): write the signature
+ to a mimepart rather than a simple stream.
+ (camel_cipher_verify): take the signature as a mimepart not a
+ stream.
+
+2003-10-22 Not Zed <NotZed@Ximian.com>
+
+ * camel-utf8.c (camel_ucs2_utf8, camel_utf8_ucs2): helpers for
+ ucs2 stuff. ucs2 is 16 bit truncated unicode.
+
2003-10-28 Jeffrey Stedfast <fejj@ximian.com>
* camel-mime-utils.c: We should check List-Post before List-Id
diff --git a/camel/Makefile.am b/camel/Makefile.am
index ac2d04cdec..a1d00a1323 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -92,6 +92,7 @@ libcamel_la_SOURCES = \
camel-seekable-substream.c \
camel-service.c \
camel-session.c \
+ camel-smime-context.c \
camel-store.c \
camel-store-summary.c \
camel-stream-buffer.c \
@@ -191,6 +192,7 @@ libcamelinclude_HEADERS = \
camel-seekable-substream.h \
camel-service.h \
camel-session.h \
+ camel-smime-context.h \
camel-store.h \
camel-store-summary.h \
camel-stream-buffer.h \
diff --git a/camel/camel-cipher-context.c b/camel/camel-cipher-context.c
index 717f79e37d..212c0fb98c 100644
--- a/camel/camel-cipher-context.c
+++ b/camel/camel-cipher-context.c
@@ -28,6 +28,7 @@
#include <pthread.h>
#include "camel-cipher-context.h"
+#include "camel-stream.h"
#define CIPHER_LOCK(ctx) g_mutex_lock (((CamelCipherContext *) ctx)->priv->lock)
#define CIPHER_UNLOCK(ctx) g_mutex_unlock (((CamelCipherContext *) ctx)->priv->lock);
@@ -40,82 +41,8 @@ struct _CamelCipherContextPrivate {
GMutex *lock;
};
-static const char *cipher_hash_to_id (CamelCipherContext *context, CamelCipherHash hash);
-static CamelCipherHash cipher_id_to_hash (CamelCipherContext *context, const char *id);
-
-static int cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex);
-static CamelCipherValidity *cipher_verify (CamelCipherContext *context, CamelCipherHash hash,
- CamelStream *istream, CamelStream *sigstream,
- CamelException *ex);
-static int cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
- GPtrArray *recipients, CamelStream *istream,
- CamelStream *ostream, CamelException *ex);
-static int cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
- CamelStream *ostream, CamelException *ex);
-static int cipher_import_keys (CamelCipherContext *context, CamelStream *istream,
- CamelException *ex);
-static int cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
- CamelStream *ostream, CamelException *ex);
-
-
static CamelObjectClass *parent_class = NULL;
-
-static void
-camel_cipher_context_init (CamelCipherContext *context)
-{
- context->priv = g_new0 (struct _CamelCipherContextPrivate, 1);
- context->priv->lock = g_mutex_new ();
-}
-
-static void
-camel_cipher_context_finalise (CamelObject *o)
-{
- CamelCipherContext *context = (CamelCipherContext *)o;
-
- camel_object_unref (context->session);
-
- g_mutex_free (context->priv->lock);
-
- g_free (context->priv);
-}
-
-static void
-camel_cipher_context_class_init (CamelCipherContextClass *camel_cipher_context_class)
-{
- parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
-
- camel_cipher_context_class->hash_to_id = cipher_hash_to_id;
- camel_cipher_context_class->id_to_hash = cipher_id_to_hash;
- camel_cipher_context_class->sign = cipher_sign;
- camel_cipher_context_class->verify = cipher_verify;
- camel_cipher_context_class->encrypt = cipher_encrypt;
- camel_cipher_context_class->decrypt = cipher_decrypt;
- camel_cipher_context_class->import_keys = cipher_import_keys;
- camel_cipher_context_class->export_keys = cipher_export_keys;
-}
-
-CamelType
-camel_cipher_context_get_type (void)
-{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- type = camel_type_register (camel_object_get_type (),
- "CamelCipherContext",
- sizeof (CamelCipherContext),
- sizeof (CamelCipherContextClass),
- (CamelObjectClassInitFunc) camel_cipher_context_class_init,
- NULL,
- (CamelObjectInitFunc) camel_cipher_context_init,
- (CamelObjectFinalizeFunc) camel_cipher_context_finalise);
- }
-
- return type;
-}
-
-
/**
* camel_cipher_context_new:
* @session: CamelSession
@@ -140,7 +67,6 @@ camel_cipher_context_new (CamelSession *session)
return context;
}
-
/**
* camel_cipher_context_construct:
* @context: CamelCipherContext
@@ -158,10 +84,9 @@ camel_cipher_context_construct (CamelCipherContext *context, CamelSession *sessi
context->session = session;
}
-
static int
cipher_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+ struct _CamelStream *istream, struct _CamelMimePart *sigpart, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Signing is not supported by this cipher"));
@@ -174,16 +99,16 @@ cipher_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
* @userid: private key to use to sign the stream
* @hash: preferred Message-Integrity-Check hash algorithm
* @istream: input stream
- * @ostream: output stream
+ * @sigpart: output signature part.
* @ex: exception
*
- * Signs the input stream and writes the resulting signature to the output stream.
+ * Signs the input stream and writes the resulting signature to output @sigpart.
*
* Return value: 0 for success or -1 for failure.
**/
int
camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+ struct _CamelStream *istream, struct _CamelMimePart *sigpart, CamelException *ex)
{
int retval;
@@ -191,24 +116,22 @@ camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherH
CIPHER_LOCK(context);
- retval = CCC_CLASS (context)->sign (context, userid, hash, istream, ostream, ex);
+ retval = CCC_CLASS (context)->sign (context, userid, hash, istream, sigpart, ex);
CIPHER_UNLOCK(context);
return retval;
}
-
static CamelCipherValidity *
-cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream,
- CamelStream *sigstream, CamelException *ex)
+cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _CamelStream *istream,
+ struct _CamelMimePart *sigpart, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Verifying is not supported by this cipher"));
return NULL;
}
-
/**
* camel_cipher_verify:
* @context: Cipher Context
@@ -226,8 +149,8 @@ cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *i
* execute at all.
**/
CamelCipherValidity *
-camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream,
- CamelStream *sigstream, CamelException *ex)
+camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, struct _CamelStream *istream,
+ struct _CamelMimePart *sigpart, CamelException *ex)
{
CamelCipherValidity *valid;
@@ -235,17 +158,16 @@ camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStr
CIPHER_LOCK(context);
- valid = CCC_CLASS (context)->verify (context, hash, istream, sigstream, ex);
+ valid = CCC_CLASS (context)->verify (context, hash, istream, sigpart, ex);
CIPHER_UNLOCK(context);
return valid;
}
-
static int
-cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+cipher_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipients,
+ struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Encryption is not supported by this cipher"));
@@ -255,8 +177,7 @@ cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
/**
* camel_cipher_encrypt:
* @context: Cipher Context
- * @sign: sign as well as encrypt
- * @userid: key id (or email address) to use when signing (assuming @sign is %TRUE)
+ * @userid: key id (or email address) to use when signing, or NULL to not sign.
* @recipients: an array of recipient key ids and/or email addresses
* @istream: cleartext input stream
* @ostream: ciphertext output stream
@@ -268,8 +189,8 @@ cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
* Return value: 0 for success or -1 for failure.
**/
int
-camel_cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+camel_cipher_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipients,
+ struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
{
int retval;
@@ -277,21 +198,19 @@ camel_cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *us
CIPHER_LOCK(context);
- retval = CCC_CLASS (context)->encrypt (context, sign, userid, recipients, istream, ostream, ex);
+ retval = CCC_CLASS (context)->encrypt (context, userid, recipients, ipart, opart, ex);
CIPHER_UNLOCK(context);
return retval;
}
-
-static int
-cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
- CamelStream *ostream, CamelException *ex)
+static struct _CamelMimePart *
+cipher_decrypt(CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Decryption is not supported by this cipher"));
- return -1;
+ return NULL;
}
/**
@@ -306,26 +225,24 @@ cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
*
* Return value: 0 for success or -1 for failure.
**/
-int
-camel_cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
- CamelStream *ostream, CamelException *ex)
+struct _CamelMimePart *
+camel_cipher_decrypt (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex)
{
- int retval;
-
- g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
+ struct _CamelMimePart *opart;
+
+ g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
CIPHER_LOCK(context);
- retval = CCC_CLASS (context)->decrypt (context, istream, ostream, ex);
+ opart = CCC_CLASS (context)->decrypt (context, ipart, ex);
CIPHER_UNLOCK(context);
- return retval;
+ return opart;
}
-
static int
-cipher_import_keys (CamelCipherContext *context, CamelStream *istream, CamelException *ex)
+cipher_import_keys (CamelCipherContext *context, struct _CamelStream *istream, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("You may not import keys with this cipher"));
@@ -333,7 +250,6 @@ cipher_import_keys (CamelCipherContext *context, CamelStream *istream, CamelExce
return -1;
}
-
/**
* camel_cipher_import_keys:
* @ctx: Cipher Context
@@ -346,7 +262,7 @@ cipher_import_keys (CamelCipherContext *context, CamelStream *istream, CamelExce
* Returns 0 on success or -1 on fail.
**/
int
-camel_cipher_import_keys (CamelCipherContext *context, CamelStream *istream, CamelException *ex)
+camel_cipher_import_keys (CamelCipherContext *context, struct _CamelStream *istream, CamelException *ex)
{
g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
g_return_val_if_fail (CAMEL_IS_STREAM (istream), -1);
@@ -354,10 +270,9 @@ camel_cipher_import_keys (CamelCipherContext *context, CamelStream *istream, Cam
return CCC_CLASS (context)->import_keys (context, istream, ex);
}
-
static int
cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
- CamelStream *ostream, CamelException *ex)
+ struct _CamelStream *ostream, CamelException *ex)
{
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("You may not export keys with this cipher"));
@@ -365,7 +280,6 @@ cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
return -1;
}
-
/**
* camel_cipher_export_keys:
* @ctx: Cipher Context
@@ -380,7 +294,7 @@ cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
**/
int
camel_cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
- CamelStream *ostream, CamelException *ex)
+ struct _CamelStream *ostream, CamelException *ex)
{
g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
g_return_val_if_fail (CAMEL_IS_STREAM (ostream), -1);
@@ -389,7 +303,6 @@ camel_cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
return CCC_CLASS (context)->export_keys (context, keys, ostream, ex);
}
-
static CamelCipherHash
cipher_id_to_hash(CamelCipherContext *context, const char *id)
{
@@ -500,3 +413,58 @@ camel_cipher_validity_free (CamelCipherValidity *validity)
g_free (validity->description);
g_free (validity);
}
+
+/* ********************************************************************** */
+
+static void
+camel_cipher_context_init (CamelCipherContext *context)
+{
+ context->priv = g_new0 (struct _CamelCipherContextPrivate, 1);
+ context->priv->lock = g_mutex_new ();
+}
+
+static void
+camel_cipher_context_finalise (CamelObject *o)
+{
+ CamelCipherContext *context = (CamelCipherContext *)o;
+
+ camel_object_unref (CAMEL_OBJECT (context->session));
+
+ g_mutex_free (context->priv->lock);
+
+ g_free (context->priv);
+}
+
+static void
+camel_cipher_context_class_init (CamelCipherContextClass *camel_cipher_context_class)
+{
+ parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
+
+ camel_cipher_context_class->hash_to_id = cipher_hash_to_id;
+ camel_cipher_context_class->id_to_hash = cipher_id_to_hash;
+ camel_cipher_context_class->sign = cipher_sign;
+ camel_cipher_context_class->verify = cipher_verify;
+ camel_cipher_context_class->encrypt = cipher_encrypt;
+ camel_cipher_context_class->decrypt = cipher_decrypt;
+ camel_cipher_context_class->import_keys = cipher_import_keys;
+ camel_cipher_context_class->export_keys = cipher_export_keys;
+}
+
+CamelType
+camel_cipher_context_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_object_get_type (),
+ "CamelCipherContext",
+ sizeof (CamelCipherContext),
+ sizeof (CamelCipherContextClass),
+ (CamelObjectClassInitFunc) camel_cipher_context_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_cipher_context_init,
+ (CamelObjectFinalizeFunc) camel_cipher_context_finalise);
+ }
+
+ return type;
+}
diff --git a/camel/camel-cipher-context.h b/camel/camel-cipher-context.h
index 45444c26a0..5d9218b83e 100644
--- a/camel/camel-cipher-context.h
+++ b/camel/camel-cipher-context.h
@@ -24,9 +24,11 @@
#define CAMEL_CIPHER_CONTEXT_H
#include <camel/camel-session.h>
-#include <camel/camel-stream.h>
#include <camel/camel-exception.h>
+struct _CamelStream;
+struct _CamelMimePart;
+
#ifdef __cplusplus
extern "C" {
#pragma }
@@ -69,24 +71,23 @@ typedef struct _CamelCipherContextClass {
const char * (*hash_to_id)(CamelCipherContext *context, CamelCipherHash hash);
int (*sign) (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex);
+ struct _CamelStream *istream, struct _CamelMimePart *sigpart, CamelException *ex);
CamelCipherValidity * (*verify) (CamelCipherContext *context, CamelCipherHash hash,
- CamelStream *istream, CamelStream *sigstream,
+ struct _CamelStream *istream, struct _CamelMimePart *sigpart,
CamelException *ex);
- int (*encrypt) (CamelCipherContext *context, gboolean sign, const char *userid,
- GPtrArray *recipients, CamelStream *istream, CamelStream *ostream,
+ int (*encrypt) (CamelCipherContext *context, const char *userid,
+ GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart,
CamelException *ex);
- int (*decrypt) (CamelCipherContext *context, CamelStream *istream, CamelStream *ostream,
- CamelException *ex);
+ struct _CamelMimePart *(*decrypt) (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
- int (*import_keys) (CamelCipherContext *context, CamelStream *istream,
+ int (*import_keys) (CamelCipherContext *context, struct _CamelStream *istream,
CamelException *ex);
int (*export_keys) (CamelCipherContext *context, GPtrArray *keys,
- CamelStream *ostream, CamelException *ex);
+ struct _CamelStream *ostream, CamelException *ex);
} CamelCipherContextClass;
CamelType camel_cipher_context_get_type (void);
@@ -99,43 +100,36 @@ void camel_cipher_context_construct (CamelCipherContext *context
CamelCipherHash camel_cipher_id_to_hash (CamelCipherContext *context, const char *id);
const char * camel_cipher_hash_to_id (CamelCipherContext *context, CamelCipherHash hash);
+/* FIXME:
+ There are some inconsistencies here, the api's should probably handle CamelMimePart's as input/outputs,
+ Something that might generate a multipart/signed should do it as part of that processing, internally
+ to the cipher, etc etc. */
+
/* cipher routines */
int camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex);
-
+ struct _CamelStream *istream, struct _CamelMimePart *sigpart, CamelException *ex);
CamelCipherValidity *camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash,
- CamelStream *istream, CamelStream *sigstream,
+ struct _CamelStream *istream, struct _CamelMimePart *sigpart,
CamelException *ex);
-
-int camel_cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
- GPtrArray *recipients, CamelStream *istream, CamelStream *ostream,
- CamelException *ex);
-
-int camel_cipher_decrypt (CamelCipherContext *context, CamelStream *istream, CamelStream *ostream,
+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);
/* key/certificate routines */
-int camel_cipher_import_keys (CamelCipherContext *context, CamelStream *istream,
+int camel_cipher_import_keys (CamelCipherContext *context, struct _CamelStream *istream,
CamelException *ex);
-
int camel_cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
- CamelStream *ostream, CamelException *ex);
+ struct _CamelStream *ostream, CamelException *ex);
/* CamelCipherValidity utility functions */
CamelCipherValidity *camel_cipher_validity_new (void);
-
void camel_cipher_validity_init (CamelCipherValidity *validity);
-
gboolean camel_cipher_validity_get_valid (CamelCipherValidity *validity);
-
void camel_cipher_validity_set_valid (CamelCipherValidity *validity, gboolean 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_free (CamelCipherValidity *validity);
#ifdef __cplusplus
diff --git a/camel/camel-gpg-context.c b/camel/camel-gpg-context.c
index 79c14d9b71..6f79cdb4ff 100644
--- a/camel/camel-gpg-context.c
+++ b/camel/camel-gpg-context.c
@@ -49,89 +49,13 @@
#include "camel-stream-mem.h"
#include "camel-stream-fs.h"
#include "camel-operation.h"
+#include "camel-mime-part.h"
+#include "camel-mime-filter-canon.h"
#define d(x)
-static void camel_gpg_context_class_init (CamelGpgContextClass *klass);
-static void camel_gpg_context_init (CamelGpgContext *obj);
-static void camel_gpg_context_finalise (CamelObject *obj);
-
-static const char *gpg_hash_to_id (CamelCipherContext *context, CamelCipherHash hash);
-static CamelCipherHash gpg_id_to_hash (CamelCipherContext *context, const char *id);
-
-static int gpg_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex);
-static CamelCipherValidity *gpg_verify (CamelCipherContext *context, CamelCipherHash hash,
- CamelStream *istream, CamelStream *sigstream,
- CamelException *ex);
-static int gpg_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
- GPtrArray *recipients, CamelStream *istream, CamelStream *ostream,
- CamelException *ex);
-static int gpg_decrypt (CamelCipherContext *context, CamelStream *istream,
- CamelStream *ostream, CamelException *ex);
-static int gpg_import_keys (CamelCipherContext *context, CamelStream *istream,
- CamelException *ex);
-static int gpg_export_keys (CamelCipherContext *context, GPtrArray *keys,
- CamelStream *ostream, CamelException *ex);
-
static CamelCipherContextClass *parent_class = NULL;
-
-CamelType
-camel_gpg_context_get_type (void)
-{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- type = camel_type_register (camel_cipher_context_get_type (),
- "CamelGpgContext",
- sizeof (CamelGpgContext),
- sizeof (CamelGpgContextClass),
- (CamelObjectClassInitFunc) camel_gpg_context_class_init,
- NULL,
- (CamelObjectInitFunc) camel_gpg_context_init,
- (CamelObjectFinalizeFunc) camel_gpg_context_finalise);
- }
-
- return type;
-}
-
-static void
-camel_gpg_context_class_init (CamelGpgContextClass *klass)
-{
- CamelCipherContextClass *cipher_class = CAMEL_CIPHER_CONTEXT_CLASS (klass);
-
- parent_class = CAMEL_CIPHER_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cipher_context_get_type ()));
-
- cipher_class->hash_to_id = gpg_hash_to_id;
- cipher_class->id_to_hash = gpg_id_to_hash;
- cipher_class->sign = gpg_sign;
- cipher_class->verify = gpg_verify;
- cipher_class->encrypt = gpg_encrypt;
- cipher_class->decrypt = gpg_decrypt;
- cipher_class->import_keys = gpg_import_keys;
- cipher_class->export_keys = gpg_export_keys;
-}
-
-static void
-camel_gpg_context_init (CamelGpgContext *context)
-{
- CamelCipherContext *cipher = (CamelCipherContext *) context;
-
- context->always_trust = FALSE;
-
- cipher->sign_protocol = "application/pgp-signature";
- cipher->encrypt_protocol = "application/pgp-encrypted";
- cipher->key_protocol = "application/pgp-keys";
-}
-
-static void
-camel_gpg_context_finalise (CamelObject *object)
-{
- ;
-}
-
-
/**
* camel_gpg_context_new:
* @session: session
@@ -1271,10 +1195,14 @@ gpg_ctx_op_wait (struct _GpgCtx *gpg)
static int
gpg_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+ CamelStream *istream, CamelMimePart *sigpart, CamelException *ex)
{
struct _GpgCtx *gpg;
-
+ CamelStream *ostream = camel_stream_mem_new();
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+ int res = -1;
+
gpg = gpg_ctx_new (context->session);
gpg_ctx_set_mode (gpg, GPG_CTX_MODE_SIGN);
gpg_ctx_set_hash (gpg, hash);
@@ -1286,9 +1214,7 @@ gpg_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
if (gpg_ctx_op_start (gpg) == -1) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed to execute gpg: %s"), g_strerror (errno));
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
while (!gpg_ctx_op_complete (gpg)) {
@@ -1296,16 +1222,12 @@ gpg_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
_("Cancelled."));
gpg_ctx_op_cancel (gpg);
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
if (gpg_ctx_op_step (gpg, ex) == -1) {
gpg_ctx_op_cancel (gpg);
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
}
@@ -1316,20 +1238,34 @@ gpg_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
diagnostics && *diagnostics ? diagnostics :
_("Failed to execute gpg."));
-
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
-
+
+ res = 0;
+
+ dw = camel_data_wrapper_new();
+ camel_stream_reset(ostream);
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+
+ ct = camel_content_type_new("application", "pgp-signature");
+ camel_content_type_set_param(ct, "name", "signature.asc");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)sigpart, dw);
+ camel_object_unref(dw);
+ camel_mime_part_set_description(sigpart, _("This is a digitally signed message part"));
+
+fail:
+ camel_object_unref(ostream);
gpg_ctx_free (gpg);
- return 0;
+ return res;
}
static char *
-swrite (CamelStream *istream)
+swrite (CamelMimePart *sigpart)
{
CamelStream *ostream;
char *template;
@@ -1341,17 +1277,19 @@ swrite (CamelStream *istream)
g_free (template);
return NULL;
}
-
+
+ /* TODO: This should probably just write the decoded message content out, not the part + headers */
+
ostream = camel_stream_fs_new_with_fd (fd);
- ret = camel_stream_write_to_stream (istream, ostream);
+ ret = camel_data_wrapper_write_to_stream((CamelDataWrapper *)sigpart, ostream);
if (ret != -1) {
ret = camel_stream_flush (ostream);
if (ret != -1)
ret = camel_stream_close (ostream);
}
-
- camel_object_unref (ostream);
-
+
+ camel_object_unref(ostream);
+
if (ret == -1) {
unlink (template);
g_free (template);
@@ -1363,7 +1301,7 @@ swrite (CamelStream *istream)
static CamelCipherValidity *
gpg_verify (CamelCipherContext *context, CamelCipherHash hash,
- CamelStream *istream, CamelStream *sigstream,
+ CamelStream *istream, CamelMimePart *sigpart,
CamelException *ex)
{
CamelCipherValidity *validity;
@@ -1372,10 +1310,10 @@ gpg_verify (CamelCipherContext *context, CamelCipherHash hash,
char *sigfile = NULL;
gboolean valid;
- if (sigstream != NULL) {
+ if (sigpart != NULL) {
/* We are going to verify a detached signature so save
the signature to a temp file. */
- sigfile = swrite (sigstream);
+ sigfile = swrite (sigpart);
if (sigfile == NULL) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot verify message signature: "
@@ -1438,51 +1376,62 @@ gpg_verify (CamelCipherContext *context, CamelCipherHash hash,
return NULL;
}
-
static int
-gpg_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
- GPtrArray *recipients, CamelStream *istream, CamelStream *ostream,
- CamelException *ex)
+gpg_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
{
CamelGpgContext *ctx = (CamelGpgContext *) context;
struct _GpgCtx *gpg;
- int i;
+ int i, res = -1;
+ CamelStream *istream, *filtered_stream, *ostream;
+ CamelMimeFilter *filter;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+
+ ostream = camel_stream_mem_new();
+
+ /* TODO: Should this just return a mimepart with an embedded multipart-encrypted? */
+
+ /* Canonicalise the input */
+ /* FIXME: Move this to a common routine */
+ istream = camel_stream_mem_new();
+ filtered_stream = (CamelStream *)camel_stream_filter_new_with_stream(istream);
+ filter = camel_mime_filter_canon_new(CAMEL_MIME_FILTER_CANON_CRLF);
+ camel_stream_filter_add((CamelStreamFilter *)filtered_stream, filter);
+ camel_object_unref(filter);
+ camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, filtered_stream);
+ camel_stream_flush(filtered_stream);
+ camel_object_unref(filtered_stream);
+ camel_stream_reset(istream);
gpg = gpg_ctx_new (context->session);
gpg_ctx_set_mode (gpg, GPG_CTX_MODE_ENCRYPT);
gpg_ctx_set_armor (gpg, TRUE);
gpg_ctx_set_userid (gpg, userid);
gpg_ctx_set_istream (gpg, istream);
+ camel_object_unref(istream);
gpg_ctx_set_ostream (gpg, ostream);
gpg_ctx_set_always_trust (gpg, ctx->always_trust);
-
+
for (i = 0; i < recipients->len; i++) {
gpg_ctx_add_recipient (gpg, recipients->pdata[i]);
}
if (gpg_ctx_op_start (gpg) == -1) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to execute gpg."));
- gpg_ctx_free (gpg);
-
- return -1;
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to execute gpg."));
+ goto fail;
}
-
- while (!gpg_ctx_op_complete (gpg)) {
- if (camel_operation_cancel_check (NULL)) {
- camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
- _("Cancelled."));
- gpg_ctx_op_cancel (gpg);
- gpg_ctx_free (gpg);
-
- return -1;
+
+ /* FIXME: move tihs to a common routine */
+ while (!gpg_ctx_op_complete(gpg)) {
+ if (camel_operation_cancel_check(NULL)) {
+ camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled."));
+ gpg_ctx_op_cancel(gpg);
+ goto fail;
}
if (gpg_ctx_op_step (gpg, ex) == -1) {
gpg_ctx_op_cancel (gpg);
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
}
@@ -1491,26 +1440,46 @@ gpg_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
diagnostics = gpg_ctx_get_diagnostics (gpg);
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- diagnostics && *diagnostics ? diagnostics :
- _("Failed to execute gpg."));
-
- gpg_ctx_free (gpg);
-
- return -1;
+ diagnostics && *diagnostics ? diagnostics : _("Failed to execute gpg."));
+ goto fail;
}
-
- gpg_ctx_free (gpg);
-
- return 0;
-}
+ res = 0;
-static int
-gpg_decrypt (CamelCipherContext *context, CamelStream *istream,
- CamelStream *ostream, CamelException *ex)
+ dw = camel_data_wrapper_new();
+ ct = camel_content_type_new("application", "octet-stream");
+ camel_content_type_set_param(ct, "name", "encrypted.asc");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+ camel_medium_set_content_object((CamelMedium *)opart, dw);
+ camel_object_unref(dw);
+
+fail:
+ camel_object_unref(ostream);
+ gpg_ctx_free(gpg);
+
+ return res;
+}
+
+static CamelMimePart *
+gpg_decrypt (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
{
struct _GpgCtx *gpg;
-
+ CamelMimePart *opart = NULL;
+ CamelStream *ostream, *istream;
+
+ istream = camel_stream_mem_new();
+ camel_data_wrapper_write_to_stream(camel_medium_get_content_object((CamelMedium *)ipart), istream);
+ /* TODO: de-canonicalise end of lines? */
+ /*stream = camel_stream_mem_new ();
+ filtered_stream = (CamelStream *) camel_stream_filter_new_with_stream (stream);
+ crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE,
+ CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
+ camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), crlf_filter);
+ camel_object_unref (crlf_filter);*/
+ ostream = camel_stream_mem_new();
+
gpg = gpg_ctx_new (context->session);
gpg_ctx_set_mode (gpg, GPG_CTX_MODE_DECRYPT);
gpg_ctx_set_istream (gpg, istream);
@@ -1519,9 +1488,7 @@ gpg_decrypt (CamelCipherContext *context, CamelStream *istream,
if (gpg_ctx_op_start (gpg) == -1) {
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed to execute gpg."));
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
while (!gpg_ctx_op_complete (gpg)) {
@@ -1529,16 +1496,12 @@ gpg_decrypt (CamelCipherContext *context, CamelStream *istream,
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
_("Cancelled."));
gpg_ctx_op_cancel (gpg);
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
if (gpg_ctx_op_step (gpg, ex) == -1) {
gpg_ctx_op_cancel (gpg);
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
}
@@ -1549,15 +1512,23 @@ gpg_decrypt (CamelCipherContext *context, CamelStream *istream,
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
diagnostics && *diagnostics ? diagnostics :
_("Failed to execute gpg."));
-
- gpg_ctx_free (gpg);
-
- return -1;
+ goto fail;
}
-
+
+ opart = camel_mime_part_new();
+ camel_stream_reset(ostream);
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream) == -1) {
+ 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 0;
+ return opart;
}
static int
@@ -1655,3 +1626,61 @@ gpg_export_keys (CamelCipherContext *context, GPtrArray *keys, CamelStream *ostr
return 0;
}
+
+/* ********************************************************************** */
+
+static void
+camel_gpg_context_class_init (CamelGpgContextClass *klass)
+{
+ CamelCipherContextClass *cipher_class = CAMEL_CIPHER_CONTEXT_CLASS (klass);
+
+ parent_class = CAMEL_CIPHER_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cipher_context_get_type ()));
+
+ cipher_class->hash_to_id = gpg_hash_to_id;
+ cipher_class->id_to_hash = gpg_id_to_hash;
+ cipher_class->sign = gpg_sign;
+ cipher_class->verify = gpg_verify;
+ cipher_class->encrypt = gpg_encrypt;
+ cipher_class->decrypt = gpg_decrypt;
+ cipher_class->import_keys = gpg_import_keys;
+ cipher_class->export_keys = gpg_export_keys;
+}
+
+static void
+camel_gpg_context_init (CamelGpgContext *context)
+{
+ CamelCipherContext *cipher = (CamelCipherContext *) context;
+
+ context->always_trust = FALSE;
+
+ cipher->sign_protocol = "application/pgp-signature";
+ cipher->encrypt_protocol = "application/pgp-encrypted";
+ cipher->key_protocol = "application/pgp-keys";
+}
+
+static void
+camel_gpg_context_finalise (CamelObject *object)
+{
+ ;
+}
+
+CamelType
+camel_gpg_context_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_cipher_context_get_type (),
+ "CamelGpgContext",
+ sizeof (CamelGpgContext),
+ sizeof (CamelGpgContextClass),
+ (CamelObjectClassInitFunc) camel_gpg_context_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_gpg_context_init,
+ (CamelObjectFinalizeFunc) camel_gpg_context_finalise);
+ }
+
+ return type;
+}
+
+
diff --git a/camel/camel-multipart-encrypted.c b/camel/camel-multipart-encrypted.c
index 90866a9a20..d906ae80fc 100644
--- a/camel/camel-multipart-encrypted.c
+++ b/camel/camel-multipart-encrypted.c
@@ -145,42 +145,20 @@ camel_multipart_encrypted_encrypt (CamelMultipartEncrypted *mpe, CamelMimePart *
CamelMimePart *version_part, *encrypted_part;
CamelContentType *mime_type;
CamelDataWrapper *wrapper;
- CamelStream *filtered_stream;
- CamelStream *stream, *ciphertext;
- CamelMimeFilter *crlf_filter;
+ CamelStream *stream;
g_return_val_if_fail (CAMEL_IS_MULTIPART_ENCRYPTED (mpe), -1);
g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (cipher), -1);
g_return_val_if_fail (cipher->encrypt_protocol != NULL, -1);
g_return_val_if_fail (CAMEL_IS_MIME_PART (content), -1);
- /* get the cleartext */
- stream = camel_stream_mem_new ();
- filtered_stream = (CamelStream *) camel_stream_filter_new_with_stream (stream);
-
- crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE,
- CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
- camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), crlf_filter);
- camel_object_unref (crlf_filter);
-
- camel_data_wrapper_write_to_stream ((CamelDataWrapper *) content, filtered_stream);
- camel_stream_flush (filtered_stream);
- camel_object_unref (filtered_stream);
-
- /* reset the content stream */
- camel_stream_reset (stream);
-
/* encrypt the content stream */
- ciphertext = camel_stream_mem_new ();
- if (camel_cipher_encrypt (cipher, FALSE, userid, recipients, stream, ciphertext, ex) == -1) {
- camel_object_unref (ciphertext);
- camel_object_unref (stream);
+ encrypted_part = camel_mime_part_new();
+ if (camel_cipher_encrypt (cipher, userid, recipients, content, encrypted_part, ex) == -1) {
+ camel_object_unref(encrypted_part);
return -1;
}
- camel_object_unref (stream);
- camel_stream_reset (ciphertext);
-
/* construct the version part */
stream = camel_stream_mem_new ();
camel_stream_write_string (stream, "Version: 1\n");
@@ -193,16 +171,7 @@ camel_multipart_encrypted_encrypt (CamelMultipartEncrypted *mpe, CamelMimePart *
camel_object_unref (stream);
camel_medium_set_content_object ((CamelMedium *) version_part, wrapper);
camel_object_unref (wrapper);
-
- /* construct the encrypted mime part */
- encrypted_part = camel_mime_part_new ();
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream; name=encrypted.asc");
- camel_data_wrapper_construct_from_stream (wrapper, ciphertext);
- camel_object_unref (ciphertext);
- camel_medium_set_content_object ((CamelMedium *) encrypted_part, wrapper);
- camel_object_unref (wrapper);
-
+
/* save the version and encrypted parts */
/* FIXME: make sure there aren't any other parts?? */
camel_multipart_add_part (CAMEL_MULTIPART (mpe), version_part);
@@ -233,10 +202,6 @@ camel_multipart_encrypted_decrypt (CamelMultipartEncrypted *mpe,
CamelMimePart *version_part, *encrypted_part, *decrypted_part;
CamelContentType *mime_type;
CamelDataWrapper *wrapper;
- CamelStream *filtered_stream;
- CamelMimeFilter *crlf_filter;
- CamelStream *ciphertext;
- CamelStream *stream;
const char *protocol;
char *content_type;
@@ -254,7 +219,7 @@ camel_multipart_encrypted_decrypt (CamelMultipartEncrypted *mpe,
if (protocol) {
/* make sure the protocol matches the cipher encrypt protocol */
- if (strcasecmp (cipher->encrypt_protocol, protocol) != 0) {
+ if (g_ascii_strcasecmp (cipher->encrypt_protocol, protocol) != 0) {
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed to decrypt MIME part: protocol error"));
@@ -269,7 +234,7 @@ camel_multipart_encrypted_decrypt (CamelMultipartEncrypted *mpe,
version_part = camel_multipart_get_part (CAMEL_MULTIPART (mpe), CAMEL_MULTIPART_ENCRYPTED_VERSION);
wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (version_part));
content_type = camel_data_wrapper_get_mime_type (wrapper);
- if (strcasecmp (content_type, protocol) != 0) {
+ if (g_ascii_strcasecmp (content_type, protocol) != 0) {
camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
_("Failed to decrypt MIME part: protocol error"));
@@ -288,44 +253,11 @@ camel_multipart_encrypted_decrypt (CamelMultipartEncrypted *mpe,
return NULL;
}
- /* get the ciphertext stream */
- ciphertext = camel_stream_mem_new ();
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (encrypted_part));
- camel_data_wrapper_write_to_stream (wrapper, ciphertext);
- camel_stream_reset (ciphertext);
-
- stream = camel_stream_mem_new ();
- filtered_stream = (CamelStream *) camel_stream_filter_new_with_stream (stream);
- crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE,
- CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
- camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), crlf_filter);
- camel_object_unref (crlf_filter);
-
- /* get the cleartext */
- if (camel_cipher_decrypt (cipher, ciphertext, filtered_stream, ex) == -1) {
- camel_object_unref (filtered_stream);
- camel_object_unref (ciphertext);
- camel_object_unref (stream);
-
- return NULL;
- }
-
- camel_stream_flush (filtered_stream);
- camel_object_unref (filtered_stream);
- camel_object_unref (ciphertext);
- camel_stream_reset (stream);
-
- decrypted_part = camel_mime_part_new ();
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (decrypted_part), stream);
-
+ decrypted_part = camel_cipher_decrypt(cipher, encrypted_part, ex);
if (decrypted_part) {
- /* cache the decrypted part */
camel_object_ref (decrypted_part);
mpe->decrypted = decrypted_part;
- } else {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to decrypt MIME part: parse error"));
}
-
+
return decrypted_part;
}
diff --git a/camel/camel-multipart-signed.c b/camel/camel-multipart-signed.c
index c249690ad4..bc5e363c8d 100644
--- a/camel/camel-multipart-signed.c
+++ b/camel/camel-multipart-signed.c
@@ -593,12 +593,10 @@ int
camel_multipart_signed_sign(CamelMultipartSigned *mps, CamelCipherContext *context, CamelMimePart *content, const char *userid, CamelCipherHash hash, CamelException *ex)
{
CamelMimeFilter *canon_filter;
- CamelStream *sigstream, *mem;
+ CamelStream *mem;
CamelStreamFilter *filter;
CamelContentType *mime_type;
- CamelMimePart *signature;
- CamelDataWrapper *dw;
- char *type;
+ CamelMimePart *sigpart;
/* this needs to be set */
g_return_val_if_fail(context->sign_protocol != NULL, -1);
@@ -624,27 +622,14 @@ camel_multipart_signed_sign(CamelMultipartSigned *mps, CamelCipherContext *conte
printf("-- end\n");
#endif
- sigstream = camel_stream_mem_new();
+ sigpart = camel_mime_part_new();
- if (camel_cipher_sign(context, userid, hash, mem, sigstream, ex) == -1) {
- camel_object_unref((CamelObject *)mem);
- camel_object_unref((CamelObject *)sigstream);
+ if (camel_cipher_sign(context, userid, hash, mem, sigpart, ex) == -1) {
+ camel_object_unref(mem);
+ camel_object_unref(sigpart);
return -1;
}
- /* create the signature wrapper object */
- signature = camel_mime_part_new();
- dw = camel_data_wrapper_new();
- type = alloca(strlen(context->sign_protocol) + 32);
- sprintf(type, "%s; name=signature.asc", context->sign_protocol);
- camel_data_wrapper_set_mime_type(dw, type);
- camel_stream_reset(sigstream);
- camel_data_wrapper_construct_from_stream(dw, sigstream);
- camel_object_unref((CamelObject *)sigstream);
- camel_medium_set_content_object((CamelMedium *)signature, dw);
- camel_object_unref((CamelObject *)dw);
- camel_mime_part_set_description(signature, _("This is a digitally signed message part"));
-
/* setup our mime type and boundary */
mime_type = camel_content_type_new("multipart", "signed");
camel_content_type_set_param(mime_type, "micalg", camel_cipher_hash_to_id(context, hash));
@@ -655,7 +640,7 @@ camel_multipart_signed_sign(CamelMultipartSigned *mps, CamelCipherContext *conte
/* just keep the whole raw content. We dont *really* need to do this because
we know how we just proccessed it, but, well, better to be safe than sorry */
- mps->signature = signature;
+ mps->signature = sigpart;
mps->contentraw = mem;
camel_stream_reset(mem);
@@ -685,7 +670,7 @@ camel_multipart_signed_verify(CamelMultipartSigned *mps, CamelCipherContext *con
{
CamelCipherValidity *valid;
CamelMimePart *sigpart;
- CamelStream *sigstream, *constream;
+ CamelStream *constream;
/* we need to be able to verify stuff we just signed as well as stuff we loaded from a stream/parser */
@@ -713,13 +698,10 @@ camel_multipart_signed_verify(CamelMultipartSigned *mps, CamelCipherContext *con
}
/* we do this as a normal mime part so we can have it handle transfer encoding etc */
- sigstream = camel_stream_mem_new();
sigpart = camel_multipart_get_part((CamelMultipart *)mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
- camel_data_wrapper_write_to_stream((CamelDataWrapper *)sigpart, sigstream);
- camel_stream_reset(sigstream);
/* do the magic, the caller must supply the right context for this kind of object */
- valid = camel_cipher_verify(context, camel_cipher_id_to_hash(context, mps->micalg), constream, sigstream, ex);
+ valid = camel_cipher_verify(context, camel_cipher_id_to_hash(context, mps->micalg), constream, sigpart, ex);
#if 0
{
@@ -733,8 +715,7 @@ camel_multipart_signed_verify(CamelMultipartSigned *mps, CamelCipherContext *con
}
#endif
- camel_object_unref((CamelObject *)constream);
- camel_object_unref((CamelObject *)sigstream);
+ camel_object_unref(constream);
return valid;
}
diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c
index 3c87c83f64..ea6a73760d 100644
--- a/camel/camel-smime-context.c
+++ b/camel/camel-smime-context.c
@@ -1,900 +1,587 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
*
- * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
-/* Note: much of the NSS code was copied from Mozilla's cmsutil.c program */
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#ifdef HAVE_NSS
-#include "camel-smime-context.h"
-
-#include "camel-mime-filter-from.h"
-#include "camel-mime-filter-crlf.h"
-#include "camel-stream-filter.h"
-#include "camel-stream-fs.h"
-#include "camel-stream-mem.h"
-#include "camel-mime-part.h"
-#include "camel-multipart.h"
-
#include "nss.h"
#include <cms.h>
#include <cert.h>
#include <certdb.h>
#include <pkcs11.h>
#include <smime.h>
+#include <pkcs11t.h>
+#include <pk11func.h>
-#define d(x)
-
-struct _CamelSMimeContextPrivate {
- CERTCertDBHandle *certdb;
-};
+#include <camel/camel-exception.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-mime-part.h>
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-mime-filter-basic.h>
+#include <camel/camel-mime-filter-canon.h>
-static CamelMimeMessage *smime_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, gboolean signing_time,
- gboolean detached, CamelException *ex);
+#include "camel-smime-context.h"
+#include "camel-operation.h"
-static CamelMimeMessage *smime_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, GPtrArray *recipients,
- CamelException *ex);
+#define d(x)
-static CamelMimeMessage *smime_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, GPtrArray *recipients,
- CamelException *ex);
+struct _CamelSMIMEContextPrivate {
+ CERTCertDBHandle *certdb;
-static CamelMimeMessage *smime_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, GPtrArray *recipients,
- CamelException *ex);
+ char *encrypt_key;
+ camel_smime_sign_t sign_mode;
-static CamelMimeMessage *smime_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
- CamelCMSValidityInfo **info, CamelException *ex);
+ unsigned int send_encrypt_key_prefs:1;
+};
-static CamelCMSContextClass *parent_class;
+static CamelCipherContextClass *parent_class = NULL;
-static void
-camel_smime_context_init (CamelSMimeContext *context)
+/**
+ * camel_smime_context_new:
+ * @session: session
+ *
+ * Creates a new sm cipher context object.
+ *
+ * Returns a new sm cipher context object.
+ **/
+CamelCipherContext *
+camel_smime_context_new(CamelSession *session)
{
- context->priv = g_new0 (struct _CamelSMimeContextPrivate, 1);
+ CamelCipherContext *cipher;
+ CamelSMIMEContext *ctx;
+
+ g_return_val_if_fail(CAMEL_IS_SESSION(session), NULL);
+
+ ctx =(CamelSMIMEContext *) camel_object_new(camel_smime_context_get_type());
+
+ cipher =(CamelCipherContext *) ctx;
+ cipher->session = session;
+ camel_object_ref(session);
+
+ return cipher;
}
-static void
-camel_smime_context_finalise (CamelObject *o)
+void
+camel_smime_context_set_encrypt_key(CamelSMIMEContext *context, gboolean use, const char *key)
{
- CamelSMimeContext *context = (CamelSMimeContext *)o;
-
- g_free (context->encryption_key);
- g_free (context->priv);
+ context->priv->send_encrypt_key_prefs = use;
+ g_free(context->priv->encrypt_key);
+ context->priv->encrypt_key = g_strdup(key);
}
-static void
-camel_smime_context_class_init (CamelSMimeContextClass *camel_smime_context_class)
+/* set signing mode, clearsigned multipart/signed or enveloped */
+void
+camel_smime_context_set_sign_mode(CamelSMIMEContext *context, camel_smime_sign_t type)
{
- CamelCMSContextClass *camel_cms_context_class =
- CAMEL_CMS_CONTEXT_CLASS (camel_smime_context_class);
-
- parent_class = CAMEL_CMS_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cms_context_get_type ()));
-
- camel_cms_context_class->sign = smime_sign;
- camel_cms_context_class->certsonly = smime_certsonly;
- camel_cms_context_class->encrypt = smime_encrypt;
- camel_cms_context_class->envelope = smime_envelope;
- camel_cms_context_class->decode = smime_decode;
+ context->priv->sign_mode = type;
}
-CamelType
-camel_smime_context_get_type (void)
+static const char *
+sm_hash_to_id(CamelCipherContext *context, CamelCipherHash hash)
{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- type = camel_type_register (camel_cms_context_get_type (),
- "CamelSMimeContext",
- sizeof (CamelSMimeContext),
- sizeof (CamelSMimeContextClass),
- (CamelObjectClassInitFunc) camel_smime_context_class_init,
- NULL,
- (CamelObjectInitFunc) camel_smime_context_init,
- (CamelObjectFinalizeFunc) camel_smime_context_finalise);
+ switch(hash) {
+ case CAMEL_CIPHER_HASH_MD5:
+ return "md5";
+ case CAMEL_CIPHER_HASH_SHA1:
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ return "sha1";
+ default:
+ return NULL;
}
-
- return type;
}
-
-/**
- * camel_smime_context_new:
- * @session: CamelSession
- * @encryption_key: preferred encryption key (used when attaching cert chains to messages)
- *
- * This creates a new CamelSMimeContext object which is used to sign,
- * verify, encrypt and decrypt streams.
- *
- * Return value: the new CamelSMimeContext
- **/
-CamelSMimeContext *
-camel_smime_context_new (CamelSession *session, const char *encryption_key)
+static CamelCipherHash
+sm_id_to_hash(CamelCipherContext *context, const char *id)
{
- CamelSMimeContext *context;
- CERTCertDBHandle *certdb;
-
- g_return_val_if_fail (session != NULL, NULL);
- g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
-
- certdb = CERT_GetDefaultCertDB ();
- if (!certdb)
- return NULL;
-
- context = CAMEL_SMIME_CONTEXT (camel_object_new (CAMEL_SMIME_CONTEXT_TYPE));
-
- camel_cms_context_construct (CAMEL_CMS_CONTEXT (context), session);
-
- context->encryption_key = g_strdup (encryption_key);
- context->priv->certdb = certdb;
+ if (id) {
+ if (!strcmp(id, "md5"))
+ return CAMEL_CIPHER_HASH_MD5;
+ else if (!strcmp(id, "sha1"))
+ return CAMEL_CIPHER_HASH_SHA1;
+ }
- return context;
+ return CAMEL_CIPHER_HASH_DEFAULT;
}
-
-struct _GetPasswdData {
- CamelSession *session;
- const char *userid;
- CamelException *ex;
-};
-
-static char *
-smime_get_password (PK11SlotInfo *info, PRBool retry, void *arg)
+/* used for decode content callback, for streaming decode */
+static void
+sm_write_stream(void *arg, const char *buf, unsigned long len)
{
- CamelSession *session = ((struct _GetPasswdData *)arg)->session;
- const char *userid = ((struct _GetPasswdData *)arg)->userid;
- CamelException *ex = ((struct _GetPasswdData *)arg)->ex;
- char *prompt, *passwd, *ret;
-
- prompt = g_strdup_printf (_("Please enter your password for %s"), userid);
- passwd = camel_session_get_password (session, prompt, FALSE, TRUE,
- NULL, userid, ex);
- g_free (prompt);
-
- ret = PL_strdup (passwd);
- g_free (passwd);
-
- return ret;
+ camel_stream_write((CamelStream *)arg, buf, len);
}
static PK11SymKey *
-decode_key_cb (void *arg, SECAlgorithmID *algid)
+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)
+{
+ printf("Password requested for '%s'\n", PK11_GetTokenName(info));
+
+ return NULL;
+}
static NSSCMSMessage *
-signed_data (CamelSMimeContext *ctx, const char *userid, gboolean signing_time,
- gboolean detached, CamelException *ex)
+sm_signing_cmsmessage(CamelSMIMEContext *context, const char *nick, SECOidTag hash, int detached, CamelException *ex)
{
+ struct _CamelSMIMEContextPrivate *p = context->priv;
NSSCMSMessage *cmsg = NULL;
NSSCMSContentInfo *cinfo;
NSSCMSSignedData *sigd;
NSSCMSSignerInfo *signerinfo;
- CERTCertificate *cert, *ekpcert;
-
- if (!userid) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Please indicate the nickname of a certificate to sign with."));
+ CERTCertificate *cert= NULL, *ekpcert = NULL;
+
+ /* TODO: usage should be hardcoded to usageSigner? */
+
+ if ((cert = CERT_FindUserCertByUsage(p->certdb,
+ (char *)nick,
+ certUsageEmailSigner,
+ PR_FALSE,
+ NULL)) == NULL) {
+ camel_exception_setv(ex, 1, "Cann't find certificate for '%s'", nick);
return NULL;
}
-
- if ((cert = CERT_FindCertByNickname (ctx->priv->certdb, (char *) userid)) == NULL) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("The signature certificate for \"%s\" does not exist."),
- userid);
- return NULL;
+
+ cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
+ if (cmsg == NULL) {
+ camel_exception_setv(ex, 1, "Can't create CMS message");
+ goto fail;
}
-
- /* create the cms message object */
- cmsg = NSS_CMSMessage_Create (NULL);
-
- /* build chain of objects: message->signedData->data */
- sigd = NSS_CMSSignedData_Create (cmsg);
-
- cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
- NSS_CMSContentInfo_SetContent_SignedData (cmsg, cinfo, sigd);
-
- cinfo = NSS_CMSSignedData_GetContentInfo (sigd);
-
- /* speciffy whether we want detached signatures or not */
- NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, detached);
-
- /* create & attach signer information */
- signerinfo = NSS_CMSSignerInfo_Create (cmsg, cert, SEC_OID_SHA1);
-
- /* include the cert chain */
- NSS_CMSSignerInfo_IncludeCerts (signerinfo, NSSCMSCM_CertChain,
- certUsageEmailSigner);
-
- if (signing_time) {
- NSS_CMSSignerInfo_AddSigningTime (signerinfo, PR_Now ());
+
+ if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
+ camel_exception_setv(ex, 1, "Can't create CMS signedData");
+ goto fail;
}
-
- if (TRUE) {
- /* Add S/MIME Capabilities */
- NSS_CMSSignerInfo_AddSMIMECaps (signerinfo);
+
+ cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
+ if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't attach CMS signedData");
+ goto fail;
}
-
- if (ctx->encryption_key) {
- /* get the cert, add it to the message */
- ekpcert = CERT_FindCertByNickname (ctx->priv->certdb, ctx->encryption_key);
- if (!ekpcert) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("The encryption certificate for \"%s\" does not exist."),
- ctx->encryption_key);
- goto exception;
- }
-
- NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs (signerinfo, ekpcert, ctx->priv->certdb);
-
- NSS_CMSSignedData_AddCertificate (sigd, ekpcert);
- } else {
- /* check signing cert for fitness as encryption cert */
- /* if yes, add signing cert as EncryptionKeyPreference */
- NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs (signerinfo, cert, ctx->priv->certdb);
+
+ /* if !detatched, the contentinfo will alloc a data item for us */
+ cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
+ if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, detached) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't attach CMS data");
+ goto fail;
}
-
- NSS_CMSSignedData_AddSignerInfo (sigd, signerinfo);
-
- return cmsg;
-
- exception:
-
- NSS_CMSMessage_Destroy (cmsg);
-
- return NULL;
-}
-static void
-smime_sign_restore (CamelMimePart *mime_part, GSList **encodings)
-{
- CamelDataWrapper *wrapper;
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
- if (!wrapper)
- return;
-
- if (CAMEL_IS_MULTIPART (wrapper)) {
- int parts, i;
-
- parts = camel_multipart_get_number (CAMEL_MULTIPART (wrapper));
- for (i = 0; i < parts; i++) {
- CamelMimePart *part = camel_multipart_get_part (CAMEL_MULTIPART (wrapper), i);
-
- smime_sign_restore (part, encodings);
- *encodings = (*encodings)->next;
- }
- } else {
- CamelTransferEncoding encoding;
-
- if (CAMEL_IS_MIME_MESSAGE (wrapper)) {
- /* restore the message parts' subparts */
- smime_sign_restore (CAMEL_MIME_PART (wrapper), encodings);
- } else {
- encoding = GPOINTER_TO_INT ((*encodings)->data);
-
- camel_mime_part_set_encoding (mime_part, encoding);
- }
+ signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, hash);
+ if (signerinfo == NULL) {
+ camel_exception_setv(ex, 1, "Can't create CMS SignerInfo");
+ goto fail;
}
-}
-static void
-smime_sign_prepare (CamelMimePart *mime_part, GSList **encodings)
-{
- CamelDataWrapper *wrapper;
- int parts, i;
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
- if (!wrapper)
- return;
-
- if (CAMEL_IS_MULTIPART (wrapper)) {
- parts = camel_multipart_get_number (CAMEL_MULTIPART (wrapper));
- for (i = 0; i < parts; i++) {
- CamelMimePart *part = camel_multipart_get_part (CAMEL_MULTIPART (wrapper), i);
-
- smime_sign_prepare (part, encodings);
- }
- } else {
- CamelTransferEncoding encoding;
-
- if (CAMEL_IS_MIME_MESSAGE (wrapper)) {
- /* prepare the message parts' subparts */
- smime_sign_prepare (CAMEL_MIME_PART (wrapper), encodings);
- } else {
- encoding = camel_mime_part_get_encoding (mime_part);
-
- /* FIXME: find the best encoding for this part and use that instead?? */
- /* the encoding should really be QP or Base64 */
- if (encoding != CAMEL_TRANSFER_ENCODING_BASE64)
- camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
-
- *encodings = g_slist_append (*encodings, GINT_TO_POINTER (encoding));
- }
+ /* we want the cert chain included for this one */
+ if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't find cert chain");
+ goto fail;
}
-}
+ /* SMIME RFC says signing time should always be added */
+ if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't add CMS SigningTime");
+ goto fail;
+ }
-static CamelMimeMessage *
-smime_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, gboolean signing_time,
- gboolean detached, CamelException *ex)
-{
- CamelMimeMessage *mesg = NULL;
- NSSCMSMessage *cmsg = NULL;
- struct _GetPasswdData *data;
- PLArenaPool *arena;
- NSSCMSEncoderContext *ecx;
- SECItem output = { 0, 0, 0 };
- CamelStream *stream;
- GSList *list, *encodings = NULL;
- GByteArray *buf;
-
- cmsg = signed_data (CAMEL_SMIME_CONTEXT (ctx), userid, signing_time, detached, ex);
- if (!cmsg)
- return NULL;
-
- arena = PORT_NewArena (1024);
- data = g_new (struct _GetPasswdData, 1);
- data->session = ctx->session;
- data->userid = userid;
- data->ex = ex;
- ecx = NSS_CMSEncoder_Start (cmsg, NULL, NULL, &output, arena,
- smime_get_password, data, NULL, NULL,
- NULL, NULL);
-
- stream = camel_stream_mem_new ();
-
- smime_sign_prepare (CAMEL_MIME_PART (message), &encodings);
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
- list = encodings;
- smime_sign_restore (CAMEL_MIME_PART (message), &list);
- g_slist_free (encodings);
-
- buf = CAMEL_STREAM_MEM (stream)->buffer;
-
- NSS_CMSEncoder_Update (ecx, buf->data, buf->len);
- NSS_CMSEncoder_Finish (ecx);
-
- camel_object_unref (stream);
- g_free (data);
-
- /* write the result to a camel stream */
- stream = camel_stream_mem_new ();
- camel_stream_write (stream, output.data, output.len);
- PORT_FreeArena (arena, PR_FALSE);
-
- NSS_CMSMessage_Destroy (cmsg);
-
- /* parse the stream into a new CamelMimeMessage */
- mesg = camel_mime_message_new ();
- camel_stream_reset (stream);
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (mesg), stream);
- camel_object_unref (stream);
-
- return mesg;
-}
+#if 0
+ /* this can but needn't be added. not sure what general usage is */
+ if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
+ fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n");
+ goto loser;
+ }
+#endif
+ /* Check if we need to send along our return encrypt cert, rfc2633 2.5.3 */
+ if (p->send_encrypt_key_prefs) {
+ CERTCertificate *enccert = NULL;
+
+ if (p->encrypt_key) {
+ /* encrypt key has its own nick */
+ if ((ekpcert = CERT_FindUserCertByUsage(
+ p->certdb,
+ p->encrypt_key,
+ certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) {
+ camel_exception_setv(ex, 1, "encryption cert for '%s' does not exist", p->encrypt_key);
+ goto fail;
+ }
+ enccert = ekpcert;
+ } else if (CERT_CheckCertUsage(cert, certUsageEmailRecipient) == SECSuccess) {
+ /* encrypt key is signing key */
+ enccert = cert;
+ } else {
+ /* encrypt key uses same nick */
+ if ((ekpcert = CERT_FindUserCertByUsage(
+ p->certdb, (char *)nick,
+ certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) {
+ camel_exception_setv(ex, 1, "encryption cert for '%s' does not exist", nick);
+ goto fail;
+ }
+ enccert = ekpcert;
+ }
-static NSSCMSMessage *
-certsonly_data (CamelSMimeContext *ctx, const char *userid, GPtrArray *recipients, CamelException *ex)
-{
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSSignedData *sigd;
- CERTCertificate **rcerts;
- int i = 0;
-
- /* find the signer's and the recipients' certs */
- rcerts = g_new (CERTCertificate *, recipients->len + 2);
- rcerts[0] = CERT_FindCertByNicknameOrEmailAddr (ctx->priv->certdb, (char *) userid);
- if (!rcerts[0]) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to find certificate for \"%s\"."),
- recipients->pdata[i]);
- goto exception;
- }
-
- for (i = 0; i < recipients->len; i++) {
- rcerts[i + 1] = CERT_FindCertByNicknameOrEmailAddr (ctx->priv->certdb,
- recipients->pdata[i]);
-
- if (!rcerts[i + 1]) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to find certificate for \"%s\"."),
- recipients->pdata[i]);
- goto exception;
+ if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) {
+ camel_exception_setv(ex, 1, "can't add SMIMEEncKeyPrefs attribute");
+ goto fail;
+ }
+
+ if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) {
+ camel_exception_setv(ex, 1, "can't add MS SMIMEEncKeyPrefs attribute");
+ goto fail;
+ }
+
+ if (ekpcert != NULL && NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
+ camel_exception_setv(ex, 1, "can't add add encryption certificate");
+ goto fail;
}
}
- rcerts[i + 1] = NULL;
-
- /* create the cms message object */
- cmsg = NSS_CMSMessage_Create (NULL);
-
- sigd = NSS_CMSSignedData_CreateCertsOnly (cmsg, rcerts[0], PR_TRUE);
-
- /* add the recipient cert chain */
- for (i = 0; i < recipients->len; i++) {
- NSS_CMSSignedData_AddCertChain (sigd, rcerts[i]);
+
+ if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
+ camel_exception_setv(ex, 1, "can't add CMS SignerInfo");
+ goto fail;
}
-
- cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
- NSS_CMSContentInfo_SetContent_SignedData (cmsg, cinfo, sigd);
-
- cinfo = NSS_CMSSignedData_GetContentInfo (sigd);
- NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, PR_FALSE);
-
- g_free (rcerts);
-
+
+ if (ekpcert)
+ CERT_DestroyCertificate(ekpcert);
+
+ if (cert)
+ CERT_DestroyCertificate(cert);
+
return cmsg;
-
- exception:
-
- NSS_CMSMessage_Destroy (cmsg);
-
- g_free (rcerts);
-
+fail:
+ if (ekpcert)
+ CERT_DestroyCertificate(ekpcert);
+
+ if (cert)
+ CERT_DestroyCertificate(cert);
+
+ NSS_CMSMessage_Destroy(cmsg);
+
return NULL;
}
-static CamelMimeMessage *
-smime_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, GPtrArray *recipients,
- CamelException *ex)
+static int
+sm_encode_cmsmessage(CamelSMIMEContext *context, NSSCMSMessage *cmsg, CamelStream *instream, CamelStream *out, CamelException *ex)
{
- CamelMimeMessage *mesg = NULL;
- struct _GetPasswdData *data;
- NSSCMSMessage *cmsg = NULL;
- PLArenaPool *arena;
- NSSCMSEncoderContext *ecx;
- SECItem output = { 0, 0, 0 };
- CamelStream *stream;
- GByteArray *buf;
-
- cmsg = certsonly_data (CAMEL_SMIME_CONTEXT (ctx), userid, recipients, ex);
- if (!cmsg)
- return NULL;
-
- arena = PORT_NewArena (1024);
- data = g_new (struct _GetPasswdData, 1);
- data->session = ctx->session;
- data->userid = userid;
- data->ex = ex;
- ecx = NSS_CMSEncoder_Start (cmsg, NULL, NULL, &output, arena,
- smime_get_password, data, NULL, NULL,
- NULL, NULL);
-
- stream = camel_stream_mem_new ();
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
- buf = CAMEL_STREAM_MEM (stream)->buffer;
-
- NSS_CMSEncoder_Update (ecx, buf->data, buf->len);
- NSS_CMSEncoder_Finish (ecx);
-
- camel_object_unref (stream);
- g_free (data);
-
- /* write the result to a camel stream */
- stream = camel_stream_mem_new ();
- camel_stream_write (stream, output.data, output.len);
- PORT_FreeArena (arena, PR_FALSE);
-
- NSS_CMSMessage_Destroy (cmsg);
-
- /* parse the stream into a new CamelMimeMessage */
- mesg = camel_mime_message_new ();
- camel_stream_reset (stream);
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (mesg), stream);
- camel_object_unref (stream);
-
- return mesg;
-}
+ NSSCMSEncoderContext *enc;
+ CamelStreamMem *mem = NULL;
+
+ enc = NSS_CMSEncoder_Start(cmsg,
+ sm_write_stream, out, /* DER output callback */
+ NULL, NULL, /* destination storage */
+ sm_get_passwd, context, /* password callback */
+ NULL, NULL, /* decrypt key callback */
+ NULL, NULL ); /* detached digests */
+ if (!enc) {
+ camel_exception_setv(ex, 1, "Cannot create encoder context");
+ goto fail;
+ }
+ /* Note: see rfc2015 or rfc3156, section 5 */
-static NSSCMSMessage *
-enveloped_data (CamelSMimeContext *ctx, const char *userid, GPtrArray *recipients, CamelException *ex)
-{
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSEnvelopedData *envd;
- NSSCMSRecipientInfo *rinfo;
- CERTCertificate **rcerts;
- SECOidTag bulkalgtag;
- int keysize, i;
-
- /* find the recipient certs by email address or nickname */
- rcerts = g_new (CERTCertificate *, recipients->len + 2);
- rcerts[0] = CERT_FindCertByNicknameOrEmailAddr (ctx->priv->certdb, (char *) userid);
- if (!rcerts[0]) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to find certificate for \"%s\"."),
- userid);
- goto exception;
- }
-
- for (i = 0; i < recipients->len; i++) {
- rcerts[i + 1] = CERT_FindCertByNicknameOrEmailAddr (ctx->priv->certdb,
- recipients->pdata[i]);
- if (!rcerts[i + 1]) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to find certificate for \"%s\"."),
- recipients->pdata[i]);
- goto exception;
- }
- }
- rcerts[i + 1] = NULL;
-
- /* find a nice bulk algorithm */
- if (!NSS_SMIMEUtil_FindBulkAlgForRecipients (rcerts, &bulkalgtag, &keysize)) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to find a common bulk algorithm."));
- goto exception;
+ /* FIXME: stream this, we stream output at least */
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+ camel_stream_write_to_stream(instream, (CamelStream *)mem);
+
+ if (NSS_CMSEncoder_Update(enc, mem->buffer->data, mem->buffer->len) != SECSuccess) {
+ NSS_CMSEncoder_Cancel(enc);
+ camel_exception_setv(ex, 1, "Failed to add data to CMS encoder");
+ goto fail;
}
-
- /* create a cms message object */
- cmsg = NSS_CMSMessage_Create (NULL);
-
- envd = NSS_CMSEnvelopedData_Create (cmsg, bulkalgtag, keysize);
- cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
- NSS_CMSContentInfo_SetContent_EnvelopedData (cmsg, cinfo, envd);
-
- cinfo = NSS_CMSEnvelopedData_GetContentInfo (envd);
- NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, PR_FALSE);
-
- /* create & attach recipient information */
- for (i = 0; rcerts[i] != NULL; i++) {
- rinfo = NSS_CMSRecipientInfo_Create (cmsg, rcerts[i]);
- NSS_CMSEnvelopedData_AddRecipient (envd, rinfo);
+
+ if (NSS_CMSEncoder_Finish(enc) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Failed to encode data");
+ goto fail;
}
-
- g_free (rcerts);
-
- return cmsg;
-
- exception:
-
- NSS_CMSMessage_Destroy (cmsg);
-
- g_free (rcerts);
-
- return NULL;
-}
-static CamelMimeMessage *
-smime_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, GPtrArray *recipients,
- CamelException *ex)
-{
- CamelMimeMessage *mesg = NULL;
- struct _GetPasswdData *data;
- NSSCMSMessage *cmsg = NULL;
- PLArenaPool *arena;
- NSSCMSEncoderContext *ecx;
- SECItem output = { 0, 0, 0 };
- CamelStream *stream;
- GByteArray *buf;
-
- cmsg = enveloped_data (CAMEL_SMIME_CONTEXT (ctx), userid, recipients, ex);
- if (!cmsg)
- return NULL;
-
- arena = PORT_NewArena (1024);
- data = g_new (struct _GetPasswdData, 1);
- data->session = ctx->session;
- data->userid = userid;
- data->ex = ex;
- ecx = NSS_CMSEncoder_Start (cmsg, NULL, NULL, &output, arena,
- smime_get_password, data, NULL, NULL,
- NULL, NULL);
-
- stream = camel_stream_mem_new ();
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
- buf = CAMEL_STREAM_MEM (stream)->buffer;
-
- NSS_CMSEncoder_Update (ecx, buf->data, buf->len);
- NSS_CMSEncoder_Finish (ecx);
-
- camel_object_unref (stream);
- g_free (data);
-
- /* write the result to a camel stream */
- stream = camel_stream_mem_new ();
- camel_stream_write (stream, output.data, output.len);
- PORT_FreeArena (arena, PR_FALSE);
-
- NSS_CMSMessage_Destroy (cmsg);
-
- /* parse the stream into a new CamelMimeMessage */
- mesg = camel_mime_message_new ();
- camel_stream_reset (stream);
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (mesg), stream);
- camel_object_unref (stream);
-
- return mesg;
-}
+ camel_object_unref(mem);
+ return 0;
-struct _BulkKey {
- PK11SymKey *bulkkey;
- SECOidTag bulkalgtag;
- int keysize;
-};
+fail:
+ if (mem)
+ camel_object_unref(mem);
-static NSSCMSMessage *
-encrypted_data (CamelSMimeContext *ctx, GByteArray *input, struct _BulkKey *key,
- CamelStream *ostream, CamelException *ex)
-{
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSEncryptedData *encd;
- NSSCMSEncoderContext *ecx = NULL;
- PLArenaPool *arena = NULL;
- SECItem output = { 0, 0, 0 };
-
- /* arena for output */
- arena = PORT_NewArena (1024);
-
- /* create cms message object */
- cmsg = NSS_CMSMessage_Create (NULL);
-
- encd = NSS_CMSEncryptedData_Create (cmsg, key->bulkalgtag, key->keysize);
-
- cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
- NSS_CMSContentInfo_SetContent_EncryptedData (cmsg, cinfo, encd);
-
- cinfo = NSS_CMSEncryptedData_GetContentInfo (encd);
- NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, PR_FALSE);
-
- ecx = NSS_CMSEncoder_Start (cmsg, NULL, NULL, &output, arena, NULL, NULL,
- decode_key_cb, key->bulkkey, NULL, NULL);
-
- NSS_CMSEncoder_Update (ecx, input->data, input->len);
-
- NSS_CMSEncoder_Finish (ecx);
-
- camel_stream_write (ostream, output.data, output.len);
-
- if (arena)
- PORT_FreeArena (arena, PR_FALSE);
-
- return cmsg;
+ return -1;
}
-static struct _BulkKey *
-get_bulkkey (CamelSMimeContext *ctx, const char *userid, GPtrArray *recipients, CamelException *ex)
+static int
+sm_sign(CamelCipherContext *ctx, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelMimePart *sigpart, CamelException *ex)
{
- struct _BulkKey *bulkkey = NULL;
- NSSCMSMessage *env_cmsg;
- NSSCMSContentInfo *cinfo;
- SECItem dummyOut = { 0, 0, 0 };
- SECItem dummyIn = { 0, 0, 0 };
- char str[] = "You are not a beautiful and unique snowflake.";
- PLArenaPool *arena;
- int i, nlevels;
-
- /* construct an enveloped data message to obtain bulk keys */
- arena = PORT_NewArena (1024);
- dummyIn.data = (unsigned char *)str;
- dummyIn.len = strlen (str);
-
- env_cmsg = enveloped_data (ctx, userid, recipients, ex);
- NSS_CMSDEREncode (env_cmsg, &dummyIn, &dummyOut, arena);
- /*camel_stream_write (envstream, dummyOut.data, dummyOut.len);*/
- PORT_FreeArena (arena, PR_FALSE);
-
- /* get the content info for the enveloped data */
- nlevels = NSS_CMSMessage_ContentLevelCount (env_cmsg);
- for (i = 0; i < nlevels; i++) {
- SECOidTag typetag;
-
- cinfo = NSS_CMSMessage_ContentLevel (env_cmsg, i);
- typetag = NSS_CMSContentInfo_GetContentTypeTag (cinfo);
- if (typetag == SEC_OID_PKCS7_DATA) {
- bulkkey = g_new (struct _BulkKey, 1);
-
- /* get the symmertic key */
- bulkkey->bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag (cinfo);
- bulkkey->keysize = NSS_CMSContentInfo_GetBulkKeySize (cinfo);
- bulkkey->bulkkey = NSS_CMSContentInfo_GetBulkKey (cinfo);
-
- return bulkkey;
+ int res;
+ NSSCMSMessage *cmsg;
+ CamelStream *ostream;
+ SECOidTag sechash;
+
+ switch (hash) {
+ case CAMEL_CIPHER_HASH_SHA1:
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ default:
+ sechash = SEC_OID_SHA1;
+ break;
+ case CAMEL_CIPHER_HASH_MD5:
+ sechash = SEC_OID_MD5;
+ break;
+ }
+
+ cmsg = sm_signing_cmsmessage((CamelSMIMEContext *)ctx, userid, sechash,
+ ((CamelSMIMEContext *)ctx)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN, ex);
+ if (cmsg == NULL)
+ return -1;
+
+ ostream = camel_stream_mem_new();
+ res = sm_encode_cmsmessage((CamelSMIMEContext *)ctx, cmsg, istream, ostream, ex);
+ NSS_CMSMessage_Destroy(cmsg);
+
+ if (res == 0) {
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+
+ dw = camel_data_wrapper_new();
+ camel_stream_reset(ostream);
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+ dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
+
+ if (((CamelSMIMEContext *)ctx)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) {
+ ct = camel_content_type_new("application", "x-pkcs7-signature");
+ camel_content_type_set_param(ct, "name", "smime.p7s");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_mime_part_set_filename(sigpart, "smime.p7s");
+ } else {
+ ct = camel_content_type_new("application", "x-pkcs7-mime");
+ camel_content_type_set_param(ct, "name", "smime.p7m");
+ camel_content_type_set_param(ct, "smime-type", "signed-data");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_mime_part_set_filename(sigpart, "smime.p7m");
+ camel_mime_part_set_description(sigpart, "S/MIME Signed Message");
}
+
+ camel_mime_part_set_disposition(sigpart, "attachment");
+ camel_mime_part_set_encoding(sigpart, CAMEL_TRANSFER_ENCODING_BASE64);
+
+ camel_medium_set_content_object((CamelMedium *)sigpart, dw);
+ camel_object_unref(dw);
}
-
- return NULL;
+
+
+ camel_object_unref(ostream);
+
+ return res;
}
-static CamelMimeMessage *
-smime_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
- const char *userid, GPtrArray *recipients,
- CamelException *ex)
+static const char *
+sm_status_description(NSSCMSVerificationStatus status)
{
- struct _BulkKey *bulkkey = NULL;
- CamelMimeMessage *mesg = NULL;
- NSSCMSMessage *cmsg = NULL;
- CamelStream *stream;
- GByteArray *buf;
-
- bulkkey = get_bulkkey (CAMEL_SMIME_CONTEXT (ctx), userid, recipients, ex);
- if (!bulkkey)
- return NULL;
-
- buf = g_byte_array_new ();
- stream = camel_stream_mem_new ();
- camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buf);
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
- camel_object_unref (stream);
-
- stream = camel_stream_mem_new ();
- cmsg = encrypted_data (CAMEL_SMIME_CONTEXT (ctx), buf, bulkkey, stream, ex);
- g_byte_array_free (buf, TRUE);
- g_free (bulkkey);
- if (!cmsg) {
- camel_object_unref (stream);
- return NULL;
+ /* could use this but then we can't control i18n? */
+ /*NSS_CMSUtil_VerificationStatusToString(status));*/
+
+ switch(status) {
+ case NSSCMSVS_Unverified:
+ default:
+ return _("Unverified");
+ case NSSCMSVS_GoodSignature:
+ return _("Good signature");
+ case NSSCMSVS_BadSignature:
+ return _("Bad signature");
+ case NSSCMSVS_DigestMismatch:
+ return _("Content tampered with or altered in transit");
+ case NSSCMSVS_SigningCertNotFound:
+ return _("Signing certificate not found");
+ case NSSCMSVS_SigningCertNotTrusted:
+ return _("Signing certificate not trusted");
+ case NSSCMSVS_SignatureAlgorithmUnknown:
+ return _("Signature algorithm unknown");
+ case NSSCMSVS_SignatureAlgorithmUnsupported:
+ return _("Siganture algorithm unsupported");
+ case NSSCMSVS_MalformedSignature:
+ return _("Malformed signature");
+ case NSSCMSVS_ProcessingError:
+ return _("Processing error");
}
-
- NSS_CMSMessage_Destroy (cmsg);
-
- /* parse the stream into a new CamelMimeMessage */
- mesg = camel_mime_message_new ();
- camel_stream_reset (stream);
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (mesg), stream);
- camel_object_unref (stream);
-
- return mesg;
}
-
-static NSSCMSMessage *
-decode_data (CamelSMimeContext *ctx, GByteArray *input, CamelStream *ostream,
- CamelCMSValidityInfo **info, CamelException *ex)
+static CamelCipherValidity *
+sm_verify(CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream, CamelMimePart *sigpart, CamelException *ex)
{
- NSSCMSDecoderContext *dcx;
- struct _GetPasswdData *data;
- CamelCMSValidityInfo *vinfo = NULL;
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
+ struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv;
+ NSSCMSDecoderContext *dec;
+ NSSCMSMessage *cmsg;
NSSCMSSignedData *sigd = NULL;
NSSCMSEnvelopedData *envd;
NSSCMSEncryptedData *encd;
- int nlevels, i, nsigners, j;
- char *signercn;
- NSSCMSSignerInfo *si;
- SECOidTag typetag;
- SECItem *item;
-
- data = g_new (struct _GetPasswdData, 1);
- data->session = CAMEL_CMS_CONTEXT (ctx)->session;
- data->userid = NULL;
- data->ex = ex;
-
- dcx = NSS_CMSDecoder_Start (NULL,
- NULL, NULL,
- smime_get_password, data,
- decode_key_cb,
- NULL);
-
- NSS_CMSDecoder_Update (dcx, input->data, input->len);
-
- cmsg = NSS_CMSDecoder_Finish (dcx);
- g_free (data);
+ SECAlgorithmID **digestalgs;
+ NSSCMSDigestContext *digcx;
+ int count, i, nsigners, j;
+ SECItem **digests;
+ PLArenaPool *poolp = NULL;
+ CamelStreamMem *mem;
+ NSSCMSVerificationStatus status;
+ 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_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to decode message."));
+ camel_exception_setv(ex, 1, "Decoder failed");
return NULL;
}
-
- nlevels = NSS_CMSMessage_ContentLevelCount (cmsg);
- for (i = 0; i < nlevels; i++) {
- CamelCMSSigner *signers = NULL;
-
- cinfo = NSS_CMSMessage_ContentLevel (cmsg, i);
- typetag = NSS_CMSContentInfo_GetContentTypeTag (cinfo);
-
- if (info && !vinfo) {
- vinfo = g_new0 (CamelCMSValidityInfo, 1);
- *info = vinfo;
- } else if (vinfo) {
- vinfo->next = g_new0 (CamelCMSValidityInfo, 1);
- vinfo = vinfo->next;
- }
-
+
+ description = g_string_new("");
+ valid = camel_cipher_validity_new();
+ camel_cipher_validity_set_valid(valid, TRUE);
+ status = NSSCMSVS_Unverified;
+
+ /* NB: this probably needs to go into a decoding routine that can be used for processing
+ enveloped data too */
+ count = NSS_CMSMessage_ContentLevelCount(cmsg);
+ for (i = 0; i < count; i++) {
+ NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
+ SECOidTag typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
+
switch (typetag) {
case SEC_OID_PKCS7_SIGNED_DATA:
- if (vinfo)
- vinfo->type = CAMEL_CMS_TYPE_SIGNED;
-
- sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent (cinfo);
-
- /* import the certificates */
- NSS_CMSSignedData_ImportCerts (sigd, ctx->priv->certdb,
- certUsageEmailSigner, PR_FALSE);
-
- /* find out about signers */
- nsigners = NSS_CMSSignedData_SignerInfoCount (sigd);
-
- if (nsigners == 0) {
- /* must be a cert transport message */
- SECStatus retval;
-
- /* XXX workaround for bug #54014 */
- NSS_CMSSignedData_ImportCerts (sigd, ctx->priv->certdb,
- certUsageEmailSigner, PR_TRUE);
-
- retval = NSS_CMSSignedData_VerifyCertsOnly (sigd, ctx->priv->certdb,
- certUsageEmailSigner);
- if (retval != SECSuccess) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to verify certificates."));
- goto exception;
+ sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
+ if (sigd == NULL) {
+ camel_exception_setv(ex, 1, "No signedData in signature");
+ goto fail;
+ }
+
+ /* need to build digests of the content */
+ if (!NSS_CMSSignedData_HasDigests(sigd)) {
+ if ((poolp = PORT_NewArena(1024)) == NULL) {
+ camel_exception_setv(ex, 1, "out of memory");
+ goto fail;
}
+
+ digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
- return cmsg;
+ digcx = NSS_CMSDigestContext_StartMultiple(digestalgs);
+ if (digcx == NULL) {
+ camel_exception_setv(ex, 1, "Cannot calculate digests");
+ goto fail;
+ }
+
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+ camel_stream_write_to_stream(istream, (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");
+ goto fail;
+ }
+
+ if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Cannot set message digests");
+ goto fail;
+ }
+
+ PORT_FreeArena(poolp, PR_FALSE);
+ poolp = NULL;
+ }
+
+ /* import the certificates */
+ if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailSigner, PR_FALSE) != SECSuccess) {
+ camel_exception_setv(ex, 1, "cert import failed");
+ goto fail;
}
-
- for (j = 0; vinfo && j < nsigners; j++) {
- if (!signers) {
- signers = g_new0 (CamelCMSSigner, 1);
- vinfo->signers = signers;
+
+ /* check for certs-only message */
+ nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
+ if (nsigners == 0) {
+ /* ?? Should we check other usages? */
+ NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailSigner, PR_TRUE);
+ if (NSS_CMSSignedData_VerifyCertsOnly(sigd, p->certdb, certUsageEmailSigner) != SECSuccess) {
+ g_string_printf(description, "Certficate only message, cannot verify certificates");
} else {
- signers->next = g_new0 (CamelCMSSigner, 1);
- signers = signers->next;
+ status = NSSCMSVS_GoodSignature;
+ g_string_printf(description, "Certficate only message, certificates imported and verified");
}
-
- si = NSS_CMSSignedData_GetSignerInfo (sigd, j);
- signercn = NSS_CMSSignerInfo_GetSignerCommonName (si);
- if (signercn == NULL)
- signercn = "";
-
- NSS_CMSSignedData_VerifySignerInfo (sigd, j, ctx->priv->certdb,
- certUsageEmailSigner);
-
- if (signers) {
- signers->signercn = g_strdup (signercn);
- signers->status = g_strdup (
- NSS_CMSUtil_VerificationStatusToString (
- NSS_CMSSignerInfo_GetVerificationStatus (si)));
+ } else {
+
+ if (!NSS_CMSSignedData_HasDigests(sigd)) {
+ camel_exception_setv(ex, 1, "Can't find signature digests");
+ goto fail;
+ }
+
+ for (j = 0; j < nsigners; j++) {
+ NSSCMSSignerInfo *si;
+ char *cn, *em;
+
+ si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
+ NSS_CMSSignedData_VerifySignerInfo(sigd, j, p->certdb, certUsageEmailSigner);
+
+ status = NSS_CMSSignerInfo_GetVerificationStatus(si);
+
+ cn = NSS_CMSSignerInfo_GetSignerCommonName(si);
+ em = NSS_CMSSignerInfo_GetSignerEmailAddress(si);
+
+ g_string_append_printf(description, _("Signer: %s <%s>: %s\n"),
+ cn?cn:"<unknown>", em?em:"<unknown>",
+ sm_status_description(status));
+
+ if (cn)
+ PORT_Free(cn);
+ if (em)
+ PORT_Free(em);
+
+ if (status != NSSCMSVS_GoodSignature)
+ camel_cipher_validity_set_valid(valid, FALSE);
}
}
break;
case SEC_OID_PKCS7_ENVELOPED_DATA:
- if (vinfo)
- vinfo->type = CAMEL_CMS_TYPE_ENVELOPED;
-
- envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent (cinfo);
+ 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:
- if (vinfo)
- vinfo->type = CAMEL_CMS_TYPE_ENCRYPTED;
-
- encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent (cinfo);
+ encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
break;
case SEC_OID_PKCS7_DATA:
break;
@@ -902,100 +589,330 @@ decode_data (CamelSMimeContext *ctx, GByteArray *input, CamelStream *ostream,
break;
}
}
-
- item = NSS_CMSMessage_GetContent (cmsg);
- camel_stream_write (ostream, item->data, item->len);
-
- return cmsg;
-
- exception:
-
- if (info)
- camel_cms_validity_info_free (*info);
-
- if (cmsg)
- NSS_CMSMessage_Destroy (cmsg);
-
+
+ camel_cipher_validity_set_valid(valid, status == NSSCMSVS_GoodSignature);
+ 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 CamelMimeMessage *
-smime_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
- CamelCMSValidityInfo **info, CamelException *ex)
+static int
+sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
{
- CamelMimeMessage *mesg = NULL;
+ struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv;
+ /*NSSCMSRecipientInfo **recipient_infos;*/
+ CERTCertificate **recipient_certs = NULL;
+ NSSCMSContentInfo *cinfo;
+ PK11SymKey *bulkkey = NULL;
+ SECOidTag bulkalgtag;
+ int bulkkeysize, i;
+ CK_MECHANISM_TYPE type;
+ PK11SlotInfo *slot;
+ PLArenaPool *poolp;
NSSCMSMessage *cmsg = NULL;
- CamelStream *stream, *ostream;
- GByteArray *buf;
-
- stream = camel_stream_mem_new ();
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
- buf = CAMEL_STREAM_MEM (stream)->buffer;
-
- ostream = camel_stream_mem_new ();
- cmsg = decode_data (CAMEL_SMIME_CONTEXT (ctx), buf, ostream, info, ex);
- camel_object_unref (stream);
- if (!cmsg) {
- camel_object_unref (ostream);
- return NULL;
+ NSSCMSEnvelopedData *envd;
+ NSSCMSEncoderContext *enc = NULL;
+ CamelStreamMem *mem;
+ CamelStream *ostream = NULL;
+ CamelDataWrapper *dw;
+ CamelContentType *ct;
+
+ poolp = PORT_NewArena(1024);
+ if (poolp == NULL) {
+ camel_exception_setv(ex, 1, "Out of memory");
+ return -1;
}
+
+ /* Lookup all recipients certs, for later working */
+ recipient_certs = (CERTCertificate **)PORT_ArenaZAlloc(poolp, sizeof(*recipient_certs[0])*(recipients->len + 1));
+ if (recipient_certs == NULL) {
+ camel_exception_setv(ex, 1, "Out of memory");
+ goto fail;
+ }
+
+ for (i=0;i<recipients->len;i++) {
+ recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr(p->certdb, recipients->pdata[i]);
+ if (recipient_certs[i] == NULL) {
+ camel_exception_setv(ex, 1, "Can't find certificate for `%s'", recipients->pdata[i]);
+ goto fail;
+ }
+ }
+
+ /* Find a common algorithm, probably 3DES anyway ... */
+ if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't find common bulk encryption algorithm");
+ goto fail;
+ }
+
+ /* Generate a new bulk key based on the common algorithm - expensive */
+ type = PK11_AlgtagToMechanism(bulkalgtag);
+ slot = PK11_GetBestSlot(type, context);
+ if (slot == NULL) {
+ /* PORT_GetError(); ?? */
+ camel_exception_setv(ex, 1, "Can't allocate slot for encryption bulk key");
+ goto fail;
+ }
+
+ bulkkey = PK11_KeyGen(slot, type, NULL, bulkkeysize/8, context);
+ PK11_FreeSlot(slot);
+
+ /* Now we can start building the message */
+ /* msg->envelopedData->data */
+ cmsg = NSS_CMSMessage_Create(NULL);
+ if (cmsg == NULL) {
+ camel_exception_setv(ex, 1, "Can't create CMS Message");
+ goto fail;
+ }
+
+ envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, bulkkeysize);
+ if (envd == NULL) {
+ camel_exception_setv(ex, 1, "Can't create CMS EnvelopedData");
+ goto fail;
+ }
+
+ cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
+ if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't attach CMS EnvelopedData");
+ goto fail;
+ }
+
+ cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
+ if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't attach CMS data object");
+ goto fail;
+ }
+
+ /* add recipient certs */
+ for (i=0;recipient_certs[i];i++) {
+ NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create(cmsg, recipient_certs[i]);
+
+ if (ri == NULL) {
+ camel_exception_setv(ex, 1, "Can't create CMS RecipientInfo");
+ goto fail;
+ }
+
+ if (NSS_CMSEnvelopedData_AddRecipient(envd, ri) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Can't add CMS RecipientInfo");
+ goto fail;
+ }
+ }
+
+ /* dump it out */
+ ostream = camel_stream_mem_new();
+ enc = NSS_CMSEncoder_Start(cmsg,
+ sm_write_stream, ostream,
+ NULL, NULL,
+ sm_get_passwd, context,
+ sm_decrypt_key, bulkkey,
+ NULL, NULL);
+ if (enc == NULL) {
+ camel_exception_setv(ex, 1, "Can't create encoder context");
+ goto fail;
+ }
+
+ /* FIXME: Stream the input */
+ /* FIXME: Canonicalise the input? */
+ mem = (CamelStreamMem *)camel_stream_mem_new();
+ camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, (CamelStream *)mem);
+ if (NSS_CMSEncoder_Update(enc, mem->buffer->data, mem->buffer->len) != SECSuccess) {
+ NSS_CMSEncoder_Cancel(enc);
+ camel_object_unref(mem);
+ camel_exception_setv(ex, 1, "Failed to add data to encoder");
+ goto fail;
+ }
+ camel_object_unref(mem);
+
+ if (NSS_CMSEncoder_Finish(enc) != SECSuccess) {
+ camel_exception_setv(ex, 1, "Failed to encode data");
+ goto fail;
+ }
+
+ PK11_FreeSymKey(bulkkey);
+ NSS_CMSMessage_Destroy(cmsg);
+ for (i=0;recipient_certs[i];i++)
+ CERT_DestroyCertificate(recipient_certs[i]);
+ PORT_FreeArena(poolp, PR_FALSE);
- /* construct a new mime message from the stream */
- mesg = camel_mime_message_new ();
- camel_stream_reset (ostream);
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (mesg), ostream);
- camel_object_unref (ostream);
-
- return mesg;
+ dw = camel_data_wrapper_new();
+ camel_data_wrapper_construct_from_stream(dw, ostream);
+ camel_object_unref(ostream);
+ dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
+
+ ct = camel_content_type_new("application", "x-pkcs7-mime");
+ camel_content_type_set_param(ct, "name", "smime.p7m");
+ camel_content_type_set_param(ct, "smime-type", "enveloped-data");
+ camel_data_wrapper_set_mime_type_field(dw, ct);
+ camel_content_type_unref(ct);
+
+ camel_medium_set_content_object((CamelMedium *)opart, dw);
+ camel_object_unref(dw);
+
+ camel_mime_part_set_disposition(opart, "attachment");
+ camel_mime_part_set_filename(opart, "smime.p7m");
+ camel_mime_part_set_description(opart, "S/MIME Encrypted Message");
+ camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64);
+
+ return 0;
+
+fail:
+ if (ostream)
+ camel_object_unref(ostream);
+ if (cmsg)
+ NSS_CMSMessage_Destroy(cmsg);
+ if (bulkkey)
+ PK11_FreeSymKey(bulkkey);
+
+ if (recipient_certs) {
+ for (i=0;recipient_certs[i];i++)
+ CERT_DestroyCertificate(recipient_certs[i]);
+ }
+
+ PORT_FreeArena(poolp, PR_FALSE);
+
+ return -1;
}
+static CamelMimePart *
+sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+{
+ NSSCMSDecoderContext *dec;
+ NSSCMSMessage *cmsg;
+ CamelStreamMem *istream;
+ CamelStream *ostream;
+ CamelMimePart *opart = NULL;
+
+ /* FIXME: This assumes the content is only encrypted. Perhaps its ok for
+ this api to do this ... */
+
+ ostream = camel_stream_mem_new();
+
+ /* 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 *)ipart), (CamelStream *)istream);
+ camel_stream_reset((CamelStream *)istream);
+
+ dec = NSS_CMSDecoder_Start(NULL,
+ sm_write_stream, ostream, /* content callback */
+ sm_get_passwd, context, /* password callback */
+ NULL, NULL); /* decrypt key callback */
+
+ if (NSS_CMSDecoder_Update(dec, istream->buffer->data, istream->buffer->len) != SECSuccess) {
+ printf("decoder update failed\n");
+ }
+ camel_object_unref(istream);
+
+ cmsg = NSS_CMSDecoder_Finish(dec);
+ if (cmsg == NULL) {
+ camel_exception_setv(ex, 1, "Decoder failed, error %d", PORT_GetError());
+ goto fail;
+ }
+
#if 0
+ /* not sure if we really care about this? */
+ if (!NSS_CMSMessage_IsEncrypted(cmsg)) {
+ camel_exception_setv(ex, 1, "S/MIME Decrypt: No encrypted content found");
+ NSS_CMSMessage_Destroy(cmsg);
+ goto fail;
+ }
+#endif
-/* Ugh, so smime context inherets from cms context, not cipher context
- this needs to be fixed ... */
+ NSS_CMSMessage_Destroy(cmsg);
-/* this has a 1:1 relationship to CamelCipherHash */
-static char **name_table[] = {
- "sha1", /* we use sha1 as the 'default' */
- NULL,
- "md5",
- "sha1",
- NULL,
-};
+ opart = camel_mime_part_new();
+ camel_stream_reset(ostream);
+ camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream);
+fail:
+ camel_object_unref(ostream);
+
+ return opart;
+}
+
+static int
+sm_import_keys(CamelCipherContext *context, CamelStream *istream, CamelException *ex)
+{
+ camel_exception_setv(ex, 1, "import keys: unimplemented");
+
+ return -1;
+}
-static const char *smime_hash_to_id(CamelCipherContext *context, CamelCipherHash hash)
+static int
+sm_export_keys(CamelCipherContext *context, GPtrArray *keys, CamelStream *ostream, CamelException *ex)
{
- /* if we dont know, just use default? */
- if (hash > sizeof(name_table)/sizeof(name_table[0])
- || name_table[hash] == NULL;
- hash = CAMEL_CIPHER_HASH_DEFAULT;
+ camel_exception_setv(ex, 1, "export keys: unimplemented");
- return name_table[hash];
+ return -1;
}
-static CamelCipherHash smime_id_to_hash(CamelCipherContext *context, const char *id)
+/* ********************************************************************** */
+
+static void
+camel_smime_context_class_init(CamelSMIMEContextClass *klass)
{
- int i;
- unsigned char *tmpid, *o, *in;
- unsigned char c;
+ CamelCipherContextClass *cipher_class = CAMEL_CIPHER_CONTEXT_CLASS(klass);
+
+ parent_class = CAMEL_CIPHER_CONTEXT_CLASS(camel_type_get_global_classfuncs(camel_cipher_context_get_type()));
+
+ cipher_class->hash_to_id = sm_hash_to_id;
+ cipher_class->id_to_hash = sm_id_to_hash;
+ cipher_class->sign = sm_sign;
+ cipher_class->verify = sm_verify;
+ cipher_class->encrypt = sm_encrypt;
+ cipher_class->decrypt = sm_decrypt;
+ cipher_class->import_keys = sm_import_keys;
+ cipher_class->export_keys = sm_export_keys;
+}
- if (id == NULL)
- return CAMEL_CIPHER_HASH_DEFAULT;
+static void
+camel_smime_context_init(CamelSMIMEContext *context)
+{
+ CamelCipherContext *cipher =(CamelCipherContext *) context;
+
+ cipher->sign_protocol = "application/x-pkcs7-signature";
+ cipher->encrypt_protocol = "application/x-pkcs7-mime";
+ cipher->key_protocol = "application/x-pkcs7-signature";
- tmpid = alloca(strlen(id)+1);
- in = id;
- o = tmpid;
- while ((c = *in++))
- *o++ = tolower(c);
+ context->priv = g_malloc0(sizeof(*context->priv));
+ context->priv->certdb = CERT_GetDefaultCertDB();
+ context->priv->sign_mode = CAMEL_SMIME_SIGN_CLEARSIGN;
+}
- for (i=1;i<sizeof(name_table)/sizeof(name_table[0]);i++) {
- if (!strcmp(name_table[i], tmpid))
- return i;
- }
+static void
+camel_smime_context_finalise(CamelObject *object)
+{
+ CamelSMIMEContext *context = (CamelSMIMEContext *)object;
- return CAMEL_CIPHER_HASH_DEFAULT;
+ /* FIXME: do we have to free the certdb? */
+
+ g_free(context->priv);
}
-#endif
-#endif /* HAVE_NSS */
+CamelType
+camel_smime_context_get_type(void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register(camel_cipher_context_get_type(),
+ "CamelSMIMEContext",
+ sizeof(CamelSMIMEContext),
+ sizeof(CamelSMIMEContextClass),
+ (CamelObjectClassInitFunc) camel_smime_context_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_smime_context_init,
+ (CamelObjectFinalizeFunc) camel_smime_context_finalise);
+ }
+
+ return type;
+}
diff --git a/camel/camel-smime-context.h b/camel/camel-smime-context.h
index 940d715d22..a68d5e1646 100644
--- a/camel/camel-smime-context.h
+++ b/camel/camel-smime-context.h
@@ -1,62 +1,70 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
*
- * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ * Copyright 2002,2003 Ximian, Inc. (www.ximian.com)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
-#ifndef CAMEL_SMIME_CONTEXT_H
-#define CAMEL_SMIME_CONTEXT_H
-
-#include <camel/camel-session.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-cms-context.h>
+#ifndef __CAMEL_SMIME_CONTEXT_H__
+#define __CAMEL_SMIME_CONTEXT_H__
#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */
-#define CAMEL_SMIME_CONTEXT_TYPE (camel_smime_context_get_type ())
-#define CAMEL_SMIME_CONTEXT(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SMIME_CONTEXT_TYPE, CamelSMimeContext))
-#define CAMEL_SMIME_CONTEXT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SMIME_CONTEXT_TYPE, CamelSMimeContextClass))
-#define CAMEL_IS_SMIME_CONTEXT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SMIME_CONTEXT_TYPE))
+#include <camel/camel-cipher-context.h>
+
+#define CAMEL_SMIME_CONTEXT_TYPE (camel_smime_context_get_type())
+#define CAMEL_SMIME_CONTEXT(obj) (CAMEL_CHECK_CAST((obj), CAMEL_SMIME_CONTEXT_TYPE, CamelSMIMEContext))
+#define CAMEL_SMIME_CONTEXT_CLASS(k)(CAMEL_CHECK_CLASS_CAST((k), CAMEL_SMIME_CONTEXT_TYPE, CamelSMIMEContextClass))
+#define CAMEL_IS_SMIME_CONTEXT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SMIME_CONTEXT_TYPE))
+
+typedef enum _camel_smime_sign_t {
+ CAMEL_SMIME_SIGN_CLEARSIGN,
+ CAMEL_SMIME_SIGN_ENVELOPED
+} camel_smime_sign_t;
+
+typedef struct _CamelSMIMEContext CamelSMIMEContext;
+typedef struct _CamelSMIMEContextClass CamelSMIMEContextClass;
+
+struct _CamelSMIMEContext {
+ CamelCipherContext cipher;
-typedef struct _CamelSMimeContext {
- CamelCMSContext parent_object;
-
- struct _CamelSMimeContextPrivate *priv;
-
- char *encryption_key;
-} CamelSMimeContext;
+ struct _CamelSMIMEContextPrivate *priv;
+};
-typedef struct _CamelSMimeContextClass {
- CamelCMSContextClass parent_class;
-
-} CamelSMimeContextClass;
+struct _CamelSMIMEContextClass {
+ CamelCipherContextClass cipher_class;
+};
+CamelType camel_smime_context_get_type(void);
-CamelType camel_smime_context_get_type (void);
+CamelCipherContext *camel_smime_context_new(CamelSession *session);
-CamelSMimeContext *camel_smime_context_new (CamelSession *session, const char *encryption_key);
+/* nick to use for SMIMEEncKeyPrefs attribute for signed data */
+void camel_smime_context_set_encrypt_key(CamelSMIMEContext *context, gboolean use, const char *key);
+/* set signing mode, clearsigned multipart/signed or enveloped */
+void camel_smime_context_set_sign_mode(CamelSMIMEContext *context, camel_smime_sign_t type);
#ifdef __cplusplus
}
#endif /* __cplusplus */
-#endif /* CAMEL_SMIME_CONTEXT_H */
+#endif /* __CAMEL_SMIME_CONTEXT_H__ */
diff --git a/camel/camel-utf8.c b/camel/camel-utf8.c
index 65ca7f90a2..8fd422c944 100644
--- a/camel/camel-utf8.c
+++ b/camel/camel-utf8.c
@@ -25,9 +25,12 @@
#include <config.h>
#endif
+#include <string.h>
+
#include <glib.h>
#include "camel-utf8.h"
+#include <netinet/in.h>
/**
* camel_utf8_putc:
@@ -338,3 +341,60 @@ camel_utf8_utf7(const char *ptr)
return ret;
}
+
+/**
+ * camel_utf8_ucs2:
+ * @ptr:
+ *
+ * Convert a utf8 string into a ucs2 one. The ucs string will be in
+ * network byte order, and terminated with a 16 bit NULL.
+ *
+ * Return value:
+ **/
+char *
+camel_utf8_ucs2(const char *ptr)
+{
+ GByteArray *work = g_byte_array_new();
+ guint32 c;
+ char *out;
+
+ /* what if c is > 0xffff ? */
+
+ while ( (c = camel_utf8_getc((const unsigned char **)&ptr)) ) {
+ guint16 s = htons(c);
+
+ g_byte_array_append(work, (char *)&s, 2);
+ }
+
+ g_byte_array_append(work, "\000\000", 2);
+ out = g_malloc(work->len);
+ memcpy(out, work->data, work->len);
+ g_byte_array_free(work, TRUE);
+
+ return out;
+}
+
+/**
+ * camel_ucs2_utf8:
+ * @ptr:
+ *
+ * Convert a ucs2 string into a utf8 one. The ucs2 string is treated
+ * as network byte ordered, and terminated with a 16 bit NUL.
+ *
+ * Return value:
+ **/
+char *camel_ucs2_utf8(const char *ptr)
+{
+ guint16 *ucs = (guint16 *)ptr;
+ guint32 c;
+ GString *work = g_string_new("");
+ char *out;
+
+ while ( (c = *ucs++) )
+ g_string_append_u(work, ntohs(c));
+
+ out = g_strdup(work->str);
+ g_string_free(work, TRUE);
+
+ return out;
+}
diff --git a/camel/camel-utf8.h b/camel/camel-utf8.h
index a29c8fc975..fadce2c7e6 100644
--- a/camel/camel-utf8.h
+++ b/camel/camel-utf8.h
@@ -34,4 +34,8 @@ void g_string_append_u(GString *out, guint32 c);
char *camel_utf7_utf8(const char *ptr);
char *camel_utf8_utf7(const char *ptr);
+/* convert ucs2 to/from utf8 */
+char *camel_utf8_ucs2(const char *ptr);
+char *camel_ucs2_utf8(const char *ptr);
+
#endif /* ! _CAMEL_UTF8_H */
diff --git a/camel/tests/smime/pgp.c b/camel/tests/smime/pgp.c
index 1075f218ad..2c8de8ccd1 100644
--- a/camel/tests/smime/pgp.c
+++ b/camel/tests/smime/pgp.c
@@ -31,6 +31,7 @@
#include <sys/wait.h>
#include <camel/camel-gpg-context.h>
#include <camel/camel-stream-mem.h>
+#include <camel/camel-mime-part.h>
#include "camel-test.h"
#include "session.h"
@@ -120,6 +121,7 @@ int main (int argc, char **argv)
CamelException *ex;
CamelCipherValidity *valid;
CamelStream *stream1, *stream2, *stream3;
+ struct _CamelMimePart *sigpart;
GPtrArray *recipients;
GByteArray *buf;
char *before, *after;
@@ -154,11 +156,10 @@ int main (int argc, char **argv)
camel_stream_write (stream1, "Hello, I am a test stream.\n", 27);
camel_stream_reset (stream1);
- stream2 = camel_stream_mem_new ();
-
+ sigpart = camel_mime_part_new();
+
camel_test_push ("PGP signing");
- camel_cipher_sign (ctx, "no.user@no.domain", CAMEL_CIPHER_HASH_SHA1,
- stream1, stream2, ex);
+ camel_cipher_sign (ctx, "no.user@no.domain", CAMEL_CIPHER_HASH_SHA1, stream1, sigpart, ex);
check_msg (!camel_exception_is_set (ex), "%s", camel_exception_get_description (ex));
camel_test_pull ();
@@ -166,15 +167,14 @@ int main (int argc, char **argv)
camel_test_push ("PGP verify");
camel_stream_reset (stream1);
- camel_stream_reset (stream2);
- valid = camel_cipher_verify (ctx, CAMEL_CIPHER_HASH_SHA1, stream1, stream2, ex);
+ valid = camel_cipher_verify (ctx, CAMEL_CIPHER_HASH_SHA1, stream1, 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 (CAMEL_OBJECT (stream1));
- camel_object_unref (CAMEL_OBJECT (stream2));
+ camel_object_unref(stream1);
+ camel_object_unref(sigpart);
stream1 = camel_stream_mem_new ();
stream2 = camel_stream_mem_new ();