summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--docs/reference/gcr/gcr-sections.txt1
-rw-r--r--egg/Makefile.am1
-rw-r--r--egg/egg-armor.c407
-rw-r--r--egg/egg-armor.h50
-rw-r--r--egg/egg-openssl.c350
-rw-r--r--egg/egg-openssl.h18
-rw-r--r--egg/tests/test-openssl.c17
-rw-r--r--gcr/Makefile.am1
-rw-r--r--gcr/gcr-certificate-exporter.c7
-rw-r--r--gcr/gcr-openpgp.c226
-rw-r--r--gcr/gcr-openpgp.h49
-rw-r--r--gcr/gcr-parser.c87
-rw-r--r--gcr/gcr-types.h3
-rw-r--r--gcr/tests/Makefile.am1
-rw-r--r--gcr/tests/files/pubring.gpgbin0 -> 21969 bytes
-rw-r--r--gcr/tests/files/werner-koch.asc71
-rw-r--r--gcr/tests/test-openpgp.c94
-rw-r--r--pkcs11/gkm/tests/test-data-der.c3
-rw-r--r--pkcs11/roots-store/gkm-roots-module.c3
-rw-r--r--pkcs11/ssh-store/gkm-ssh-openssh.c5
21 files changed, 999 insertions, 396 deletions
diff --git a/.gitignore b/.gitignore
index d569cf7a..35ab7616 100644
--- a/.gitignore
+++ b/.gitignore
@@ -133,6 +133,7 @@ run-tests
/gcr/tests/test-gnupg-key
/gcr/tests/test-gnupg-process
/gcr/tests/test-memory-icon
+/gcr/tests/test-openpgp
/gcr/tests/test-openssh
/gcr/tests/test-parser
/gcr/tests/test-pkcs11-certificate
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index dfb22ab0..ea40ee1c 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -590,4 +590,5 @@ GcrMemoryIconPrivate
GCR_ERROR
gcr_error_get_domain
GcrOpensshPubCallback
+GcrOpenpgpCallback
</SECTION>
diff --git a/egg/Makefile.am b/egg/Makefile.am
index 917d8848..4b61830c 100644
--- a/egg/Makefile.am
+++ b/egg/Makefile.am
@@ -23,6 +23,7 @@ libegg_la_CFLAGS = \
$(GLIB_CFLAGS)
libegg_la_SOURCES = \
+ egg-armor.c egg-armor.h \
egg-asn1x.c egg-asn1x.h \
egg-buffer.c egg-buffer.h \
egg-byte-array.c egg-byte-array.h \
diff --git a/egg/egg-armor.c b/egg/egg-armor.c
new file mode 100644
index 00000000..5a4b0476
--- /dev/null
+++ b/egg/egg-armor.c
@@ -0,0 +1,407 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-openssl.c - OpenSSL compatibility functionality
+
+ Copyright (C) 2007 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef@memberwebs.com>
+*/
+
+#include "config.h"
+
+#include "egg-hex.h"
+#include "egg-armor.h"
+#include "egg-secure-memory.h"
+
+#include <gcrypt.h>
+
+#include <glib.h>
+
+#include <ctype.h>
+#include <string.h>
+
+/*
+ * Armor looks like:
+ *
+ * -----BEGIN RSA PRIVATE KEY-----
+ * Proc-Type: 4,ENCRYPTED
+ * DEK-Info: DES-EDE3-CBC,704CFFD62FBA03E9
+ *
+ * 4AV/g0BiTeb07hzo4/Ct47HGhHEshMhBPGJ843QzuAinpZBbg3OxwPsQsLgoPhJL
+ * Bg6Oxyz9M4UN1Xlx6Lyo2lRT908mBP6dl/OItLsVArqAzM+e29KHQVNjV1h7xN9F
+ * u84tOgZftKun+ZkQUOoRvMLLu4yV4CUraks9tgyXquugGba/tbeyj2MYsC8wwSJX
+ * ................................................................
+ * =on29
+ * -----END RSA PRIVATE KEY-----
+ *
+ * The last line before END is an option OpenPGP armor checksum
+ */
+
+EGG_SECURE_DECLARE (armor);
+
+#define ARMOR_SUFF "-----"
+#define ARMOR_SUFF_L 5
+#define ARMOR_PREF_BEGIN "-----BEGIN "
+#define ARMOR_PREF_BEGIN_L 11
+#define ARMOR_PREF_END "-----END "
+#define ARMOR_PREF_END_L 9
+
+static void
+parse_header_lines (const gchar *hbeg,
+ const gchar *hend,
+ GHashTable **result)
+{
+ gchar **lines, **l;
+ gchar *line, *name, *value;
+ gchar *copy;
+
+ copy = g_strndup (hbeg, hend - hbeg);
+ lines = g_strsplit (copy, "\n", 0);
+ g_free (copy);
+
+ for (l = lines; l && *l; ++l) {
+ line = *l;
+ g_strstrip (line);
+
+ /* Look for the break between name: value */
+ value = strchr (line, ':');
+ if (value == NULL)
+ continue;
+
+ *value = 0;
+ value = g_strdup (value + 1);
+ g_strstrip (value);
+
+ name = g_strdup (line);
+ g_strstrip (name);
+
+ if (!*result)
+ *result = egg_armor_headers_new ();
+ g_hash_table_replace (*result, name, value);
+ }
+
+ g_strfreev (lines);
+}
+
+static const gchar*
+armor_find_begin (const gchar *data,
+ gsize n_data,
+ GQuark *type,
+ const gchar **outer)
+{
+ const gchar *pref, *suff;
+ gchar *stype;
+
+ /* Look for a prefix */
+ pref = g_strstr_len ((gchar*)data, n_data, ARMOR_PREF_BEGIN);
+ if (!pref)
+ return NULL;
+
+ n_data -= (pref - data) + ARMOR_PREF_BEGIN_L;
+ data = pref + ARMOR_PREF_BEGIN_L;
+
+ /* Look for the end of that begin */
+ suff = g_strstr_len ((gchar*)data, n_data, ARMOR_SUFF);
+ if (!suff)
+ return NULL;
+
+ /* Make sure on the same line */
+ if (memchr (pref, '\n', suff - pref))
+ return NULL;
+
+ if (outer)
+ *outer = pref;
+
+ if (type) {
+ *type = 0;
+ pref += ARMOR_PREF_BEGIN_L;
+ g_assert (suff > pref);
+ stype = g_alloca (suff - pref + 1);
+ memcpy (stype, pref, suff - pref);
+ stype[suff - pref] = 0;
+ *type = g_quark_from_string (stype);
+ }
+
+ /* The byte after this ---BEGIN--- */
+ return suff + ARMOR_SUFF_L;
+}
+
+static const gchar*
+armor_find_end (const gchar *data,
+ gsize n_data,
+ GQuark type,
+ const gchar **outer)
+{
+ const gchar *stype;
+ const gchar *pref;
+ const gchar *line;
+ gsize n_type;
+
+ /* Look for a prefix */
+ pref = g_strstr_len (data, n_data, ARMOR_PREF_END);
+ if (!pref)
+ return NULL;
+
+ n_data -= (pref - data) + ARMOR_PREF_END_L;
+ data = pref + ARMOR_PREF_END_L;
+
+ /* Next comes the type string */
+ stype = g_quark_to_string (type);
+ n_type = strlen (stype);
+ if (strncmp ((gchar*)data, stype, n_type) != 0)
+ return NULL;
+
+ n_data -= n_type;
+ data += n_type;
+
+ /* Next comes the suffix */
+ if (strncmp ((gchar*)data, ARMOR_SUFF, ARMOR_SUFF_L) != 0)
+ return NULL;
+
+ /*
+ * Check if there's a OpenPGP style armor checksum line. OpenPGP
+ * does not insist that we validate this line, and is more useful
+ * for PGP messages, rather than the keys we usually see.
+ */
+ line = memrchr (data, '\n', (pref - 1) - data);
+ if (line && line[1] == '=')
+ pref = line;
+
+ if (outer != NULL) {
+ data += ARMOR_SUFF_L;
+ if (isspace (data[0]))
+ data++;
+ *outer = data;
+ }
+
+ /* The end of the data */
+ return pref;
+}
+
+static gboolean
+armor_parse_block (const gchar *data,
+ gsize n_data,
+ guchar **decoded,
+ gsize *n_decoded,
+ GHashTable **headers)
+{
+ const gchar *x, *hbeg, *hend;
+ const gchar *p, *end;
+ gint state = 0;
+ guint save = 0;
+
+ g_assert (data);
+ g_assert (n_data);
+
+ g_assert (decoded);
+ g_assert (n_decoded);
+
+ p = data;
+ end = p + n_data;
+
+ hbeg = hend = NULL;
+
+ /* Try and find a pair of blank lines with only white space between */
+ while (hend == NULL) {
+ x = memchr (p, '\n', end - p);
+ if (!x)
+ break;
+ ++x;
+ while (isspace (*x)) {
+ /* Found a second line, with only spaces between */
+ if (*x == '\n') {
+ hbeg = data;
+ hend = x;
+ break;
+ /* Found a space between two lines */
+ } else {
+ ++x;
+ }
+ }
+
+ /* Try next line */
+ p = x;
+ }
+
+ /* Headers found? */
+ if (hbeg && hend) {
+ data = hend;
+ n_data = end - data;
+ }
+
+ *n_decoded = (n_data * 3) / 4 + 1;
+ if (egg_secure_check (data))
+ *decoded = egg_secure_alloc (*n_decoded);
+ else
+ *decoded = g_malloc0 (*n_decoded);
+ g_return_val_if_fail (*decoded, FALSE);
+
+ *n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save);
+ if (!*n_decoded) {
+ egg_secure_free (*decoded);
+ return FALSE;
+ }
+
+ if (headers && hbeg && hend)
+ parse_header_lines (hbeg, hend, headers);
+
+ return TRUE;
+}
+
+GHashTable*
+egg_armor_headers_new (void)
+{
+ return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
+guint
+egg_armor_parse (gconstpointer data,
+ gsize n_data,
+ EggArmorCallback callback,
+ gpointer user_data)
+{
+ const gchar *beg, *end;
+ const gchar *outer_beg, *outer_end;
+ guint nfound = 0;
+ guchar *decoded = NULL;
+ gsize n_decoded = 0;
+ GHashTable *headers = NULL;
+ GQuark type;
+
+ g_return_val_if_fail (data, 0);
+ g_return_val_if_fail (n_data, 0);
+
+ while (n_data > 0) {
+
+ /* This returns the first character after the PEM BEGIN header */
+ beg = armor_find_begin ((const gchar*)data, n_data, &type, &outer_beg);
+ if (beg == NULL)
+ break;
+
+ g_assert (type);
+
+ /* This returns the character position before the PEM END header */
+ end = armor_find_end ((const gchar*)beg,
+ n_data - ((const gchar*)beg - (const gchar *)data),
+ type, &outer_end);
+ if (end == NULL)
+ break;
+
+ if (beg != end) {
+ if (armor_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) {
+ g_assert (outer_end > outer_beg);
+ if (callback != NULL)
+ (callback) (type,
+ decoded, n_decoded,
+ outer_beg, outer_end - outer_beg,
+ headers, user_data);
+ ++nfound;
+ egg_secure_free (decoded);
+ if (headers)
+ g_hash_table_remove_all (headers);
+ }
+ }
+
+ /* Try for another block */
+ end += ARMOR_SUFF_L;
+ n_data -= (const gchar*)end - (const gchar*)data;
+ data = end;
+ }
+
+ if (headers)
+ g_hash_table_destroy (headers);
+
+ return nfound;
+}
+
+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);
+ g_string_append_c (string, '\n');
+}
+
+guchar*
+egg_armor_write (const guchar *data,
+ gsize n_data,
+ GQuark type,
+ GHashTable *headers,
+ gsize *n_result)
+{
+ GString *string;
+ gint state, save;
+ 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, ARMOR_PREF_BEGIN, ARMOR_PREF_BEGIN_L);
+ g_string_append (string, g_quark_to_string (type));
+ g_string_append_len (string, ARMOR_SUFF, ARMOR_SUFF_L);
+ g_string_append_c (string, '\n');
+
+ /* The headers */
+ if (headers && g_hash_table_size (headers) > 0) {
+ g_hash_table_foreach (headers, append_each_header, string);
+ g_string_append_c (string, '\n');
+ }
+
+ /* Resize string to fit the base64 data. Algorithm from Glib reference */
+ estimate = n_data * 4 / 3 + n_data * 4 / (3 * 65) + 7;
+ n_prefix = string->len;
+ 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, 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_len (string, ARMOR_PREF_END, ARMOR_PREF_END_L);
+ g_string_append (string, g_quark_to_string (type));
+ g_string_append_len (string, ARMOR_SUFF, ARMOR_SUFF_L);
+ g_string_append_c (string, '\n');
+
+ *n_result = string->len;
+ return (guchar*)g_string_free (string, FALSE);
+}
diff --git a/egg/egg-armor.h b/egg/egg-armor.h
new file mode 100644
index 00000000..e0f13d3c
--- /dev/null
+++ b/egg/egg-armor.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-armor.h - Armor routines
+
+ Copyright (C) 2007 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef@memberwebs.com>
+*/
+
+#ifndef EGG_ARMOR_H_
+#define EGG_ARMOR_H_
+
+#include <glib.h>
+
+typedef void (*EggArmorCallback) (GQuark type,
+ const guchar *data,
+ gsize n_data,
+ const gchar *outer,
+ gsize n_outer,
+ GHashTable *headers,
+ gpointer user_data);
+
+GHashTable* egg_armor_headers_new (void);
+
+guint egg_armor_parse (gconstpointer data,
+ gsize n_data,
+ EggArmorCallback callback,
+ gpointer user_data);
+
+guchar* egg_armor_write (const guchar *data,
+ gsize n_data,
+ GQuark type,
+ GHashTable *headers,
+ gsize *n_result);
+
+#endif /* EGG_ARMOR_H_ */
diff --git a/egg/egg-openssl.c b/egg/egg-openssl.c
index 45daccb2..352451f7 100644
--- a/egg/egg-openssl.c
+++ b/egg/egg-openssl.c
@@ -35,358 +35,8 @@
#include <ctype.h>
#include <string.h>
-/*
- * PEM looks like:
- *
- * -----BEGIN RSA PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: DES-EDE3-CBC,704CFFD62FBA03E9
- *
- * 4AV/g0BiTeb07hzo4/Ct47HGhHEshMhBPGJ843QzuAinpZBbg3OxwPsQsLgoPhJL
- * Bg6Oxyz9M4UN1Xlx6Lyo2lRT908mBP6dl/OItLsVArqAzM+e29KHQVNjV1h7xN9F
- * u84tOgZftKun+ZkQUOoRvMLLu4yV4CUraks9tgyXquugGba/tbeyj2MYsC8wwSJX
- * ....
- * -----END RSA PRIVATE KEY-----
- */
-
-#define PEM_SUFF "-----"
-#define PEM_SUFF_L 5
-#define PEM_PREF_BEGIN "-----BEGIN "
-#define PEM_PREF_BEGIN_L 11
-#define PEM_PREF_END "-----END "
-#define PEM_PREF_END_L 9
-
EGG_SECURE_DECLARE (openssl);
-static void
-parse_header_lines (const gchar *hbeg, const gchar *hend, GHashTable **result)
-{
- gchar **lines, **l;
- gchar *line, *name, *value;
- gchar *copy;
-
- copy = g_strndup (hbeg, hend - hbeg);
- lines = g_strsplit (copy, "\n", 0);
- g_free (copy);
-
- for (l = lines; l && *l; ++l) {
- line = *l;
- g_strstrip (line);
-
- /* Look for the break between name: value */
- value = strchr (line, ':');
- if (value == NULL)
- continue;
-
- *value = 0;
- value = g_strdup (value + 1);
- g_strstrip (value);
-
- name = g_strdup (line);
- g_strstrip (name);
-
- if (!*result)
- *result = egg_openssl_headers_new ();
- g_hash_table_replace (*result, name, value);
- }
-
- g_strfreev (lines);
-}
-
-static const gchar*
-pem_find_begin (const gchar *data,
- gsize n_data,
- GQuark *type,
- const gchar **outer)
-{
- const gchar *pref, *suff;
- gchar *stype;
-
- /* Look for a prefix */
- pref = g_strstr_len ((gchar*)data, n_data, PEM_PREF_BEGIN);
- if (!pref)
- return NULL;
-
- n_data -= (pref - data) + PEM_PREF_BEGIN_L;
- data = pref + PEM_PREF_BEGIN_L;
-
- /* Look for the end of that begin */
- suff = g_strstr_len ((gchar*)data, n_data, PEM_SUFF);
- if (!suff)
- return NULL;
-
- /* Make sure on the same line */
- if (memchr (pref, '\n', suff - pref))
- return NULL;
-
- if (outer)
- *outer = pref;
-
- if (type) {
- *type = 0;
- pref += PEM_PREF_BEGIN_L;
- g_assert (suff > pref);
- stype = g_alloca (suff - pref + 1);
- memcpy (stype, pref, suff - pref);
- stype[suff - pref] = 0;
- *type = g_quark_from_string (stype);
- }
-
- /* The byte after this ---BEGIN--- */
- return suff + PEM_SUFF_L;
-}
-
-static const gchar*
-pem_find_end (const gchar *data,
- gsize n_data,
- GQuark type,
- const gchar **outer)
-{
- const gchar *stype;
- const gchar *pref;
- gsize n_type;
-
- /* Look for a prefix */
- pref = g_strstr_len (data, n_data, PEM_PREF_END);
- if (!pref)
- return NULL;
-
- n_data -= (pref - data) + PEM_PREF_END_L;
- data = pref + PEM_PREF_END_L;
-
- /* Next comes the type string */
- stype = g_quark_to_string (type);
- n_type = strlen (stype);
- if (strncmp ((gchar*)data, stype, n_type) != 0)
- return NULL;
-
- n_data -= n_type;
- data += n_type;
-
- /* Next comes the suffix */
- if (strncmp ((gchar*)data, PEM_SUFF, PEM_SUFF_L) != 0)
- return NULL;
-
- if (outer != NULL) {
- data += PEM_SUFF_L;
- if (isspace (data[0]))
- data++;
- *outer = data;
- }
-
- /* The beginning of this ---END--- */
- return pref;
-}
-
-static gboolean
-pem_parse_block (const gchar *data, gsize n_data, guchar **decoded, gsize *n_decoded,
- GHashTable **headers)
-{
- const gchar *x, *hbeg, *hend;
- const gchar *p, *end;
- gint state = 0;
- guint save = 0;
-
- g_assert (data);
- g_assert (n_data);
-
- g_assert (decoded);
- g_assert (n_decoded);
-
- p = data;
- end = p + n_data;
-
- hbeg = hend = NULL;
-
- /* Try and find a pair of blank lines with only white space between */
- while (hend == NULL) {
- x = memchr (p, '\n', end - p);
- if (!x)
- break;
- ++x;
- while (isspace (*x)) {
- /* Found a second line, with only spaces between */
- if (*x == '\n') {
- hbeg = data;
- hend = x;
- break;
- /* Found a space between two lines */
- } else {
- ++x;
- }
- }
-
- /* Try next line */
- p = x;
- }
-
- /* Headers found? */
- if (hbeg && hend) {
- data = hend;
- n_data = end - data;
- }
-
- *n_decoded = (n_data * 3) / 4 + 1;
- if (egg_secure_check (data))
- *decoded = egg_secure_alloc (*n_decoded);
- else
- *decoded = g_malloc0 (*n_decoded);
- g_return_val_if_fail (*decoded, FALSE);
-
- *n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save);
- if (!*n_decoded) {
- egg_secure_free (*decoded);
- return FALSE;
- }
-
- if (headers && hbeg && hend)
- parse_header_lines (hbeg, hend, headers);
-
- return TRUE;
-}
-
-GHashTable*
-egg_openssl_headers_new (void)
-{
- return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-}
-
-guint
-egg_openssl_pem_parse (gconstpointer data, gsize n_data,
- EggOpensslPemCallback callback, gpointer user_data)
-{
- const gchar *beg, *end;
- const gchar *outer_beg, *outer_end;
- guint nfound = 0;
- guchar *decoded = NULL;
- gsize n_decoded = 0;
- GHashTable *headers = NULL;
- GQuark type;
-
- g_return_val_if_fail (data, 0);
- g_return_val_if_fail (n_data, 0);
- g_return_val_if_fail (callback, 0);
-
- while (n_data > 0) {
-
- /* This returns the first character after the PEM BEGIN header */
- beg = pem_find_begin ((const gchar*)data, n_data, &type, &outer_beg);
- if (!beg)
- break;
-
- g_assert (type);
-
- /* This returns the character position before the PEM END header */
- end = pem_find_end ((const gchar*)beg, n_data - ((const gchar*)beg - (const gchar *)data),
- type, &outer_end);
- if (!end)
- break;
-
- if (beg != end) {
- if (pem_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) {
- g_assert (outer_end > outer_beg);
- (callback) (type,
- decoded, n_decoded,
- outer_beg, outer_end - outer_beg,
- headers, user_data);
- ++nfound;
- egg_secure_free (decoded);
- if (headers)
- g_hash_table_remove_all (headers);
- }
- }
-
- /* Try for another block */
- end += PEM_SUFF_L;
- n_data -= (const gchar*)end - (const gchar*)data;
- data = end;
- }
-
- if (headers)
- g_hash_table_destroy (headers);
-
- return nfound;
-}
-
-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);
- g_string_append_c (string, '\n');
-}
-
-guchar*
-egg_openssl_pem_write (const guchar *data, gsize n_data, GQuark type,
- GHashTable *headers, gsize *n_result)
-{
- GString *string;
- gint state, save;
- 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));
- g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
- g_string_append_c (string, '\n');
-
- /* The headers */
- if (headers && g_hash_table_size (headers) > 0) {
- g_hash_table_foreach (headers, append_each_header, string);
- g_string_append_c (string, '\n');
- }
-
- /* Resize string to fit the base64 data. Algorithm from Glib reference */
- estimate = n_data * 4 / 3 + n_data * 4 / (3 * 65) + 7;
- n_prefix = string->len;
- 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, 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_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);
-}
-
-/* ----------------------------------------------------------------------------
- * DEFINITIONS
- */
-
static const struct {
const gchar *desc;
int algo;
diff --git a/egg/egg-openssl.h b/egg/egg-openssl.h
index 49716dd6..7d4e4f06 100644
--- a/egg/egg-openssl.h
+++ b/egg/egg-openssl.h
@@ -26,24 +26,6 @@
#include <glib.h>
-typedef void (*EggOpensslPemCallback) (GQuark type,
- const guchar *data,
- gsize n_data,
- const gchar *outer,
- gsize n_outer,
- GHashTable *headers,
- gpointer user_data);
-
-GHashTable* egg_openssl_headers_new (void);
-
-guint egg_openssl_pem_parse (gconstpointer data, gsize n_data,
- EggOpensslPemCallback callback,
- gpointer user_data);
-
-guchar* egg_openssl_pem_write (const guchar *data, gsize n_data,
- GQuark type, GHashTable *headers,
- gsize *n_result);
-
int egg_openssl_parse_algo (const gchar *name, int *mode);
gboolean egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password,
diff --git a/egg/tests/test-openssl.c b/egg/tests/test-openssl.c
index e2c35167..da5e4572 100644
--- a/egg/tests/test-openssl.c
+++ b/egg/tests/test-openssl.c
@@ -1,5 +1,5 @@
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* unit-test-pkix-openssl.c: Test PKIX openssl
+/* test-openssl.c: Test openssl
Copyright (C) 2008 Stefan Walter
@@ -23,6 +23,7 @@
#include "config.h"
+#include "egg/egg-armor.h"
#include "egg/egg-symkey.h"
#include "egg/egg-openssl.h"
#include "egg/egg-secure-memory.h"
@@ -93,7 +94,7 @@ parse_reference (GQuark type,
g_assert ("no headers present in file" && headers != NULL);
g_assert (!test->refheaders);
- test->refheaders = egg_openssl_headers_new ();
+ test->refheaders = egg_armor_headers_new ();
g_hash_table_foreach (headers, copy_each_key_value, test->refheaders);
dekinfo = egg_openssl_get_dekinfo (headers);
g_assert ("no dekinfo in headers" && dekinfo != NULL);
@@ -109,7 +110,7 @@ test_parse_reference (Test *test, gconstpointer unused)
{
guint num;
- num = egg_openssl_pem_parse (test->input, test->n_input, parse_reference, test);
+ num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
g_assert ("couldn't PEM block in reference data" && num == 1);
g_assert ("parse_reference() wasn't called" && test->refdata != NULL);
@@ -124,7 +125,7 @@ test_write_reference (Test *test, gconstpointer unused)
gboolean ret;
guint num;
- num = egg_openssl_pem_parse (test->input, test->n_input, parse_reference, test);
+ num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
g_assert ("couldn't PEM block in reference data" && num == 1);
dekinfo = egg_openssl_get_dekinfo (test->refheaders);
@@ -146,11 +147,11 @@ test_write_exactly_same (Test *test, gconstpointer unused)
gsize n_result;
guint num;
- num = egg_openssl_pem_parse (test->input, test->n_input, parse_reference, test);
+ num = egg_armor_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);
+ result = egg_armor_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
@@ -177,7 +178,7 @@ test_openssl_roundtrip (Test *test, gconstpointer unused)
int i;
guint num;
- num = egg_openssl_pem_parse (test->input, test->n_input, parse_reference, test);
+ num = egg_armor_parse (test->input, test->n_input, parse_reference, test);
g_assert ("couldn't PEM block in reference data" && num == 1);
dekinfo = egg_openssl_prep_dekinfo (test->refheaders);
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index f89100c2..38d8856c 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -103,6 +103,7 @@ libgcr_base_@GCR_MAJOR@_la_SOURCES = \
gcr-internal.h \
gcr-memory.c \
gcr-memory-icon.c gcr-memory-icon.h \
+ gcr-openpgp.c gcr-openpgp.h \
gcr-openssh.c gcr-openssh.h \
gcr-parser.c gcr-parser.h \
gcr-pkcs11-certificate.c gcr-pkcs11-certificate.h \
diff --git a/gcr/gcr-certificate-exporter.c b/gcr/gcr-certificate-exporter.c
index 115b0302..7806533e 100644
--- a/gcr/gcr-certificate-exporter.c
+++ b/gcr/gcr-certificate-exporter.c
@@ -24,6 +24,7 @@
#include "gcr-certificate.h"
#include "gcr-certificate-exporter.h"
+#include "egg/egg-armor.h"
#include "egg/egg-openssl.h"
#include <glib/gi18n-lib.h>
@@ -96,9 +97,9 @@ prepare_data_for_pem (GcrCertificateExporter *self)
self->pv->buffer = g_byte_array_new ();
- encoded = egg_openssl_pem_write (data, n_data,
- g_quark_from_static_string ("CERTIFICATE"),
- NULL, &n_encoded);
+ encoded = egg_armor_write (data, n_data,
+ g_quark_from_static_string ("CERTIFICATE"),
+ NULL, &n_encoded);
g_byte_array_append (self->pv->buffer, encoded, n_encoded);
g_free (encoded);
diff --git a/gcr/gcr-openpgp.c b/gcr/gcr-openpgp.c
new file mode 100644
index 00000000..073ec7d6
--- /dev/null
+++ b/gcr/gcr-openpgp.c
@@ -0,0 +1,226 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gcr-openpgp.h"
+#include "gcr-internal.h"
+#include "gcr-record.h"
+#include "gcr-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <string.h>
+
+static gboolean
+read_byte (const guchar **at,
+ const guchar *end,
+ guchar *result)
+{
+ g_assert (at);
+ if (*at == end)
+ *at = NULL;
+ if (*at == NULL)
+ return FALSE;
+ *result = *((*at)++);
+ return TRUE;
+}
+
+static gboolean
+read_bytes (const guchar **at,
+ const guchar *end,
+ gpointer buffer,
+ gsize length)
+{
+ g_assert (at);
+ if (*at + length >= end)
+ *at = NULL;
+ if (*at == NULL)
+ return FALSE;
+ memcpy (buffer, *at, length);
+ (*at) += length;
+ return TRUE;
+}
+
+static gboolean
+read_uint32 (const guchar **at,
+ const guchar *end,
+ guint32 *value)
+{
+ guchar buf[4];
+ if (!read_bytes (at, end, buf, 4))
+ return FALSE;
+ *value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+ return TRUE;
+}
+
+static gboolean
+read_uint16 (const guchar **at,
+ const guchar *end,
+ guint16 *value)
+{
+ guchar buf[2];
+ if (!read_bytes (at, end, buf, 2))
+ return FALSE;
+ *value = buf[0] << 8 | buf[1];
+ return TRUE;
+}
+
+static gboolean
+read_new_length (const guchar **at,
+ const guchar *end,
+ gsize *pkt_len)
+{
+ guchar c, c1;
+ guint32 val;
+
+ if (!read_byte (at, end, &c))
+ return FALSE;
+ if (c < 192) {
+ *pkt_len = c;
+ } else if (c >= 192 && c <= 223) {
+ if (!read_byte (at, end, &c1))
+ return FALSE;
+ *pkt_len = ((c - 192) << 8) + c1 + 192;
+ } else if (c == 255) {
+ if (!read_uint32 (at, end, &val))
+ return FALSE;
+ *pkt_len = val;
+ } else {
+ /* We don't support partial length */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+read_old_length (const guchar **at,
+ const guchar *end,
+ guchar ctb,
+ gsize *pkt_len)
+{
+ gsize llen = ctb & 0x03;
+ guint16 v16;
+ guint32 v32;
+ guchar c;
+
+ if (llen == 0) {
+ if (!read_byte (at, end, &c))
+ return FALSE;
+ *pkt_len = c;
+ } else if (llen == 1) {
+ if (!read_uint16 (at, end, &v16))
+ return FALSE;
+ *pkt_len = v16;
+ } else if (llen == 2) {
+ if (!read_uint32 (at, end, &v32))
+ return FALSE;
+ *pkt_len = v32;
+ } else {
+ *pkt_len = end - *at;
+ }
+
+ return TRUE;
+}
+
+static GcrDataError
+read_openpgp_packet (const guchar **at,
+ const guchar *end,
+ GPtrArray *records,
+ gsize *length)
+{
+ guchar pkt_type;
+ gboolean new_ctb;
+ guchar ctb;
+ gboolean ret;
+
+ if (!read_byte (at, end, &ctb))
+ return GCR_ERROR_UNRECOGNIZED;
+ if (!(ctb & 0x80))
+ return GCR_ERROR_UNRECOGNIZED;
+
+ /* RFC2440 packet format. */
+ if (ctb & 0x40) {
+ pkt_type = ctb & 0x3f;
+ new_ctb = TRUE;
+
+ /* the old RFC1991 packet format. */
+ } else {
+ pkt_type = ctb & 0x3f;
+ pkt_type >>= 2;
+ new_ctb = FALSE;
+ }
+
+ if (pkt_type > 63)
+ return GCR_ERROR_UNRECOGNIZED;
+
+ if (new_ctb)
+ ret = read_new_length (at, end, length);
+ else
+ ret = read_old_length (at, end, ctb, length);
+ if (!ret)
+ return GCR_ERROR_UNRECOGNIZED;
+
+ if ((*at) + *length > end)
+ return GCR_ERROR_FAILURE;
+ return GCR_SUCCESS;
+}
+
+guint
+_gcr_openpgp_parse (gconstpointer data,
+ gsize n_data,
+ GcrOpenpgpCallback callback,
+ gpointer user_data)
+{
+ const guchar *at;
+ const guchar *beg;
+ const guchar *end;
+ GPtrArray *records;
+ GcrDataError res;
+ gsize length;
+ guint num_packets = 0;
+
+ g_return_val_if_fail (data != NULL, 0);
+
+ at = data;
+ end = at + n_data;
+
+ while (at != NULL && at != end) {
+ beg = at;
+ records = g_ptr_array_new_with_free_func (_gcr_record_free);
+ res = read_openpgp_packet (&at, end, records, &length);
+ if (res == GCR_SUCCESS && callback != NULL)
+ (callback) (records, beg, (at - beg) + length, user_data);
+
+ g_ptr_array_unref (records);
+
+ if (res != GCR_SUCCESS)
+ break;
+
+ at += length;
+ num_packets++;
+ }
+
+ return num_packets;
+}
diff --git a/gcr/gcr-openpgp.h b/gcr/gcr-openpgp.h
new file mode 100644
index 00000000..35759215
--- /dev/null
+++ b/gcr/gcr-openpgp.h
@@ -0,0 +1,49 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#ifndef __GCR_OPENPGP_H__
+#define __GCR_OPENPGP_H__
+
+#include <glib.h>
+
+#include <gck/gck.h>
+
+G_BEGIN_DECLS
+
+typedef void (*GcrOpenpgpCallback) (GPtrArray *records,
+ const guchar *outer,
+ gsize n_outer,
+ gpointer user_data);
+
+guint _gcr_openpgp_parse (gconstpointer data,
+ gsize n_data,
+ GcrOpenpgpCallback callback,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __GCR_OPENPGP_H__ */
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 9e15573e..8f8b92f8 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -27,10 +27,12 @@
#include "gcr-importer.h"
#include "gcr-marshal.h"
#include "gcr-oids.h"
+#include "gcr-openpgp.h"
#include "gcr-openssh.h"
#include "gcr-parser.h"
#include "gcr-types.h"
+#include "egg/egg-armor.h"
#include "egg/egg-asn1x.h"
#include "egg/egg-asn1-defs.h"
#include "egg/egg-dn.h"
@@ -90,6 +92,8 @@
* @GCR_FORMAT_DER_PKCS8_ENCRYPTED: Encrypted DER encoded PKCS\#8 file which can contain a key
* @GCR_FORMAT_DER_PKCS12: DER encoded PKCS\#12 file which can contain certificates and/or keys
* @GCR_FORMAT_OPENSSH_PUBLIC: OpenSSH v1 or v2 public key
+ * @GCR_FORMAT_OPENPGP_PACKET: OpenPGP key packet(s)
+ * @GCR_FORMAT_OPENPGP_ARMOR: OpenPGP public or private key armor encoded data
* @GCR_FORMAT_PEM: An OpenSSL style PEM file with unspecified contents
* @GCR_FORMAT_PEM_PRIVATE_KEY_RSA: An OpenSSL style PEM file with a private RSA key
* @GCR_FORMAT_PEM_PRIVATE_KEY_DSA: An OpenSSL style PEM file with a private DSA key
@@ -186,6 +190,9 @@ static GQuark PEM_PRIVATE_KEY;
static GQuark PEM_PKCS7;
static GQuark PEM_PKCS12;
+static GQuark ARMOR_PGP_PUBLIC_KEY_BLOCK;
+static GQuark ARMOR_PGP_PRIVATE_KEY_BLOCK;
+
static void
init_quarks (void)
{
@@ -206,7 +213,9 @@ init_quarks (void)
QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY");
QUARK (PEM_PKCS7, "PKCS7");
QUARK (PEM_PKCS12, "PKCS12");
-
+ QUARK (ARMOR_PGP_PRIVATE_KEY_BLOCK, "PGP PRIVATE KEY BLOCK");
+ QUARK (ARMOR_PGP_PUBLIC_KEY_BLOCK, "PGP PUBLIC KEY BLOCK");
+
#undef QUARK
g_once_init_leave (&quarks_inited, 1);
@@ -1360,6 +1369,40 @@ done:
return ret;
}
+
+/* -----------------------------------------------------------------------------
+ * OPENPGP
+ */
+
+static void
+on_openpgp_packet (GPtrArray *records,
+ const guchar *outer,
+ gsize n_outer,
+ gpointer user_data)
+{
+ GcrParser *self = GCR_PARSER (user_data);
+
+ /* All we can do is the packet bounds */
+ parsing_begin (self, outer, n_outer);
+ parsing_object (self, CKO_DATA);
+ parsed_fire (self);
+ parsing_end (self);
+}
+
+static gint
+parse_openpgp_packets (GcrParser *self,
+ const guchar *data,
+ gsize n_data)
+{
+ gint num_parsed;
+
+ num_parsed = _gcr_openpgp_parse (data, n_data, on_openpgp_packet, self);
+
+ if (num_parsed == 0)
+ return GCR_ERROR_UNRECOGNIZED;
+ return SUCCESS;
+}
+
/* -----------------------------------------------------------------------------
* PEM PARSING
*/
@@ -1394,7 +1437,13 @@ handle_plain_pem (GcrParser *self, GQuark type, gint subformat,
else if (type == PEM_PKCS12)
format_id = GCR_FORMAT_DER_PKCS12;
-
+
+ else if (type == ARMOR_PGP_PRIVATE_KEY_BLOCK)
+ format_id = GCR_FORMAT_OPENPGP_PACKET;
+
+ else if (type == ARMOR_PGP_PUBLIC_KEY_BLOCK)
+ format_id = GCR_FORMAT_OPENPGP_PACKET;
+
else
return GCR_ERROR_UNRECOGNIZED;
@@ -1549,7 +1598,7 @@ handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_
if (n_data == 0)
return GCR_ERROR_UNRECOGNIZED;
- found = egg_openssl_pem_parse (data, n_data, handle_pem_data, &ctx);
+ found = egg_armor_parse (data, n_data, handle_pem_data, &ctx);
if (found == 0)
return GCR_ERROR_UNRECOGNIZED;
@@ -1579,31 +1628,39 @@ parse_pem_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
static gint
parse_pem_certificate (GcrParser *self, const guchar *data, gsize n_data)
{
- return handle_pem_format (self, GCR_FORMAT_PEM_CERTIFICATE_X509, data, n_data);
+ return handle_pem_format (self, GCR_FORMAT_DER_CERTIFICATE_X509, data, n_data);
}
static gint
parse_pem_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS8_PLAIN, data, n_data);
+ return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_PLAIN, data, n_data);
}
static gint
parse_pem_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS8_ENCRYPTED, data, n_data);
+ return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data, n_data);
}
static gint
parse_pem_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS7, data, n_data);
+ return handle_pem_format (self, GCR_FORMAT_DER_PKCS7, data, n_data);
}
static gint
parse_pem_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS12, data, n_data);
+ return handle_pem_format (self, GCR_FORMAT_DER_PKCS12, data, n_data);
+}
+
+static gint
+parse_openpgp_armor (GcrParser *self,
+ const guchar *data,
+ gsize n_data)
+{
+ return handle_pem_format (self, GCR_FORMAT_OPENPGP_PACKET, data, n_data);
}
/* -----------------------------------------------------------------------------
@@ -1628,9 +1685,9 @@ on_openssh_public_key_parsed (GckAttributes *attrs,
}
static gint
-parse_der_openssh_public (GcrParser *self,
- const guchar *data,
- gsize n_data)
+parse_openssh_public (GcrParser *self,
+ const guchar *data,
+ gsize n_data)
{
guint num_parsed;
@@ -1656,7 +1713,9 @@ static const ParserFormat parser_normal[] = {
{ GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain },
{ GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted },
{ GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 },
- { GCR_FORMAT_OPENSSH_PUBLIC, parse_der_openssh_public },
+ { GCR_FORMAT_OPENSSH_PUBLIC, parse_openssh_public },
+ { GCR_FORMAT_OPENPGP_PACKET, parse_openpgp_packets },
+ { GCR_FORMAT_OPENPGP_ARMOR, parse_openpgp_armor },
};
/* Must be in format_id numeric order */
@@ -1670,7 +1729,9 @@ static const ParserFormat parser_formats[] = {
{ GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain },
{ GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted },
{ GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 },
- { GCR_FORMAT_OPENSSH_PUBLIC, parse_der_openssh_public },
+ { GCR_FORMAT_OPENSSH_PUBLIC, parse_openssh_public },
+ { GCR_FORMAT_OPENPGP_PACKET, parse_openpgp_packets },
+ { GCR_FORMAT_OPENPGP_ARMOR, parse_openpgp_armor },
{ GCR_FORMAT_PEM, parse_pem },
{ GCR_FORMAT_PEM_PRIVATE_KEY_RSA, parse_pem_private_key_rsa },
{ GCR_FORMAT_PEM_PRIVATE_KEY_DSA, parse_pem_private_key_dsa },
diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h
index 184eedd5..317e5520 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -73,6 +73,9 @@ typedef enum {
GCR_FORMAT_OPENSSH_PUBLIC = 600,
+ GCR_FORMAT_OPENPGP_PACKET = 700,
+ GCR_FORMAT_OPENPGP_ARMOR,
+
GCR_FORMAT_PEM = 1000,
GCR_FORMAT_PEM_PRIVATE_KEY_RSA,
GCR_FORMAT_PEM_PRIVATE_KEY_DSA,
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index a63b0909..aef09b0b 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -26,6 +26,7 @@ TEST_PROGS = \
test-certificate-chain \
test-fingerprint \
test-pkcs11-certificate \
+ test-openpgp \
test-openssh \
test-trust \
test-parser \
diff --git a/gcr/tests/files/pubring.gpg b/gcr/tests/files/pubring.gpg
new file mode 100644
index 00000000..10b1372d
--- /dev/null
+++ b/gcr/tests/files/pubring.gpg
Binary files differ
diff --git a/gcr/tests/files/werner-koch.asc b/gcr/tests/files/werner-koch.asc
new file mode 100644
index 00000000..eb70c972
--- /dev/null
+++ b/gcr/tests/files/werner-koch.asc
@@ -0,0 +1,71 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.11 (GNU/Linux)
+
+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
+/Yn6BAmPF+6YxQo2W98rzq0THS5wKJjXmHw=
+=F0ww
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/gcr/tests/test-openpgp.c b/gcr/tests/test-openpgp.c
new file mode 100644
index 00000000..7d4fd5eb
--- /dev/null
+++ b/gcr/tests/test-openpgp.c
@@ -0,0 +1,94 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ Copyright (C) 2011 Collabora Ltd
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stefw@collabora.co.uk>
+*/
+
+#include "config.h"
+
+#include "gcr/gcr.h"
+#include "gcr/gcr-openpgp.h"
+
+#include "egg/egg-armor.h"
+#include "egg/egg-testing.h"
+
+#include <gcrypt.h>
+#include <glib.h>
+#include <string.h>
+
+static void
+on_openpgp_packet (GPtrArray *records,
+ const guchar *outer,
+ gsize n_outer,
+ gpointer user_data)
+{
+ guint num_packets;
+
+ /* Should be parseable again */
+ num_packets = _gcr_openpgp_parse (outer, n_outer, NULL, NULL);
+ g_assert_cmpuint (num_packets, ==, 1);
+}
+
+static void
+on_armor_parsed (GQuark type,
+ const guchar *data,
+ gsize n_data,
+ const gchar *outer,
+ gsize n_outer,
+ GHashTable *headers,
+ gpointer user_data)
+{
+ const gchar *value;
+ guint num_packets;
+
+ value = g_hash_table_lookup (headers, "Version");
+ g_assert_cmpstr (value, ==, "GnuPG v1.4.11 (GNU/Linux)");
+
+ num_packets = _gcr_openpgp_parse (data, n_data, on_openpgp_packet, NULL);
+ g_assert_cmpuint (num_packets, ==, 21);
+}
+
+static void
+test_armor_parse (void)
+{
+ GError *error = NULL;
+ gchar *armor;
+ gsize length;
+ guint parts;
+
+ g_file_get_contents (SRCDIR "/files/werner-koch.asc", &armor, &length, &error);
+ g_assert_no_error (error);
+
+ parts = egg_armor_parse (armor, length, on_armor_parsed, NULL);
+ g_assert_cmpuint (parts, ==, 1);
+
+ g_free (armor);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-gnupg-process");
+
+ g_test_add_func ("/gcr/openpgp/armor_parse", test_armor_parse);
+
+ return g_test_run ();
+}
diff --git a/pkcs11/gkm/tests/test-data-der.c b/pkcs11/gkm/tests/test-data-der.c
index 6b5531d9..2bc90dfa 100644
--- a/pkcs11/gkm/tests/test-data-der.c
+++ b/pkcs11/gkm/tests/test-data-der.c
@@ -28,6 +28,7 @@
#include "gkm/gkm-data-der.h"
#include "gkm/gkm-sexp.h"
+#include "egg/egg-armor.h"
#include "egg/egg-asn1x.h"
#include "egg/egg-asn1-defs.h"
#include "egg/egg-openssl.h"
@@ -338,7 +339,7 @@ test_read_ca_certificates_public_key_info (Test *test, gconstpointer unused)
if (!g_file_get_contents (SRCDIR "/files/ca-certificates.crt", &data, &n_data, NULL))
g_assert_not_reached ();
- egg_openssl_pem_parse (data, n_data, on_ca_certificate_public_key_info, NULL);
+ egg_armor_parse (data, n_data, on_ca_certificate_public_key_info, NULL);
g_free (data);
}
diff --git a/pkcs11/roots-store/gkm-roots-module.c b/pkcs11/roots-store/gkm-roots-module.c
index 32569f41..e337623f 100644
--- a/pkcs11/roots-store/gkm-roots-module.c
+++ b/pkcs11/roots-store/gkm-roots-module.c
@@ -28,6 +28,7 @@
#include "gkm/gkm-file-tracker.h"
#include "gkm/gkm-serializable.h"
+#include "egg/egg-armor.h"
#include "egg/egg-error.h"
#include "egg/egg-openssl.h"
@@ -210,7 +211,7 @@ file_load (GkmFileTracker *tracker, const gchar *path, GkmRootsModule *self)
g_list_free (objects);
/* Try and parse the PEM */
- egg_openssl_pem_parse (data, n_data, parsed_pem_block, &ctx);
+ egg_armor_parse (data, n_data, parsed_pem_block, &ctx);
/* If no PEM data, try to parse directly as DER */
if (ctx.count == 0) {
diff --git a/pkcs11/ssh-store/gkm-ssh-openssh.c b/pkcs11/ssh-store/gkm-ssh-openssh.c
index a20ce92b..50034711 100644
--- a/pkcs11/ssh-store/gkm-ssh-openssh.c
+++ b/pkcs11/ssh-store/gkm-ssh-openssh.c
@@ -5,6 +5,7 @@
#include "gkm/gkm-data-der.h"
#include "gkm/gkm-data-types.h"
+#include "egg/egg-armor.h"
#include "egg/egg-asn1x.h"
#include "egg/egg-buffer.h"
#include "egg/egg-openssl.h"
@@ -385,7 +386,7 @@ gkm_ssh_openssh_parse_private_key (gconstpointer data, gsize n_data,
ctx.password = password;
ctx.n_password = n_password;
- num = egg_openssl_pem_parse (data, n_data, parsed_pem_block, &ctx);
+ num = egg_armor_parse (data, n_data, parsed_pem_block, &ctx);
/* Didn't find any private key there */
if (num == 0 || !ctx.seen) {
@@ -401,6 +402,6 @@ gchar*
gkm_ssh_openssh_digest_private_key (const guchar *data, gsize n_data)
{
gchar *result = NULL;
- egg_openssl_pem_parse (data, n_data, digest_pem_block, &result);
+ egg_armor_parse (data, n_data, digest_pem_block, &result);
return result;
}