aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@ximian.com>2001-04-21 05:21:34 +0800
committerJeffrey Stedfast <fejj@src.gnome.org>2001-04-21 05:21:34 +0800
commit986252ceaf4239d36294d90e75c6acd305e06dfa (patch)
tree199ef1cc4117b3a9065f0052e7cbca6f42ba4b33
parentc36302e415de5eabc850fac77ff570a40d8e129e (diff)
downloadgsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.tar
gsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.tar.gz
gsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.tar.bz2
gsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.tar.lz
gsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.tar.xz
gsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.tar.zst
gsoc2013-evolution-986252ceaf4239d36294d90e75c6acd305e06dfa.zip
Implemented using the secmime.h convenience functions. (smime_clearsign):
2001-04-20 Jeffrey Stedfast <fejj@ximian.com> * camel-smime-context.c (smime_sign): Implemented using the secmime.h convenience functions. (smime_clearsign): We just error our here, there is no clearsign for smime. (smime_verify): Copied code over from the pkcs7 verify - same state, ugly and unknown :-) (smime_encrypt): Implemented using the secmime.h convenience functions. (smime_decrypt): Same as the code in pkcs7-context. svn path=/trunk/; revision=9480
-rw-r--r--camel/ChangeLog12
-rw-r--r--camel/camel-pkcs7-context.c41
-rw-r--r--camel/camel-smime-context.c643
-rw-r--r--camel/camel-smime-context.h73
4 files changed, 754 insertions, 15 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 18e38249bf..0e0014d5df 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,15 @@
+2001-04-20 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-smime-context.c (smime_sign): Implemented using the
+ secmime.h convenience functions.
+ (smime_clearsign): We just error our here, there is no clearsign
+ for smime.
+ (smime_verify): Copied code over from the pkcs7 verify - same
+ state, ugly and unknown :-)
+ (smime_encrypt): Implemented using the secmime.h convenience
+ functions.
+ (smime_decrypt): Same as the code in pkcs7-context.
+
2001-04-19 Jeffrey Stedfast <fejj@ximian.com>
* camel-pkcs7-context.c (pkcs7_sign): Implemented.
diff --git a/camel/camel-pkcs7-context.c b/camel/camel-pkcs7-context.c
index 7d9091758a..fee277e079 100644
--- a/camel/camel-pkcs7-context.c
+++ b/camel/camel-pkcs7-context.c
@@ -412,18 +412,18 @@ pkcs7_clearsign (CamelCipherContext *ctx, const char *userid, CamelCipherHash ha
#if 0
/* this is just meant as a reference so I can see what the valid enums are */
typedef enum {
- certUsageSSLClient,
- certUsageSSLServer,
- certUsageSSLServerWithStepUp,
- certUsageSSLCA,
- certUsageEmailSigner,
- certUsageEmailRecipient,
- certUsageObjectSigner,
- certUsageUserCertImport,
- certUsageVerifyCA,
- certUsageProtectedObjectSigner,
- certUsageStatusResponder,
- certUsageAnyCA
+ certUsageSSLClient,
+ certUsageSSLServer,
+ certUsageSSLServerWithStepUp,
+ certUsageSSLCA,
+ certUsageEmailSigner,
+ certUsageEmailRecipient,
+ certUsageObjectSigner,
+ certUsageUserCertImport,
+ certUsageVerifyCA,
+ certUsageProtectedObjectSigner,
+ certUsageStatusResponder,
+ certUsageAnyCA
} SECCertUsage;
#endif
@@ -509,6 +509,9 @@ pkcs7_verify (CamelCipherContext *ctx, CamelCipherHash hash, CamelStream *istrea
SEC_PKCS7DestroyContentInfo (cinfo);
+ /* FIXME: set a meaningful description...in UTF8 */
+ camel_cipher_validity_set_description (valid, "");
+
return valid;
}
@@ -549,9 +552,17 @@ pkcs7_encrypt (CamelCipherContext *ctx, gboolean sign, const char *userid, GPtrA
goto exception;
}
- cinfo = SEC_PKCS7CreateEnvelopedData (cert, certUsageEmailRecipient,
- NULL, SEC_OID_DES_EDE3_CBC, 0,
- NULL, NULL);
+ data = g_new (struct _GetPasswdData, 1);
+ data->session = session;
+ data->userid = userid;
+ data->ex = ex;
+
+ /* FIXME: extend CamelCipherContext to allow selecting an encryption algorithm?? */
+ cinfo = SEC_PKCS7CreateEncryptedData (SEC_OID_DES_EDE3_CBC, 0,
+ get_password, data);
+
+ g_free (data);
+
if (!cinfo) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
_("Could not encrypt: failed to create enveloped data."));
diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c
new file mode 100644
index 0000000000..b1d9fb28d7
--- /dev/null
+++ b/camel/camel-smime-context.c
@@ -0,0 +1,643 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "camel-smime-context.h"
+
+#include "camel-stream-fs.h"
+#include "camel-stream-mem.h"
+
+#include <nss.h>
+#include <cert.h>
+#include <secpkcs7.h>
+
+#include <gtk/gtk.h> /* for _() macro */
+
+#define d(x)
+
+struct _CamelSMimeContextPrivate {
+ CERTCertDBHandle *certdb;
+};
+
+
+static int smime_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
+ CamelStream *istream, CamelStream *ostream, CamelException *ex);
+static int smime_clearsign (CamelCipherContext *context, const char *userid,
+ CamelCipherHash hash, CamelStream *istream,
+ CamelStream *ostream, CamelException *ex);
+static CamelCipherValidity *smime_verify (CamelCipherContext *context, CamelStream *istream,
+ CamelStream *sigstream, CamelException *ex);
+static int smime_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
+ GPtrArray *recipients, CamelStream *istream, CamelStream *ostream,
+ CamelException *ex);
+static int smime_decrypt (CamelCipherContext *context, CamelStream *istream,
+ CamelStream *ostream, CamelException *ex);
+
+
+static CamelCipherContextClass *parent_class;
+
+static void
+camel_smime_context_init (CamelSMimeContext *context)
+{
+ context->priv = g_new0 (struct _CamelSMimeContextPrivate, 1);
+}
+
+static void
+camel_smime_context_finalise (CamelObject *o)
+{
+ CamelSMimeContext *context = (CamelSMimeContext *)o;
+
+ CERT_ClosePermCertDB (context->priv->certdb);
+ g_free (context->priv->certdb);
+
+ g_free (context->priv);
+}
+
+static void
+camel_smime_context_class_init (CamelSMimeContextClass *camel_smime_context_class)
+{
+ CamelCipherContextClass *camel_cipher_context_class =
+ CAMEL_CIPHER_CONTEXT_CLASS (camel_smime_context_class);
+
+ parent_class = CAMEL_CIPHER_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cipher_context_get_type ()));
+
+ camel_cipher_context_class->sign = smime_sign;
+ camel_cipher_context_class->clearsign = smime_clearsign;
+ camel_cipher_context_class->verify = smime_verify;
+ camel_cipher_context_class->encrypt = smime_encrypt;
+ camel_cipher_context_class->decrypt = smime_decrypt;
+}
+
+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;
+}
+
+
+/**
+ * camel_smime_context_new:
+ * @session: CamelSession
+ * @certdb: certificate db
+ *
+ * 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 *certdb)
+{
+ CamelSMimeContext *context;
+ CERTCertDBHandle *handle;
+
+ g_return_val_if_fail (session != NULL, NULL);
+
+ context = CAMEL_SMIME_CONTEXT (camel_object_new (CAMEL_SMIME_CONTEXT_TYPE));
+
+ camel_cipher_construct (CAMEL_CIPHER_CONTEXT (context), session);
+
+ handle = g_new0 (CERTCertDBHandle, 1);
+ if (certdb) {
+ if (!CERT_OpenCertDBFilename (handle, certdb, FALSE)) {
+ g_free (handle);
+ return NULL;
+ }
+ } else {
+ if (!CERT_OpenVolatileCertDB (handle)) {
+ g_free (handle);
+ return NULL;
+ }
+ }
+
+ context->priv->certdb = handle;
+
+ return context;
+}
+
+/*----------------------------------------------------------------------*
+ * Public crypto functions
+ *----------------------------------------------------------------------*/
+
+struct _GetPasswdData {
+ CamelSession *session;
+ CamelException *ex;
+ const char *userid;
+};
+
+static SECItem *
+get_zero_len_passwd (SECKEYKeyDBHandle *handle)
+{
+ SECItem *pwitem;
+ SECStatus rv;
+
+ /* hash the empty string as a password */
+ pwitem = SECKEY_DeriveKeyDBPassword (handle, "");
+ if (pwitem == NULL)
+ return NULL;
+
+ /* check to see if this is the right password */
+ rv = SECKEY_CheckKeyDBPassword (handle, pwitem);
+ if (rv == SECFailure)
+ return NULL;
+
+ return pwitem;
+}
+
+static SECItem *
+get_password (void *arg, SECKEYKeyDBHandle *handle)
+{
+ CamelSession *session = ((struct _GetPasswdData *) arg)->session;
+ CamelException *ex = ((struct _GetPasswdData *) arg)->ex;
+ const char *userid = ((struct _GetPasswdData *) arg)->userid;
+ char *prompt, *passwd = NULL;
+ SECItem *pwitem;
+ SECStatus rv;
+
+ /* Check to see if zero length password or not */
+ pwitem = get_zero_len_passwd (handle);
+ if (pwitem)
+ return pwitem;
+
+ prompt = g_strdup_printf (_("Please enter your password for %s"), userid);
+ passwd = camel_session_query_authenticator (session, CAMEL_AUTHENTICATOR_ASK,
+ prompt, TRUE, NULL, userid,
+ NULL);
+ g_free (prompt);
+
+ /* hash the password */
+ pwitem = SECKEY_DeriveKeyDBPassword (handle, passwd ? passwd : "");
+
+ /* clear out the password strings */
+ if (passwd) {
+ memset (passwd, 0, strlen (passwd));
+ g_free (passwd);
+ }
+
+ if (pwitem == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Error hashing password."));
+
+ return NULL;
+ }
+
+ /* confirm the password */
+ rv = SECKEY_CheckKeyDBPassword (handle, pwitem);
+ if (rv) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Invalid password."));
+
+ SECITEM_ZfreeItem (pwitem, PR_TRUE);
+
+ return NULL;
+ }
+
+ return pwitem;
+}
+
+static HASH_HashType
+camel_cipher_hash_to_nss (CamelCipherHash hash)
+{
+ switch (hash) {
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ return HASH_AlgSHA1;
+ case CAMEL_CIPHER_HASH_MD2:
+ return HASH_AlgMD2;
+ case CAMEL_CIPHER_HASH_MD5:
+ return HASH_AlgMD5;
+ case CAMEL_CIPHER_HASH_SHA1:
+ return HASH_AlgSHA1;
+ }
+
+ return HASH_AlgNULL;
+}
+
+static SECOidTag
+nss_hash_to_sec_oid (HASH_HashType hash)
+{
+ switch (hash) {
+ case HASH_AlgMD2:
+ return SEC_OID_MD2;
+ case HASH_AlgMD5:
+ return SEC_OID_MD5;
+ case Hash_AlgSHA1:
+ return SEC_OID_SHA1;
+ default:
+ g_assert_not_reached ();
+ return 0;
+ }
+}
+
+static int
+smime_digest (SECItem *data, char *digestdata, unsigned int *len, unsigned int maxlen, HASH_HashType hash)
+{
+ SECHashObject *hashObj;
+ void *hashcx;
+
+ hashObj = &SECHashObjects[hash];
+
+ hashcx = (* hashObj->create)();
+ if (hashcx == NULL)
+ return -1;
+
+ (* hashObj->begin)(hashcx);
+ (* hashObj->update)(hashcx, data->data, data->len);
+ (* hashObj->end)(hashcx, (unsigned char *)digestdata, len, maxlen);
+ (* hashObj->destroy)(hashcx, PR_TRUE);
+
+ return 0;
+}
+
+static void
+smime_output_cb (void *arg, const char *buf, unsigned long len)
+{
+ CamelStream *stream;
+
+ stream = CAMEL_STREAM (arg);
+ camel_stream_write (stream, buf, len);
+}
+
+static int
+smime_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
+ CamelStream *istream, CamelStream *ostream, CamelException *ex)
+{
+ CamelSMimeContext *context = CAMEL_SMIME_CONTEXT (ctx);
+ SEC_PKCS7EncoderContext *ecx = NULL;
+ struct _GetPasswdData *data = NULL;
+ SEC_PKCS7ContentInfo *cinfo = NULL;
+ SECItem data2sign, digest;
+ HASH_HashType hash_type;
+ CERTCertificate *cert;
+ guchar digestdata[32];
+ CamelStream *stream;
+ GByteArray *buf;
+ guint len;
+
+ g_return_val_if_fail (userid != NULL, -1);
+ g_return_val_if_fail (istream != NULL, -1);
+ g_return_val_if_fail (ostream != NULL, -1);
+
+ stream = camel_stream_mem_new ();
+ camel_stream_write_to_stream (istream, stream);
+ buf = CAMEL_STREAM_MEM (stream)->buffer;
+ data2sign.data = buf->data;
+ data2sign.len = buf->len;
+
+ hash_type = camel_cipher_hash_to_nss (hash);
+ smime_digest (&data2sign, digestdata, &len, 32, hash_type);
+ digest.data = (unsigned char *)digestdata;
+ digest.len = len;
+
+ camel_object_unref (CAMEL_OBJECT (stream));
+
+ cert = CERT_FindCertByNickname (context->priv->certdb, userid);
+ if (!cert) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not sign: certificate not found for \"%s\"."),
+ userid);
+ return -1;
+ }
+
+ data = g_new (struct _GetPasswdData, 1);
+ data->session = ctx->session;
+ data->userid = userid;
+ data->ex = ex;
+
+ cinfo = SECMIME_CreateSigned (cert, cert, context->priv->certdb,
+ nss_hash_to_sec_oid (hash_type),
+ &digest, get_password, data);
+
+ if (cinfo == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not sign: failed to create content info."));
+ goto exception;
+ }
+
+ ecx = SEC_PKCS7EncoderStart (cinfo, smime_output_cb, ostream, NULL);
+ if (ecx == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not sign: failed to create signing context."));
+ goto exception;
+ }
+
+ if (SEC_PKCS7EncoderFinish (ecx, NULL, NULL) != SECSuccess) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not sign: failed to create signature."));
+ goto exception;
+ }
+
+ g_free (data);
+
+ SEC_PKCS7DestroyContentInfo (cinfo);
+
+ return 0;
+
+ exception:
+
+ if (cinfo)
+ SEC_PKCS7DestroyContentInfo (cinfo);
+
+ if (data)
+ g_free (data);
+
+ return -1;
+}
+
+
+static int
+smime_clearsign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
+ CamelStream *istream, CamelStream *ostream, CamelException *ex)
+{
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("'clearsign' is not supported by S/MIME."));
+ return -1;
+}
+
+#if 0
+/* this is just meant as a reference so I can see what the valid enums are */
+typedef enum {
+ certUsageSSLClient,
+ certUsageSSLServer,
+ certUsageSSLServerWithStepUp,
+ certUsageSSLCA,
+ certUsageEmailSigner,
+ certUsageEmailRecipient,
+ certUsageObjectSigner,
+ certUsageUserCertImport,
+ certUsageVerifyCA,
+ certUsageProtectedObjectSigner,
+ certUsageStatusResponder,
+ certUsageAnyCA
+} SECCertUsage;
+#endif
+
+/* FIXME: god knows if this code works, NSS "docs" are so not helpful at all */
+static CamelCipherValidity *
+smime_verify (CamelCipherContext *ctx, CamelCipherHash hash, CamelStream *istream,
+ CamelStream *sigstream, CamelException *ex)
+{
+ CamelSMimeContext *context = CAMEL_SMIME_CONTEXT (ctx);
+ CamelCipherValidity *valid = NULL;
+ SEC_PKCS7ContentInfo *cinfo;
+ SECCertUsage usage;
+ GByteArray *plaintext;
+ CamelStream *stream;
+
+ /* create our ContentInfo object */
+ stream = camel_stream_mem_new ();
+ camel_stream_write_to_stream (istream, stream);
+ plaintext = CAMEL_STREAM_MEM (stream)->buffer;
+ cinfo = SEC_PKCS7CreateData ();
+ SEC_PKCS7SetContent (cinfo, plaintext->data, plaintext->len);
+ camel_object_unref (CAMEL_OBJECT (stream));
+
+ usage = certUsageEmailSigner; /* just a guess. or maybe certUsageVerifyCA?? */
+
+ valid = camel_cipher_validity_new ();
+
+ if (sigstream) {
+ HASH_HashType digest_type;
+ GByteArray *signature;
+ SECItem digest;
+
+ /* create our digest object */
+ stream = camel_stream_mem_new ();
+ camel_stream_write_to_stream (sigstream, stream);
+ signature = CAMEL_STREAM_MEM (stream)->buffer;
+ digest.data = signature->data;
+ digest.len = signature->len;
+
+ switch (hash) {
+ default:
+ case CAMEL_CIPHER_HASH_DEFAULT:
+ digest_type = HASH_AlgNULL;
+ break;
+ case CAMEL_CIPHER_HASH_MD2:
+ digest_type = HASH_AlgMD2;
+ break;
+ case CAMEL_CIPHER_HASH_MD5:
+ digest_type = HASH_AlgMD5;
+ break;
+ case CAMEL_CIPHER_HASH_SHA1:
+ digest_type = HASH_AlgSHA1;
+ break;
+ }
+
+ valid->valid = SEC_PKCS7VerifyDetachedSignature (cinfo, usage, &digest,
+ digest_type, PR_FALSE);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ } else {
+ valid->valid = SEC_PKCS7VerifySignature (cinfo, usage, PR_FALSE);
+ }
+
+ SEC_PKCS7DestroyContentInfo (cinfo);
+
+ /* FIXME: set a meaningful description...in UTF8 */
+ camel_cipher_validity_set_description (valid, "");
+
+ return valid;
+}
+
+static int
+smime_encrypt (CamelCipherContext *ctx, gboolean sign, const char *userid, GPtrArray *recipients,
+ CamelStream *istream, CamelStream *ostream, CamelException *ex)
+{
+ CamelSMimeContext *context = CAMEL_SMIME_CONTEXT (ctx);
+ const char *invalid_userkey = NULL;
+ SEC_PKCS7ContentInfo *cinfo = NULL;
+ GPtrArray *certificates = NULL;
+ SEC_PKCS7EncoderContext *ecx;
+ struct _GetPasswdData *data;
+ CamelStream *stream = NULL;
+ CERTCertificate *scert;
+ SECItem secdata;
+ GByteArray *buf;
+ int i = 0;
+
+ g_return_val_if_fail (userid != NULL, -1);
+ g_return_val_if_fail (recipients != NULL, -1);
+ g_return_val_if_fail (recipients->len != 0, -1);
+ g_return_val_if_fail (istream != NULL, -1);
+ g_return_val_if_fail (ostream != NULL, -1);
+
+ scert = CERT_FindCertByNickname (context->priv->certdb, userid);
+ if (!scert) {
+ invalid_userkey = recipients->pdata[i];
+ goto exception;
+ }
+
+ certificates = g_ptr_array_new ();
+ for (i = 0; i < recipients->len; i++) {
+ CERTCertificate *cert;
+
+ cert = CERT_FindCertByNickname (context->priv->certdb, recipients->pdata[i]);
+ if (!cert) {
+ invalid_userkey = recipients->pdata[i];
+ goto exception;
+ }
+
+ g_ptr_array_add (certificates, cert);
+ }
+ g_ptr_array_add (certificates, NULL);
+
+ data = g_new (struct _GetPasswdData, 1);
+ data->session = session;
+ data->userid = userid;
+ data->ex = ex;
+
+ cinfo = SECMIME_CreateEncrypted (scert, (CERTCertificate **) certificates->pdata,
+ context->priv->certdb, get_password, data);
+
+ g_free (data);
+
+ if (!cinfo) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not encrypt: failed to create enveloped data."));
+ goto exception;
+ }
+
+ ecx = SEC_PKCS7EncoderStart (cinfo, smime_output_cb, ostream, NULL);
+ if (ecx == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not encrypt: failed to create encryption context."));
+ goto exception;
+ }
+
+ stream = camel_stream_mem_new ();
+ camel_stream_write_to_stream (istream, stream);
+ buf = CAMEL_STREAM_MEM (stream)->buffer;
+ if (SEC_PKCS7EncoderUpdate (ecx, buf->data, buf->len) != SECSuccess)
+ goto exception;
+
+ camel_object_unref (CAMEL_OBJECT (stream));
+ stream = NULL;
+
+ if (SEC_PKCS7EncoderFinish (ecx, NULL, NULL) != SECSuccess)
+ goto exception;
+
+ g_ptr_array_free (certificates, TRUE);
+
+ SEC_PKCS7DestroyContentInfo (cinfo);
+
+ return 0;
+
+ exception:
+
+ if (certificates)
+ g_ptr_array_free (certificates, TRUE);
+
+ if (stream)
+ camel_object_unref (CAMEL_OBJECT (stream));
+
+ if (cinfo)
+ SEC_PKCS7DestroyContentInfo (cinfo);
+
+ if (invalid_userkey) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not encrypt data: invalid user key: \"%s\"."),
+ invalid_userkey);
+ }
+
+ if (!camel_exception_is_set (ex)) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Could not encrypt: encoding failed."));
+ }
+
+ return -1;
+}
+
+static PRBool
+decryption_allowed (SECAlgorithmID *algid, PK11SymKey *key)
+{
+ return PR_TRUE;
+}
+
+static int
+smime_decrypt (CamelCipherContext *ctx, CamelStream *istream,
+ CamelStream *ostream, CamelException *ex)
+{
+ CamelSMimeContext *context = CAMEL_SMIME_CONTEXT (ctx);
+ struct _GetPasswdData *data;
+ SEC_PKCS7DecoderContext *dcx;
+ SEC_PKCS7ContentInfo *cinfo;
+ CamelStream *stream = NULL;
+ SECItem secdata;
+ GByteArray *buf;
+
+ g_return_val_if_fail (istream != NULL, -1);
+ g_return_val_if_fail (ostream != NULL, -1);
+
+ stream = camel_stream_mem_new ();
+ camel_stream_write_to_stream (istream, stream);
+ buf = CAMEL_STREAM_MEM (stream)->buffer;
+ secdata.data = buf->data;
+ secdata.len = buf->len;
+
+ data = g_new (struct _GetPasswdData, 1);
+ data->session = ctx->session;
+ data->userid = NULL;
+ data->ex = ex;
+
+ dcx = SEC_PKCS7DecoderStart (smime_output_cb, ostream, get_password, data,
+ NULL, NULL, decryption_allowed);
+ if (dcx == NULL)
+ goto exception;
+
+ SEC_PKCS7DecoderUpdate (dcx, secdata.data, secdata.len);
+ cinfo = SEC_PKCS7DecoderFinish (dcx);
+
+ camel_object_unref (CAMEL_OBJECT (stream));
+ g_free (data);
+
+ if (cinfo == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to decrypt: Unknown"));
+ return -1;
+ }
+
+ SEC_PKCS7DestroyContentInfo (cinfo);
+
+ return 0;
+
+ exception:
+
+ if (stream)
+ camel_object_unref (CAMEL_OBJECT (stream));
+
+ return -1;
+}
diff --git a/camel/camel-smime-context.h b/camel/camel-smime-context.h
new file mode 100644
index 0000000000..a132c3918f
--- /dev/null
+++ b/camel/camel-smime-context.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ *
+ * 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.
+ *
+ * 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-stream.h>
+#include <camel/camel-exception.h>
+#include <camel/camel-cipher-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))
+
+typedef struct _CamelSMimeContext {
+ CamelCipherContext parent_object;
+
+ struct _CamelSMimeContextPrivate *priv;
+
+} CamelSMimeContext;
+
+typedef struct _CamelSMimeContextClass {
+ CamelCipherContextClass parent_class;
+
+} CamelSMimeContextClass;
+
+
+CamelType camel_smime_context_get_type (void);
+
+CamelSMimeContext *camel_smime_context_new (CamelSession *session, const char *certdb_path);
+
+/* SMIME routines */
+#define camel_smime_sign(c, u, h, i, o, e) camel_cipher_sign (CAMEL_CIPHER_CONTEXT (c), u, h, i, o, e)
+
+#define camel_smime_clearsign(c, u, h, i, o, e) camel_cipher_clearsign (CAMEL_CIPHER_CONTEXT (c), u, h, i, o, e)
+
+#define camel_smime_verify(c, i, s, e) camel_cipher_verify (CAMEL_CIPHER_CONTEXT (c), i, s, e)
+
+#define camel_smime_encrypt(c, s, u, r, i, o, e) camel_cipher_encrypt (CAMEL_CIPHER_CONTEXT (c), s, u, r, i, o, e)
+
+#define camel_smime_decrypt(c, i, o, e) camel_cipher_decrypt (CAMEL_CIPHER_CONTEXT (c), i, o, e)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_SMIME_CONTEXT_H */