1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000-2012 Jeffrey Stedfast
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.
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.
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
30 #include "gmime-pkcs7-context.h"
32 #include "gmime-filter-charset.h"
33 #include "gmime-stream-filter.h"
34 #include "gmime-stream-pipe.h"
35 #include "gmime-stream-mem.h"
36 #include "gmime-stream-fs.h"
37 #include "gmime-charset.h"
38 #endif /* ENABLE_SMIME */
39 #include "gmime-error.h"
55 * SECTION: gmime-pkcs7-context
56 * @title: GMimePkcs7Context
57 * @short_description: PKCS7 crypto contexts
58 * @see_also: #GMimeCryptoContext
60 * A #GMimePkcs7Context is a #GMimeCryptoContext that uses GnuPG to do
61 * all of the encryption and digital signatures.
64 typedef struct _GMimePkcs7ContextPrivate {
65 gboolean always_trust;
71 static void g_mime_pkcs7_context_class_init (GMimePkcs7ContextClass *klass);
72 static void g_mime_pkcs7_context_init (GMimePkcs7Context *ctx, GMimePkcs7ContextClass *klass);
73 static void g_mime_pkcs7_context_finalize (GObject *object);
75 static GMimeDigestAlgo pkcs7_digest_id (GMimeCryptoContext *ctx, const char *name);
77 static const char *pkcs7_digest_name (GMimeCryptoContext *ctx, GMimeDigestAlgo digest);
79 static const char *pkcs7_get_signature_protocol (GMimeCryptoContext *ctx);
81 static const char *pkcs7_get_encryption_protocol (GMimeCryptoContext *ctx);
83 static const char *pkcs7_get_key_exchange_protocol (GMimeCryptoContext *ctx);
85 static int pkcs7_sign (GMimeCryptoContext *ctx, const char *userid,
86 GMimeDigestAlgo digest, GMimeStream *istream,
87 GMimeStream *ostream, GError **err);
89 static GMimeSignatureList *pkcs7_verify (GMimeCryptoContext *ctx, GMimeDigestAlgo digest,
90 GMimeStream *istream, GMimeStream *sigstream,
93 static int pkcs7_encrypt (GMimeCryptoContext *ctx, gboolean sign, const char *userid,
94 GMimeDigestAlgo digest, GPtrArray *recipients, GMimeStream *istream,
95 GMimeStream *ostream, GError **err);
97 static GMimeDecryptResult *pkcs7_decrypt (GMimeCryptoContext *ctx, GMimeStream *istream,
98 GMimeStream *ostream, GError **err);
100 static int pkcs7_import_keys (GMimeCryptoContext *ctx, GMimeStream *istream,
103 static int pkcs7_export_keys (GMimeCryptoContext *ctx, GPtrArray *keys,
104 GMimeStream *ostream, GError **err);
107 static GMimeCryptoContextClass *parent_class = NULL;
111 g_mime_pkcs7_context_get_type (void)
113 static GType type = 0;
116 static const GTypeInfo info = {
117 sizeof (GMimePkcs7ContextClass),
118 NULL, /* base_class_init */
119 NULL, /* base_class_finalize */
120 (GClassInitFunc) g_mime_pkcs7_context_class_init,
121 NULL, /* class_finalize */
122 NULL, /* class_data */
123 sizeof (GMimePkcs7Context),
125 (GInstanceInitFunc) g_mime_pkcs7_context_init,
128 type = g_type_register_static (GMIME_TYPE_CRYPTO_CONTEXT, "GMimePkcs7Context", &info, 0);
136 g_mime_pkcs7_context_class_init (GMimePkcs7ContextClass *klass)
138 GObjectClass *object_class = G_OBJECT_CLASS (klass);
139 GMimeCryptoContextClass *crypto_class = GMIME_CRYPTO_CONTEXT_CLASS (klass);
141 parent_class = g_type_class_ref (G_TYPE_OBJECT);
143 object_class->finalize = g_mime_pkcs7_context_finalize;
145 crypto_class->digest_id = pkcs7_digest_id;
146 crypto_class->digest_name = pkcs7_digest_name;
147 crypto_class->sign = pkcs7_sign;
148 crypto_class->verify = pkcs7_verify;
149 crypto_class->encrypt = pkcs7_encrypt;
150 crypto_class->decrypt = pkcs7_decrypt;
151 crypto_class->import_keys = pkcs7_import_keys;
152 crypto_class->export_keys = pkcs7_export_keys;
153 crypto_class->get_signature_protocol = pkcs7_get_signature_protocol;
154 crypto_class->get_encryption_protocol = pkcs7_get_encryption_protocol;
155 crypto_class->get_key_exchange_protocol = pkcs7_get_key_exchange_protocol;
159 g_mime_pkcs7_context_init (GMimePkcs7Context *ctx, GMimePkcs7ContextClass *klass)
161 ctx->priv = g_slice_new (Pkcs7Ctx);
162 ctx->priv->always_trust = FALSE;
164 ctx->priv->ctx = NULL;
169 g_mime_pkcs7_context_finalize (GObject *object)
171 GMimePkcs7Context *ctx = (GMimePkcs7Context *) object;
175 gpgme_release (ctx->priv->ctx);
178 g_slice_free (Pkcs7Ctx, ctx->priv);
180 G_OBJECT_CLASS (parent_class)->finalize (object);
183 static GMimeDigestAlgo
184 pkcs7_digest_id (GMimeCryptoContext *ctx, const char *name)
187 return GMIME_DIGEST_ALGO_DEFAULT;
189 if (!g_ascii_strcasecmp (name, "md2"))
190 return GMIME_DIGEST_ALGO_MD2;
191 else if (!g_ascii_strcasecmp (name, "md4"))
192 return GMIME_DIGEST_ALGO_MD4;
193 else if (!g_ascii_strcasecmp (name, "md5"))
194 return GMIME_DIGEST_ALGO_MD5;
195 else if (!g_ascii_strcasecmp (name, "sha1"))
196 return GMIME_DIGEST_ALGO_SHA1;
197 else if (!g_ascii_strcasecmp (name, "sha224"))
198 return GMIME_DIGEST_ALGO_SHA224;
199 else if (!g_ascii_strcasecmp (name, "sha256"))
200 return GMIME_DIGEST_ALGO_SHA256;
201 else if (!g_ascii_strcasecmp (name, "sha384"))
202 return GMIME_DIGEST_ALGO_SHA384;
203 else if (!g_ascii_strcasecmp (name, "sha512"))
204 return GMIME_DIGEST_ALGO_SHA512;
205 else if (!g_ascii_strcasecmp (name, "ripemd160"))
206 return GMIME_DIGEST_ALGO_RIPEMD160;
207 else if (!g_ascii_strcasecmp (name, "tiger192"))
208 return GMIME_DIGEST_ALGO_TIGER192;
209 else if (!g_ascii_strcasecmp (name, "haval-5-160"))
210 return GMIME_DIGEST_ALGO_HAVAL5160;
212 return GMIME_DIGEST_ALGO_DEFAULT;
216 pkcs7_digest_name (GMimeCryptoContext *ctx, GMimeDigestAlgo digest)
219 case GMIME_DIGEST_ALGO_MD2:
221 case GMIME_DIGEST_ALGO_MD4:
223 case GMIME_DIGEST_ALGO_MD5:
225 case GMIME_DIGEST_ALGO_SHA1:
227 case GMIME_DIGEST_ALGO_SHA224:
229 case GMIME_DIGEST_ALGO_SHA256:
231 case GMIME_DIGEST_ALGO_SHA384:
233 case GMIME_DIGEST_ALGO_SHA512:
235 case GMIME_DIGEST_ALGO_RIPEMD160:
237 case GMIME_DIGEST_ALGO_TIGER192:
239 case GMIME_DIGEST_ALGO_HAVAL5160:
240 return "haval-5-160";
247 pkcs7_get_signature_protocol (GMimeCryptoContext *ctx)
249 return "application/pkcs7-signature";
253 pkcs7_get_encryption_protocol (GMimeCryptoContext *ctx)
255 return "application/pkcs7-mime";
259 pkcs7_get_key_exchange_protocol (GMimeCryptoContext *ctx)
261 return "application/pkcs7-keys";
266 pkcs7_passphrase_cb (void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd)
268 GMimeCryptoContext *context = (GMimeCryptoContext *) hook;
274 if (context->request_passwd) {
275 stream = g_mime_stream_pipe_new (fd);
276 rv = context->request_passwd (context, uid_hint, passphrase_info, prev_was_bad, stream, &err);
277 g_object_unref (stream);
279 return GPG_ERR_GENERAL;
283 error = GPG_ERR_CANCELED;
286 error = GPG_ERR_NO_ERROR;
293 pkcs7_stream_read (void *stream, void *buffer, size_t size)
295 return g_mime_stream_read ((GMimeStream *) stream, (char *) buffer, size);
299 pkcs7_stream_write (void *stream, const void *buffer, size_t size)
301 return g_mime_stream_write ((GMimeStream *) stream, (const char *) buffer, size);
305 pkcs7_stream_seek (void *stream, off_t offset, int whence)
309 return (off_t) g_mime_stream_seek ((GMimeStream *) stream, (gint64) offset, GMIME_STREAM_SEEK_SET);
311 return (off_t) g_mime_stream_seek ((GMimeStream *) stream, (gint64) offset, GMIME_STREAM_SEEK_CUR);
313 return (off_t) g_mime_stream_seek ((GMimeStream *) stream, (gint64) offset, GMIME_STREAM_SEEK_END);
320 pkcs7_stream_free (void *stream)
325 static struct gpgme_data_cbs pkcs7_stream_funcs = {
334 #define KEY_IS_OK(k) (!((k)->expired || (k)->revoked || \
335 (k)->disabled || (k)->invalid))
338 pkcs7_get_key_by_name (Pkcs7Ctx *pkcs7, const char *name, gboolean secret, GError **err)
340 time_t now = time (NULL);
341 gpgme_key_t key = NULL;
342 gpgme_subkey_t subkey;
343 gboolean bad = FALSE;
347 if ((error = gpgme_op_keylist_start (pkcs7->ctx, name, secret)) != GPG_ERR_NO_ERROR) {
349 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list secret keys for \"%s\""), name);
351 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list keys for \"%s\""), name);
355 while ((error = gpgme_op_keylist_next (pkcs7->ctx, &key)) == GPG_ERR_NO_ERROR) {
356 /* check if this key and the relevant subkey are usable */
357 if (KEY_IS_OK (key)) {
358 subkey = key->subkeys;
360 while (subkey && ((secret && !subkey->can_sign) ||
361 (!secret && !subkey->can_encrypt)))
362 subkey = subkey->next;
364 if (subkey && KEY_IS_OK (subkey) &&
365 (subkey->expires == 0 || subkey->expires > now))
369 errval = GPG_ERR_KEY_EXPIRED;
371 errval = GPG_ERR_BAD_KEY;
374 errval = GPG_ERR_KEY_EXPIRED;
376 errval = GPG_ERR_BAD_KEY;
379 gpgme_key_unref (key);
384 gpgme_op_keylist_end (pkcs7->ctx);
386 if (error != GPG_ERR_NO_ERROR && error != GPG_ERR_EOF) {
388 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list secret keys for \"%s\""), name);
390 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list keys for \"%s\""), name);
396 if (strchr (name, '@')) {
398 g_set_error (err, GMIME_GPGME_ERROR, errval,
399 _("A key for %s is present, but it is expired, disabled, revoked or invalid"),
402 g_set_error (err, GMIME_GPGME_ERROR, GPG_ERR_NOT_FOUND,
403 _("Could not find a key for %s"), name);
406 g_set_error (err, GMIME_GPGME_ERROR, errval,
407 _("A key with id %s is present, but it is expired, disabled, revoked or invalid"),
410 g_set_error (err, GMIME_GPGME_ERROR, GPG_ERR_NOT_FOUND,
411 _("Could not find a key with id %s"), name);
421 pkcs7_add_signer (Pkcs7Ctx *pkcs7, const char *signer, GError **err)
423 gpgme_key_t key = NULL;
425 if (!(key = pkcs7_get_key_by_name (pkcs7, signer, TRUE, err)))
428 /* set the key (the previous operation guaranteed that it exists, no need
429 * 2 check return values...) */
430 gpgme_signers_add (pkcs7->ctx, key);
431 gpgme_key_unref (key);
435 #endif /* ENABLE_SMIME */
438 pkcs7_sign (GMimeCryptoContext *context, const char *userid, GMimeDigestAlgo digest,
439 GMimeStream *istream, GMimeStream *ostream, GError **err)
442 GMimePkcs7Context *ctx = (GMimePkcs7Context *) context;
443 Pkcs7Ctx *pkcs7 = ctx->priv;
444 gpgme_sign_result_t result;
445 gpgme_data_t input, output;
448 if (!pkcs7_add_signer (pkcs7, userid, err))
451 gpgme_set_armor (pkcs7->ctx, FALSE);
453 if ((error = gpgme_data_new_from_cbs (&input, &pkcs7_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
454 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
458 if ((error = gpgme_data_new_from_cbs (&output, &pkcs7_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
459 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
460 gpgme_data_release (input);
464 /* sign the input stream */
465 if ((error = gpgme_op_sign (pkcs7->ctx, input, output, GPGME_SIG_MODE_DETACH)) != GPG_ERR_NO_ERROR) {
466 g_set_error (err, GMIME_GPGME_ERROR, error, _("Signing failed"));
467 gpgme_data_release (output);
468 gpgme_data_release (input);
472 gpgme_data_release (output);
473 gpgme_data_release (input);
475 /* return the digest algorithm used for signing */
476 result = gpgme_op_sign_result (pkcs7->ctx);
478 return pkcs7_digest_id (context, gpgme_hash_algo_name (result->signatures->hash_algo));
480 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("S/MIME support is not enabled in this build"));
483 #endif /* ENABLE_SMIME */
487 static GMimeCertificateTrust
488 pkcs7_trust (gpgme_validity_t trust)
491 case GPGME_VALIDITY_UNKNOWN:
493 return GMIME_CERTIFICATE_TRUST_NONE;
494 case GPGME_VALIDITY_UNDEFINED:
495 return GMIME_CERTIFICATE_TRUST_UNDEFINED;
496 case GPGME_VALIDITY_NEVER:
497 return GMIME_CERTIFICATE_TRUST_NEVER;
498 case GPGME_VALIDITY_MARGINAL:
499 return GMIME_CERTIFICATE_TRUST_MARGINAL;
500 case GPGME_VALIDITY_FULL:
501 return GMIME_CERTIFICATE_TRUST_FULLY;
502 case GPGME_VALIDITY_ULTIMATE:
503 return GMIME_CERTIFICATE_TRUST_ULTIMATE;
507 static GMimeSignatureList *
508 pkcs7_get_signatures (Pkcs7Ctx *pkcs7, gboolean verify)
510 GMimeSignatureList *signatures;
511 GMimeSignature *signature;
512 gpgme_verify_result_t result;
513 gpgme_subkey_t subkey;
514 gpgme_signature_t sig;
518 /* get the signature verification results from GpgMe */
519 if (!(result = gpgme_op_verify_result (pkcs7->ctx)) || !result->signatures)
520 return verify ? g_mime_signature_list_new () : NULL;
522 /* create a new signature list to return */
523 signatures = g_mime_signature_list_new ();
525 sig = result->signatures;
527 while (sig != NULL) {
528 signature = g_mime_signature_new ();
529 g_mime_signature_list_add (signatures, signature);
531 if (sig->status != GPG_ERR_NO_ERROR)
532 g_mime_signature_set_status (signature, GMIME_SIGNATURE_STATUS_ERROR);
534 g_mime_signature_set_status (signature, GMIME_SIGNATURE_STATUS_GOOD);
536 g_mime_certificate_set_pubkey_algo (signature->cert, sig->pubkey_algo);
537 g_mime_certificate_set_digest_algo (signature->cert, sig->hash_algo);
538 g_mime_certificate_set_fingerprint (signature->cert, sig->fpr);
539 g_mime_signature_set_expires (signature, sig->exp_timestamp);
540 g_mime_signature_set_created (signature, sig->timestamp);
542 if (sig->exp_timestamp != 0 && sig->exp_timestamp <= time (NULL)) {
543 /* signature expired, automatically results in a BAD signature */
544 signature->errors |= GMIME_SIGNATURE_ERROR_EXPSIG;
545 signature->status = GMIME_SIGNATURE_STATUS_BAD;
548 if (gpgme_get_key (pkcs7->ctx, sig->fpr, &key, 0) == GPG_ERR_NO_ERROR && key) {
549 /* get more signer info from their signing key */
550 g_mime_certificate_set_trust (signature->cert, pkcs7_trust (key->owner_trust));
551 g_mime_certificate_set_issuer_serial (signature->cert, key->issuer_serial);
552 g_mime_certificate_set_issuer_name (signature->cert, key->issuer_name);
554 /* get the keyid, name, and email address */
557 if (uid->name && *uid->name)
558 g_mime_certificate_set_name (signature->cert, uid->name);
560 if (uid->email && *uid->email)
561 g_mime_certificate_set_email (signature->cert, uid->email);
563 if (uid->uid && *uid->uid)
564 g_mime_certificate_set_key_id (signature->cert, uid->uid);
566 if (signature->cert->name && signature->cert->email && signature->cert->keyid)
572 /* get the subkey used for signing */
573 subkey = key->subkeys;
574 while (subkey && !subkey->can_sign)
575 subkey = subkey->next;
578 g_mime_certificate_set_created (signature->cert, subkey->timestamp);
579 g_mime_certificate_set_expires (signature->cert, subkey->expires);
581 if (subkey->revoked) {
582 /* signer's key has been revoked, automatic BAD status */
583 signature->errors |= GMIME_SIGNATURE_ERROR_REVKEYSIG;
584 signature->status = GMIME_SIGNATURE_STATUS_BAD;
587 if (subkey->expired) {
588 /* signer's key has expired, automatic BAD status */
589 signature->errors |= GMIME_SIGNATURE_ERROR_EXPKEYSIG;
590 signature->status = GMIME_SIGNATURE_STATUS_BAD;
593 /* If we don't have the subkey used by the signer, then we can't
594 * tell what the status is, so set to ERROR if it hasn't already
595 * been designated as BAD. */
596 if (signature->status != GMIME_SIGNATURE_STATUS_BAD)
597 signature->status = GMIME_SIGNATURE_STATUS_ERROR;
598 signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
601 gpgme_key_unref (key);
603 /* If we don't have the signer's public key, then we can't tell what
604 * the status is, so set it to ERROR if it hasn't already been
605 * designated as BAD. */
606 g_mime_certificate_set_trust (signature->cert, GMIME_CERTIFICATE_TRUST_UNDEFINED);
607 if (signature->status != GMIME_SIGNATURE_STATUS_BAD)
608 signature->status = GMIME_SIGNATURE_STATUS_ERROR;
609 signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
617 #endif /* ENABLE_SMIME */
619 static GMimeSignatureList *
620 pkcs7_verify (GMimeCryptoContext *context, GMimeDigestAlgo digest,
621 GMimeStream *istream, GMimeStream *sigstream,
625 GMimePkcs7Context *ctx = (GMimePkcs7Context *) context;
626 gpgme_data_t message, signature;
627 Pkcs7Ctx *pkcs7 = ctx->priv;
630 if ((error = gpgme_data_new_from_cbs (&message, &pkcs7_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
631 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
635 /* if @sigstream is non-NULL, then it is a detached signature */
636 if (sigstream != NULL) {
637 if ((error = gpgme_data_new_from_cbs (&signature, &pkcs7_stream_funcs, sigstream)) != GPG_ERR_NO_ERROR) {
638 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open signature stream"));
639 gpgme_data_release (message);
646 if ((error = gpgme_op_verify (pkcs7->ctx, signature, message, NULL)) != GPG_ERR_NO_ERROR) {
647 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not verify pkcs7 signature"));
649 gpgme_data_release (signature);
650 gpgme_data_release (message);
655 gpgme_data_release (signature);
658 gpgme_data_release (message);
660 /* get/return the pkcs7 signatures */
661 return pkcs7_get_signatures (pkcs7, TRUE);
663 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("S/MIME support is not enabled in this build"));
666 #endif /* ENABLE_SMIME */
671 key_list_free (gpgme_key_t *keys)
673 gpgme_key_t *key = keys;
675 while (key != NULL) {
676 gpgme_key_unref (*key);
682 #endif /* ENABLE_SMIME */
685 pkcs7_encrypt (GMimeCryptoContext *context, gboolean sign, const char *userid,
686 GMimeDigestAlgo digest, GPtrArray *recipients, GMimeStream *istream,
687 GMimeStream *ostream, GError **err)
690 GMimePkcs7Context *ctx = (GMimePkcs7Context *) context;
691 Pkcs7Ctx *pkcs7 = ctx->priv;
692 gpgme_data_t input, output;
699 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED,
700 _("Cannot sign and encrypt a stream at the same time using pkcs7"));
704 /* create an array of recipient keys for GpgMe */
705 rcpts = g_new0 (gpgme_key_t, recipients->len + 1);
706 for (i = 0; i < recipients->len; i++) {
707 if (!(key = pkcs7_get_key_by_name (pkcs7, recipients->pdata[i], FALSE, err))) {
708 key_list_free (rcpts);
715 if ((error = gpgme_data_new_from_cbs (&input, &pkcs7_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
716 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
717 key_list_free (rcpts);
721 if ((error = gpgme_data_new_from_cbs (&output, &pkcs7_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
722 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
723 gpgme_data_release (input);
724 key_list_free (rcpts);
728 /* encrypt the input stream */
729 error = gpgme_op_encrypt (pkcs7->ctx, rcpts, GPGME_ENCRYPT_ALWAYS_TRUST, input, output);
730 gpgme_data_release (output);
731 gpgme_data_release (input);
732 key_list_free (rcpts);
734 if (error != GPG_ERR_NO_ERROR) {
735 g_set_error (err, GMIME_GPGME_ERROR, error, _("Encryption failed"));
741 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("S/MIME support is not enabled in this build"));
744 #endif /* ENABLE_SMIME */
748 static GMimeDecryptResult *
749 pkcs7_get_decrypt_result (Pkcs7Ctx *pkcs7)
751 GMimeDecryptResult *result;
752 gpgme_decrypt_result_t res;
753 gpgme_recipient_t recipient;
754 GMimeCertificate *cert;
756 result = g_mime_decrypt_result_new ();
757 result->recipients = g_mime_certificate_list_new ();
758 result->signatures = pkcs7_get_signatures (pkcs7, FALSE);
760 if (!(res = gpgme_op_decrypt_result (pkcs7->ctx)) || !res->recipients)
763 recipient = res->recipients;
764 while (recipient != NULL) {
765 cert = g_mime_certificate_new ();
766 g_mime_certificate_list_add (result->recipients, cert);
768 g_mime_certificate_set_pubkey_algo (cert, recipient->pubkey_algo);
769 g_mime_certificate_set_key_id (cert, recipient->keyid);
771 recipient = recipient->next;
776 #endif /* ENABLE_SMIME */
778 static GMimeDecryptResult *
779 pkcs7_decrypt (GMimeCryptoContext *context, GMimeStream *istream,
780 GMimeStream *ostream, GError **err)
783 GMimePkcs7Context *ctx = (GMimePkcs7Context *) context;
784 GMimeDecryptResult *result;
785 Pkcs7Ctx *pkcs7 = ctx->priv;
786 gpgme_decrypt_result_t res;
787 gpgme_data_t input, output;
790 if ((error = gpgme_data_new_from_cbs (&input, &pkcs7_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
791 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
795 if ((error = gpgme_data_new_from_cbs (&output, &pkcs7_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
796 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
797 gpgme_data_release (input);
801 /* decrypt the input stream */
802 if ((error = gpgme_op_decrypt_verify (pkcs7->ctx, input, output)) != GPG_ERR_NO_ERROR) {
803 g_set_error (err, GMIME_GPGME_ERROR, error, _("Decryption failed"));
804 gpgme_data_release (output);
805 gpgme_data_release (input);
809 gpgme_data_release (output);
810 gpgme_data_release (input);
812 return pkcs7_get_decrypt_result (pkcs7);
814 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("S/MIME support is not enabled in this build"));
817 #endif /* ENABLE_SMIME */
821 pkcs7_import_keys (GMimeCryptoContext *context, GMimeStream *istream, GError **err)
824 GMimePkcs7Context *ctx = (GMimePkcs7Context *) context;
825 Pkcs7Ctx *pkcs7 = ctx->priv;
826 gpgme_data_t keydata;
829 if ((error = gpgme_data_new_from_cbs (&keydata, &pkcs7_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
830 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
834 /* import the key(s) */
835 if ((error = gpgme_op_import (pkcs7->ctx, keydata)) != GPG_ERR_NO_ERROR) {
836 //printf ("import error (%d): %s\n", error & GPG_ERR_CODE_MASK, gpg_strerror (error));
837 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not import key data"));
838 gpgme_data_release (keydata);
842 gpgme_data_release (keydata);
846 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("S/MIME support is not enabled in this build"));
849 #endif /* ENABLE_SMIME */
853 pkcs7_export_keys (GMimeCryptoContext *context, GPtrArray *keys, GMimeStream *ostream, GError **err)
856 GMimePkcs7Context *ctx = (GMimePkcs7Context *) context;
857 Pkcs7Ctx *pkcs7 = ctx->priv;
858 gpgme_data_t keydata;
862 if ((error = gpgme_data_new_from_cbs (&keydata, &pkcs7_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
863 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
867 /* export the key(s) */
868 for (i = 0; i < keys->len; i++) {
869 if ((error = gpgme_op_export (pkcs7->ctx, keys->pdata[i], 0, keydata)) != GPG_ERR_NO_ERROR) {
870 g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not export key data"));
871 gpgme_data_release (keydata);
876 gpgme_data_release (keydata);
880 g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("S/MIME support is not enabled in this build"));
883 #endif /* ENABLE_SMIME */
888 * g_mime_pkcs7_context_new:
889 * @request_passwd: a #GMimePasswordRequestFunc
891 * Creates a new pkcs7 crypto context object.
893 * Returns: a new pkcs7 crypto context object.
896 g_mime_pkcs7_context_new (GMimePasswordRequestFunc request_passwd)
899 GMimeCryptoContext *crypto;
900 GMimePkcs7Context *pkcs7;
903 /* make sure GpgMe supports the CMS protocols */
904 if (gpgme_engine_check_version (GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
907 /* create the GpgMe context */
908 if (gpgme_new (&ctx) != GPG_ERR_NO_ERROR)
911 pkcs7 = g_object_newv (GMIME_TYPE_PKCS7_CONTEXT, 0, NULL);
912 gpgme_set_passphrase_cb (ctx, pkcs7_passphrase_cb, pkcs7);
913 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
914 pkcs7->priv->ctx = ctx;
916 crypto = (GMimeCryptoContext *) pkcs7;
917 crypto->request_passwd = request_passwd;
922 #endif /* ENABLE_SMIME */
927 * g_mime_pkcs7_context_get_always_trust:
928 * @ctx: a #GMimePkcs7Context
930 * Gets the @always_trust flag on the pkcs7 context.
932 * Returns: the @always_trust flag on the pkcs7 context.
935 g_mime_pkcs7_context_get_always_trust (GMimePkcs7Context *ctx)
937 g_return_val_if_fail (GMIME_IS_PKCS7_CONTEXT (ctx), FALSE);
939 return ctx->priv->always_trust;
944 * g_mime_pkcs7_context_set_always_trust:
945 * @ctx: a #GMimePkcs7Context
946 * @always_trust: always trust flag
948 * Sets the @always_trust flag on the pkcs7 context which is used for
952 g_mime_pkcs7_context_set_always_trust (GMimePkcs7Context *ctx, gboolean always_trust)
954 g_return_if_fail (GMIME_IS_PKCS7_CONTEXT (ctx));
956 ctx->priv->always_trust = always_trust;