aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-pkcs7-context.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-pkcs7-context.c')
-rw-r--r--camel/camel-pkcs7-context.c691
1 files changed, 0 insertions, 691 deletions
diff --git a/camel/camel-pkcs7-context.c b/camel/camel-pkcs7-context.c
deleted file mode 100644
index 185ae09ccc..0000000000
--- a/camel/camel-pkcs7-context.c
+++ /dev/null
@@ -1,691 +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-pkcs7-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 _CamelPkcs7ContextPrivate {
- CERTCertDBHandle *certdb;
-};
-
-
-static int pkcs7_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex);
-static int pkcs7_clearsign (CamelCipherContext *context, const char *userid,
- CamelCipherHash hash, CamelStream *istream,
- CamelStream *ostream, CamelException *ex);
-static CamelCipherValidity *pkcs7_verify (CamelCipherContext *context, CamelStream *istream,
- CamelStream *sigstream, CamelException *ex);
-static int pkcs7_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
- GPtrArray *recipients, CamelStream *istream, CamelStream *ostream,
- CamelException *ex);
-static int pkcs7_decrypt (CamelCipherContext *context, CamelStream *istream,
- CamelStream *ostream, CamelException *ex);
-
-
-static CamelCipherContextClass *parent_class;
-
-static void
-camel_pkcs7_context_init (CamelPkcs7Context *context)
-{
- context->priv = g_new0 (struct _CamelPkcs7ContextPrivate, 1);
-}
-
-static void
-camel_pkcs7_context_finalise (CamelObject *o)
-{
- CamelPkcs7Context *context = (CamelPkcs7Context *)o;
-
- CERT_ClosePermCertDB (context->priv->certdb);
- g_free (context->priv->certdb);
-
- g_free (context->priv);
-}
-
-static void
-camel_pkcs7_context_class_init (CamelPkcs7ContextClass *camel_pkcs7_context_class)
-{
- CamelCipherContextClass *camel_cipher_context_class =
- CAMEL_CIPHER_CONTEXT_CLASS (camel_pkcs7_context_class);
-
- parent_class = CAMEL_CIPHER_CONTEXT_CLASS (camel_type_get_global_classfuncs (camel_cipher_context_get_type ()));
-
- camel_cipher_context_class->sign = pkcs7_sign;
- camel_cipher_context_class->clearsign = pkcs7_clearsign;
- camel_cipher_context_class->verify = pkcs7_verify;
- camel_cipher_context_class->encrypt = pkcs7_encrypt;
- camel_cipher_context_class->decrypt = pkcs7_decrypt;
-}
-
-CamelType
-camel_pkcs7_context_get_type (void)
-{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- type = camel_type_register (camel_cipher_context_get_type (),
- "CamelPkcs7Context",
- sizeof (CamelPkcs7Context),
- sizeof (CamelPkcs7ContextClass),
- (CamelObjectClassInitFunc) camel_pkcs7_context_class_init,
- NULL,
- (CamelObjectInitFunc) camel_pkcs7_context_init,
- (CamelObjectFinalizeFunc) camel_pkcs7_context_finalise);
- }
-
- return type;
-}
-
-
-/**
- * camel_pkcs7_context_new:
- * @session: CamelSession
- * @certdb: certificate db
- *
- * This creates a new CamelPkcs7Context object which is used to sign,
- * verify, encrypt and decrypt streams.
- *
- * Return value: the new CamelPkcs7Context
- **/
-CamelPkcs7Context *
-camel_pkcs7_context_new (CamelSession *session, const char *certdb)
-{
- CamelPkcs7Context *context;
- CERTCertDBHandle *handle;
-
- g_return_val_if_fail (session != NULL, NULL);
-
- context = CAMEL_PKCS7_CONTEXT (camel_object_new (CAMEL_PKCS7_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_get_password (session, 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
-pkcs7_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
-sec_output_cb (void *arg, const char *buf, unsigned long len)
-{
- CamelStream *stream;
-
- stream = CAMEL_STREAM (arg);
- camel_stream_write (stream, buf, len);
-}
-
-static int
-pkcs7_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
-{
- CamelPkcs7Context *context = CAMEL_PKCS7_CONTEXT (ctx);
- struct _GetPasswdData *data;
- SEC_PKCS7ContentInfo *cinfo;
- 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);
- pkcs7_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;
- }
-
- cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL,
- nss_hash_to_sec_oid (hash_type),
- &digest, NULL, NULL);
-
- SEC_PKCS7IncludeCertChain (cinfo, NULL);
-
- data = g_new (struct _GetPasswdData, 1);
- data->session = ctx->session;
- data->userid = userid;
- data->ex = ex;
-
- SEC_PKCS7Encode (cinfo, sec_output_cb, ostream, NULL, get_password, data);
-
- g_free (data);
-
- SEC_PKCS7DestroyContentInfo (cinfo);
-
- return 0;
-}
-
-
-static int
-pkcs7_clearsign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
-{
- CamelPkcs7Context *context = CAMEL_PKCS7_CONTEXT (ctx);
- struct _GetPasswdData *data;
- SEC_PKCS7ContentInfo *cinfo;
- HASH_HashType hash_type;
- CERTCertificate *cert;
- CamelStream *stream;
- SECItem data2sign;
- GByteArray *buf;
-
- g_return_val_if_fail (userid != NULL, -1);
- g_return_val_if_fail (istream != NULL, -1);
- g_return_val_if_fail (ostream != NULL, -1);
-
- hash_type = camel_cipher_hash_to_nss (hash);
-
- cert = CERT_FindCertByNickname (context->priv->certdb, userid);
- if (!cert) {
- camel_object_unref (CAMEL_OBJECT (stream));
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Could not clearsign: certificate not found for \"%s\"."),
- userid);
- return -1;
- }
-
- cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL,
- nss_hash_to_sec_oid (hash_type),
- NULL, NULL, NULL);
-
- 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;
- SEC_PKCS7SetContent (cinfo, (char *)data2sign.data, data2sign.len);
- camel_object_unref (CAMEL_OBJECT (stream));
-
- SEC_PKCS7IncludeCertChain (cinfo, NULL);
-
- data = g_new (struct _GetPasswdData, 1);
- data->session = ctx->session;
- data->userid = userid;
- data->ex = ex;
-
- SEC_PKCS7Encode (cinfo, sec_output_cb, ostream, NULL, get_password, data);
-
- g_free (data);
-
- SEC_PKCS7DestroyContentInfo (cinfo);
-
- return 0;
-}
-
-#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
-
-#if 0
-static HASH_HashType
-AlgorithmToHashType (SECAlgorithmID *digestAlgorithms)
-{
- SECOidTag tag;
-
- tag = SECOID_GetAlgorithmTag (digestAlgorithms);
-
- switch (tag) {
- case SEC_OID_MD2:
- return HASH_AlgMD2;
- case SEC_OID_MD5:
- return HASH_AlgMD5;
- case SEC_OID_SHA1:
- return HASH_AlgSHA1;
- default:
- g_assert_not_reached ();
- return HASH_AlgNULL;
- }
-}
-#endif
-
-/* FIXME: god knows if this code works, NSS "docs" are so not helpful at all */
-static CamelCipherValidity *
-pkcs7_verify (CamelCipherContext *ctx, CamelCipherHash hash, CamelStream *istream,
- CamelStream *sigstream, CamelException *ex)
-{
- CamelPkcs7Context *context = CAMEL_PKCS7_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;
-}
-
-/* FIXME: we need to respect the 'sign' argument... */
-static int
-pkcs7_encrypt (CamelCipherContext *ctx, gboolean sign, const char *userid, GPtrArray *recipients,
- CamelStream *istream, CamelStream *ostream, CamelException *ex)
-{
- CamelPkcs7Context *context = CAMEL_PKCS7_CONTEXT (ctx);
- const char *invalid_userkey = NULL;
- SEC_PKCS7ContentInfo *cinfo = NULL;
- CERTCertificate *cert, *usercert;
- SEC_PKCS7EncoderContext *ecx;
- struct _GetPasswdData *data;
- CamelStream *stream = NULL;
- 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);
-
-#if 0
- /* this isn't needed until we respect the 'sign' argument... */
- usercert = CERT_FindCertByNickname (context->priv->certdb, userid);
- if (!usercert) {
- invalid_userkey = userid;
- goto exception;
- }
-#endif
-
- cert = CERT_FindCertByNickname (context->priv->certdb, recipients->pdata[i]);
- if (!cert) {
- invalid_userkey = recipients->pdata[i];
- goto exception;
- }
-
- 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."));
- goto exception;
- }
-
- for (i++; i < recipients->len; i++) {
- SECStatus retval;
-
- cert = CERT_FindCertByNickname (context->priv->certdb, recipients->pdata[i]);
- if (!cert) {
- invalid_userkey = recipients->pdata[i];
- goto exception;
- }
-
- retval = SEC_PKCS7AddRecipient (cinfo, cert, certUsageEmailRecipient, NULL);
- if (retval != SECSuccess) {
- invalid_userkey = recipients->pdata[i];
- goto exception;
- }
- }
-
- ecx = SEC_PKCS7EncoderStart (cinfo, sec_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;
-
- SEC_PKCS7DestroyContentInfo (cinfo);
-
- return 0;
-
- exception:
-
- 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
-pkcs7_decrypt (CamelCipherContext *ctx, CamelStream *istream,
- CamelStream *ostream, CamelException *ex)
-{
- CamelPkcs7Context *context = CAMEL_PKCS7_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 (sec_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;
-}