1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* GMime
3 * Copyright (C) 2000-2020 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 <string.h>
27
28 #include "gmime-application-pkcs7-mime.h"
29 #include "gmime-filter-dos2unix.h"
30 #include "gmime-stream-filter.h"
31 #include "gmime-filter-basic.h"
32 #include "gmime-stream-mem.h"
33 #include "gmime-internal.h"
34 #include "gmime-parser.h"
35 #include "gmime-error.h"
36
37 #define _(x) x
38
39 /**
40 * SECTION: gmime-application-pkcs7-mime
41 * @title: GMimeApplicationPkcs7Mime
42 * @short_description: Pkcs7 MIME parts
43 * @see_also:
44 *
45 * A #GMimeApplicationPkcs7Mime represents the application/pkcs7-mime MIME part.
46 **/
47
48 /* GObject class methods */
49 static void g_mime_application_pkcs7_mime_class_init (GMimeApplicationPkcs7MimeClass *klass);
50 static void g_mime_application_pkcs7_mime_init (GMimeApplicationPkcs7Mime *catpart, GMimeApplicationPkcs7MimeClass *klass);
51 static void g_mime_application_pkcs7_mime_finalize (GObject *object);
52
53 /* GMimeObject class methods */
54 static void application_pkcs7_mime_set_content_type (GMimeObject *object, GMimeContentType *content_type);
55
56
57 static GMimePartClass *parent_class = NULL;
58
59
60 GType
g_mime_application_pkcs7_mime_get_type(void)61 g_mime_application_pkcs7_mime_get_type (void)
62 {
63 static GType type = 0;
64
65 if (!type) {
66 static const GTypeInfo info = {
67 sizeof (GMimeApplicationPkcs7MimeClass),
68 NULL, /* base_class_init */
69 NULL, /* base_class_finalize */
70 (GClassInitFunc) g_mime_application_pkcs7_mime_class_init,
71 NULL, /* class_finalize */
72 NULL, /* class_data */
73 sizeof (GMimeApplicationPkcs7Mime),
74 0, /* n_preallocs */
75 (GInstanceInitFunc) g_mime_application_pkcs7_mime_init,
76 };
77
78 type = g_type_register_static (GMIME_TYPE_PART, "GMimeApplicationPkcs7Mime", &info, 0);
79 }
80
81 return type;
82 }
83
84
85 static void
g_mime_application_pkcs7_mime_class_init(GMimeApplicationPkcs7MimeClass * klass)86 g_mime_application_pkcs7_mime_class_init (GMimeApplicationPkcs7MimeClass *klass)
87 {
88 GMimeObjectClass *object_class = GMIME_OBJECT_CLASS (klass);
89 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
90
91 parent_class = g_type_class_ref (GMIME_TYPE_PART);
92
93 gobject_class->finalize = g_mime_application_pkcs7_mime_finalize;
94
95 object_class->set_content_type = application_pkcs7_mime_set_content_type;
96 }
97
98 static void
g_mime_application_pkcs7_mime_init(GMimeApplicationPkcs7Mime * pkcs7_mime,GMimeApplicationPkcs7MimeClass * klass)99 g_mime_application_pkcs7_mime_init (GMimeApplicationPkcs7Mime *pkcs7_mime, GMimeApplicationPkcs7MimeClass *klass)
100 {
101 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_UNKNOWN;
102 }
103
104 static void
g_mime_application_pkcs7_mime_finalize(GObject * object)105 g_mime_application_pkcs7_mime_finalize (GObject *object)
106 {
107 G_OBJECT_CLASS (parent_class)->finalize (object);
108 }
109
110
111 static void
application_pkcs7_mime_set_content_type(GMimeObject * object,GMimeContentType * content_type)112 application_pkcs7_mime_set_content_type (GMimeObject *object, GMimeContentType *content_type)
113 {
114 GMimeApplicationPkcs7Mime *pkcs7_mime = (GMimeApplicationPkcs7Mime *) object;
115 const char *value;
116
117 if ((value = g_mime_content_type_get_parameter (content_type, "smime-type")) != NULL) {
118 if (!g_ascii_strcasecmp (value, "compressed-data"))
119 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_COMPRESSED_DATA;
120 else if (!g_ascii_strcasecmp (value, "enveloped-data"))
121 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA;
122 else if (!g_ascii_strcasecmp (value, "signed-data"))
123 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_SIGNED_DATA;
124 else if (!g_ascii_strcasecmp (value, "certs-only"))
125 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_CERTS_ONLY;
126 else
127 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_UNKNOWN;
128 } else {
129 pkcs7_mime->smime_type = GMIME_SECURE_MIME_TYPE_UNKNOWN;
130 }
131
132 GMIME_OBJECT_CLASS (parent_class)->set_content_type (object, content_type);
133 }
134
135 /**
136 * g_mime_application_pkcs7_mime_new:
137 * @type: The type of S/MIME data contained within the part.
138 *
139 * Creates a new application/pkcs7-mime object.
140 *
141 * Returns: an empty application/pkcs7-mime object.
142 **/
143 GMimeApplicationPkcs7Mime *
g_mime_application_pkcs7_mime_new(GMimeSecureMimeType type)144 g_mime_application_pkcs7_mime_new (GMimeSecureMimeType type)
145 {
146 GMimeApplicationPkcs7Mime *pkcs7_mime;
147 GMimeContentType *content_type;
148 const char *name;
149
150 g_return_val_if_fail (type != GMIME_SECURE_MIME_TYPE_UNKNOWN, NULL);
151
152 pkcs7_mime = g_object_new (GMIME_TYPE_APPLICATION_PKCS7_MIME, NULL);
153 content_type = g_mime_content_type_new ("application", "pkcs7-mime");
154
155 switch (type) {
156 case GMIME_SECURE_MIME_TYPE_COMPRESSED_DATA:
157 g_mime_content_type_set_parameter (content_type, "smime-type", "compressed-data");
158 name = "smime.p7z";
159 break;
160 case GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA:
161 g_mime_content_type_set_parameter (content_type, "smime-type", "enveloped-data");
162 name = "smime.p7m";
163 break;
164 case GMIME_SECURE_MIME_TYPE_SIGNED_DATA:
165 g_mime_content_type_set_parameter (content_type, "smime-type", "signed-data");
166 name = "smime.p7m";
167 break;
168 case GMIME_SECURE_MIME_TYPE_CERTS_ONLY:
169 g_mime_content_type_set_parameter (content_type, "smime-type", "certs-only");
170 name = "smime.p7c";
171 break;
172 default:
173 g_assert_not_reached ();
174 break;
175 }
176
177 g_mime_object_set_content_type ((GMimeObject *) pkcs7_mime, content_type);
178 g_object_unref (content_type);
179
180 g_mime_part_set_filename ((GMimePart *) pkcs7_mime, name);
181 g_mime_part_set_content_encoding ((GMimePart *) pkcs7_mime, GMIME_CONTENT_ENCODING_BASE64);
182
183 return pkcs7_mime;
184 }
185
186
187 /**
188 * g_mime_application_pkcs7_mime_get_smime_type:
189 * @pkcs7_mime: A #GMimeApplicationPkcs7Mime object
190 *
191 * Gets the smime-type value of the Content-Type header.
192 *
193 * Returns: the smime-type value.
194 **/
195 GMimeSecureMimeType
g_mime_application_pkcs7_mime_get_smime_type(GMimeApplicationPkcs7Mime * pkcs7_mime)196 g_mime_application_pkcs7_mime_get_smime_type (GMimeApplicationPkcs7Mime *pkcs7_mime)
197 {
198 g_return_val_if_fail (GMIME_IS_APPLICATION_PKCS7_MIME (pkcs7_mime), GMIME_SECURE_MIME_TYPE_UNKNOWN);
199
200 return pkcs7_mime->smime_type;
201 }
202
203
204 #if 0
205 GMimeApplicationPkcs7Mime *
206 g_mime_application_pkcs7_mime_compress (GMimeObject *entity, GError **err)
207 {
208 GMimeApplicationPkcs7Mime *pkcs7_mime;
209 GMimeStream *compressed, *stream;
210 GMimeFormatOptions *options;
211 GMimeDataWrapper *content;
212 GMimeCryptoContext *ctx;
213
214 g_return_val_if_fail (GMIME_IS_OBJECT (entity), NULL);
215
216 if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
217 g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
218 _("Cannot compress application/pkcs7-mime part: no crypto context registered for this type."));
219
220 return NULL;
221 }
222
223 options = _g_mime_format_options_clone (NULL, FALSE);
224 g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
225
226 /* get the cleartext */
227 stream = g_mime_stream_mem_new ();
228 g_mime_object_write_to_stream (entity, options, stream);
229 g_mime_format_options_free (options);
230
231 /* reset the content stream */
232 g_mime_stream_reset (stream);
233
234 /* compress the content stream */
235 compressed = g_mime_stream_mem_new ();
236 if (g_mime_crypto_context_compress (ctx, stream, compressed, err) == -1) {
237 g_object_unref (compressed);
238 g_object_unref (stream);
239 g_object_unref (ctx);
240 return NULL;
241 }
242
243 g_object_unref (stream);
244 g_mime_stream_reset (compressed);
245 g_object_unref (ctx);
246
247 /* construct the application/pkcs7-mime part */
248 pkcs7_mime = g_mime_application_pkcs7_mime_new (GMIME_SECURE_MIME_TYPE_COMPRESSED_DATA);
249 content = g_mime_data_wrapper_new_with_stream (compressed, GMIME_CONTENT_ENCODING_DEFAULT);
250 g_mime_part_set_content ((GMimePart *) pkcs7_mime, content);
251 g_object_unref (compressed);
252 g_object_unref (content);
253
254 return pkcs7_mime;
255 }
256
257
258 GMimeObject *
259 g_mime_application_pkcs7_mime_decompress (GMimeApplicationPkcs7Mime *pkcs7_mime)
260 {
261 GMimeStream *filtered, *compressed, *stream;
262 GMimeObject *decompressed;
263 GMimeDataWrapper *content;
264 GMimeCryptoContext *ctx;
265 GMimeDecryptResult *res;
266 GMimeFilter *filter;
267 GMimeParser *parser;
268
269 g_return_val_if_fail (GMIME_IS_APPLICATION_PKCS7_MIME (pkcs7_mime), NULL);
270
271 if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
272 g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
273 _("Cannot decompress application/pkcs7-mime part: no crypto context registered for this type."));
274
275 return NULL;
276 }
277
278 /* get the compressed stream */
279 content = g_mime_part_get_content ((GMimePart *) pkcs7_mime);
280 compressed = g_mime_stream_mem_new ();
281 g_mime_data_wrapper_write_to_stream (content, compressed);
282 g_mime_stream_reset (compressed);
283
284 stream = g_mime_stream_mem_new ();
285 filtered = g_mime_stream_filter_new (stream);
286 filter = g_mime_filter_dos2unix_new (FALSE);
287 g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
288 g_object_unref (filter);
289
290 /* decompress the content stream */
291 if (g_mime_crypto_context_decompress (ctx, compressed, stream, err) == -1) {
292 g_object_unref (compressed);
293 g_object_unref (filtered);
294 g_object_unref (stream);
295 g_object_unref (ctx);
296
297 return NULL;
298 }
299
300 g_mime_stream_flush (filtered);
301 g_object_unref (compressed);
302 g_object_unref (filtered);
303 g_object_unref (ctx);
304
305 g_mime_stream_reset (stream);
306 parser = g_mime_parser_new ();
307 g_mime_parser_init_with_stream (parser, stream);
308 g_object_unref (stream);
309
310 decompressed = g_mime_parser_construct_part (parser, NULL);
311 g_object_unref (parser);
312
313 if (!decompressed) {
314 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
315 _("Cannot decompress application/pkcs7-mime part: failed to parse decompressed content."));
316
317 return NULL;
318 }
319
320 return decompressed;
321 }
322 #endif
323
324
325 /**
326 * g_mime_application_pkcs7_mime_encrypt:
327 * @entity: a #GMimeObject to encrypt
328 * @flags: a #GMimeEncryptFlags
329 * @recipients: (element-type utf8): an array of recipients to encrypt to
330 * @err: a #GError
331 *
332 * Attempts to encrypt the @entity MIME part to the public keys of @recipients
333 * using S/MIME. If successful, a new application/pkcs7-mime object is returned.
334 *
335 * Returns: (nullable) (transfer full): a new #GMimeApplicationPkcs7Mime object on success
336 * or %NULL on fail. If encrypting fails, an exception will be set on @err to provide
337 * information as to why the failure occurred.
338 **/
339 GMimeApplicationPkcs7Mime *
g_mime_application_pkcs7_mime_encrypt(GMimeObject * entity,GMimeEncryptFlags flags,GPtrArray * recipients,GError ** err)340 g_mime_application_pkcs7_mime_encrypt (GMimeObject *entity, GMimeEncryptFlags flags, GPtrArray *recipients, GError **err)
341 {
342 GMimeApplicationPkcs7Mime *pkcs7_mime;
343 GMimeStream *ciphertext, *stream;
344 GMimeFormatOptions *options;
345 GMimeDataWrapper *content;
346 GMimeCryptoContext *ctx;
347
348 g_return_val_if_fail (GMIME_IS_OBJECT (entity), NULL);
349 g_return_val_if_fail (recipients != NULL, NULL);
350
351 if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
352 g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
353 _("Cannot encrypt application/pkcs7-mime part: no crypto context registered for this type."));
354
355 return NULL;
356 }
357
358 options = _g_mime_format_options_clone (NULL, FALSE);
359 g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
360
361 /* get the cleartext */
362 stream = g_mime_stream_mem_new ();
363 g_mime_object_write_to_stream (entity, options, stream);
364 g_mime_format_options_free (options);
365
366 /* reset the content stream */
367 g_mime_stream_reset (stream);
368
369 /* encrypt the content stream */
370 ciphertext = g_mime_stream_mem_new ();
371 if (g_mime_crypto_context_encrypt (ctx, FALSE, NULL, flags, recipients, stream, ciphertext, err) == -1) {
372 g_object_unref (ciphertext);
373 g_object_unref (stream);
374 g_object_unref (ctx);
375 return NULL;
376 }
377
378 g_object_unref (stream);
379 g_mime_stream_reset (ciphertext);
380 g_object_unref (ctx);
381
382 /* construct the application/pkcs7-mime part */
383 pkcs7_mime = g_mime_application_pkcs7_mime_new (GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA);
384 content = g_mime_data_wrapper_new_with_stream (ciphertext, GMIME_CONTENT_ENCODING_DEFAULT);
385 g_mime_part_set_content ((GMimePart *) pkcs7_mime, content);
386 g_object_unref (ciphertext);
387 g_object_unref (content);
388
389 return pkcs7_mime;
390 }
391
392
393 /**
394 * g_mime_application_pkcs7_mime_decrypt:
395 * @pkcs7_mime: a #GMimeApplicationPkcs7Mime
396 * @flags: a #GMimeDecryptFlags
397 * @session_key: session key to use or %NULL
398 * @result: the decryption result
399 * @err: a #GError
400 *
401 * Attempts to decrypt the encrypted application/pkcs7-mime part.
402 *
403 * When non-%NULL, @session_key should be a %NULL-terminated string,
404 * such as the one returned by g_mime_decrypt_result_get_session_key()
405 * from a previous decryption. If the @session_key is not valid, decryption
406 * will fail.
407 *
408 * If @result is non-%NULL, then on a successful decrypt operation, it will be
409 * updated to point to a newly-allocated #GMimeDecryptResult with signature
410 * status information as well as a list of recipients that the part was
411 * encrypted to.
412 *
413 * Returns: (nullable) (transfer full): the decrypted MIME part on success or
414 * %NULL on fail. If the decryption fails, an exception will be set on
415 * @err to provide information as to why the failure occurred.
416 **/
417 GMimeObject *
g_mime_application_pkcs7_mime_decrypt(GMimeApplicationPkcs7Mime * pkcs7_mime,GMimeDecryptFlags flags,const char * session_key,GMimeDecryptResult ** result,GError ** err)418 g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime,
419 GMimeDecryptFlags flags, const char *session_key,
420 GMimeDecryptResult **result, GError **err)
421 {
422 GMimeStream *filtered, *ciphertext, *stream;
423 GMimeDataWrapper *content;
424 GMimeCryptoContext *ctx;
425 GMimeDecryptResult *res;
426 GMimeObject *decrypted;
427 GMimeFilter *filter;
428 GMimeParser *parser;
429
430 g_return_val_if_fail (GMIME_IS_APPLICATION_PKCS7_MIME (pkcs7_mime), NULL);
431
432 if (result)
433 *result = NULL;
434
435 if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
436 g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
437 _("Cannot decrypt application/pkcs7-mime part: no crypto context registered for this type."));
438
439 return NULL;
440 }
441
442 /* get the ciphertext stream */
443 content = g_mime_part_get_content ((GMimePart *) pkcs7_mime);
444 ciphertext = g_mime_stream_mem_new ();
445 g_mime_data_wrapper_write_to_stream (content, ciphertext);
446 g_mime_stream_reset (ciphertext);
447
448 stream = g_mime_stream_mem_new ();
449 filtered = g_mime_stream_filter_new (stream);
450 filter = g_mime_filter_dos2unix_new (FALSE);
451 g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
452 g_object_unref (filter);
453
454 /* decrypt the content stream */
455 if (!(res = g_mime_crypto_context_decrypt (ctx, flags, session_key, ciphertext, filtered, err))) {
456 g_object_unref (ciphertext);
457 g_object_unref (filtered);
458 g_object_unref (stream);
459 g_object_unref (ctx);
460
461 return NULL;
462 }
463
464 g_mime_stream_flush (filtered);
465 g_object_unref (ciphertext);
466 g_object_unref (filtered);
467 g_object_unref (ctx);
468
469 g_mime_stream_reset (stream);
470 parser = g_mime_parser_new ();
471 g_mime_parser_init_with_stream (parser, stream);
472 g_object_unref (stream);
473
474 decrypted = g_mime_parser_construct_part (parser, NULL);
475 g_object_unref (parser);
476
477 if (!decrypted) {
478 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
479 _("Cannot decrypt application/pkcs7-mime part: failed to parse decrypted content."));
480
481 g_object_unref (res);
482
483 return NULL;
484 }
485
486 if (!result)
487 g_object_unref (res);
488 else
489 *result = res;
490
491 return decrypted;
492 }
493
494
495 /**
496 * g_mime_application_pkcs7_mime_sign:
497 * @entity: a #GMimeObject
498 * @userid: the user id to sign with
499 * @err: a #GError
500 *
501 * Attempts to sign the @entity MIME part with @userid's private key using
502 * S/MIME. If successful, a new application/pkcs7-mime object is returned.
503 *
504 * Returns: (nullable) (transfer full): a new #GMimeApplicationPkcs7Mime object on success
505 * or %NULL on fail. If signing fails, an exception will be set on @err to provide
506 * information as to why the failure occurred.
507 **/
508 GMimeApplicationPkcs7Mime *
g_mime_application_pkcs7_mime_sign(GMimeObject * entity,const char * userid,GError ** err)509 g_mime_application_pkcs7_mime_sign (GMimeObject *entity, const char *userid, GError **err)
510 {
511 GMimeApplicationPkcs7Mime *pkcs7_mime;
512 GMimeStream *ciphertext, *stream;
513 GMimeFormatOptions *options;
514 GMimeDataWrapper *content;
515 GMimeCryptoContext *ctx;
516
517 g_return_val_if_fail (GMIME_IS_OBJECT (entity), NULL);
518 g_return_val_if_fail (userid != NULL, NULL);
519
520 if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
521 g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
522 _("Cannot sign application/pkcs7-mime part: no crypto context registered for this type."));
523
524 return NULL;
525 }
526
527 options = _g_mime_format_options_clone (NULL, FALSE);
528 g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
529
530 /* get the cleartext */
531 stream = g_mime_stream_mem_new ();
532 g_mime_object_write_to_stream (entity, options, stream);
533 g_mime_format_options_free (options);
534
535 /* reset the content stream */
536 g_mime_stream_reset (stream);
537
538 /* sign the content stream */
539 ciphertext = g_mime_stream_mem_new ();
540 if (g_mime_crypto_context_sign (ctx, FALSE, userid, stream, ciphertext, err) == -1) {
541 g_object_unref (ciphertext);
542 g_object_unref (stream);
543 g_object_unref (ctx);
544 return NULL;
545 }
546
547 g_object_unref (stream);
548 g_mime_stream_reset (ciphertext);
549 g_object_unref (ctx);
550
551 /* construct the application/pkcs7-mime part */
552 pkcs7_mime = g_mime_application_pkcs7_mime_new (GMIME_SECURE_MIME_TYPE_SIGNED_DATA);
553 content = g_mime_data_wrapper_new_with_stream (ciphertext, GMIME_CONTENT_ENCODING_DEFAULT);
554 g_mime_part_set_content ((GMimePart *) pkcs7_mime, content);
555 g_object_unref (ciphertext);
556 g_object_unref (content);
557
558 return pkcs7_mime;
559 }
560
561
562 /**
563 * g_mime_application_pkcs7_mime_verify:
564 * @pkcs7_mime: a #GMimeApplicationPkcs7Mime
565 * @flags: a #GMimeVerifyFlags
566 * @entity: (out) (transfer full): the extracted entity
567 * @err: a #GError
568 *
569 * Attempts to verify the signed @pkcs7_mime part and extract the original
570 * MIME entity.
571 *
572 * Returns: (nullable) (transfer full): a new #GMimeSignatureList object on
573 * success or %NULL on fail. If the verification fails, an exception
574 * will be set on @err to provide information as to why the failure
575 * occurred.
576 **/
577 GMimeSignatureList *
g_mime_application_pkcs7_mime_verify(GMimeApplicationPkcs7Mime * pkcs7_mime,GMimeVerifyFlags flags,GMimeObject ** entity,GError ** err)578 g_mime_application_pkcs7_mime_verify (GMimeApplicationPkcs7Mime *pkcs7_mime, GMimeVerifyFlags flags, GMimeObject **entity, GError **err)
579 {
580 GMimeStream *filtered, *ciphertext, *stream;
581 GMimeSignatureList *signatures;
582 GMimeDataWrapper *content;
583 GMimeCryptoContext *ctx;
584 GMimeFilter *filter;
585 GMimeParser *parser;
586
587 g_return_val_if_fail (GMIME_IS_APPLICATION_PKCS7_MIME (pkcs7_mime), NULL);
588 g_return_val_if_fail (entity != NULL, NULL);
589
590 *entity = NULL;
591
592 if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
593 g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
594 _("Cannot verify application/pkcs7-mime part: no crypto context registered for this type."));
595
596 return NULL;
597 }
598
599 /* get the ciphertext stream */
600 content = g_mime_part_get_content ((GMimePart *) pkcs7_mime);
601 ciphertext = g_mime_stream_mem_new ();
602 g_mime_data_wrapper_write_to_stream (content, ciphertext);
603 g_mime_stream_reset (ciphertext);
604
605 stream = g_mime_stream_mem_new ();
606 filtered = g_mime_stream_filter_new (stream);
607 filter = g_mime_filter_dos2unix_new (FALSE);
608 g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
609 g_object_unref (filter);
610
611 /* decrypt the content stream */
612 if (!(signatures = g_mime_crypto_context_verify (ctx, flags, ciphertext, NULL, filtered, err))) {
613 g_object_unref (ciphertext);
614 g_object_unref (filtered);
615 g_object_unref (stream);
616 g_object_unref (ctx);
617
618 return NULL;
619 }
620
621 g_mime_stream_flush (filtered);
622 g_object_unref (ciphertext);
623 g_object_unref (filtered);
624 g_object_unref (ctx);
625
626 g_mime_stream_reset (stream);
627 parser = g_mime_parser_new ();
628 g_mime_parser_init_with_stream (parser, stream);
629 g_object_unref (stream);
630
631 *entity = g_mime_parser_construct_part (parser, NULL);
632 g_object_unref (parser);
633
634 if (*entity == NULL) {
635 g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
636 _("Cannot verify application/pkcs7-mime part: failed to parse extracted content."));
637
638 g_object_unref (signatures);
639
640 return NULL;
641 }
642
643 return signatures;
644 }
645