[gnome-keyring] [egg] Complete implementation of openssl sytle PEM writing
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring] [egg] Complete implementation of openssl sytle PEM writing
- Date: Tue, 8 Mar 2011 17:13:35 +0000 (UTC)
commit a78de9fffce4ef2ac669e389b2283e0efbb6feb2
Author: Stef Walter <stefw collabora co uk>
Date: Tue Mar 8 18:10:19 2011 +0100
[egg] Complete implementation of openssl sytle PEM writing
The openssl PEM parser is particularly fragile, so write some
stringent tests to check.
egg/egg-openssl.c | 46 +++++++++++++++++++++++++++++-----------------
egg/tests/test-openssl.c | 29 +++++++++++++++++++++++++++++
2 files changed, 58 insertions(+), 17 deletions(-)
---
diff --git a/egg/egg-openssl.c b/egg/egg-openssl.c
index ef715dd..2e83e63 100644
--- a/egg/egg-openssl.c
+++ b/egg/egg-openssl.c
@@ -284,13 +284,11 @@ egg_openssl_pem_parse (const guchar *data, gsize n_data,
return nfound;
}
-#ifdef UNTESTED_CODE
-
static void
append_each_header (gpointer key, gpointer value, gpointer user_data)
{
GString *string = (GString*)user_data;
-
+
g_string_append (string, (gchar*)key);
g_string_append (string, ": ");
g_string_append (string, (gchar*)value);
@@ -303,14 +301,15 @@ egg_openssl_pem_write (const guchar *data, gsize n_data, GQuark type,
{
GString *string;
gint state, save;
- gsize length, n_prefix;
-
+ gsize i, length;
+ gsize n_prefix, estimate;
+
g_return_val_if_fail (data || !n_data, NULL);
g_return_val_if_fail (type, NULL);
g_return_val_if_fail (n_result, NULL);
string = g_string_sized_new (4096);
-
+
/* The prefix */
g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L);
g_string_append (string, g_quark_to_string (type));
@@ -324,29 +323,42 @@ egg_openssl_pem_write (const guchar *data, gsize n_data, GQuark type,
}
/* Resize string to fit the base64 data. Algorithm from Glib reference */
- length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7;
+ estimate = n_data * 4 / 3 + n_data * 4 / (3 * 65) + 7;
n_prefix = string->len;
- g_string_set_size (string, n_prefix + length);
-
- /* The actual base64 data */
+ g_string_set_size (string, n_prefix + estimate);
+
+ /* The actual base64 data, without line breaks */
state = save = 0;
- length = g_base64_encode_step (data, n_data, TRUE,
- string->str + string->len, &state, &save);
+ length = g_base64_encode_step (data, n_data, FALSE,
+ string->str + n_prefix, &state, &save);
+ length += g_base64_encode_close (TRUE, string->str + n_prefix + length,
+ &state, &save);
+
+ g_assert (length <= estimate);
g_string_set_size (string, n_prefix + length);
-
+
+ /*
+ * OpenSSL is absolutely certain that it wants its PEM base64
+ * lines to be 64 characters in length. So go through and break
+ * those lines up.
+ */
+
+ for (i = 64; i < length; i += 64) {
+ g_string_insert_c (string, n_prefix + i, '\n');
+ ++length;
+ ++i;
+ }
+
/* The suffix */
- g_string_append_c (string, '\n');
g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L);
g_string_append (string, g_quark_to_string (type));
g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
g_string_append_c (string, '\n');
-
+
*n_result = string->len;
return (guchar*)g_string_free (string, FALSE);
}
-#endif /* UNTESTED_CODE */
-
/* ----------------------------------------------------------------------------
* DEFINITIONS
*/
diff --git a/egg/tests/test-openssl.c b/egg/tests/test-openssl.c
index bf8134a..18f9fd9 100644
--- a/egg/tests/test-openssl.c
+++ b/egg/tests/test-openssl.c
@@ -33,12 +33,14 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
EGG_SECURE_GLIB_DEFINITIONS ();
typedef struct {
guchar *input;
gsize n_input;
+ GQuark reftype;
guchar *refenc;
guchar *refdata;
gsize n_refenc;
@@ -76,6 +78,9 @@ parse_reference (GQuark type, const guchar *data, gsize n_data,
gboolean res;
const gchar *dekinfo;
+ g_assert (type);
+ test->reftype = type;
+
g_assert ("no data in PEM callback" && data != NULL);
g_assert ("no data in PEM callback" && n_data > 0);
test->refenc = g_memdup (data, n_data);
@@ -129,6 +134,29 @@ test_write_reference (Test *test, gconstpointer unused)
g_assert ("data doesn't match input" && memcmp (encrypted, test->refenc, n_encrypted) == 0);
}
+static void
+test_write_exactly_same (Test *test, gconstpointer unused)
+{
+ guchar *result;
+ gsize n_result;
+ guint num;
+
+ num = egg_openssl_pem_parse (test->input, test->n_input, parse_reference, test);
+ g_assert ("couldn't PEM block in reference data" && num == 1);
+
+ result = egg_openssl_pem_write (test->refenc, test->n_refenc, test->reftype,
+ test->refheaders, &n_result);
+
+ /*
+ * Yes sirrr. Openssl's parser is so fragile, that we have to make it
+ * character for character identical. This includes line breaks, whitespace
+ * and line endings.
+ */
+
+ egg_assert_cmpmem (test->input, test->n_input, ==, result, n_result);
+ g_free (result);
+}
+
/* 29 bytes (prime number, so block length has bad chance of matching */
static const guchar *TEST_DATA = (guchar*)"ABCDEFGHIJKLMNOPQRSTUVWXYZ123";
const gsize TEST_DATA_L = 29;
@@ -175,6 +203,7 @@ main (int argc, char **argv)
g_test_add ("/openssl/parse_reference", Test, NULL, setup, test_parse_reference, teardown);
g_test_add ("/openssl/write_reference", Test, NULL, setup, test_write_reference, teardown);
+ g_test_add ("/openssl/write_exactly_same", Test, NULL, setup, test_write_exactly_same, teardown);
g_test_add ("/openssl/openssl_roundtrip", Test, NULL, setup, test_openssl_roundtrip, teardown);
return g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]