[gmime] Implemented g_mime_application_pkcs7_mime_verify()



commit 02dc4fe673bb8de9ad94dcefc051f6d57ac4a145
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Sun Feb 19 16:36:12 2017 -0500

    Implemented g_mime_application_pkcs7_mime_verify()

 gmime/gmime-application-pkcs7-mime.c |   81 ++++++++++++++++++++++++++++++---
 gmime/gmime-application-pkcs7-mime.h |    8 ++--
 gmime/gmime-crypto-context.c         |   19 +++++---
 gmime/gmime-crypto-context.h         |    6 ++-
 gmime/gmime-gpg-context.c            |   27 ++++++++++--
 gmime/gmime-multipart-encrypted.c    |    2 +-
 gmime/gmime-multipart-signed.c       |    2 +-
 gmime/gmime-pkcs7-context.c          |   25 +++++++++-
 8 files changed, 139 insertions(+), 31 deletions(-)
---
diff --git a/gmime/gmime-application-pkcs7-mime.c b/gmime/gmime-application-pkcs7-mime.c
index dc6b45b..4ef5268 100644
--- a/gmime/gmime-application-pkcs7-mime.c
+++ b/gmime/gmime-application-pkcs7-mime.c
@@ -342,7 +342,6 @@ g_mime_data_wrapper_get_decoded_stream (GMimeDataWrapper *wrapper)
 /**
  * g_mime_application_pkcs7_mime_decrypt:
  * @pkcs7_mime: a #GMimeApplicationPkcs7Mime
- * @ctx: a #GMimePkcs7Context
  * @flags: a #GMimeDecryptFlags
  * @session_key: session key to use or %NULL
  * @result: the decryption result
@@ -365,23 +364,30 @@ g_mime_data_wrapper_get_decoded_stream (GMimeDataWrapper *wrapper)
  * @err to provide information as to why the failure occured.
  **/
 GMimeObject *
-g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime, GMimePkcs7Context *ctx,
+g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime,
                                       GMimeDecryptFlags flags, const char *session_key,
                                       GMimeDecryptResult **result, GError **err)
 {
        GMimeStream *filtered_stream, *ciphertext, *stream;
        GMimeDataWrapper *wrapper;
        GMimeFilter *crlf_filter;
+       GMimeCryptoContext *ctx;
        GMimeDecryptResult *res;
        GMimeObject *decrypted;
        GMimeParser *parser;
        
        g_return_val_if_fail (GMIME_IS_APPLICATION_PKCS7_MIME (pkcs7_mime), NULL);
-       g_return_val_if_fail (GMIME_IS_PKCS7_CONTEXT (ctx), NULL);
        
        if (result)
                *result = NULL;
        
+       if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
+               g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
+                            _("Cannot decrypt application/pkcs7-mime part: no crypto context registered for 
this type."));
+               
+               return NULL;
+       }
+       
        /* get the ciphertext stream */
        wrapper = g_mime_part_get_content_object (GMIME_PART (pkcs7_mime));
        ciphertext = g_mime_data_wrapper_get_decoded_stream (wrapper);
@@ -394,10 +400,11 @@ g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime, GM
        g_object_unref (crlf_filter);
        
        /* decrypt the content stream */
-       if (!(res = g_mime_crypto_context_decrypt ((GMimeCryptoContext *) ctx, flags, session_key, 
ciphertext, filtered_stream, err))) {
+       if (!(res = g_mime_crypto_context_decrypt (ctx, flags, session_key, ciphertext, filtered_stream, 
err))) {
                g_object_unref (filtered_stream);
                g_object_unref (ciphertext);
                g_object_unref (stream);
+               g_object_unref (ctx);
                
                return NULL;
        }
@@ -405,6 +412,7 @@ g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime, GM
        g_mime_stream_flush (filtered_stream);
        g_object_unref (filtered_stream);
        g_object_unref (ciphertext);
+       g_object_unref (ctx);
        
        g_mime_stream_reset (stream);
        parser = g_mime_parser_new ();
@@ -497,7 +505,6 @@ g_mime_application_pkcs7_mime_sign (GMimePkcs7Context *ctx, GMimeObject *entity,
 /**
  * g_mime_application_pkcs7_mime_verify:
  * @pkcs7_mime: a #GMimeApplicationPkcs7Mime
- * @ctx: a #GMimePkcs7Context
  * @flags: a #GMimeVerifyFlags
  * @entity: the extracted entity
  * @err: a #GError
@@ -507,11 +514,69 @@ g_mime_application_pkcs7_mime_sign (GMimePkcs7Context *ctx, GMimeObject *entity,
  * Returns: the list of signers.
  **/
 GMimeSignatureList *
-g_mime_application_pkcs7_mime_verify (GMimeApplicationPkcs7Mime *pkcs7_mime, GMimePkcs7Context *ctx, 
GMimeVerifyFlags flags, GMimeObject **entity, GError **err)
+g_mime_application_pkcs7_mime_verify (GMimeApplicationPkcs7Mime *pkcs7_mime, GMimeVerifyFlags flags, 
GMimeObject **entity, GError **err)
 {
+       GMimeStream *filtered_stream, *ciphertext, *stream;
+       GMimeSignatureList *signatures;
+       GMimeDataWrapper *wrapper;
+       GMimeFilter *crlf_filter;
+       GMimeCryptoContext *ctx;
+       GMimeParser *parser;
+       
        g_return_val_if_fail (GMIME_IS_APPLICATION_PKCS7_MIME (pkcs7_mime), NULL);
-       g_return_val_if_fail (GMIME_IS_PKCS7_CONTEXT (ctx), NULL);
        g_return_val_if_fail (entity != NULL, NULL);
        
-       return NULL;
+       *entity = NULL;
+       
+       if (!(ctx = g_mime_crypto_context_new ("application/pkcs7-mime"))) {
+               g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
+                            _("Cannot decrypt application/pkcs7-mime part: no crypto context registered for 
this type."));
+               
+               return NULL;
+       }
+       
+       /* get the ciphertext stream */
+       wrapper = g_mime_part_get_content_object (GMIME_PART (pkcs7_mime));
+       ciphertext = g_mime_data_wrapper_get_decoded_stream (wrapper);
+       g_mime_stream_reset (ciphertext);
+       
+       stream = g_mime_stream_mem_new ();
+       filtered_stream = g_mime_stream_filter_new (stream);
+       crlf_filter = g_mime_filter_crlf_new (FALSE, FALSE);
+       g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), crlf_filter);
+       g_object_unref (crlf_filter);
+       
+       /* decrypt the content stream */
+       if (!(signatures = g_mime_crypto_context_verify (ctx, flags, GMIME_DIGEST_ALGO_DEFAULT, ciphertext, 
NULL, filtered_stream, err))) {
+               g_object_unref (filtered_stream);
+               g_object_unref (ciphertext);
+               g_object_unref (stream);
+               g_object_unref (ctx);
+               
+               return NULL;
+       }
+       
+       g_mime_stream_flush (filtered_stream);
+       g_object_unref (filtered_stream);
+       g_object_unref (ciphertext);
+       g_object_unref (ctx);
+       
+       g_mime_stream_reset (stream);
+       parser = g_mime_parser_new ();
+       g_mime_parser_init_with_stream (parser, stream);
+       g_object_unref (stream);
+       
+       *entity = g_mime_parser_construct_part (parser);
+       g_object_unref (parser);
+       
+       if (*entity == NULL) {
+               g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
+                                    _("Cannot verify application/pkcs7-mime part: failed to parse extracted 
content."));
+               
+               g_object_unref (signatures);
+               
+               return NULL;
+       }
+       
+       return signatures;
 }
diff --git a/gmime/gmime-application-pkcs7-mime.h b/gmime/gmime-application-pkcs7-mime.h
index c197d48..ac38e48 100644
--- a/gmime/gmime-application-pkcs7-mime.h
+++ b/gmime/gmime-application-pkcs7-mime.h
@@ -82,13 +82,13 @@ GMimeApplicationPkcs7Mime *g_mime_application_pkcs7_mime_new (GMimeSecureMimeTyp
 GMimeSecureMimeType g_mime_application_pkcs7_mime_get_smime_type (GMimeApplicationPkcs7Mime *pkcs7_mime);
 
 /*GMimeApplicationPkcs7Mime *g_mime_application_pkcs7_mime_compress (GMimePkcs7Context *ctx, GMimeObject 
*entity, GError **err);*/
-/*GMimeObject *g_mime_application_pkcs7_mime_decompress (GMimeApplicationPkcs7Mime *pkcs7_mime, 
GMimePkcs7Context *ctx);*/
+/*GMimeObject *g_mime_application_pkcs7_mime_decompress (GMimeApplicationPkcs7Mime *pkcs7_mime);*/
 
 GMimeApplicationPkcs7Mime *g_mime_application_pkcs7_mime_encrypt (GMimePkcs7Context *ctx, GMimeObject 
*entity,
                                                                  GMimeEncryptFlags flags, GPtrArray 
*recipients,
                                                                  GError **err);
 
-GMimeObject *g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime, GMimePkcs7Context 
*ctx,
+GMimeObject *g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime,
                                                    GMimeDecryptFlags flags, const char *session_key,
                                                    GMimeDecryptResult **result, GError **err);
 
@@ -96,8 +96,8 @@ GMimeApplicationPkcs7Mime *g_mime_application_pkcs7_mime_sign (GMimePkcs7Context
                                                               const char *userid, GMimeDigestAlgo digest,
                                                               GError **err);
 
-GMimeSignatureList *g_mime_application_pkcs7_mime_verify (GMimeApplicationPkcs7Mime *pkcs7_mime, 
GMimePkcs7Context *ctx,
-                                                         GMimeVerifyFlags flags, GMimeObject **entity, 
GError **err);
+GMimeSignatureList *g_mime_application_pkcs7_mime_verify (GMimeApplicationPkcs7Mime *pkcs7_mime, 
GMimeVerifyFlags flags,
+                                                         GMimeObject **entity, GError **err);
 
 G_END_DECLS
 
diff --git a/gmime/gmime-crypto-context.c b/gmime/gmime-crypto-context.c
index 54d8d1e..ec84b6a 100644
--- a/gmime/gmime-crypto-context.c
+++ b/gmime/gmime-crypto-context.c
@@ -60,7 +60,8 @@ static int crypto_sign (GMimeCryptoContext *ctx, gboolean detach,
        
 static GMimeSignatureList *crypto_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags,
                                          GMimeDigestAlgo digest, GMimeStream *istream,
-                                         GMimeStream *sigstream, GError **err);
+                                         GMimeStream *sigstream, GMimeStream *ostream,
+                                         GError **err);
        
 static int crypto_encrypt (GMimeCryptoContext *ctx, gboolean sign,
                           const char *userid, GMimeDigestAlgo digest,
@@ -391,7 +392,7 @@ g_mime_crypto_context_sign (GMimeCryptoContext *ctx, gboolean detach, const char
 
 static GMimeSignatureList *
 crypto_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags, GMimeDigestAlgo digest,
-              GMimeStream *istream, GMimeStream *sigstream, GError **err)
+              GMimeStream *istream, GMimeStream *sigstream, GMimeStream *ostream, GError **err)
 {
        g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED,
                     "Verifying is not supported by this crypto context");
@@ -407,24 +408,26 @@ crypto_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags, GMimeDigestAlgo
  * @digest: digest algorithm used, if known
  * @istream: input stream
  * @sigstream: optional detached-signature stream
+ * @ostream: optional output stream for use with encapsulated signature input streams
  * @err: a #GError
  *
- * 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.
+ * Verifies the signature. If @istream is a clearsigned stream, you
+ * should pass %NULL as the @sigstream parameter and may wish to
+ * provide an @ostream argument for GMime to output the original
+ * plaintext into. Otherwise @sigstream is assumed to be the signature
+ * stream and is used to verify the integirity of the @istream.
  *
  * Returns: (transfer full): a #GMimeSignatureList object containing
  * the status of each signature or %NULL on error.
  **/
 GMimeSignatureList *
 g_mime_crypto_context_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags, GMimeDigestAlgo digest,
-                             GMimeStream *istream, GMimeStream *sigstream, GError **err)
+                             GMimeStream *istream, GMimeStream *sigstream, GMimeStream *ostream, GError 
**err)
 {
        g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), NULL);
        g_return_val_if_fail (GMIME_IS_STREAM (istream), NULL);
        
-       return GMIME_CRYPTO_CONTEXT_GET_CLASS (ctx)->verify (ctx, flags, digest, istream, sigstream, err);
+       return GMIME_CRYPTO_CONTEXT_GET_CLASS (ctx)->verify (ctx, flags, digest, istream, sigstream, ostream, 
err);
 }
 
 
diff --git a/gmime/gmime-crypto-context.h b/gmime/gmime-crypto-context.h
index 6051527..5423324 100644
--- a/gmime/gmime-crypto-context.h
+++ b/gmime/gmime-crypto-context.h
@@ -145,7 +145,8 @@ struct _GMimeCryptoContextClass {
        
        GMimeSignatureList *     (* verify)      (GMimeCryptoContext *ctx, GMimeVerifyFlags flags,
                                                  GMimeDigestAlgo digest, GMimeStream *istream,
-                                                 GMimeStream *sigstream, GError **err);
+                                                 GMimeStream *sigstream, GMimeStream *ostream,
+                                                 GError **err);
        
        int                      (* encrypt)     (GMimeCryptoContext *ctx, gboolean sign,
                                                  const char *userid, GMimeDigestAlgo digest,
@@ -192,7 +193,8 @@ int g_mime_crypto_context_sign (GMimeCryptoContext *ctx, gboolean detach,
 
 GMimeSignatureList *g_mime_crypto_context_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags,
                                                  GMimeDigestAlgo digest, GMimeStream *istream,
-                                                 GMimeStream *sigstream, GError **err);
+                                                 GMimeStream *sigstream, GMimeStream *ostream,
+                                                 GError **err);
 
 int g_mime_crypto_context_encrypt (GMimeCryptoContext *ctx, gboolean sign,
                                   const char *userid, GMimeDigestAlgo digest,
diff --git a/gmime/gmime-gpg-context.c b/gmime/gmime-gpg-context.c
index 4f96197..0959cf2 100644
--- a/gmime/gmime-gpg-context.c
+++ b/gmime/gmime-gpg-context.c
@@ -99,7 +99,8 @@ static const char *gpg_get_key_exchange_protocol (GMimeCryptoContext *ctx);
 
 static GMimeSignatureList *gpg_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags,
                                       GMimeDigestAlgo digest, GMimeStream *istream,
-                                      GMimeStream *sigstream, GError **err);
+                                      GMimeStream *sigstream, GMimeStream *ostream,
+                                      GError **err);
 
 static int gpg_encrypt (GMimeCryptoContext *ctx, gboolean sign, const char *userid, GMimeDigestAlgo digest,
                        GMimeEncryptFlags flags, GPtrArray *recipients, GMimeStream *istream, GMimeStream 
*ostream,
@@ -597,11 +598,11 @@ gpg_get_signatures (GMimeGpgContext *gpg, gboolean verify)
 
 static GMimeSignatureList *
 gpg_verify (GMimeCryptoContext *context, GMimeVerifyFlags flags, GMimeDigestAlgo digest,
-           GMimeStream *istream, GMimeStream *sigstream, GError **err)
+           GMimeStream *istream, GMimeStream *sigstream, GMimeStream *ostream, GError **err)
 {
 #ifdef ENABLE_CRYPTO
        GMimeGpgContext *gpg = (GMimeGpgContext *) context;
-       gpgme_data_t message, signature;
+       gpgme_data_t message, signature, plaintext;
        gpgme_error_t error;
        
        if ((error = gpgme_data_new_from_cbs (&message, &gpg_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
@@ -620,16 +621,34 @@ gpg_verify (GMimeCryptoContext *context, GMimeVerifyFlags flags, GMimeDigestAlgo
                signature = NULL;
        }
        
+       /* if @ostream is non-NULL, then we are expected to write the extracted plaintext to it */
+       if (ostream != NULL) {
+               if ((error = gpgme_data_new_from_cbs (&plaintext, &gpg_stream_funcs, ostream)) != 
GPG_ERR_NO_ERROR) {
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
+                       if (signature)
+                               gpgme_data_release (signature);
+                       gpgme_data_release (message);
+                       return NULL;
+               }
+       } else {
+               plaintext = NULL;
+       }
+       
        // FIXME: enable auto-key-retrieve
        
-       if ((error = gpgme_op_verify (gpg->ctx, signature, message, NULL)) != GPG_ERR_NO_ERROR) {
+       if ((error = gpgme_op_verify (gpg->ctx, signature, message, plaintext)) != GPG_ERR_NO_ERROR) {
                g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not verify gpg signature"));
+               if (plaintext)
+                       gpgme_data_release (plaintext);
                if (signature)
                        gpgme_data_release (signature);
                gpgme_data_release (message);
                return NULL;
        }
        
+       if (plaintext)
+               gpgme_data_release (plaintext);
+       
        if (signature)
                gpgme_data_release (signature);
        
diff --git a/gmime/gmime-multipart-encrypted.c b/gmime/gmime-multipart-encrypted.c
index f37dfff..db6c6f4 100644
--- a/gmime/gmime-multipart-encrypted.c
+++ b/gmime/gmime-multipart-encrypted.c
@@ -326,7 +326,7 @@ g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe, GMimeDecryptFl
        
        if (!(ctx = g_mime_crypto_context_new (protocol))) {
                g_set_error (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
-                            _("Cannot verify multipart/encrypted part: unregistered encryption protocol 
'%s'."),
+                            _("Cannot decrypt multipart/encrypted part: unregistered encryption protocol 
'%s'."),
                             protocol);
                
                return NULL;
diff --git a/gmime/gmime-multipart-signed.c b/gmime/gmime-multipart-signed.c
index 9ffaf74..054a79e 100644
--- a/gmime/gmime-multipart-signed.c
+++ b/gmime/gmime-multipart-signed.c
@@ -470,7 +470,7 @@ g_mime_multipart_signed_verify (GMimeMultipartSigned *mps, GMimeVerifyFlags flag
        
        /* verify the signature */
        digest = g_mime_crypto_context_digest_id (ctx, micalg);
-       signatures = g_mime_crypto_context_verify (ctx, flags, digest, stream, sigstream, err);
+       signatures = g_mime_crypto_context_verify (ctx, flags, digest, stream, sigstream, NULL, err);
        
        d(printf ("attempted to verify:\n----- BEGIN SIGNED PART -----\n%.*s----- END SIGNED PART -----\n",
                  (int) GMIME_STREAM_MEM (stream)->buffer->len, GMIME_STREAM_MEM (stream)->buffer->data));
diff --git a/gmime/gmime-pkcs7-context.c b/gmime/gmime-pkcs7-context.c
index 8b9f8a1..3626757 100644
--- a/gmime/gmime-pkcs7-context.c
+++ b/gmime/gmime-pkcs7-context.c
@@ -98,7 +98,8 @@ static int pkcs7_sign (GMimeCryptoContext *ctx, gboolean detach,
        
 static GMimeSignatureList *pkcs7_verify (GMimeCryptoContext *ctx, GMimeVerifyFlags flags,
                                         GMimeDigestAlgo digest, GMimeStream *istream,
-                                        GMimeStream *sigstream, GError **err);
+                                        GMimeStream *sigstream, GMimeStream *ostream,
+                                        GError **err);
 
 static int pkcs7_encrypt (GMimeCryptoContext *ctx, gboolean sign, const char *userid, GMimeDigestAlgo digest,
                          GMimeEncryptFlags flags, GPtrArray *recipients, GMimeStream *istream,
@@ -591,11 +592,11 @@ pkcs7_get_signatures (GMimePkcs7Context *pkcs7, gboolean verify)
 
 static GMimeSignatureList *
 pkcs7_verify (GMimeCryptoContext *context, GMimeVerifyFlags flags, GMimeDigestAlgo digest,
-             GMimeStream *istream, GMimeStream *sigstream, GError **err)
+             GMimeStream *istream, GMimeStream *sigstream, GMimeStream *ostream, GError **err)
 {
 #ifdef ENABLE_CRYPTO
        GMimePkcs7Context *pkcs7 = (GMimePkcs7Context *) context;
-       gpgme_data_t message, signature;
+       gpgme_data_t message, signature, plaintext;
        gpgme_error_t error;
        
        if ((error = gpgme_data_new_from_cbs (&message, &pkcs7_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
@@ -614,16 +615,34 @@ pkcs7_verify (GMimeCryptoContext *context, GMimeVerifyFlags flags, GMimeDigestAl
                signature = NULL;
        }
        
+       /* if @ostream is non-NULL, then we are expected to write the extracted plaintext to it */
+       if (ostream != NULL) {
+               if ((error = gpgme_data_new_from_cbs (&plaintext, &gpg_stream_funcs, ostream)) != 
GPG_ERR_NO_ERROR) {
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
+                       if (signature)
+                               gpgme_data_release (signature);
+                       gpgme_data_release (message);
+                       return NULL;
+               }
+       } else {
+               plaintext = NULL;
+       }
+       
        // FIXME: enable auto-key-retrieve
        
        if ((error = gpgme_op_verify (pkcs7->ctx, signature, message, NULL)) != GPG_ERR_NO_ERROR) {
                g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not verify pkcs7 signature"));
+               if (plaintext)
+                       gpgme_data_release (plaintext);
                if (signature)
                        gpgme_data_release (signature);
                gpgme_data_release (message);
                return NULL;
        }
        
+       if (plaintext)
+               gpgme_data_release (plaintext);
+       
        if (signature)
                gpgme_data_release (signature);
        


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]