diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | docs/reference/gcr/gcr-sections.txt | 1 | ||||
-rw-r--r-- | egg/Makefile.am | 1 | ||||
-rw-r--r-- | egg/egg-armor.c | 407 | ||||
-rw-r--r-- | egg/egg-armor.h | 50 | ||||
-rw-r--r-- | egg/egg-openssl.c | 350 | ||||
-rw-r--r-- | egg/egg-openssl.h | 18 | ||||
-rw-r--r-- | egg/tests/test-openssl.c | 17 | ||||
-rw-r--r-- | gcr/Makefile.am | 1 | ||||
-rw-r--r-- | gcr/gcr-certificate-exporter.c | 7 | ||||
-rw-r--r-- | gcr/gcr-openpgp.c | 226 | ||||
-rw-r--r-- | gcr/gcr-openpgp.h | 49 | ||||
-rw-r--r-- | gcr/gcr-parser.c | 87 | ||||
-rw-r--r-- | gcr/gcr-types.h | 3 | ||||
-rw-r--r-- | gcr/tests/Makefile.am | 1 | ||||
-rw-r--r-- | gcr/tests/files/pubring.gpg | bin | 0 -> 21969 bytes | |||
-rw-r--r-- | gcr/tests/files/werner-koch.asc | 71 | ||||
-rw-r--r-- | gcr/tests/test-openpgp.c | 94 | ||||
-rw-r--r-- | pkcs11/gkm/tests/test-data-der.c | 3 | ||||
-rw-r--r-- | pkcs11/roots-store/gkm-roots-module.c | 3 | ||||
-rw-r--r-- | pkcs11/ssh-store/gkm-ssh-openssh.c | 5 |
21 files changed, 999 insertions, 396 deletions
@@ -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 Binary files differnew file mode 100644 index 00000000..10b1372d --- /dev/null +++ b/gcr/tests/files/pubring.gpg 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; } |