[gmime] Added unit tests for decrypt_session()
- From: Jeffrey Stedfast <fejj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gmime] Added unit tests for decrypt_session()
- Date: Mon, 5 Dec 2016 15:17:30 +0000 (UTC)
commit c0d9e42f1a8a35cd80c354c0c6831517bbcd72ce
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date: Mon Dec 5 10:16:48 2016 -0500
Added unit tests for decrypt_session()
Thanks to Daniel Kahn Gillmor for this patch
tests/test-pgpmime.c | 88 +++++++++++++++++++++++++++++++++++++++-----------
tests/testsuite.c | 63 +++++++++++++++++++++++++++++-------
tests/testsuite.h | 1 +
3 files changed, 121 insertions(+), 31 deletions(-)
---
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index 27e6b6b..90f3e5b 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -259,18 +259,15 @@ test_multipart_signed (GMimeCryptoContext *ctx)
#define MULTIPART_ENCRYPTED_CONTENT "This is a test of multipart/encrypted.\n"
static void
-test_multipart_encrypted (GMimeCryptoContext *ctx, gboolean sign)
+create_encrypted_message (GMimeCryptoContext *ctx, gboolean sign,
+ GMimeStream **cleartext_out, GMimeStream **stream_out)
{
GMimeStream *cleartext, *stream;
GMimeMultipartEncrypted *mpe;
- GMimeDecryptResult *result;
GMimeDataWrapper *content;
- GMimeObject *decrypted;
GPtrArray *recipients;
GMimeMessage *message;
Exception *ex = NULL;
- GMimeParser *parser;
- GByteArray *buf[2];
GError *err = NULL;
GMimePart *part;
@@ -324,12 +321,34 @@ test_multipart_encrypted (GMimeCryptoContext *ctx, gboolean sign)
stream = g_mime_stream_mem_new ();
g_mime_object_write_to_stream ((GMimeObject *) message, stream);
- g_mime_stream_reset (stream);
g_object_unref (message);
+ *stream_out = stream;
+ *cleartext_out = cleartext;
+}
+
+static char *
+test_multipart_encrypted (GMimeCryptoContext *ctx, gboolean sign,
+ GMimeStream *cleartext, GMimeStream *stream,
+ const char *session_key)
+{
+ GMimeStream *test_stream;
+ GMimeMultipartEncrypted *mpe;
+ GMimeDecryptResult *result;
+ GMimeDataWrapper *content;
+ GMimeObject *decrypted;
+ GMimeMessage *message;
+ Exception *ex = NULL;
+ GMimeParser *parser;
+ GByteArray *buf[2];
+ GError *err = NULL;
+ GMimePart *part;
+ char *ret = NULL;
+
+ g_mime_stream_reset (stream);
+ g_mime_stream_reset (cleartext);
parser = g_mime_parser_new ();
g_mime_parser_init_with_stream (parser, stream);
- g_object_unref (stream);
message = g_mime_parser_construct_message (parser);
g_object_unref (parser);
@@ -343,19 +362,18 @@ test_multipart_encrypted (GMimeCryptoContext *ctx, gboolean sign)
mpe = (GMimeMultipartEncrypted *) message->mime_part;
/* okay, now to test our decrypt function... */
- decrypted = g_mime_multipart_encrypted_decrypt (mpe, ctx, &result, &err);
+ decrypted = g_mime_multipart_encrypted_decrypt_session (mpe, ctx, session_key, &result, &err);
if (!decrypted || err != NULL) {
ex = exception_new ("decryption failed: %s", err->message);
- g_object_unref (cleartext);
g_error_free (err);
throw (ex);
}
if (!result->session_key) {
ex = exception_new ("No session key returned!");
- g_object_unref (cleartext);
throw (ex);
}
+ ret = g_strdup (result->session_key);
if (result->signatures)
v(print_verify_results (result->signatures));
@@ -371,24 +389,28 @@ test_multipart_encrypted (GMimeCryptoContext *ctx, gboolean sign)
g_object_unref (result);
if (ex != NULL) {
- g_object_unref (cleartext);
+ g_free (ret);
+ ret = 0;
throw (ex);
}
- stream = g_mime_stream_mem_new ();
- g_mime_object_write_to_stream (decrypted, stream);
+ test_stream = g_mime_stream_mem_new ();
+ g_mime_object_write_to_stream (decrypted, test_stream);
buf[0] = GMIME_STREAM_MEM (cleartext)->buffer;
- buf[1] = GMIME_STREAM_MEM (stream)->buffer;
+ buf[1] = GMIME_STREAM_MEM (test_stream)->buffer;
if (buf[0]->len != buf[1]->len || memcmp (buf[0]->data, buf[1]->data, buf[0]->len) != 0)
ex = exception_new ("decrypted data does not match original cleartext");
- g_object_unref (cleartext);
- g_object_unref (stream);
+ g_object_unref (test_stream);
- if (ex != NULL)
+ if (ex != NULL) {
+ g_free (ret);
+ ret = 0;
throw (ex);
+ }
+ return ret;
}
static void
@@ -420,6 +442,8 @@ int main (int argc, char *argv[])
struct stat st;
char *key;
int i;
+ GMimeStream *stream = NULL, *cleartext = NULL;
+ char *session_key = NULL;
g_mime_init (0);
@@ -470,19 +494,45 @@ int main (int argc, char *argv[])
testsuite_check ("multipart/encrypted");
try {
- test_multipart_encrypted (ctx, FALSE);
+ create_encrypted_message (ctx, FALSE, &cleartext, &stream);
+ session_key = test_multipart_encrypted (ctx, FALSE, cleartext, stream, NULL);
+ if (testsuite_can_safely_override_session_key ())
+ g_free (test_multipart_encrypted (ctx, FALSE, cleartext, stream, session_key));
testsuite_check_passed ();
} catch (ex) {
testsuite_check_failed ("multipart/encrypted failed: %s", ex->message);
} finally;
+ if (cleartext)
+ g_object_unref (cleartext);
+ if (stream)
+ g_object_unref (stream);
+ cleartext = stream = NULL;
+ if (session_key) {
+ memset (session_key, 0, strlen (session_key));
+ g_free (session_key);
+ session_key = NULL;
+ }
testsuite_check ("multipart/encrypted+sign");
try {
- test_multipart_encrypted (ctx, TRUE);
+ create_encrypted_message (ctx, TRUE, &cleartext, &stream);
+ session_key = test_multipart_encrypted (ctx, TRUE, cleartext, stream, NULL);
+ if (testsuite_can_safely_override_session_key ())
+ g_free (test_multipart_encrypted (ctx, TRUE, cleartext, stream, session_key));
testsuite_check_passed ();
} catch (ex) {
testsuite_check_failed ("multipart/encrypted+sign failed: %s", ex->message);
} finally;
+ if (cleartext)
+ g_object_unref (cleartext);
+ if (stream)
+ g_object_unref (stream);
+ cleartext = stream = NULL;
+ if (session_key) {
+ memset (session_key, 0, strlen (session_key));
+ g_free (session_key);
+ session_key = NULL;
+ }
g_object_unref (ctx);
diff --git a/tests/testsuite.c b/tests/testsuite.c
index 68f9522..4e6cdc2 100644
--- a/tests/testsuite.c
+++ b/tests/testsuite.c
@@ -350,39 +350,79 @@ g_throw (Exception *ex)
longjmp (env->env, 1);
}
-static int
-is_gpg_modern (void)
+static const char *
+get_gpg_version (void)
{
+ static gboolean found = FALSE;
+ static char version[1024];
const char vheader[] = "gpg (GnuPG) ";
char *vstring = NULL;
size_t vlen = 0;
FILE *vpipe;
int ret;
+ if (found)
+ return version;
+
if ((vpipe = popen ("gpg --version", "r")) == NULL)
- return 0;
+ return NULL;
if (getline (&vstring, &vlen, vpipe) == -1) {
free (vstring);
pclose (vpipe);
- return 0;
+ return NULL;
}
pclose (vpipe);
if (strncmp (vstring, vheader, sizeof (vheader) - 1)) {
free (vstring);
- return 0;
+ return NULL;
}
- ret = (vstring[sizeof (vheader) - 1] > '2') ||
- (vstring[sizeof (vheader) - 1] == '2' &&
- vstring[sizeof (vheader)] == '.' &&
- vstring[sizeof (vheader) + 1] >= '1');
-
+ strncpy (version, vstring + sizeof (vheader) - 1, sizeof (version) - 1);
+ version[sizeof (version) - 1] = '\0';
free (vstring);
+ found = TRUE;
- return ret;
+ return version;
+}
+
+static int
+is_gpg_modern (void)
+{
+ const char *ver = get_gpg_version ();
+
+ if (!ver)
+ return 0;
+
+ return (ver[0] > '2') ||
+ (ver[0] == '2' &&
+ ver[1] == '.' &&
+ ver[2] >= '1');
+}
+
+/* in versions of gpg before 2.1.16, the only mechanism to override
+ the session key was --override-session-key, which leaks its
+ argument to the process table.
+
+ in 2.1.16, gpg introduced --override-session-key-fd, which is what
+ gmime uses to be safe.
+*/
+
+int
+testsuite_can_safely_override_session_key (void)
+{
+ const char *ver = get_gpg_version ();
+
+ if (!ver)
+ return 0;
+
+ return (ver[0] > '2') ||
+ ((ver[0] == '2' && ver[1] == '.' ) &&
+ ((ver[2] > '1') ||
+ ((ver[2] == '1' && ver[3] == '.') &&
+ (atoi(ver+4) >= 16))));
}
int
@@ -421,7 +461,6 @@ testsuite_setup_gpghome (void)
return EXIT_FAILURE;
}
-
return EXIT_SUCCESS;
}
diff --git a/tests/testsuite.h b/tests/testsuite.h
index a5f9392..87d3126 100644
--- a/tests/testsuite.h
+++ b/tests/testsuite.h
@@ -48,6 +48,7 @@ int testsuite_total_errors (void);
/* GnuPG test suite utility functions */
int testsuite_setup_gpghome (void);
int testsuite_destroy_gpghome (void);
+int testsuite_can_safely_override_session_key (void);
/*#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
#define G_GNUC_NORETURN __attribute__((noreturn))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]