c495a6479cf8a116ed94278913f37d16b1da9a6c
[platform/upstream/evolution-data-server.git] / camel / camel-cipher-context.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2001 Ximian, Inc. (www.ximian.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "camel-cipher-context.h"
28
29 #include <glib.h>
30
31 #ifdef ENABLE_THREADS
32 #include <pthread.h>
33 #define CIPHER_LOCK(ctx)   g_mutex_lock (((CamelCipherContext *) ctx)->priv->lock)
34 #define CIPHER_UNLOCK(ctx) g_mutex_unlock (((CamelCipherContext *) ctx)->priv->lock);
35 #else
36 #define CIPHER_LOCK(ctx)
37 #define CIPHER_UNLOCK(ctx)
38 #endif
39
40 #define d(x)
41
42 #define CCC_CLASS(o) CAMEL_CIPHER_CONTEXT_CLASS(CAMEL_OBJECT_GET_CLASS(o))
43
44 struct _CamelCipherContextPrivate {
45 #ifdef ENABLE_THREADS
46         GMutex *lock;
47 #endif
48 };
49
50 static const char *cipher_hash_to_id (CamelCipherContext *context, CamelCipherHash hash);
51 static CamelCipherHash cipher_id_to_hash (CamelCipherContext *context, const char *id);
52
53 static int                  cipher_sign    (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
54                                             CamelStream *istream, CamelStream *ostream, CamelException *ex);
55 static CamelCipherValidity *cipher_verify  (CamelCipherContext *context, CamelCipherHash hash,
56                                             CamelStream *istream, CamelStream *sigstream,
57                                             CamelException *ex);
58 static int                  cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid,
59                                             GPtrArray *recipients, CamelStream *istream,
60                                             CamelStream *ostream, CamelException *ex);
61 static int                  cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
62                                             CamelStream *ostream, CamelException *ex);
63 static int              cipher_import_keys (CamelCipherContext *context, CamelStream *istream,
64                                             CamelException *ex);
65 static int              cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
66                                             CamelStream *ostream, CamelException *ex);
67
68
69 static CamelObjectClass *parent_class;
70
71
72 static void
73 camel_cipher_context_init (CamelCipherContext *context)
74 {
75         context->priv = g_new0 (struct _CamelCipherContextPrivate, 1);
76 #ifdef ENABLE_THREADS
77         context->priv->lock = g_mutex_new ();
78 #endif
79 }
80
81 static void
82 camel_cipher_context_finalise (CamelObject *o)
83 {
84         CamelCipherContext *context = (CamelCipherContext *)o;
85         
86         camel_object_unref (CAMEL_OBJECT (context->session));
87         
88 #ifdef ENABLE_THREADS
89         g_mutex_free (context->priv->lock);
90 #endif
91         
92         g_free (context->priv);
93 }
94
95 static void
96 camel_cipher_context_class_init (CamelCipherContextClass *camel_cipher_context_class)
97 {
98         parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
99         
100         camel_cipher_context_class->hash_to_id = cipher_hash_to_id;
101         camel_cipher_context_class->id_to_hash = cipher_id_to_hash;
102         camel_cipher_context_class->sign = cipher_sign;
103         camel_cipher_context_class->verify = cipher_verify;
104         camel_cipher_context_class->encrypt = cipher_encrypt;
105         camel_cipher_context_class->decrypt = cipher_decrypt;
106         camel_cipher_context_class->import_keys = cipher_import_keys;
107         camel_cipher_context_class->export_keys = cipher_export_keys;
108 }
109
110 CamelType
111 camel_cipher_context_get_type (void)
112 {
113         static CamelType type = CAMEL_INVALID_TYPE;
114         
115         if (type == CAMEL_INVALID_TYPE) {
116                 type = camel_type_register (camel_object_get_type (),
117                                             "CamelCipherContext",
118                                             sizeof (CamelCipherContext),
119                                             sizeof (CamelCipherContextClass),
120                                             (CamelObjectClassInitFunc) camel_cipher_context_class_init,
121                                             NULL,
122                                             (CamelObjectInitFunc) camel_cipher_context_init,
123                                             (CamelObjectFinalizeFunc) camel_cipher_context_finalise);
124         }
125         
126         return type;
127 }
128
129
130 /**
131  * camel_cipher_context_new:
132  * @session: CamelSession
133  *
134  * This creates a new CamelCipherContext object which is used to sign,
135  * verify, encrypt and decrypt streams.
136  *
137  * Return value: the new CamelCipherContext
138  **/
139 CamelCipherContext *
140 camel_cipher_context_new (CamelSession *session)
141 {
142         CamelCipherContext *context;
143         
144         g_return_val_if_fail (session != NULL, NULL);
145         
146         context = CAMEL_CIPHER_CONTEXT (camel_object_new (CAMEL_CIPHER_CONTEXT_TYPE));
147         
148         camel_object_ref (CAMEL_OBJECT (session));
149         context->session = session;
150         
151         return context;
152 }
153
154
155 /**
156  * camel_cipher_context_construct:
157  * @context: CamelCipherContext
158  * @session: CamelSession
159  *
160  * Constucts the CamelCipherContext
161  **/
162 void
163 camel_cipher_context_construct (CamelCipherContext *context, CamelSession *session)
164 {
165         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
166         g_return_if_fail (CAMEL_IS_SESSION (session));
167         
168         camel_object_ref (CAMEL_OBJECT (session));
169         context->session = session;
170 }
171
172
173 static int
174 cipher_sign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
175              CamelStream *istream, CamelStream *ostream, CamelException *ex)
176 {
177         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
178                              _("Signing is not supported by this cipher"));
179         return -1;
180 }
181
182 /**
183  * camel_cipher_sign:
184  * @context: Cipher Context
185  * @userid: private key to use to sign the stream
186  * @hash: preferred Message-Integrity-Check hash algorithm
187  * @istream: input stream
188  * @ostream: output stream
189  * @ex: exception
190  *
191  * Signs the input stream and writes the resulting signature to the output stream.
192  *
193  * Return value: 0 for success or -1 for failure.
194  **/
195 int
196 camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
197                    CamelStream *istream, CamelStream *ostream, CamelException *ex)
198 {
199         int retval;
200         
201         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
202         
203         CIPHER_LOCK(context);
204         
205         retval = CCC_CLASS (context)->sign (context, userid, hash, istream, ostream, ex);
206         
207         CIPHER_UNLOCK(context);
208         
209         return retval;
210 }
211
212
213 static CamelCipherValidity *
214 cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream,
215                CamelStream *sigstream, CamelException *ex)
216 {
217         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
218                              _("Verifying is not supported by this cipher"));
219         return NULL;
220 }
221
222
223 /**
224  * camel_cipher_verify:
225  * @context: Cipher Context
226  * @istream: input stream
227  * @sigstream: optional detached-signature stream
228  * @ex: exception
229  *
230  * Verifies the signature. If @istream is a clearsigned stream,
231  * you should pass %NULL as the sigstream parameter. Otherwise
232  * @sigstream is assumed to be the signature stream and is used to
233  * verify the integirity of the @istream.
234  *
235  * Return value: a CamelCipherValidity structure containing information
236  * about the integrity of the input stream or %NULL on failure to
237  * execute at all.
238  **/
239 CamelCipherValidity *
240 camel_cipher_verify (CamelCipherContext *context, CamelCipherHash hash, CamelStream *istream,
241                      CamelStream *sigstream, CamelException *ex)
242 {
243         CamelCipherValidity *valid;
244         
245         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
246         
247         CIPHER_LOCK(context);
248         
249         valid = CCC_CLASS (context)->verify (context, hash, istream, sigstream, ex);
250         
251         CIPHER_UNLOCK(context);
252         
253         return valid;
254 }
255
256
257 static int
258 cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients,
259                 CamelStream *istream, CamelStream *ostream, CamelException *ex)
260 {
261         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
262                              _("Encryption is not supported by this cipher"));
263         return -1;
264 }
265
266 /**
267  * camel_cipher_encrypt:
268  * @context: Cipher Context
269  * @sign: sign as well as encrypt
270  * @userid: key id (or email address) to use when signing (assuming @sign is %TRUE)
271  * @recipients: an array of recipient key ids and/or email addresses
272  * @istream: cleartext input stream
273  * @ostream: ciphertext output stream
274  * @ex: exception
275  *
276  * Encrypts (and optionally signs) the cleartext input stream and
277  * writes the resulting ciphertext to the output stream.
278  *
279  * Return value: 0 for success or -1 for failure.
280  **/
281 int
282 camel_cipher_encrypt (CamelCipherContext *context, gboolean sign, const char *userid, GPtrArray *recipients,
283                       CamelStream *istream, CamelStream *ostream, CamelException *ex)
284 {
285         int retval;
286         
287         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
288         
289         CIPHER_LOCK(context);
290         
291         retval = CCC_CLASS (context)->encrypt (context, sign, userid, recipients, istream, ostream, ex);
292         
293         CIPHER_UNLOCK(context);
294         
295         return retval;
296 }
297
298
299 static int
300 cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
301                 CamelStream *ostream, CamelException *ex)
302 {
303         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
304                              _("Decryption is not supported by this cipher"));
305         return -1;
306 }
307
308 /**
309  * camel_cipher_decrypt:
310  * @context: Cipher Context
311  * @ciphertext: ciphertext stream (ie input stream)
312  * @cleartext: cleartext stream (ie output stream)
313  * @ex: exception
314  *
315  * Decrypts the ciphertext input stream and writes the resulting
316  * cleartext to the output stream.
317  *
318  * Return value: 0 for success or -1 for failure.
319  **/
320 int
321 camel_cipher_decrypt (CamelCipherContext *context, CamelStream *istream,
322                       CamelStream *ostream, CamelException *ex)
323 {
324         int retval;
325         
326         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
327         
328         CIPHER_LOCK(context);
329         
330         retval = CCC_CLASS (context)->decrypt (context, istream, ostream, ex);
331         
332         CIPHER_UNLOCK(context);
333         
334         return retval;
335 }
336
337
338 static int
339 cipher_import_keys (CamelCipherContext *context, CamelStream *istream, CamelException *ex)
340 {
341         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
342                              _("You may not import keys with this cipher"));
343         
344         return -1;
345 }
346
347
348 /**
349  * camel_cipher_import_keys:
350  * @ctx: Cipher Context
351  * @istream: input stream (containing keys)
352  * @ex: exception
353  *
354  * Imports a stream of keys/certificates contained within @istream
355  * into the key/certificate database controlled by @ctx.
356  *
357  * Returns 0 on success or -1 on fail.
358  **/
359 int
360 camel_cipher_import_keys (CamelCipherContext *context, CamelStream *istream, CamelException *ex)
361 {
362         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
363         g_return_val_if_fail (CAMEL_IS_STREAM (istream), -1);
364         
365         return CCC_CLASS (context)->import_keys (context, istream, ex);
366 }
367
368
369 static int
370 cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
371                     CamelStream *ostream, CamelException *ex)
372 {
373         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
374                              _("You may not export keys with this cipher"));
375         
376         return -1;
377 }
378
379
380 /**
381  * camel_cipher_export_keys:
382  * @ctx: Cipher Context
383  * @keys: an array of key ids
384  * @ostream: output stream
385  * @ex: exception
386  *
387  * Exports the keys/certificates in @keys to the stream @ostream from
388  * the key/certificate database controlled by @ctx.
389  *
390  * Returns 0 on success or -1 on fail.
391  **/
392 int
393 camel_cipher_export_keys (CamelCipherContext *context, GPtrArray *keys,
394                           CamelStream *ostream, CamelException *ex)
395 {
396         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
397         g_return_val_if_fail (CAMEL_IS_STREAM (ostream), -1);
398         g_return_val_if_fail (keys != NULL, -1);
399         
400         return CCC_CLASS (context)->export_keys (context, keys, ostream, ex);
401 }
402
403
404 static CamelCipherHash
405 cipher_id_to_hash(CamelCipherContext *context, const char *id)
406 {
407         return CAMEL_CIPHER_HASH_DEFAULT;
408 }
409
410 /* a couple of util functions */
411 CamelCipherHash
412 camel_cipher_id_to_hash(CamelCipherContext *context, const char *id)
413 {
414         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), CAMEL_CIPHER_HASH_DEFAULT);
415         
416         return CCC_CLASS (context)->id_to_hash (context, id);
417 }
418
419 static const char *
420 cipher_hash_to_id(CamelCipherContext *context, CamelCipherHash hash)
421 {
422         return NULL;
423 }
424
425 const char *
426 camel_cipher_hash_to_id(CamelCipherContext *context, CamelCipherHash hash)
427 {
428         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
429         
430         return CCC_CLASS (context)->hash_to_id (context, hash);
431 }
432
433 /* Cipher Validity stuff */
434 struct _CamelCipherValidity {
435         gboolean valid;
436         gchar *description;
437 };
438
439 CamelCipherValidity *
440 camel_cipher_validity_new (void)
441 {
442         CamelCipherValidity *validity;
443         
444         validity = g_new (CamelCipherValidity, 1);
445         validity->valid = FALSE;
446         validity->description = NULL;
447         
448         return validity;
449 }
450
451 void
452 camel_cipher_validity_init (CamelCipherValidity *validity)
453 {
454         g_assert (validity != NULL);
455         
456         validity->valid = FALSE;
457         validity->description = NULL;
458 }
459
460 gboolean
461 camel_cipher_validity_get_valid (CamelCipherValidity *validity)
462 {
463         if (validity == NULL)
464                 return FALSE;
465         
466         return validity->valid;
467 }
468
469 void
470 camel_cipher_validity_set_valid (CamelCipherValidity *validity, gboolean valid)
471 {
472         g_assert (validity != NULL);
473         
474         validity->valid = valid;
475 }
476
477 gchar *
478 camel_cipher_validity_get_description (CamelCipherValidity *validity)
479 {
480         if (validity == NULL)
481                 return NULL;
482         
483         return validity->description;
484 }
485
486 void
487 camel_cipher_validity_set_description (CamelCipherValidity *validity, const gchar *description)
488 {
489         g_assert (validity != NULL);
490         
491         g_free (validity->description);
492         validity->description = g_strdup (description);
493 }
494
495 void
496 camel_cipher_validity_clear (CamelCipherValidity *validity)
497 {
498         g_assert (validity != NULL);
499         
500         validity->valid = FALSE;
501         g_free (validity->description);
502         validity->description = NULL;
503 }
504
505 void
506 camel_cipher_validity_free (CamelCipherValidity *validity)
507 {
508         if (validity == NULL)
509                 return;
510         
511         g_free (validity->description);
512         g_free (validity);
513 }