Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-multipart-encrypted.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  GMime
3  *  Copyright (C) 2000-2012 Jeffrey Stedfast
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public License
7  *  as published by the Free Software Foundation; either version 2.1
8  *  of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free
17  *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
18  *  02110-1301, USA.
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "gmime-multipart-encrypted.h"
30 #include "gmime-stream-filter.h"
31 #include "gmime-filter-basic.h"
32 #include "gmime-filter-from.h"
33 #include "gmime-filter-crlf.h"
34 #include "gmime-stream-mem.h"
35 #include "gmime-parser.h"
36 #include "gmime-part.h"
37 #include "gmime-error.h"
38
39 #ifdef ENABLE_DEBUG
40 #define d(x) x
41 #else
42 #define d(x)
43 #endif
44
45 #define _(x) x
46
47
48 /**
49  * SECTION: gmime-multipart-encrypted
50  * @title: GMimeMultipartEncrypted
51  * @short_description: Encrypted MIME multiparts
52  * @see_also: #GMimeMultipart
53  *
54  * A #GMimeMultipartEncrypted part is a special subclass of
55  * #GMimeMultipart to make it easier to manipulate the
56  * multipart/encrypted MIME type.
57  **/
58
59
60 /* GObject class methods */
61 static void g_mime_multipart_encrypted_class_init (GMimeMultipartEncryptedClass *klass);
62 static void g_mime_multipart_encrypted_init (GMimeMultipartEncrypted *mps, GMimeMultipartEncryptedClass *klass);
63 static void g_mime_multipart_encrypted_finalize (GObject *object);
64
65
66 static GMimeMultipartClass *parent_class = NULL;
67
68
69 GType
70 g_mime_multipart_encrypted_get_type (void)
71 {
72         static GType type = 0;
73         
74         if (!type) {
75                 static const GTypeInfo info = {
76                         sizeof (GMimeMultipartEncryptedClass),
77                         NULL, /* base_class_init */
78                         NULL, /* base_class_finalize */
79                         (GClassInitFunc) g_mime_multipart_encrypted_class_init,
80                         NULL, /* class_finalize */
81                         NULL, /* class_data */
82                         sizeof (GMimeMultipartEncrypted),
83                         0,    /* n_preallocs */
84                         (GInstanceInitFunc) g_mime_multipart_encrypted_init,
85                 };
86                 
87                 type = g_type_register_static (GMIME_TYPE_MULTIPART, "GMimeMultipartEncrypted", &info, 0);
88         }
89         
90         return type;
91 }
92
93
94 static void
95 g_mime_multipart_encrypted_class_init (GMimeMultipartEncryptedClass *klass)
96 {
97         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
98         
99         parent_class = g_type_class_ref (GMIME_TYPE_MULTIPART);
100         
101         gobject_class->finalize = g_mime_multipart_encrypted_finalize;
102 }
103
104 static void
105 g_mime_multipart_encrypted_init (GMimeMultipartEncrypted *mpe, GMimeMultipartEncryptedClass *klass)
106 {
107         
108 }
109
110 static void
111 g_mime_multipart_encrypted_finalize (GObject *object)
112 {
113         G_OBJECT_CLASS (parent_class)->finalize (object);
114 }
115
116
117 /**
118  * g_mime_multipart_encrypted_new:
119  *
120  * Creates a new MIME multipart/encrypted object.
121  *
122  * Returns: an empty MIME multipart/encrypted object.
123  **/
124 GMimeMultipartEncrypted *
125 g_mime_multipart_encrypted_new (void)
126 {
127         GMimeMultipartEncrypted *multipart;
128         GMimeContentType *content_type;
129         
130         multipart = g_object_newv (GMIME_TYPE_MULTIPART_ENCRYPTED, 0, NULL);
131         
132         content_type = g_mime_content_type_new ("multipart", "encrypted");
133         g_mime_object_set_content_type (GMIME_OBJECT (multipart), content_type);
134         g_object_unref (content_type);
135         
136         return multipart;
137 }
138
139
140 /**
141  * g_mime_multipart_encrypted_encrypt:
142  * @mpe: multipart/encrypted object
143  * @content: MIME part to encrypt
144  * @ctx: encryption context
145  * @sign: %TRUE if the content should also be signed or %FALSE otherwise
146  * @userid: user id to use for signing (only used if @sign is %TRUE)
147  * @digest: digest algorithm to use when signing
148  * @recipients: an array of recipients to encrypt to
149  * @err: a #GError
150  *
151  * Attempts to encrypt (and conditionally sign) the @content MIME part
152  * to the public keys of @recipients using the @ctx encryption
153  * context. If successful, the encrypted #GMimeObject is set as the
154  * encrypted part of the multipart/encrypted object @mpe.
155  *
156  * Returns: %0 on success or %-1 on fail. If the encryption fails, an
157  * exception will be set on @err to provide information as to why the
158  * failure occured.
159  **/
160 int
161 g_mime_multipart_encrypted_encrypt (GMimeMultipartEncrypted *mpe, GMimeObject *content,
162                                     GMimeCryptoContext *ctx, gboolean sign,
163                                     const char *userid, GMimeDigestAlgo digest,
164                                     GPtrArray *recipients, GError **err)
165 {
166         GMimeStream *filtered_stream, *ciphertext, *stream;
167         GMimePart *version_part, *encrypted_part;
168         GMimeContentType *content_type;
169         GMimeDataWrapper *wrapper;
170         GMimeFilter *crlf_filter;
171         const char *protocol;
172         
173         g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED (mpe), -1);
174         g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), -1);
175         g_return_val_if_fail (GMIME_IS_OBJECT (content), -1);
176         
177         if (!(protocol = g_mime_crypto_context_get_encryption_protocol (ctx))) {
178                 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("Encryption not supported."));
179                 return -1;
180         }
181         
182         /* get the cleartext */
183         stream = g_mime_stream_mem_new ();
184         filtered_stream = g_mime_stream_filter_new (stream);
185         
186         crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE);
187         g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), crlf_filter);
188         g_object_unref (crlf_filter);
189         
190         g_mime_object_write_to_stream (content, filtered_stream);
191         g_mime_stream_flush (filtered_stream);
192         g_object_unref (filtered_stream);
193         
194         /* reset the content stream */
195         g_mime_stream_reset (stream);
196         
197         /* encrypt the content stream */
198         ciphertext = g_mime_stream_mem_new ();
199         if (g_mime_crypto_context_encrypt (ctx, sign, userid, digest, recipients, stream, ciphertext, err) == -1) {
200                 g_object_unref (ciphertext);
201                 g_object_unref (stream);
202                 return -1;
203         }
204         
205         g_object_unref (stream);
206         g_mime_stream_reset (ciphertext);
207         
208         /* construct the version part */
209         content_type = g_mime_content_type_new_from_string (protocol);
210         version_part = g_mime_part_new_with_type (content_type->type, content_type->subtype);
211         g_object_unref (content_type);
212         
213         content_type = g_mime_content_type_new_from_string (protocol);
214         g_mime_object_set_content_type (GMIME_OBJECT (version_part), content_type);
215         g_mime_part_set_content_encoding (version_part, GMIME_CONTENT_ENCODING_7BIT);
216         stream = g_mime_stream_mem_new_with_buffer ("Version: 1\n", strlen ("Version: 1\n"));
217         wrapper = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_7BIT);
218         g_mime_part_set_content_object (version_part, wrapper);
219         g_object_unref (wrapper);
220         g_object_unref (stream);
221         
222         /* construct the encrypted mime part */
223         encrypted_part = g_mime_part_new_with_type ("application", "octet-stream");
224         g_mime_part_set_content_encoding (encrypted_part, GMIME_CONTENT_ENCODING_7BIT);
225         wrapper = g_mime_data_wrapper_new_with_stream (ciphertext, GMIME_CONTENT_ENCODING_7BIT);
226         g_mime_part_set_content_object (encrypted_part, wrapper);
227         g_object_unref (ciphertext);
228         g_object_unref (wrapper);
229         
230         /* save the version and encrypted parts */
231         /* FIXME: make sure there aren't any other parts?? */
232         g_mime_multipart_add (GMIME_MULTIPART (mpe), GMIME_OBJECT (version_part));
233         g_mime_multipart_add (GMIME_MULTIPART (mpe), GMIME_OBJECT (encrypted_part));
234         g_object_unref (encrypted_part);
235         g_object_unref (version_part);
236         
237         /* set the content-type params for this multipart/encrypted part */
238         g_mime_object_set_content_type_parameter (GMIME_OBJECT (mpe), "protocol", protocol);
239         g_mime_multipart_set_boundary (GMIME_MULTIPART (mpe), NULL);
240         
241         return 0;
242 }
243
244
245 static GMimeStream *
246 g_mime_data_wrapper_get_decoded_stream (GMimeDataWrapper *wrapper)
247 {
248         GMimeStream *decoded_stream;
249         GMimeFilter *decoder;
250         
251         g_mime_stream_reset (wrapper->stream);
252         
253         switch (wrapper->encoding) {
254         case GMIME_CONTENT_ENCODING_BASE64:
255         case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
256         case GMIME_CONTENT_ENCODING_UUENCODE:
257                 decoder = g_mime_filter_basic_new (wrapper->encoding, FALSE);
258                 decoded_stream = g_mime_stream_filter_new (wrapper->stream);
259                 g_mime_stream_filter_add (GMIME_STREAM_FILTER (decoded_stream), decoder);
260                 g_object_unref (decoder);
261                 break;
262         default:
263                 decoded_stream = wrapper->stream;
264                 g_object_ref (wrapper->stream);
265                 break;
266         }
267         
268         return decoded_stream;
269 }
270
271
272 /**
273  * g_mime_multipart_encrypted_decrypt:
274  * @mpe: multipart/encrypted object
275  * @ctx: decryption context
276  * @result: a #GMimeDecryptionResult
277  * @err: a #GError
278  *
279  * Attempts to decrypt the encrypted MIME part contained within the
280  * multipart/encrypted object @mpe using the @ctx decryption context.
281  *
282  * If @result is non-%NULL, then on a successful decrypt operation, it will be
283  * updated to point to a newly-allocated #GMimeDecryptResult with signature
284  * status information as well as a list of recipients that the part was
285  * encrypted to.
286  *
287  * Returns: the decrypted MIME part on success or %NULL on fail. If the
288  * decryption fails, an exception will be set on @err to provide
289  * information as to why the failure occured.
290  **/
291 GMimeObject *
292 g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe, GMimeCryptoContext *ctx,
293                                     GMimeDecryptResult **result, GError **err)
294 {
295         GMimeObject *decrypted, *version, *encrypted;
296         GMimeStream *stream, *ciphertext;
297         const char *protocol, *supported;
298         GMimeStream *filtered_stream;
299         GMimeContentType *mime_type;
300         GMimeDataWrapper *wrapper;
301         GMimeFilter *crlf_filter;
302         GMimeDecryptResult *res;
303         GMimeParser *parser;
304         char *content_type;
305         
306         g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED (mpe), NULL);
307         g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), NULL);
308         
309         if (result)
310                 *result = NULL;
311         
312         protocol = g_mime_object_get_content_type_parameter (GMIME_OBJECT (mpe), "protocol");
313         supported = g_mime_crypto_context_get_encryption_protocol (ctx);
314         
315         if (protocol) {
316                 /* make sure the protocol matches the crypto encrypt protocol */
317                 if (!supported || g_ascii_strcasecmp (supported, protocol) != 0) {
318                         g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
319                                      _("Cannot decrypt multipart/encrypted part: unsupported encryption protocol '%s'."),
320                                      protocol);
321                         
322                         return NULL;
323                 }
324         } else if (supported != NULL) {
325                 /* *shrug* - I guess just go on as if they match? */
326                 protocol = supported;
327         } else {
328                 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
329                                      _("Cannot decrypt multipart/encrypted part: unspecified encryption protocol."));
330                 
331                 return NULL;
332         }
333         
334         version = g_mime_multipart_get_part (GMIME_MULTIPART (mpe), GMIME_MULTIPART_ENCRYPTED_VERSION);
335         
336         /* make sure the protocol matches the version part's content-type */
337         content_type = g_mime_content_type_to_string (version->content_type);
338         if (g_ascii_strcasecmp (content_type, protocol) != 0) {
339                 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
340                                      _("Cannot decrypt multipart/encrypted part: content-type does not match protocol."));
341                 
342                 g_free (content_type);
343                 
344                 return NULL;
345         }
346         g_free (content_type);
347         
348         /* get the encrypted part and check that it is of type application/octet-stream */
349         encrypted = g_mime_multipart_get_part (GMIME_MULTIPART (mpe), GMIME_MULTIPART_ENCRYPTED_CONTENT);
350         mime_type = g_mime_object_get_content_type (encrypted);
351         if (!g_mime_content_type_is_type (mime_type, "application", "octet-stream")) {
352                 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
353                                      _("Cannot decrypt multipart/encrypted part: unexpected content type."));
354                 
355                 return NULL;
356         }
357         
358         /* get the ciphertext stream */
359         wrapper = g_mime_part_get_content_object (GMIME_PART (encrypted));
360         ciphertext = g_mime_data_wrapper_get_decoded_stream (wrapper);
361         g_mime_stream_reset (ciphertext);
362         
363         stream = g_mime_stream_mem_new ();
364         filtered_stream = g_mime_stream_filter_new (stream);
365         crlf_filter = g_mime_filter_crlf_new (FALSE, FALSE);
366         g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), crlf_filter);
367         g_object_unref (crlf_filter);
368         
369         /* get the cleartext */
370         if (!(res = g_mime_crypto_context_decrypt (ctx, ciphertext, filtered_stream, err))) {
371                 g_object_unref (filtered_stream);
372                 g_object_unref (ciphertext);
373                 g_object_unref (stream);
374                 
375                 return NULL;
376         }
377         
378         g_mime_stream_flush (filtered_stream);
379         g_object_unref (filtered_stream);
380         g_object_unref (ciphertext);
381         
382         g_mime_stream_reset (stream);
383         parser = g_mime_parser_new ();
384         g_mime_parser_init_with_stream (parser, stream);
385         g_object_unref (stream);
386         
387         decrypted = g_mime_parser_construct_part (parser);
388         g_object_unref (parser);
389         
390         if (!decrypted) {
391                 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
392                                      _("Cannot decrypt multipart/encrypted part: failed to parse decrypted content."));
393                 
394                 g_object_unref (res);
395                 
396                 return NULL;
397         }
398         
399         if (!result)
400                 g_object_unref (res);
401         else
402                 *result = res;
403         
404         return decrypted;
405 }