/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Authors: Jeffrey Stedfast * * 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 #endif #include "camel-cipher-context.h" #include #include #ifdef ENABLE_THREADS #include #define CIPHER_LOCK(ctx) g_mutex_lock (((CamelCipherContext *) ctx)->priv->lock) #define CIPHER_UNLOCK(ctx) g_mutex_unlock (((CamelCipherContext *) ctx)->priv->lock); #else #define CIPHER_LOCK(ctx) #define CIPHER_UNLOCK(ctx) #endif #define d(x) #define CCC_CLASS(o) CAMEL_CIPHER_CONTEXT_CLASS(CAMEL_OBJECT_GET_CLASS(o)) struct _CamelCipherContextPrivate { #ifdef ENABLE_THREADS GMutex *lock; #endif }; static int cipher_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelStream *ostream, CamelException *ex); static int cipher_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelStream *ostream, CamelException *ex); static CamelCipherValidity *cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream, CamelStream *sigstream, CamelException *ex); static int cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients, CamelStream *istream, CamelStream *ostream, CamelException *ex); static int cipher_decrypt (CamelCipherContext *context, CamelStream *istream, CamelStream *ostream, CamelException *ex); static CamelObjectClass *parent_class; static void camel_cipher_context_init (CamelCipherContext *context) { context->priv = g_new0 (struct _CamelCipherContextPrivate, 1); #ifdef ENABLE_THREADS context->priv->lock = g_mutex_new (); #endif } static void camel_cipher_context_finalise (CamelObject *o) { CamelCipherContext *context = (CamelCipherContext *)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_cipher_context_class_init (CamelCipherContextClass *camel_cipher_context_class) { parent_class = camel_type_get_global_classfuncs (camel_object_get_type ()); camel_cipher_context_class->sign = cipher_sign; camel_cipher_context_class->clearsign = cipher_clearsign; camel_cipher_context_class->verify = cipher_verify; camel_cipher_context_class->encrypt = cipher_encrypt; camel_cipher_context_class->decrypt = cipher_decrypt; } CamelType camel_cipher_context_get_type (void) { static CamelType type = CAMEL_INVALID_TYPE; if (type == CAMEL_INVALID_TYPE) { type = camel_type_register (camel_object_get_type (), "CamelCipherContext", sizeof (CamelCipherContext), sizeof (CamelCipherContextClass), (CamelObjectClassInitFunc) camel_cipher_context_class_init, NULL, (CamelObjectInitFunc) camel_cipher_context_init, (CamelObjectFinalizeFunc) camel_cipher_context_finalise); } return type; } /** * camel_cipher_context_new: * @session: CamelSession * * This creates a new CamelCipherContext object which is used to sign, * verify, encrypt and decrypt streams. * * Return value: the new CamelCipherContext **/ CamelCipherContext * camel_cipher_context_new (CamelSession *session) { CamelCipherContext *context; g_return_val_if_fail (session != NULL, NULL); context = CAMEL_CIPHER_CONTEXT (camel_object_new (CAMEL_CIPHER_CONTEXT_TYPE)); camel_object_ref (CAMEL_OBJECT (session)); context->session = session; return context; } /** * camel_cipher_context_construct: * @context: CamelCipherContext * @session: CamelSession * * Constucts the CamelCipherContext **/ void camel_cipher_context_construct (CamelCipherContext *context, CamelSession *session) { g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context)); g_return_if_fail (CAMEL_IS_SESSION (session)); camel_object_ref (CAMEL_OBJECT (session)); context->session = session; } static int cipher_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelStream *ostream, CamelException *ex) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Signing is not supported by this cipher")); return -1; } /** * camel_cipher_sign: * @context: Cipher Context * @userid: private key to use to sign the stream * @hash: preferred Message-Integrity-Check hash algorithm * @istream: input stream * @ostream: output stream * @ex: exception * * Signs the input stream and writes the resulting signature to the output stream. * * Return value: 0 for success or -1 for failure. **/ int camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelStream *ostream, CamelException *ex) { int retval; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); CIPHER_LOCK(context); retval = CCC_CLASS (context)->sign (context, userid, hash, istream, ostream, ex); CIPHER_UNLOCK(context); return retval; } static int cipher_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelStream *ostream, CamelException *ex) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Clearsigning is not supported by this cipher")); return -1; } /** * camel_cipher_clearsign: * @context: Cipher Context * @userid: key id or email address of the private key to sign with * @hash: preferred Message-Integrity-Check hash algorithm * @istream: input stream * @ostream: output stream * @ex: exception * * Clearsigns the input stream and writes the resulting clearsign to the output stream. * * Return value: 0 for success or -1 for failure. **/ int camel_cipher_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelStream *istream, CamelStream *ostream, CamelException *ex) { int retval; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); CIPHER_LOCK(context); retval = CCC_CLASS (context)->clearsign (context, userid, hash, istream, ostream, ex); CIPHER_UNLOCK(context); return retval; } static CamelCipherValidity * cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream, CamelStream *sigstream, CamelException *ex) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Verifying is not supported by this cipher")); return NULL; } /** * camel_cipher_verify: * @context: Cipher Context * @istream: input stream * @sigstream: optional detached-signature stream * @ex: exception * * Verifies the signature. If @istream is a clearsigned stream, * you should pass %NULL as the sigstream parameter. Otherwise * @sigstream is assumed to be the signature stream and is used to * verify the integirity of the @istream. * * Return value: a CamelCipherValidity structure containing information * about the integrity of the input stream or %NULL on failure to * execute at all. **/ CamelCipherValidity * camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream, CamelStream *sigstream, CamelException *ex) { CamelCipherValidity *valid; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL); CIPHER_LOCK(context); valid = CCC_CLASS (context)->verify (context, hash, istream, sigstream, ex); CIPHER_UNLOCK(context); return valid; } static int cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients, CamelStream *istream, CamelStream *ostream, CamelException *ex) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption is not supported by this cipher")); return -1; } /** * camel_cipher_encrypt: * @context: Cipher Context * @sign: sign as well as encrypt * @userid: key id (or email address) to use when signing (assuming @sign is %TRUE) * @recipients: an array of recipient key ids and/or email addresses * @istream: cleartext input stream * @ostream: ciphertext output stream * @ex: exception * * Encrypts (and optionally signs) the cleartext input stream and * writes the resulting ciphertext to the output stream. * * Return value: 0 for success or -1 for failure. **/ int camel_cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients, CamelStream *istream, CamelStream *ostream, CamelException *ex) { int retval; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); CIPHER_LOCK(context); retval = CCC_CLASS (context)->encrypt (context, sign, userid, recipients, istream, ostream, ex); CIPHER_UNLOCK(context); return retval; } static int cipher_decrypt (CamelCipherContext *context, CamelStream *istream, CamelStream *ostream, CamelException *ex) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Decryption is not supported by this cipher")); return -1; } /** * camel_cipher_decrypt: * @context: Cipher Context * @ciphertext: ciphertext stream (ie input stream) * @cleartext: cleartext stream (ie output stream) * @ex: exception * * Decrypts the ciphertext input stream and writes the resulting * cleartext to the output stream. * * Return value: 0 for success or -1 for failure. **/ int camel_cipher_decrypt (CamelCipherContext *context, CamelStream *istream, CamelStream *ostream, CamelException *ex) { int retval; g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1); CIPHER_LOCK(context); retval = CCC_CLASS (context)->decrypt (context, istream, ostream, ex); CIPHER_UNLOCK(context); return retval; } /* Cipher Validity stuff */ struct _CamelCipherValidity { gboolean valid; gchar *description; }; CamelCipherValidity * camel_cipher_validity_new (void) { CamelCipherValidity *validity; validity = g_new (CamelCipherValidity, 1); validity->valid = FALSE; validity->description = NULL; return validity; } void camel_cipher_validity_init (CamelCipherValidity *validity) { g_assert (validity != NULL); validity->valid = FALSE; validity->description = NULL; } gboolean camel_cipher_validity_get_valid (CamelCipherValidity *validity) { if (validity == NULL) return FALSE; return validity->valid; } void camel_cipher_validity_set_valid (CamelCipherValidity *validity, gboolean valid) { g_assert (validity != NULL); validity->valid = valid; } gchar * camel_cipher_validity_get_description (CamelCipherValidity *validity) { if (validity == NULL) return NULL; return validity->description; } void camel_cipher_validity_set_description (CamelCipherValidity *validity, const gchar *description) { g_assert (validity != NULL); g_free (validity->description); validity->description = g_strdup (description); } void camel_cipher_validity_clear (CamelCipherValidity *validity) { g_assert (validity != NULL); validity->valid = FALSE; g_free (validity->description); validity->description = NULL; } void camel_cipher_validity_free (CamelCipherValidity *validity) { if (validity == NULL) return; g_free (validity->description); g_free (validity); }