diff options
author | Not Zed <NotZed@Ximian.com> | 2003-10-30 12:58:33 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2003-10-30 12:58:33 +0800 |
commit | 52759f2d4018b8ff0ce173aa1237b08783f1424c (patch) | |
tree | c6b392bea311df4d965b3e234cb769d6bf78e7e0 | |
parent | 4c9e3c871c301e92711b91f0df0aca2521567db1 (diff) | |
download | gsoc2013-evolution-52759f2d4018b8ff0ce173aa1237b08783f1424c.tar.gz 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
-rw-r--r-- | camel/ChangeLog | 57 | ||||
-rw-r--r-- | camel/Makefile.am | 2 | ||||
-rw-r--r-- | camel/camel-cipher-context.c | 204 | ||||
-rw-r--r-- | camel/camel-cipher-context.h | 50 | ||||
-rw-r--r-- | camel/camel-gpg-context.c | 343 | ||||
-rw-r--r-- | camel/camel-multipart-encrypted.c | 86 | ||||
-rw-r--r-- | camel/camel-multipart-signed.c | 39 | ||||
-rw-r--r-- | camel/camel-smime-context.c | 1613 | ||||
-rw-r--r-- | camel/camel-smime-context.h | 80 | ||||
-rw-r--r-- | camel/camel-utf8.c | 60 | ||||
-rw-r--r-- | camel/camel-utf8.h | 4 | ||||
-rw-r--r-- | camel/tests/smime/pgp.c | 16 |
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 (); |