aboutsummaryrefslogtreecommitdiffstats
path: root/camel
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@ximian.com>2001-06-01 04:15:35 +0800
committerJeffrey Stedfast <fejj@src.gnome.org>2001-06-01 04:15:35 +0800
commitfb099f5619f60f6c47658c052fae8d9a597b86d6 (patch)
tree36a17e4f354ba594f36efb819a5e2460f2596512 /camel
parent9e7473e1de1484de4720205b437f824fb2b0c615 (diff)
downloadgsoc2013-evolution-fb099f5619f60f6c47658c052fae8d9a597b86d6.tar.gz
gsoc2013-evolution-fb099f5619f60f6c47658c052fae8d9a597b86d6.tar.zst
gsoc2013-evolution-fb099f5619f60f6c47658c052fae8d9a597b86d6.zip
New virtual class for manipulating cryptographic message syntax messages
2001-05-31 Jeffrey Stedfast <fejj@ximian.com> * camel-cms-context.[c,h]: New virtual class for manipulating cryptographic message syntax messages (like S/MIME). * camel-smime-context.[c,h]: Modified to inherit from the CamelCMSContext class rather than the CamelCipherContext class. * camel-smime.[c,h]: Removed - just use camel-smime-context directly. * camel-smime-utils.[c,h]: New source files. Moved the 2 useful functions from camel-smime.[c,h] into here. svn path=/trunk/; revision=10065
Diffstat (limited to 'camel')
-rw-r--r--camel/ChangeLog14
-rw-r--r--camel/Makefile.am6
-rw-r--r--camel/camel-cms-context.c324
-rw-r--r--camel/camel-cms-context.h128
-rw-r--r--camel/camel-smime-context.c1080
-rw-r--r--camel/camel-smime-context.h20
-rw-r--r--camel/camel-smime-utils.c126
-rw-r--r--camel/camel-smime-utils.h (renamed from camel/camel-smime.h)28
-rw-r--r--camel/camel-smime.c504
9 files changed, 1291 insertions, 939 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index a56052f885..fb13e24c4d 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,17 @@
+2001-05-31 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-cms-context.[c,h]: New virtual class for manipulating
+ cryptographic message syntax messages (like S/MIME).
+
+ * camel-smime-context.[c,h]: Modified to inherit from the
+ CamelCMSContext class rather than the CamelCipherContext class.
+
+ * camel-smime.[c,h]: Removed - just use camel-smime-context
+ directly.
+
+ * camel-smime-utils.[c,h]: New source files. Moved the 2 useful
+ functions from camel-smime.[c,h] into here.
+
2001-05-30 Dan Winship <danw@ximian.com>
* camel-charset-map.c: Redo the BUILD_MAP code to not depend on
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 8284d35abc..c3a964b991 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -22,6 +22,7 @@ libcamel_la_SOURCES = \
broken-date-parser.c \
camel-address.c \
camel-cipher-context.c \
+ camel-cms-context.c \
camel-data-wrapper.c \
camel-digest-folder.c \
camel-disco-diary.c \
@@ -60,7 +61,7 @@ libcamel_la_SOURCES = \
camel-pgp-context.c \
camel-pgp-mime.c \
camel-smime-context.c \
- camel-smime.c \
+ camel-smime-utils.c \
camel-provider.c \
camel-remote-store.c \
camel-sasl.c \
@@ -103,6 +104,7 @@ libcamelinclude_HEADERS = \
camel-address.h \
camel-charset-map.h \
camel-cipher-context.h \
+ camel-cms-context.h \
camel-data-wrapper.h \
camel-digest-folder.h \
camel-disco-diary.h \
@@ -142,7 +144,7 @@ libcamelinclude_HEADERS = \
camel-pgp-context.h \
camel-pgp-mime.h \
camel-smime-context.h \
- camel-smime.h \
+ camel-smime-utils.h \
camel-provider.h \
camel-remote-store.h \
camel-sasl.h \
diff --git a/camel/camel-cms-context.c b/camel/camel-cms-context.c
new file mode 100644
index 0000000000..dea3951877
--- /dev/null
+++ b/camel/camel-cms-context.c
@@ -0,0 +1,324 @@
+/* -*- 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-cms-context.h"
+
+#include <glib.h>
+
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#define CMS_LOCK(ctx) g_mutex_lock (((CamelCMSContext *) ctx)->priv->lock)
+#define CMS_UNLOCK(ctx) g_mutex_unlock (((CamelCMSContext *) ctx)->priv->lock);
+#else
+#define CMS_LOCK(ctx)
+#define CMS_UNLOCK(ctx)
+#endif
+
+#define d(x)
+
+#define CCC_CLASS(o) CAMEL_CMS_CONTEXT_CLASS(CAMEL_OBJECT_GET_CLASS(o))
+
+struct _CamelCMSContextPrivate {
+#ifdef ENABLE_THREADS
+ GMutex *lock;
+#endif
+};
+
+static CamelMimeMessage *cms_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex);
+
+static CamelMimeMessage *cms_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+static CamelMimeMessage *cms_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+static CamelMimeMessage *cms_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+static CamelMimeMessage *cms_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex);
+
+static CamelObjectClass *parent_class;
+
+static void
+camel_cms_context_init (CamelCMSContext *context)
+{
+ context->priv = g_new0 (struct _CamelCMSContextPrivate, 1);
+#ifdef ENABLE_THREADS
+ context->priv->lock = g_mutex_new ();
+#endif
+}
+
+static void
+camel_cms_context_finalise (CamelObject *o)
+{
+ CamelCMSContext *context = (CamelCMSContext *)o;
+
+ camel_object_unref (CAMEL_OBJECT (context->session));
+
+#ifdef ENABLE_THREADS
+ g_mutex_free (context->priv->lock);
+#endif
+
+ g_free (context->priv);
+}
+
+static void
+camel_cms_context_class_init (CamelCMSContextClass *camel_cms_context_class)
+{
+ parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
+
+ camel_cms_context_class->sign = cms_sign;
+ camel_cms_context_class->certsonly = cms_certsonly;
+ camel_cms_context_class->encrypt = cms_encrypt;
+ camel_cms_context_class->envelope = cms_envelope;
+ camel_cms_context_class->decode = cms_decode;
+}
+
+CamelType
+camel_cms_context_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (camel_object_get_type (),
+ "CamelCMSContext",
+ sizeof (CamelCMSContext),
+ sizeof (CamelCMSContextClass),
+ (CamelObjectClassInitFunc) camel_cms_context_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_cms_context_init,
+ (CamelObjectFinalizeFunc) camel_cms_context_finalise);
+ }
+
+ return type;
+}
+
+
+/**
+ * camel_cms_context_new:
+ * @session: CamelSession
+ * @encryption_key: preferred encryption key nickname
+ *
+ * This creates a new CamelCMSContext object which is used to sign,
+ * encrypt, envelope and decode CMS messages.
+ *
+ * Return value: the new CamelCMSContext
+ **/
+CamelCMSContext *
+camel_cms_context_new (CamelSession *session)
+{
+ CamelCMSContext *context;
+
+ g_return_val_if_fail (session != NULL, NULL);
+ g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
+
+ context = CAMEL_CMS_CONTEXT (camel_object_new (CAMEL_CMS_CONTEXT_TYPE));
+
+ camel_object_ref (CAMEL_OBJECT (session));
+ context->session = session;
+
+ return context;
+}
+
+
+/**
+ * camel_cms_context_construct:
+ * @context: CMS Context
+ * @session: CamelSession
+ *
+ * Construct the CMS Context.
+ **/
+void
+camel_cms_context_construct (CamelCMSContext *context, CamelSession *session)
+{
+ g_return_if_fail (CAMEL_IS_CMS_CONTEXT (context));
+ g_return_if_fail (CAMEL_IS_SESSION (session));
+
+ camel_object_ref (CAMEL_OBJECT (session));
+ context->session = session;
+}
+
+
+static CamelMimeMessage *
+cms_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex)
+{
+ g_warning ("Using default CamelCMSContext::sign() method.");
+
+ return NULL;
+}
+
+
+CamelMimeMessage *
+camel_cms_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_CMS_CONTEXT (ctx), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_val_if_fail (userid != NULL, NULL);
+
+ return CCC_CLASS (ctx)->sign (ctx, message, userid, signing_time, detached, ex);
+}
+
+
+static CamelMimeMessage *
+cms_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
+{
+ g_warning ("Using default CamelCMSContext::certsonly() method.");
+
+ return NULL;
+}
+
+
+CamelMimeMessage *
+camel_cms_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_CMS_CONTEXT (ctx), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_val_if_fail (userid != NULL, NULL);
+ g_return_val_if_fail (recipients != NULL, NULL);
+
+ return CCC_CLASS (ctx)->certsonly (ctx, message, userid, recipients, ex);
+}
+
+
+static CamelMimeMessage *
+cms_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
+{
+ g_warning ("Using default CamelCMSContext::envelope() method.");
+
+ return NULL;
+}
+
+
+CamelMimeMessage *
+camel_cms_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_CMS_CONTEXT (ctx), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_val_if_fail (userid != NULL, NULL);
+ g_return_val_if_fail (recipients != NULL, NULL);
+
+ return CCC_CLASS (ctx)->envelope (ctx, message, userid, recipients, ex);
+}
+
+
+static CamelMimeMessage *
+cms_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
+{
+ g_warning ("Using default CamelCMSContext::encrypt() method.");
+
+ return NULL;
+}
+
+
+CamelMimeMessage *
+camel_cms_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_CMS_CONTEXT (ctx), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_val_if_fail (userid != NULL, NULL);
+ g_return_val_if_fail (recipients != NULL, NULL);
+
+ return CCC_CLASS (ctx)->encrypt (ctx, message, userid, recipients, ex);
+}
+
+
+static CamelMimeMessage *
+cms_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex)
+{
+ g_warning ("Using default CamelCMSContext::decode() method.");
+
+ return NULL;
+}
+
+
+CamelMimeMessage *
+camel_cms_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex)
+{
+ g_return_val_if_fail (CAMEL_IS_CMS_CONTEXT (ctx), NULL);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+ return CCC_CLASS (ctx)->decode (ctx, message, info, ex);
+}
+
+
+void
+camel_cms_signer_free (CamelCMSSigner *signer)
+{
+ CamelCMSSigner *next;
+
+ if (!signer)
+ return;
+
+ while (signer) {
+ next = signer->next;
+ g_free (signer->signercn);
+ g_free (signer->status);
+ g_free (signer);
+ signer = next;
+ }
+}
+
+
+void
+camel_cms_validity_info_free (CamelCMSValidityInfo *info)
+{
+ CamelCMSValidityInfo *next;
+
+ if (!info)
+ return;
+
+ while (info) {
+ next = info->next;
+ if (info->type == CAMEL_CMS_TYPE_SIGNED)
+ camel_cms_signer_free (info->signers);
+ g_free (info);
+ info = next;
+ }
+}
diff --git a/camel/camel-cms-context.h b/camel/camel-cms-context.h
new file mode 100644
index 0000000000..b68547e8b0
--- /dev/null
+++ b/camel/camel-cms-context.h
@@ -0,0 +1,128 @@
+/* -*- 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_CMS_CONTEXT_H
+#define CAMEL_CMS_CONTEXT_H
+
+#include <camel/camel-session.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-exception.h>
+#include <camel/camel-mime-message.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define CAMEL_CMS_CONTEXT_TYPE (camel_cms_context_get_type ())
+#define CAMEL_CMS_CONTEXT(obj) (CAMEL_CHECK_CAST((obj), CAMEL_CMS_CONTEXT_TYPE, CamelCMSContext))
+#define CAMEL_CMS_CONTEXT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_CMS_CONTEXT_TYPE, CamelCMSContextClass))
+#define CAMEL_IS_CMS_CONTEXT(o) (CAMEL_CHECK_TYPE((o), CAMEL_CMS_CONTEXT_TYPE))
+
+typedef enum {
+ CAMEL_CMS_TYPE_DATA,
+ CAMEL_CMS_TYPE_SIGNED,
+ CAMEL_CMS_TYPE_ENVELOPED,
+ CAMEL_CMS_TYPE_ENCRYPTED
+} CamelCMSType;
+
+typedef struct _CamelCMSSigner {
+ struct _CamelCMSSigner *next;
+ char *signercn;
+ char *status;
+} CamelCMSSigner;
+
+typedef struct _CamelCMSValidityInfo {
+ struct _CamelCMSValidityInfo *next;
+ CamelCMSType type;
+ CamelCMSSigner *signers;
+} CamelCMSValidityInfo;
+
+
+typedef struct _CamelCMSContext {
+ CamelObject parent_object;
+
+ struct _CamelCMSContextPrivate *priv;
+
+ CamelSession *session;
+} CamelCMSContext;
+
+typedef struct _CamelCMSContextClass {
+ CamelObjectClass parent_class;
+
+ CamelMimeMessage *(*sign) (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex);
+
+ CamelMimeMessage *(*certsonly) (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+ CamelMimeMessage *(*encrypt) (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+ CamelMimeMessage *(*envelope) (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+ CamelMimeMessage *(*decode) (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex);
+
+} CamelCMSContextClass;
+
+CamelType camel_cms_context_get_type (void);
+
+CamelCMSContext *camel_cms_context_new (CamelSession *session);
+
+void camel_cms_context_construct (CamelCMSContext *context, CamelSession *session);
+
+/* cms routines */
+CamelMimeMessage *camel_cms_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex);
+
+CamelMimeMessage *camel_cms_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+CamelMimeMessage *camel_cms_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+CamelMimeMessage *camel_cms_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+CamelMimeMessage *camel_cms_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex);
+
+
+void camel_cms_signer_free (CamelCMSSigner *signer);
+
+void camel_cms_validity_info_free (CamelCMSValidityInfo *info);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAMEL_CMS_CONTEXT_H */
diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c
index 7115c13ad1..7d2814fb82 100644
--- a/camel/camel-smime-context.c
+++ b/camel/camel-smime-context.c
@@ -27,18 +27,14 @@
#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 "nss.h"
-#include <cert.h>
-#include <certt.h>
-#include <certdb.h>
-#include <hasht.h>
-#include <keylow.h>
-#include <secpkcs7.h>
-#include <secmime.h>
-#include <smime.h>
+#include <cms.h>
#include <gtk/gtk.h> /* for _() macro */
@@ -49,20 +45,24 @@ struct _CamelSMimeContextPrivate {
};
-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, CamelCipherHash hash,
- CamelStream *istream, CamelStream *sigstream,
+static CamelMimeMessage *smime_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex);
+
+static CamelMimeMessage *smime_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+static CamelMimeMessage *smime_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex);
+
+static CamelMimeMessage *smime_envelope (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
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 CamelMimeMessage *smime_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex);
static CamelCipherContextClass *parent_class;
@@ -77,22 +77,23 @@ camel_smime_context_finalise (CamelObject *o)
{
CamelSMimeContext *context = (CamelSMimeContext *)o;
+ g_free (context->encryption_key);
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);
+ CamelCMSContextClass *camel_cms_context_class =
+ CAMEL_CMS_CONTEXT_CLASS (camel_smime_context_class);
- parent_class = CAMEL_CIPHER_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cipher_context_get_type ()));
+ parent_class = CAMEL_CMS_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cms_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;
+ camel_cms_context_class->sign = cms_sign;
+ camel_cms_context_class->certsonly = cms_certsonly;
+ camel_cms_context_class->encrypt = cms_encrypt;
+ camel_cms_context_class->envelope = cms_envelope;
+ camel_cms_context_class->decode = cms_decode;
}
CamelType
@@ -101,7 +102,7 @@ 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 (),
+ type = camel_type_register (camel_cms_context_get_type (),
"CamelSMimeContext",
sizeof (CamelSMimeContext),
sizeof (CamelSMimeContextClass),
@@ -118,6 +119,7 @@ camel_smime_context_get_type (void)
/**
* 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.
@@ -125,519 +127,811 @@ camel_smime_context_get_type (void)
* Return value: the new CamelSMimeContext
**/
CamelSMimeContext *
-camel_smime_context_new (CamelSession *session)
+camel_smime_context_new (CamelSession *session, const char *encryption_key)
{
CamelSMimeContext *context;
- CERTCertDBHandle *handle;
+ 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_cipher_context_construct (CAMEL_CIPHER_CONTEXT (context), session);
+ camel_cms_context_construct (CAMEL_CMS_CONTEXT (context), session);
- handle = CERT_GetDefaultCertDB ();
- if (!handle) {
- camel_object_unref (CAMEL_OBJECT (context));
- return NULL;
- }
-
- context->priv->certdb = handle;
+ context->encryption_key = g_strdup (encryption_key);
+ context->priv->certdb = certdb;
return context;
}
-/*----------------------------------------------------------------------*
- * Public crypto functions
- *----------------------------------------------------------------------*/
struct _GetPasswdData {
CamelSession *session;
- CamelException *ex;
const char *userid;
+ CamelException *ex;
};
-static SECItem *
-get_zero_len_passwd (SECKEYKeyDBHandle *handle)
+static char *
+smime_get_password (PK11SlotInfo *info, PRBool retry, void *arg)
{
- SECItem *pwitem;
- SECStatus rv;
+ CamelSession *session = ((struct _GetPasswdData *)arg)->session;
+ const char *userid = ((struct _GetPasswdData *)arg)->userid;
+ CamelException *ex = ((struct _GetPasswdData *)arg)->ex;
+ char *prompt, *passwd, *ret;
- /* hash the empty string as a password */
- pwitem = SECKEY_DeriveKeyDBPassword (handle, "");
- if (pwitem == NULL)
- return NULL;
+ prompt = g_strdup_printf (_("Please enter your password for %s"), userid);
+ passwd = camel_session_get_password (session, prompt, TRUE,
+ NULL, userid, ex);
+ g_free (prompt);
- /* check to see if this is the right password */
- rv = SECKEY_CheckKeyDBPassword (handle, pwitem);
- if (rv == SECFailure)
- return NULL;
+ ret = PL_strdup (passwd);
+ g_free (passwd);
- return pwitem;
+ return ret;
+}
+
+static PK11SymKey *
+decode_key_cb (void *arg, SECAlgorithmID *algid)
+{
+ return (PK11SymKey *)arg;
}
-static SECItem *
-get_password (void *arg, SECKEYKeyDBHandle *handle)
+
+static NSSCMSMessage *
+signed_data (CamelSMimeContext *ctx, const char *userid, gboolean signing_time,
+ gboolean detached, CamelException *ex)
{
- 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;
+ 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."));
+ return NULL;
+ }
- prompt = g_strdup_printf (_("Please enter your password for %s"), userid);
- passwd = camel_session_get_password (session, prompt, TRUE,
- NULL, userid, NULL);
- g_free (prompt);
+ if ((cert = CERT_FindCertByNickname (ctx->priv->certdb, userid)) == NULL) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("The signature certificate for \"%s\" does not exist."),
+ userid);
+ return NULL;
+ }
+
+ /* create the cms message object */
+ cmsg = NSS_CMSMessage_Create (NULL);
+
+ /* build chain of objects: message->signedData->data */
+ sigd = NSS_CMSSignedData_Create (cmsg);
- /* hash the password */
- pwitem = SECKEY_DeriveKeyDBPassword (handle, passwd ? passwd : "");
+ cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
+ NSS_CMSContentInfo_SetContent_SignedData (cmsg, cinfo, sigd);
- /* clear out the password strings */
- if (passwd) {
- memset (passwd, 0, strlen (passwd));
- g_free (passwd);
+ 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 (pwitem == NULL) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Error hashing password."));
-
- return NULL;
+ if (TRUE) {
+ /* Add S/MIME Capabilities */
+ NSS_CMSSignerInfo_AddSMIMECaps (signerinfo);
}
- /* confirm the password */
- rv = SECKEY_CheckKeyDBPassword (handle, pwitem);
- if (rv) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Invalid password."));
+ 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;
+ }
- SECITEM_ZfreeItem (pwitem, PR_TRUE);
+ NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs (signerinfo, ekpcert, ctx->priv->certdb);
- return NULL;
+ 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);
}
- 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;
- }
+ NSS_CMSSignedData_AddSignerInfo (sigd, signerinfo);
- 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;
- }
+ return cmsg;
+
+ exception:
+
+ NSS_CMSMessage_Destroy (cmsg);
+
+ return NULL;
}
-static int
-smime_digest (SECItem *data, char *digestdata, unsigned int *len, unsigned int maxlen, HASH_HashType hash)
+static void
+smime_sign_restore (CamelMimePart *mime_part, GSList *encodings)
{
- const SECHashObject *hashObj;
- void *hashcx;
+ CamelDataWrapper *wrapper;
- hashObj = &SECHashObjects[hash];
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+ if (!wrapper)
+ return;
- 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;
+ 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 {
+ CamelMimePartEncodingType encoding;
+
+ encoding = GPOINTER_TO_INT (encodings->data);
+
+ camel_mime_part_set_encoding (mime_part, encoding);
+ }
}
static void
-smime_output_cb (void *arg, const char *buf, unsigned long len)
+smime_sign_prepare (CamelMimePart *mime_part, GSList **encodings)
{
- CamelStream *stream;
-
- stream = CAMEL_STREAM (arg);
- camel_stream_write (stream, buf, len);
+ 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 {
+ CamelMimePartEncodingType encoding;
+
+ 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_MIME_PART_ENCODING_BASE64)
+ camel_mime_part_set_encoding (mime_part, CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE);
+
+ *encodings = g_slist_append (*encodings, GINT_TO_POINTER (encoding));
+ }
}
-static int
-smime_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+
+static CamelMimeMessage *
+smime_sign (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, gboolean signing_time,
+ gboolean detached, 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];
+ CamelMimeMessage *mesg = NULL;
+ NSSCMSMessage *cmsg = NULL;
+ struct _GetPasswdData *data;
+ PLArenaPool *arena;
+ NSSCMSEncoderContext *ecx;
+ SECItem output = { 0, 0, 0 };
CamelStream *stream;
+ GSList *encodings = NULL;
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);
+ 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 ();
- camel_stream_write_to_stream (istream, stream);
+
+ smime_sign_prepare (CAMEL_MIME_PART (message), &encodings);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
+ smime_sign_restore (CAMEL_MIME_PART (message), encodings);
+ g_slist_free (encodings);
+
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;
+ NSS_CMSEncoder_Update (ecx, buf->data, buf->len);
+ NSS_CMSEncoder_Finish (ecx);
camel_object_unref (CAMEL_OBJECT (stream));
+ g_free (data);
- cert = CERT_FindCertByNickname (context->priv->certdb, (char *) userid);
- if (!cert) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not sign: certificate not found for \"%s\"."),
- userid);
- return -1;
- }
+ /* 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);
- data = g_new (struct _GetPasswdData, 1);
- data->session = ctx->session;
- data->userid = userid;
- data->ex = ex;
+ NSS_CMSMessage_Destroy (cmsg);
- cinfo = SECMIME_CreateSigned (cert, cert, context->priv->certdb,
- nss_hash_to_sec_oid (hash_type),
- &digest, get_password, data);
+ /* 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 (CAMEL_OBJECT (stream));
- if (cinfo == NULL) {
+ return mesg;
+}
+
+
+static NSSCMSMessage *
+certsonly_data (CamelSMimeContext *ctx, const char *userid, GByteArray *recipients, CamelException *ex)
+{
+ NSSCMSMessage *cmsg = NULL;
+ NSSCMSContentInfo *cinfo;
+ NSSCMSSignedData *sigd;
+ CERTCertificate **rcerts;
+ int i;
+
+ /* find the signer's and the recipients' certs */
+ rcerts = g_new (CERTCertificate *, recipients->len + 2);
+ rcerts[0] = CERT_FindCertByNicknameOrEmailAddr (ctx->priv->certdb, userid);
+ if (!rcerts[0]) {
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not sign: failed to create content info."));
+ _("Failed to find certificate for \"%s\"."),
+ recipients->pdata[i]);
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;
+ 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;
- if (SEC_PKCS7EncoderFinish (ecx, NULL, NULL) != SECSuccess) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not sign: failed to create signature."));
- goto exception;
+ /* 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, certs[i]);
}
- g_free (data);
+ cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
+ NSS_CMSContentInfo_SetContent_SignedData (cmsg, cinfo, sigd);
- SEC_PKCS7DestroyContentInfo (cinfo);
+ cinfo = NSS_CMSSignedData_GetContentInfo (sigd);
+ NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, PR_FALSE);
+
+ g_free (rcerts);
+
+ return cmsg;
- return 0;
-
exception:
- if (cinfo)
- SEC_PKCS7DestroyContentInfo (cinfo);
+ NSS_CMSMessage_Destroy (cmsg);
- if (data)
- g_free (data);
+ g_free (rcerts);
- 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;
+ return NULL;
}
-#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)
+static CamelMimeMessage *
+smime_certsonly (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
{
- CamelSMimeContext *context = CAMEL_SMIME_CONTEXT (ctx);
- CamelCipherValidity *valid = NULL;
- SEC_PKCS7ContentInfo *cinfo;
- SECCertUsage usage;
- GByteArray *plaintext;
+ CamelMimeMessage *mesg = NULL;
+ NSSCMSMessage *cmsg = NULL;
+ PLArenaPool *arena;
+ NSSCMSEncoderContext *ecx;
+ SECItem output = { 0, 0, 0 };
CamelStream *stream;
- gboolean isvalid;
+ GByteArray *buf;
- /* 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));
+ cmsg = certsonly_data (CAMEL_SMIME_CONTEXT (ctx), userid, recipients, ex);
+ if (!cmsg)
+ return NULL;
- usage = certUsageEmailSigner; /* just a guess. or maybe certUsageVerifyCA?? */
+ 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);
- valid = camel_cipher_validity_new ();
+ stream = camel_stream_mem_new ();
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
+ buf = CAMEL_STREAM_MEM (stream)->buffer;
- 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;
- }
-
- isvalid = SEC_PKCS7VerifyDetachedSignature (cinfo, usage, &digest,
- digest_type, PR_FALSE);
- camel_object_unref (CAMEL_OBJECT (stream));
- } else {
- isvalid = SEC_PKCS7VerifySignature (cinfo, usage, PR_FALSE);
- }
+ NSS_CMSEncoder_Update (ecx, buf->data, buf->len);
+ NSS_CMSEncoder_Finish (ecx);
+
+ camel_object_unref (CAMEL_OBJECT (stream));
+ g_free (data);
- camel_cipher_validity_set_valid (valid, isvalid);
+ /* 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);
- SEC_PKCS7DestroyContentInfo (cinfo);
+ NSS_CMSMessage_Destroy (cmsg);
- /* FIXME: set a meaningful description...in UTF8 */
- camel_cipher_validity_set_description (valid, "");
+ /* 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 (CAMEL_OBJECT (stream));
- return valid;
+ return mesg;
}
-static int
-smime_encrypt (CamelCipherContext *ctx, gboolean sign, const char *userid, GPtrArray *recipients,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
+
+static NSSCMSMessage *
+enveloped_data (CamelSMimeContext *ctx, const char *userid, GPtrArray *recipients, 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;
- 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, (char *) userid);
- if (!scert) {
- invalid_userkey = recipients->pdata[i];
+ 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, userid);
+ if (!rcerts[0]) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to find certificate for \"%s\"."),
+ userid);
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];
+ 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;
}
-
- g_ptr_array_add (certificates, cert);
}
- g_ptr_array_add (certificates, NULL);
+ 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;
+ }
+
+ /* 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);
+ }
+
+ 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;
+ 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);
- cinfo = SECMIME_CreateEncrypted (scert, (CERTCertificate **) certificates->pdata,
- context->priv->certdb, get_password, data);
-
- g_free (data);
+ stream = camel_stream_mem_new ();
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
+ buf = CAMEL_STREAM_MEM (stream)->buffer;
- if (!cinfo) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not encrypt: failed to create enveloped data."));
- goto exception;
- }
+ NSS_CMSEncoder_Update (ecx, buf->data, buf->len);
+ NSS_CMSEncoder_Finish (ecx);
- 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;
- }
+ camel_object_unref (CAMEL_OBJECT (stream));
+ g_free (data);
+ /* write the result to a camel stream */
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_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 (CAMEL_OBJECT (stream));
- stream = NULL;
- if (SEC_PKCS7EncoderFinish (ecx, NULL, NULL) != SECSuccess)
- goto exception;
+ return mesg;
+}
+
+
+struct _BulkKey {
+ PK11KeySym *bulkkey;
+ SECOidTag bulkkeytag;
+ int keysize;
+};
+
+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 };
- g_ptr_array_free (certificates, TRUE);
+ /* arena for output */
+ arena = PORT_NewArena (1024);
- SEC_PKCS7DestroyContentInfo (cinfo);
+ /* create cms message object */
+ cmsg = NSS_CMSMessage_Create (NULL);
- return 0;
+ encd = NSS_CMSEncryptedData_Create (cmsg, key->bulkalgtag, key->keysize);
- exception:
+ cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
+ NSS_CMSContentInfo_SetContent_EncryptedData (cmsg, cinfo, encd);
- if (certificates)
- g_ptr_array_free (certificates, TRUE);
+ cinfo = NSS_CMSEncryptedData_GetContentInfo (encd);
+ NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, PR_FALSE);
- if (stream)
- camel_object_unref (CAMEL_OBJECT (stream));
+ ecx = NSS_CMSEncoder_Start (cmsg, NULL, NULL, &output, arena, NULL, NULL,
+ decode_key_cb, key->bulkkey, NULL, NULL);
- if (cinfo)
- SEC_PKCS7DestroyContentInfo (cinfo);
+ NSS_CMSEncoder_Update (ecx, input->data, input->len);
- if (invalid_userkey) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not encrypt data: invalid user key: \"%s\"."),
- invalid_userkey);
- }
+ NSS_CMSEncoder_Finish (ecx);
- if (!camel_exception_is_set (ex)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not encrypt: encoding failed."));
- }
+ camel_stream_write (ostream, output.data, output.len);
- return -1;
+ if (arena)
+ PORT_FreeArena (arena, PR_FALSE);
+
+ return cmsg;
}
-static PRBool
-decryption_allowed (SECAlgorithmID *algid, PK11SymKey *key)
+static struct _BulkKey *
+get_bulkkey (CamelSMimeContext *ctx, const char *userid, GPtrArray *recipients, CamelException *ex)
{
- return PR_TRUE;
+ 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;
+ }
+ }
+
+ return NULL;
}
-static int
-smime_decrypt (CamelCipherContext *ctx, CamelStream *istream,
- CamelStream *ostream, CamelException *ex)
+static CamelMimeMessage *
+smime_encrypt (CamelCMSContext *ctx, CamelMimeMessage *message,
+ const char *userid, GPtrArray *recipients,
+ CamelException *ex)
{
- struct _GetPasswdData *data;
- SEC_PKCS7DecoderContext *dcx;
- SEC_PKCS7ContentInfo *cinfo;
- CamelStream *stream = NULL;
- SECItem secdata;
+ struct _BulkKey *bulkkey = NULL;
+ CamelMimeMessage *mesg = NULL;
+ NSSCMSMessage *cmsg = NULL;
+ CamelStream *stream;
GByteArray *buf;
- g_return_val_if_fail (istream != NULL, -1);
- g_return_val_if_fail (ostream != NULL, -1);
+ 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_write_to_stream (istream, stream);
- buf = CAMEL_STREAM_MEM (stream)->buffer;
- secdata.data = buf->data;
- secdata.len = buf->len;
+ 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 (CAMEL_OBJECT (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 (CAMEL_OBJECT (stream));
+ return NULL;
+ }
+
+ 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 (CAMEL_OBJECT (stream));
+
+ return mesg;
+}
+
+
+static NSSCMSMessage *
+decode (CamelSMimeContext *ctx, GByteArray *input, CamelStream *ostream,
+ CamelCMSValidityInfo **info, CamelExcepton *ex)
+{
+ NSSCMSDecoderContext *dcx;
+ struct _GetPasswdData *data;
+ CamelCMSValidityInfo *vinfo = NULL;
+ NSSCMSMessage *cmsg = NULL;
+ NSSCMSContentInfo *cinfo;
+ NSSCMSSignedData *sigd = NULL;
+ NSSCMSEnvelopedData *envd;
+ NSSCMSEncryptedData *encd;
+ SECAlgorithmID **digestalgs;
+ int nlevels, i, nsigners, j;
+ char *signercn;
+ NSSCMSSignerInfo *si;
+ SECOidTag typetag;
+ SECItem **digests;
+ PLArenaPool *arena;
+ SECItem *item, sitem = { 0, 0, 0 };
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;
+ dcx = NSS_CMSDecoder_Start (NULL,
+ NULL, NULL,
+ smime_get_password, data,
+ decode_key_cb,
+ decodeOptions->bulkkey);
- SEC_PKCS7DecoderUpdate (dcx, secdata.data, secdata.len);
- cinfo = SEC_PKCS7DecoderFinish (dcx);
+ NSS_CMSDecoder_Update (dcx, input->data, input->len);
- camel_object_unref (CAMEL_OBJECT (stream));
+ cmsg = NSS_CMSDecoder_Finish (dcx);
g_free (data);
+ if (cmsg == NULL) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to decode message."));
+ return NULL;
+ }
- if (cinfo == NULL) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Failed to decrypt: Unknown"));
- return -1;
+ 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;
+ }
+
+ 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;
+ }
+
+ return cmsg;
+ }
+
+ for (j = 0; vinfo && j < nsigners; j++) {
+ if (!signers) {
+ signers = g_new0 (CamelCMSSigner, 1);
+ vinfo->signers = signers;
+ } else {
+ signers->next = g_new0 (CamelCMSSigner, 1);
+ signers = signers->next;
+ }
+
+ 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->signeercn = g_strdup (signercn);
+ signers->status = g_strdup (
+ NSS_CMSUtil_VerificationStatusToString (
+ NSS_CMSSignerInfo_GetVerificationStatus (si)));
+ }
+ }
+ break;
+ case SEC_OID_PKCS7_ENVELOPED_DATA:
+ if (vinfo)
+ vinfo->type = CAMEL_CMS_TYPE_ENVELOPED;
+
+ envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent (cinfo);
+ break;
+ case SEC_OID_PKCS7_ENCRYPTED_DATA:
+ if (vinfo)
+ vinfo->type = CAMEL_CMS_TYPE_ENCRYPTED;
+
+ encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent (cinfo);
+ break;
+ case SEC_OID_PKCS7_DATA:
+ break;
+ default:
+ break;
+ }
}
- SEC_PKCS7DestroyContentInfo (cinfo);
+ item = NSS_CMSMessage_GetContent (cmsg);
+ camel_stream_write (ostream, item->data, item->len);
- return 0;
+ return cmsg;
exception:
- if (stream)
- camel_object_unref (CAMEL_OBJECT (stream));
+ if (info)
+ camel_cms_validity_info_free (*info);
+
+ if (cmsg)
+ NSS_CMSMessage_Destroy (cmsg);
+
+ return NULL;
+}
+
+
+static CamelMimeMessage *
+smime_decode (CamelCMSContext *ctx, CamelMimeMessage *message,
+ CamelCMSValidityInfo **info, CamelException *ex)
+{
+ CamelMimeMessage *mesg = NULL;
+ 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 (CAMEL_SMIME_CONTEXT (ctx), buf, ostream, info, ex);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ if (!cmsg) {
+ camel_object_unref (CAMEL_OBJECT (ostream));
+ return NULL;
+ }
+
+ /* 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 (CAMEL_OBJECT (ostream));
- return -1;
+ return mesg;
}
#endif /* HAVE_NSS */
diff --git a/camel/camel-smime-context.h b/camel/camel-smime-context.h
index 0ced7b9c1b..3a2214fc3a 100644
--- a/camel/camel-smime-context.h
+++ b/camel/camel-smime-context.h
@@ -24,9 +24,8 @@
#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>
+#include <camel/camel-cms-context.h>
#ifdef __cplusplus
extern "C" {
@@ -39,32 +38,21 @@ extern "C" {
#define CAMEL_IS_SMIME_CONTEXT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SMIME_CONTEXT_TYPE))
typedef struct _CamelSMimeContext {
- CamelCipherContext parent_object;
+ CamelCMSContext parent_object;
struct _CamelSMimeContextPrivate *priv;
} CamelSMimeContext;
typedef struct _CamelSMimeContextClass {
- CamelCipherContextClass parent_class;
+ CamelCMSContextClass parent_class;
} CamelSMimeContextClass;
CamelType camel_smime_context_get_type (void);
-CamelSMimeContext *camel_smime_context_new (CamelSession *session);
-
-/* 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, h, i, s, e) camel_cipher_verify (CAMEL_CIPHER_CONTEXT (c), h, 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)
+CamelSMimeContext *camel_smime_context_new (CamelSession *session, const char *encryption_key);
#ifdef __cplusplus
}
diff --git a/camel/camel-smime-utils.c b/camel/camel-smime-utils.c
new file mode 100644
index 0000000000..cf588898f3
--- /dev/null
+++ b/camel/camel-smime-utils.c
@@ -0,0 +1,126 @@
+/* -*- 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-utils.h"
+#include "camel-multipart.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define d(x) x
+
+/** rfc2633 stuff (aka S/MIME v3) ********************************/
+
+gboolean
+camel_smime_is_smime_v3_signed (CamelMimePart *mime_part)
+{
+ CamelDataWrapper *wrapper;
+ CamelMultipart *mp;
+ CamelMimePart *part;
+ CamelContentType *type;
+ const gchar *param, *micalg;
+ int nparts;
+
+ /* check that we have a multipart/signed */
+ type = camel_mime_part_get_content_type (mime_part);
+ if (!header_content_type_is (type, "multipart", "signed"))
+ return FALSE;
+
+ /* check that we have a protocol param with the value: "application/pkcs7-signature" */
+ param = header_content_type_param (type, "protocol");
+ if (!param || g_strcasecmp (param, "application/pkcs7-signature"))
+ return FALSE;
+
+ /* check that we have a micalg parameter */
+ micalg = header_content_type_param (type, "micalg");
+ if (!micalg)
+ return FALSE;
+
+ /* check that we have exactly 2 subparts */
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+ mp = CAMEL_MULTIPART (wrapper);
+ nparts = camel_multipart_get_number (mp);
+ if (nparts != 2)
+ return FALSE;
+
+ /* The first part may be of any type except for
+ * application/pkcs7-signature - check it. */
+ part = camel_multipart_get_part (mp, 0);
+ type = camel_mime_part_get_content_type (part);
+ if (header_content_type_is (type, "application", "pkcs7-signature"))
+ return FALSE;
+
+ /* The second part should be application/pkcs7-signature. */
+ part = camel_multipart_get_part (mp, 1);
+ type = camel_mime_part_get_content_type (part);
+ if (!header_content_type_is (type, "application", "pkcs7-signature"))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+camel_smime_is_smime_v3_encrypted (CamelMimePart *mime_part)
+{
+ char *types[] = { "p7m", "p7c", "p7s", NULL };
+ const gchar *param, *filename;
+ CamelContentType *type;
+ int i;
+
+ /* check that we have a application/pkcs7-mime part */
+ type = camel_mime_part_get_content_type (mime_part);
+ if (header_content_type_is (type, "application", "pkcs7-mime")) {
+ /* check to make sure it's an encrypted pkcs7-mime part? */
+ return TRUE;
+ }
+
+ if (header_content_type_is (type, "application", "octent-stream")) {
+ /* check to see if we have a paremeter called "smime-type" */
+ param = header_content_type_param (type, "smime-type");
+ if (param)
+ return TRUE;
+
+ /* check to see if there is a name param and if it has a smime extension */
+ param = header_content_type_param (type, "smime-type");
+ if (param && *param && strlen (param) > 4) {
+ for (i = 0; types[i]; i++)
+ if (!g_strcasecmp (param + strlen (param)-4, types[i]))
+ return TRUE;
+ }
+
+ /* check to see if there is a name param and if it has a smime extension */
+ filename = camel_mime_part_get_filename (mime_part);
+ if (filename && *filename && strlen (filename) > 4) {
+ for (i = 0; types[i]; i++)
+ if (!g_strcasecmp (filename + strlen (filename)-4, types[i]))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/camel/camel-smime.h b/camel/camel-smime-utils.h
index 67cb027588..4d955baa77 100644
--- a/camel/camel-smime.h
+++ b/camel/camel-smime-utils.h
@@ -21,13 +21,11 @@
*/
-#ifndef CAMEL_SMIME_H
-#define CAMEL_SMIME_H
+#ifndef CAMEL_SMIME_UTILS_H
+#define CAMEL_SMIME_UTILS_H
#include <glib.h>
#include <camel/camel-mime-part.h>
-#include <camel/camel-smime-context.h>
-#include <camel/camel-exception.h>
#ifdef __cplusplus
extern "C" {
@@ -35,29 +33,11 @@ extern "C" {
#endif /* __cplusplus */
gboolean camel_smime_is_smime_v3_signed (CamelMimePart *part);
-gboolean camel_smime_is_smime_v3_encrypted (CamelMimePart *part);
-
-void camel_smime_part_sign (CamelSMimeContext *context,
- CamelMimePart **mime_part,
- const char *userid,
- CamelCipherHash hash,
- CamelException *ex);
-
-CamelCipherValidity *camel_smime_part_verify (CamelSMimeContext *context,
- CamelMimePart *mime_part,
- CamelException *ex);
-void camel_smime_part_encrypt (CamelSMimeContext *context,
- CamelMimePart **mime_part,
- GPtrArray *recipients,
- CamelException *ex);
-
-CamelMimePart *camel_smime_part_decrypt (CamelSMimeContext *context,
- CamelMimePart *mime_part,
- CamelException *ex);
+gboolean camel_smime_is_smime_v3_encrypted (CamelMimePart *part);
#ifdef __cplusplus
}
#endif /* __cplusplus */
-#endif /* ! CAMEL_SMIME_H */
+#endif /* ! CAMEL_SMIME_UTILS_H */
diff --git a/camel/camel-smime.c b/camel/camel-smime.c
deleted file mode 100644
index 587fcb6057..0000000000
--- a/camel/camel-smime.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/* -*- 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.h"
-#include "camel-mime-filter-from.h"
-#include "camel-mime-filter-crlf.h"
-#include "camel-stream-filter.h"
-#include "camel-stream-mem.h"
-#include "camel-multipart.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define d(x) x
-
-/** rfc2633 stuff (aka S/MIME v3) ********************************/
-
-gboolean
-camel_smime_is_smime_v3_signed (CamelMimePart *mime_part)
-{
- CamelDataWrapper *wrapper;
- CamelMultipart *mp;
- CamelMimePart *part;
- CamelContentType *type;
- const gchar *param, *micalg;
- int nparts;
-
- /* check that we have a multipart/signed */
- type = camel_mime_part_get_content_type (mime_part);
- if (!header_content_type_is (type, "multipart", "signed"))
- return FALSE;
-
- /* check that we have a protocol param with the value: "application/pkcs7-signature" */
- param = header_content_type_param (type, "protocol");
- if (!param || g_strcasecmp (param, "application/pkcs7-signature"))
- return FALSE;
-
- /* check that we have a micalg parameter */
- micalg = header_content_type_param (type, "micalg");
- if (!micalg)
- return FALSE;
-
- /* check that we have exactly 2 subparts */
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
- mp = CAMEL_MULTIPART (wrapper);
- nparts = camel_multipart_get_number (mp);
- if (nparts != 2)
- return FALSE;
-
- /* The first part may be of any type except for
- * application/pkcs7-signature - check it. */
- part = camel_multipart_get_part (mp, 0);
- type = camel_mime_part_get_content_type (part);
- if (header_content_type_is (type, "application", "pkcs7-signature"))
- return FALSE;
-
- /* The second part should be application/pkcs7-signature. */
- part = camel_multipart_get_part (mp, 1);
- type = camel_mime_part_get_content_type (part);
- if (!header_content_type_is (type, "application", "pkcs7-signature"))
- return FALSE;
-
- return TRUE;
-}
-
-gboolean
-camel_smime_is_smime_v3_encrypted (CamelMimePart *mime_part)
-{
- char *types[] = { "p7m", "p7c", "p7s", NULL };
- const gchar *param, *filename;
- CamelContentType *type;
- int i;
-
- /* check that we have a application/pkcs7-mime part */
- type = camel_mime_part_get_content_type (mime_part);
- if (header_content_type_is (type, "application", "pkcs7-mime")) {
- /* check to make sure it's an encrypted pkcs7-mime part? */
- return TRUE;
- }
-
- if (header_content_type_is (type, "application", "octent-stream")) {
- /* check to see if we have a paremeter called "smime-type" */
- param = header_content_type_param (type, "smime-type");
- if (param)
- return TRUE;
-
- /* check to see if there is a name param and if it has a smime extension */
- param = header_content_type_param (type, "smime-type");
- if (param && *param && strlen (param) > 4) {
- for (i = 0; types[i]; i++)
- if (!g_strcasecmp (param + strlen (param)-4, types[i]))
- return TRUE;
- }
-
- /* check to see if there is a name param and if it has a smime extension */
- filename = camel_mime_part_get_filename (mime_part);
- if (filename && *filename && strlen (filename) > 4) {
- for (i = 0; types[i]; i++)
- if (!g_strcasecmp (filename + strlen (filename)-4, types[i]))
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-
-static void
-smime_part_sign_restore_part (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_part_sign_restore_part (part, encodings);
- encodings = encodings->next;
- }
- } else {
- CamelMimePartEncodingType encoding;
-
- encoding = GPOINTER_TO_INT (encodings->data);
-
- camel_mime_part_set_encoding (mime_part, encoding);
- }
-}
-
-static void
-smime_part_sign_prepare_part (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_part_sign_prepare_part (part, encodings);
- }
- } else {
- CamelMimePartEncodingType encoding;
-
- 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_MIME_PART_ENCODING_BASE64)
- camel_mime_part_set_encoding (mime_part, CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE);
-
- *encodings = g_slist_append (*encodings, GINT_TO_POINTER (encoding));
- }
-}
-
-
-/**
- * camel_smime_part_sign:
- * @context: S/MIME Context
- * @mime_part: a MIME part that will be replaced by an S/MIME signed part
- * @userid: userid to sign with
- * @hash: one of CAMEL_CIPHER_HASH_TYPE_MD5 or CAMEL_CIPHER_HASH_TYPE_SHA1
- * @ex: exception which will be set if there are any errors.
- *
- * Constructs a S/MIME multipart in compliance with rfc2015/rfc2633 and
- * replaces @part with the generated multipart/signed. On failure,
- * @ex will be set and #part will remain untouched.
- **/
-void
-camel_smime_part_sign (CamelSMimeContext *context, CamelMimePart **mime_part, const char *userid,
- CamelCipherHash hash, CamelException *ex)
-{
- CamelMimePart *part, *signed_part;
- CamelMultipart *multipart;
- CamelContentType *mime_type;
- CamelStreamFilter *filtered_stream;
- CamelMimeFilter *crlf_filter, *from_filter;
- CamelStream *stream, *sigstream;
- gchar *hash_type = NULL;
- GSList *encodings = NULL;
-
- g_return_if_fail (*mime_part != NULL);
- g_return_if_fail (CAMEL_IS_MIME_PART (*mime_part));
- g_return_if_fail (userid != NULL);
-
- part = *mime_part;
-
- /* Prepare all the parts for signing... */
- smime_part_sign_prepare_part (part, &encodings);
-
- /* get the cleartext */
- stream = camel_stream_mem_new ();
- crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE,
- CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
- from_filter = CAMEL_MIME_FILTER (camel_mime_filter_from_new ());
- filtered_stream = camel_stream_filter_new_with_stream (stream);
- camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlf_filter));
- camel_object_unref (CAMEL_OBJECT (crlf_filter));
- camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (from_filter));
- camel_object_unref (CAMEL_OBJECT (from_filter));
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (part), CAMEL_STREAM (filtered_stream));
- camel_object_unref (CAMEL_OBJECT (filtered_stream));
-
- /* reset the stream */
- camel_stream_reset (stream);
-
- /* construct the signature stream */
- sigstream = camel_stream_mem_new ();
-
- switch (hash) {
- case CAMEL_CIPHER_HASH_MD5:
- hash_type = "md5";
- break;
- case CAMEL_CIPHER_HASH_SHA1:
- hash_type = "sha1";
- break;
- default:
- /* set a reasonable default */
- hash = CAMEL_CIPHER_HASH_SHA1;
- hash_type = "sha1";
- break;
- }
-
- /* get the signature */
- if (camel_smime_sign (context, userid, hash, stream, sigstream, ex) == -1) {
- camel_object_unref (CAMEL_OBJECT (stream));
- camel_object_unref (CAMEL_OBJECT (sigstream));
-
- /* restore the original encoding */
- smime_part_sign_restore_part (part, encodings);
- g_slist_free (encodings);
- return;
- }
-
- camel_object_unref (CAMEL_OBJECT (stream));
- camel_stream_reset (sigstream);
-
- /* we don't need these anymore... */
- g_slist_free (encodings);
-
- /* construct the pkcs7-signature mime part */
- signed_part = camel_mime_part_new ();
- camel_mime_part_set_content (signed_part, CAMEL_STREAM_MEM (sigstream)->buffer->data,
- CAMEL_STREAM_MEM (sigstream)->buffer->len,
- "application/pkcs7-signature");
- camel_object_unref (CAMEL_OBJECT (sigstream));
- camel_mime_part_set_encoding (signed_part, CAMEL_MIME_PART_ENCODING_BASE64);
- camel_mime_part_set_filename (signed_part, "smime.p7s");
-
- /* construct the container multipart/signed */
- multipart = camel_multipart_new ();
-
- mime_type = header_content_type_new ("multipart", "signed");
- header_content_type_set_param (mime_type, "micalg", hash_type);
- header_content_type_set_param (mime_type, "protocol", "application/pkcs7-signature");
- camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (multipart), mime_type);
- header_content_type_unref (mime_type);
-
- camel_multipart_set_boundary (multipart, NULL);
-
- /* add the parts to the multipart */
- camel_multipart_add_part (multipart, part);
- camel_object_unref (CAMEL_OBJECT (part));
- camel_multipart_add_part (multipart, signed_part);
- camel_object_unref (CAMEL_OBJECT (signed_part));
-
- /* replace the input part with the output part */
- *mime_part = camel_mime_part_new ();
- camel_medium_set_content_object (CAMEL_MEDIUM (*mime_part),
- CAMEL_DATA_WRAPPER (multipart));
- camel_object_unref (CAMEL_OBJECT (multipart));
-}
-
-struct {
- char *name;
- CamelCipherHash hash;
-} known_hash_types[] = {
- { "md5", CAMEL_CIPHER_HASH_MD5 },
- { "rsa-md5", CAMEL_CIPHER_HASH_MD5 },
- { "sha1", CAMEL_CIPHER_HASH_SHA1 },
- { "rsa-sha1", CAMEL_CIPHER_HASH_SHA1 },
- { NULL, CAMEL_CIPHER_HASH_DEFAULT }
-};
-
-static CamelCipherHash
-get_hash_type (const char *string)
-{
- int i;
-
- for (i = 0; known_hash_types[i].name; i++)
- if (!g_strcasecmp (known_hash_types[i].name, string))
- return known_hash_types[i].hash;
-
- return CAMEL_CIPHER_HASH_DEFAULT;
-}
-
-/**
- * camel_smime_part_verify:
- * @context: S/MIME Context
- * @mime_part: a multipart/signed MIME Part
- * @ex: exception
- *
- * Returns a CamelCipherValidity on success or NULL on fail.
- **/
-CamelCipherValidity *
-camel_smime_part_verify (CamelSMimeContext *context, CamelMimePart *mime_part, CamelException *ex)
-{
- CamelDataWrapper *wrapper;
- CamelMultipart *multipart;
- CamelMimePart *part, *sigpart;
- CamelStreamFilter *filtered_stream;
- CamelMimeFilter *crlf_filter, *from_filter;
- CamelStream *stream, *sigstream;
- CamelContentType *type;
- CamelCipherValidity *valid;
- CamelCipherHash hash;
- const char *hash_str;
-
- g_return_val_if_fail (mime_part != NULL, NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
-
- if (!camel_smime_is_smime_v3_signed (mime_part))
- return NULL;
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
- multipart = CAMEL_MULTIPART (wrapper);
-
- /* get the plain part */
- part = camel_multipart_get_part (multipart, 0);
- stream = camel_stream_mem_new ();
- crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE,
- CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
- from_filter = CAMEL_MIME_FILTER (camel_mime_filter_from_new ());
- filtered_stream = camel_stream_filter_new_with_stream (stream);
- camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlf_filter));
- camel_object_unref (CAMEL_OBJECT (crlf_filter));
- camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (from_filter));
- camel_object_unref (CAMEL_OBJECT (from_filter));
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (part), CAMEL_STREAM (filtered_stream));
- camel_object_unref (CAMEL_OBJECT (filtered_stream));
- camel_stream_reset (stream);
-
- /* get the signed part */
- sigpart = camel_multipart_get_part (multipart, 1);
- sigstream = camel_stream_mem_new ();
- camel_data_wrapper_write_to_stream (camel_medium_get_content_object (CAMEL_MEDIUM (sigpart)),
- sigstream);
- camel_stream_reset (sigstream);
-
- /* verify */
- type = camel_mime_part_get_content_type (sigpart);
- hash_str = header_content_type_param (type, "micalg");
- hash = get_hash_type (hash_str);
- valid = camel_smime_verify (context, hash, stream, sigstream, ex);
-
- camel_object_unref (CAMEL_OBJECT (sigstream));
- camel_object_unref (CAMEL_OBJECT (stream));
-
- return valid;
-}
-
-
-/**
- * camel_smime_part_encrypt:
- * @context: S/MIME Context
- * @mime_part: a MIME part that will be replaced by a pgp encrypted part
- * @recipients: list of recipient PGP Key IDs
- * @ex: exception which will be set if there are any errors.
- *
- * Constructs a PGP/MIME multipart in compliance with rfc2015 and
- * replaces #mime_part with the generated multipart/signed. On failure,
- * #ex will be set and #part will remain untouched.
- **/
-void
-camel_smime_part_encrypt (CamelSMimeContext *context, CamelMimePart **mime_part,
- GPtrArray *recipients, CamelException *ex)
-{
- CamelMimePart *part, *encrypted_part;
- CamelStreamFilter *filtered_stream;
- CamelMimeFilter *crlf_filter;
- CamelStream *stream, *ciphertext;
-
- g_return_if_fail (*mime_part != NULL);
- g_return_if_fail (CAMEL_IS_MIME_PART (*mime_part));
- g_return_if_fail (recipients != NULL);
-
- part = *mime_part;
-
- /* get the contents */
- stream = camel_stream_mem_new ();
- crlf_filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE,
- CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
- filtered_stream = camel_stream_filter_new_with_stream (stream);
- camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlf_filter));
- camel_object_unref (CAMEL_OBJECT (crlf_filter));
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (part), CAMEL_STREAM (filtered_stream));
- camel_object_unref (CAMEL_OBJECT (filtered_stream));
- camel_stream_reset (stream);
-
- /* smime encrypt */
- ciphertext = camel_stream_mem_new ();
- if (camel_smime_encrypt (context, FALSE, NULL, recipients, stream, ciphertext, ex) == -1) {
- camel_object_unref (CAMEL_OBJECT (stream));
- camel_object_unref (CAMEL_OBJECT (ciphertext));
- return;
- }
-
- camel_object_unref (CAMEL_OBJECT (stream));
- camel_stream_reset (ciphertext);
-
- /* construct the encrypted mime part */
- encrypted_part = camel_mime_part_new ();
- camel_mime_part_set_content (encrypted_part, CAMEL_STREAM_MEM (ciphertext)->buffer->data,
- CAMEL_STREAM_MEM (ciphertext)->buffer->len,
- "application/pkcs7-mime; smime-type=enveloped-data");
- camel_mime_part_set_encoding (encrypted_part, CAMEL_MIME_PART_ENCODING_BASE64);
- camel_object_unref (CAMEL_OBJECT (ciphertext));
-
- /* replace the input part with the output part */
- camel_object_unref (CAMEL_OBJECT (*mime_part));
- *mime_part = encrypted_part;
-}
-
-
-/**
- * camel_smime_part_decrypt:
- * @context: S/MIME Context
- * @mime_part: a S/MIME encrypted MIME Part
- * @ex: exception
- *
- * Returns the decrypted MIME Part on success or NULL on fail.
- **/
-CamelMimePart *
-camel_smime_part_decrypt (CamelSMimeContext *context, CamelMimePart *mime_part, CamelException *ex)
-{
- CamelMimePart *part;
- CamelStream *stream, *ciphertext;
-
- g_return_val_if_fail (mime_part != NULL, NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
-
- /* make sure the mime part is a S/MIME encrypted */
- if (!camel_smime_is_smime_v3_encrypted (mime_part))
- return NULL;
-
- /* get the ciphertext */
- ciphertext = camel_stream_mem_new ();
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_part), ciphertext);
- camel_stream_reset (ciphertext);
-
- /* get the cleartext */
- stream = camel_stream_mem_new ();
- if (camel_smime_decrypt (context, ciphertext, stream, ex) == -1) {
- camel_object_unref (CAMEL_OBJECT (ciphertext));
- camel_object_unref (CAMEL_OBJECT (stream));
- return NULL;
- }
-
- camel_object_unref (CAMEL_OBJECT (ciphertext));
- camel_stream_reset (stream);
-
- /* construct the new decrypted mime part from the stream */
- part = camel_mime_part_new ();
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (part), stream);
- camel_object_unref (CAMEL_OBJECT (stream));
-
- return part;
-}