[gnome-keyring] gcr: Implement OpenSSH public key parser
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring] gcr: Implement OpenSSH public key parser
- Date: Tue, 27 Sep 2011 15:14:47 +0000 (UTC)
commit ad4fc192b5cf9c51ed73306b43e43fb36747ab22
Author: Stef Walter <stefw collabora co uk>
Date: Tue Sep 13 08:04:41 2011 +0200
gcr: Implement OpenSSH public key parser
* And add tests for various formats.
.gitignore | 1 +
docs/reference/gcr/gcr-sections.txt | 1 +
gcr/Makefile.am | 1 +
gcr/gcr-internal.h | 3 +
gcr/gcr-live-search.c | 19 ++-
gcr/gcr-openssh.c | 491 +++++++++++++++++++++++++++++++++++
gcr/gcr-openssh.h | 51 ++++
gcr/gcr-parser.c | 108 +++++++--
gcr/gcr-types.h | 2 +
gcr/tests/Makefile.am | 1 +
gcr/tests/files/openssh_keys.pub | 2 +
gcr/tests/test-openssh.c | 196 ++++++++++++++
testing/ssh-example/README | 1 +
testing/ssh-example/id_dsa | 15 +
testing/ssh-example/id_dsa.pub | 1 +
testing/ssh-example/id_rsa | 30 +++
testing/ssh-example/id_rsa.pub | 1 +
testing/ssh-example/identity | Bin 0 -> 988 bytes
testing/ssh-example/identity.pub | 1 +
19 files changed, 908 insertions(+), 17 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index dc31879..d569cf7 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-openssh
/gcr/tests/test-parser
/gcr/tests/test-pkcs11-certificate
/gcr/tests/test-record
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index 0f22399..dfb22ab 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -589,4 +589,5 @@ GcrMemoryIconClass
GcrMemoryIconPrivate
GCR_ERROR
gcr_error_get_domain
+GcrOpensshPubCallback
</SECTION>
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index eb8585e..f89100c 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-openssh.c gcr-openssh.h \
gcr-parser.c gcr-parser.h \
gcr-pkcs11-certificate.c gcr-pkcs11-certificate.h \
gcr-record.c gcr-record.h \
diff --git a/gcr/gcr-internal.h b/gcr/gcr-internal.h
index 6923f5d..9ae3831 100644
--- a/gcr/gcr-internal.h
+++ b/gcr/gcr-internal.h
@@ -26,6 +26,9 @@
#include <glib.h>
+/* Should only be used internally */
+#define GCR_SUCCESS 0
+
void _gcr_initialize_library (void);
gboolean _gcr_initialize_pkcs11 (GCancellable *cancellable,
diff --git a/gcr/gcr-live-search.c b/gcr/gcr-live-search.c
index 71c8a06..291a6d2 100644
--- a/gcr/gcr-live-search.c
+++ b/gcr/gcr-live-search.c
@@ -64,7 +64,11 @@ stripped_char (gunichar ch)
{
gunichar retval = 0;
GUnicodeType utype;
+#if GLIB_CHECK_VERSION (2,30,0)
gunichar decomp[4];
+#else
+ gunichar *decomp;
+#endif
gsize dlen;
utype = g_unichar_type (ch);
@@ -74,7 +78,11 @@ stripped_char (gunichar ch)
case G_UNICODE_FORMAT:
case G_UNICODE_UNASSIGNED:
case G_UNICODE_NON_SPACING_MARK:
+#if GLIB_CHECK_VERSION (2,30,0)
case G_UNICODE_SPACING_MARK:
+#else
+ case G_UNICODE_COMBINING_MARK:
+#endif
case G_UNICODE_ENCLOSING_MARK:
/* Ignore those */
break;
@@ -104,9 +112,18 @@ stripped_char (gunichar ch)
case G_UNICODE_SPACE_SEPARATOR:
default:
ch = g_unichar_tolower (ch);
+#if GLIB_CHECK_VERSION (2,30,0)
dlen = g_unichar_fully_decompose (ch, FALSE, decomp, 4);
- if (dlen > 0)
+ if (dlen > 0) {
+#else
+ decomp = g_unicode_canonical_decomposition (ch, &dlen);
+ if (decomp != NULL) {
+#endif
retval = decomp[0];
+#if !GLIB_CHECK_VERSION (2,30,0)
+ g_free (decomp);
+#endif
+ }
}
return retval;
diff --git a/gcr/gcr-openssh.c b/gcr/gcr-openssh.c
new file mode 100644
index 0000000..e285465
--- /dev/null
+++ b/gcr/gcr-openssh.c
@@ -0,0 +1,491 @@
+/*
+ * 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-openssh.h"
+#include "gcr-internal.h"
+#include "gcr-types.h"
+
+#include "egg/egg-buffer.h"
+#include "egg/egg-decimal.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <string.h>
+
+typedef struct {
+ GcrOpensshPubCallback callback;
+ gpointer user_data;
+} OpensshPubClosure;
+
+static void
+skip_spaces (const gchar ** line,
+ gsize *n_line)
+{
+ while (*n_line > 0 && (*line)[0] == ' ') {
+ (*line)++;
+ (*n_line)--;
+ }
+}
+
+static gboolean
+next_word (const gchar **line,
+ gsize *n_line,
+ const gchar **word,
+ gsize *n_word)
+{
+ const gchar *beg;
+ const gchar *end;
+ const gchar *at;
+ gboolean quotes;
+
+ skip_spaces (line, n_line);
+
+ if (!*n_line) {
+ *word = NULL;
+ *n_word = 0;
+ return FALSE;
+ }
+
+ beg = at = *line;
+ end = beg + *n_line;
+ quotes = FALSE;
+
+ do {
+ switch (*at) {
+ case '"':
+ quotes = !quotes;
+ at++;
+ break;
+ case ' ':
+ if (!quotes)
+ end = at;
+ else
+ at++;
+ break;
+ default:
+ at++;
+ break;
+ }
+ } while (at < end);
+
+ *word = beg;
+ *n_word = end - beg;
+ (*line) += *n_word;
+ (*n_line) -= *n_word;
+ return TRUE;
+}
+
+static gboolean
+match_word (const gchar *word,
+ gsize n_word,
+ const gchar *matches)
+{
+ gsize len = strlen (matches);
+ if (len != n_word)
+ return FALSE;
+ return memcmp (word, matches, n_word) == 0;
+}
+
+static gulong
+keytype_to_algo (const gchar *algo,
+ gsize length)
+{
+ if (!algo)
+ return G_MAXULONG;
+ else if (match_word (algo, length, "ssh-rsa"))
+ return CKK_RSA;
+ else if (match_word (algo, length, "ssh-dss"))
+ return CKK_DSA;
+ return G_MAXULONG;
+}
+
+static gboolean
+read_decimal_mpi (const gchar *decimal,
+ gsize n_decimal,
+ GckAttributes *attrs,
+ gulong attribute_type)
+{
+ gpointer data;
+ gsize n_data;
+
+ data = egg_decimal_decode (decimal, n_decimal, &n_data);
+ if (data == NULL)
+ return FALSE;
+
+ gck_attributes_add_data (attrs, attribute_type, data, n_data);
+ return TRUE;
+}
+
+static gint
+atoin (const char *p, gint digits)
+{
+ gint ret = 0, base = 1;
+ while(--digits >= 0) {
+ if (p[digits] < '0' || p[digits] > '9')
+ return -1;
+ ret += (p[digits] - '0') * base;
+ base *= 10;
+ }
+ return ret;
+}
+
+static GcrDataError
+parse_v1_public_line (const gchar *line,
+ gsize length,
+ GcrOpensshPubCallback callback,
+ gpointer user_data)
+{
+ const gchar *word_bits, *word_exponent, *word_modulus, *word_options, *outer;
+ gsize len_bits, len_exponent, len_modulus, len_options, n_outer;
+ GckAttributes *attrs;
+ gchar *label, *options;
+ gint bits;
+
+ g_assert (line);
+
+ outer = line;
+ n_outer = length;
+ options = NULL;
+ label = NULL;
+
+ /* Eat space at the front */
+ skip_spaces (&line, &length);
+
+ /* Blank line or comment */
+ if (length == 0 || line[0] == '#')
+ return GCR_ERROR_UNRECOGNIZED;
+
+ /*
+ * If the line starts with a digit, then no options:
+ *
+ * 2048 35 25213680043....93533757 Label
+ *
+ * If the line doesn't start with a digit, then have options:
+ *
+ * option,option 2048 35 25213680043....93533757 Label
+ */
+ if (g_ascii_isdigit (line[0])) {
+ word_options = NULL;
+ len_options = 0;
+ } else {
+ if (!next_word (&line, &length, &word_options, &len_options))
+ return GCR_ERROR_UNRECOGNIZED;
+ }
+
+ if (!next_word (&line, &length, &word_bits, &len_bits) ||
+ !next_word (&line, &length, &word_exponent, &len_exponent) ||
+ !next_word (&line, &length, &word_modulus, &len_modulus))
+ return GCR_ERROR_UNRECOGNIZED;
+
+ bits = atoin (word_bits, len_bits);
+ if (bits <= 0)
+ return GCR_ERROR_UNRECOGNIZED;
+
+ attrs = gck_attributes_new ();
+
+ if (!read_decimal_mpi (word_exponent, len_exponent, attrs, CKA_PUBLIC_EXPONENT) ||
+ !read_decimal_mpi (word_modulus, len_modulus, attrs, CKA_MODULUS)) {
+ gck_attributes_unref (attrs);
+ return GCR_ERROR_UNRECOGNIZED;
+ }
+
+ gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA);
+ gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+
+ skip_spaces (&line, &length);
+ if (length > 0) {
+ label = g_strndup (line, length);
+ g_strstrip (label);
+ gck_attributes_add_string (attrs, CKA_LABEL, label);
+ }
+
+ if (word_options)
+ options = g_strndup (word_options, len_options);
+
+ if (callback != NULL)
+ (callback) (attrs, label, options, outer, n_outer, user_data);
+
+ gck_attributes_unref (attrs);
+ g_free (options);
+ g_free (label);
+ return GCR_SUCCESS;
+}
+
+static gboolean
+read_buffer_mpi (EggBuffer *buffer,
+ gsize *offset,
+ GckAttributes *attrs,
+ gulong attribute_type)
+{
+ const guchar *data;
+ gsize len;
+
+ if (!egg_buffer_get_byte_array (buffer, *offset, offset, &data, &len))
+ return FALSE;
+
+ gck_attributes_add_data (attrs, attribute_type, data, len);
+ return TRUE;
+}
+
+static GckAttributes *
+read_v2_public_dsa (EggBuffer *buffer,
+ gsize *offset)
+{
+ GckAttributes *attrs;
+
+ attrs = gck_attributes_new ();
+
+ if (!read_buffer_mpi (buffer, offset, attrs, CKA_PRIME) ||
+ !read_buffer_mpi (buffer, offset, attrs, CKA_SUBPRIME) ||
+ !read_buffer_mpi (buffer, offset, attrs, CKA_BASE) ||
+ !read_buffer_mpi (buffer, offset, attrs, CKA_VALUE)) {
+ gck_attributes_unref (attrs);
+ return NULL;
+ }
+
+ gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_DSA);
+ gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+
+ return attrs;
+}
+
+static GckAttributes *
+read_v2_public_rsa (EggBuffer *buffer,
+ gsize *offset)
+{
+ GckAttributes *attrs;
+
+ attrs = gck_attributes_new ();
+
+ if (!read_buffer_mpi (buffer, offset, attrs, CKA_PUBLIC_EXPONENT) ||
+ !read_buffer_mpi (buffer, offset, attrs, CKA_MODULUS)) {
+ gck_attributes_unref (attrs);
+ return NULL;
+ }
+
+ gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA);
+ gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+
+ return attrs;
+}
+
+static GckAttributes *
+read_v2_public_key (gulong algo,
+ gconstpointer data,
+ gsize n_data)
+{
+ GckAttributes *attrs;
+ EggBuffer buffer;
+ gsize offset;
+ gchar *stype;
+ int alg;
+
+ egg_buffer_init_static (&buffer, data, n_data);
+ offset = 0;
+
+ /* The string algorithm */
+ if (!egg_buffer_get_string (&buffer, offset, &offset,
+ &stype, (EggBufferAllocator)g_realloc))
+ return NULL;
+
+ alg = keytype_to_algo (stype, stype ? strlen (stype) : 0);
+ g_free (stype);
+
+ if (alg != algo) {
+ g_message ("invalid or mis-matched algorithm in ssh public key: %s", stype);
+ egg_buffer_uninit (&buffer);
+ return NULL;
+ }
+
+ switch (algo) {
+ case CKK_RSA:
+ attrs = read_v2_public_rsa (&buffer, &offset);
+ break;
+ case CKK_DSA:
+ attrs = read_v2_public_dsa (&buffer, &offset);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ egg_buffer_uninit (&buffer);
+ return attrs;
+}
+
+static GckAttributes *
+decode_v2_public_key (gulong algo,
+ const gchar *data,
+ gsize n_data)
+{
+ GckAttributes *attrs;
+ gpointer decoded;
+ gsize n_decoded;
+ guint save;
+ gint state;
+
+ /* Decode the base64 key */
+ save = state = 0;
+ decoded = g_malloc (n_data * 3 / 4);
+ n_decoded = g_base64_decode_step ((gchar*)data, n_data, decoded, &state, &save);
+
+ if (!n_decoded) {
+ g_free (decoded);
+ return NULL;
+ }
+
+ /* Parse the actual key */
+ attrs = read_v2_public_key (algo, decoded, n_decoded);
+
+ g_free (decoded);
+
+ return attrs;
+}
+
+static GcrDataError
+parse_v2_public_line (const gchar *line,
+ gsize length,
+ GcrOpensshPubCallback callback,
+ gpointer user_data)
+{
+ const gchar *word_options, *word_algo, *word_key;
+ gsize len_options, len_algo, len_key;
+ GckAttributes *attrs;
+ gchar *options;
+ gchar *label = NULL;
+ const gchar *outer = line;
+ gsize n_outer = length;
+ gulong algo;
+
+ g_assert (line);
+
+ /* Eat space at the front */
+ skip_spaces (&line, &length);
+
+ /* Blank line or comment */
+ if (length == 0 || line[0] == '#')
+ return GCR_ERROR_UNRECOGNIZED;
+
+ if (!next_word (&line, &length, &word_algo, &len_algo))
+ return GCR_ERROR_UNRECOGNIZED;
+
+ /*
+ * If the first word is not the algorithm, then we have options:
+ *
+ * option,option ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAI...EAz8Ji= Label here
+ *
+ * If the first word is the algorithm, then we have no options:
+ *
+ * ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAI...EAz8Ji= Label here
+ */
+ algo = keytype_to_algo (word_algo, len_algo);
+ if (algo == G_MAXULONG) {
+ word_options = word_algo;
+ len_options = len_algo;
+ if (!next_word (&line, &length, &word_algo, &len_algo))
+ return GCR_ERROR_UNRECOGNIZED;
+ algo = keytype_to_algo (word_algo, len_algo);
+ if (algo == G_MAXULONG)
+ return GCR_ERROR_UNRECOGNIZED;
+ } else {
+ word_options = NULL;
+ len_options = 0;
+ }
+
+ /* Must have at least two words */
+ if (!next_word (&line, &length, &word_key, &len_key))
+ return GCR_ERROR_FAILURE;
+
+ attrs = decode_v2_public_key (algo, word_key, len_key);
+ if (attrs == NULL)
+ return GCR_ERROR_FAILURE;
+
+ if (word_options)
+ options = g_strndup (word_options, len_options);
+ else
+ options = NULL;
+
+ /* The remainder of the line is the label */
+ skip_spaces (&line, &length);
+ if (length > 0) {
+ label = g_strndup (line, length);
+ g_strstrip (label);
+ gck_attributes_add_string (attrs, CKA_LABEL, label);
+ }
+
+ if (callback != NULL)
+ (callback) (attrs, label, options, outer, n_outer, user_data);
+
+ gck_attributes_unref (attrs);
+ g_free (options);
+ g_free (label);
+ return GCR_SUCCESS;
+}
+
+guint
+_gcr_openssh_pub_parse (gconstpointer data,
+ gsize n_data,
+ GcrOpensshPubCallback callback,
+ gpointer user_data)
+{
+ const gchar *line;
+ const gchar *end;
+ gsize length;
+ gboolean last;
+ GcrDataError res;
+ guint num_parsed;
+
+ g_return_val_if_fail (data, FALSE);
+
+ line = data;
+ length = n_data;
+ last = FALSE;
+ num_parsed = 0;
+
+ for (;;) {
+ end = memchr (line, '\n', length);
+ if (end == NULL) {
+ end = line + length;
+ last = TRUE;
+ }
+
+ if (line != end) {
+ res = parse_v2_public_line (line, end - line, callback, user_data);
+ if (res == GCR_ERROR_UNRECOGNIZED)
+ res = parse_v1_public_line (line, end - line, callback, user_data);
+ if (res == GCR_SUCCESS)
+ num_parsed++;
+ }
+
+ if (last)
+ break;
+
+ end++;
+ length -= (end - line);
+ line = end;
+ }
+
+ return num_parsed;
+}
diff --git a/gcr/gcr-openssh.h b/gcr/gcr-openssh.h
new file mode 100644
index 0000000..2fdac2a
--- /dev/null
+++ b/gcr/gcr-openssh.h
@@ -0,0 +1,51 @@
+/*
+ * 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_OPENSSH_H__
+#define __GCR_OPENSSH_H__
+
+#include <glib.h>
+
+#include <gck/gck.h>
+
+G_BEGIN_DECLS
+
+typedef void (*GcrOpensshPubCallback) (GckAttributes *attrs,
+ const gchar *label,
+ const gchar *options,
+ const gchar *outer,
+ gsize n_outer,
+ gpointer user_data);
+
+guint _gcr_openssh_pub_parse (gconstpointer data,
+ gsize n_data,
+ GcrOpensshPubCallback callback,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __GCR_OPENSSH_H__ */
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 92bb256..9e15573 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -27,6 +27,7 @@
#include "gcr-importer.h"
#include "gcr-marshal.h"
#include "gcr-oids.h"
+#include "gcr-openssh.h"
#include "gcr-parser.h"
#include "gcr-types.h"
@@ -88,6 +89,7 @@
* @GCR_FORMAT_DER_PKCS8_PLAIN: Unencrypted DER encoded PKCS\#8 file which can contain a key
* @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_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
@@ -238,7 +240,6 @@ parsed_asn1_attribute (GcrParser *self, GNode *asn, const guchar *data, gsize n_
static void
parsing_begin (GcrParser *self,
- CK_OBJECT_CLASS klass,
gconstpointer block,
gsize n_block)
{
@@ -248,12 +249,16 @@ parsing_begin (GcrParser *self,
if (self->pv->parsed_attrs)
gck_attributes_unref (self->pv->parsed_attrs);
- if (klass == CKO_PRIVATE_KEY)
- self->pv->parsed_attrs = gck_attributes_new_full ((GckAllocator)egg_secure_realloc);
- else
- self->pv->parsed_attrs = gck_attributes_new ();
- gck_attributes_add_ulong (self->pv->parsed_attrs, CKA_CLASS, klass);
+ self->pv->parsed_attrs = NULL;
+
+ self->pv->parsing_block = block;
+ self->pv->parsing_n_block = n_block;
+}
+static void
+parsed_description (GcrParser *self,
+ CK_OBJECT_CLASS klass)
+{
switch (klass) {
case CKO_PRIVATE_KEY:
self->pv->parsed_desc = _("Private Key");
@@ -268,9 +273,34 @@ parsing_begin (GcrParser *self,
self->pv->parsed_desc = NULL;
break;
}
+}
- self->pv->parsing_block = block;
- self->pv->parsing_n_block = n_block;
+static void
+parsing_object (GcrParser *self,
+ CK_OBJECT_CLASS klass)
+{
+ g_return_if_fail (self->pv->parsed_attrs == NULL);
+
+ if (klass == CKO_PRIVATE_KEY)
+ self->pv->parsed_attrs = gck_attributes_new_full ((GckAllocator)egg_secure_realloc);
+ else
+ self->pv->parsed_attrs = gck_attributes_new ();
+ gck_attributes_add_ulong (self->pv->parsed_attrs, CKA_CLASS, klass);
+ parsed_description (self, klass);
+}
+
+static void
+parsed_attributes (GcrParser *self,
+ GckAttributes *attrs)
+{
+ gulong klass;
+
+ g_return_if_fail (self->pv->parsed_attrs == NULL);
+ g_return_if_fail (attrs != NULL);
+
+ self->pv->parsed_attrs = gck_attributes_ref (attrs);
+ if (gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
+ parsed_description (self, klass);
}
static void
@@ -389,7 +419,8 @@ parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
if (!asn)
goto done;
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
+ parsing_begin (self, data, n_data);
+ parsing_object (self, CKO_PRIVATE_KEY);
parsed_ulong (self, CKA_KEY_TYPE, CKK_RSA);
parsed_boolean (self, CKA_PRIVATE, CK_TRUE);
res = GCR_ERROR_FAILURE;
@@ -438,7 +469,8 @@ parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
if (!asn)
goto done;
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
+ parsing_begin (self, data, n_data);
+ parsing_object (self, CKO_PRIVATE_KEY);
parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
parsed_boolean (self, CKA_PRIVATE, CK_TRUE);
ret = GCR_ERROR_FAILURE;
@@ -568,11 +600,14 @@ done:
/* Try the normal sane format */
ret = parse_der_private_key_dsa (self, keydata, n_keydata);
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
+ parsing_begin (self, data, n_data);
+ parsing_object (self, CKO_PRIVATE_KEY);
+
/* Otherwise try the two part format that everyone seems to like */
if (ret == GCR_ERROR_UNRECOGNIZED && params && n_params)
ret = parse_der_private_key_dsa_parts (self, keydata, n_keydata,
params, n_params);
+
parsing_end (self);
break;
default:
@@ -619,7 +654,8 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
+ parsing_begin (self, data, n_data);
+ parsing_object (self, CKO_PRIVATE_KEY);
/* Loop to try different passwords */
for (;;) {
@@ -704,7 +740,8 @@ parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
if (asn == NULL)
return GCR_ERROR_UNRECOGNIZED;
- parsing_begin (self, CKO_CERTIFICATE, data, n_data);
+ parsing_begin (self, data, n_data);
+ parsing_object (self, CKO_CERTIFICATE);
parsed_ulong (self, CKA_CERTIFICATE_TYPE, CKC_X_509);
@@ -1285,7 +1322,7 @@ parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
if (!asn)
goto done;
- parsing_begin (self, 0, data, n_data);
+ parsing_begin (self, data, n_data);
oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "authSafe", "contentType", NULL));
if (!oid)
@@ -1476,7 +1513,8 @@ handle_pem_data (GQuark type,
return;
/* Fill in information necessary for prompting */
- parsing_begin (args->parser, pem_type_to_class (type), outer, n_outer);
+ parsing_begin (args->parser, outer, n_outer);
+ parsing_object (args->parser, pem_type_to_class (type));
/* See if it's encrypted PEM all openssl like*/
if (headers) {
@@ -1569,6 +1607,42 @@ parse_pem_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
}
/* -----------------------------------------------------------------------------
+ * OPENSSH
+ */
+
+static void
+on_openssh_public_key_parsed (GckAttributes *attrs,
+ const gchar *label,
+ const gchar *options,
+ const gchar *outer,
+ gsize n_outer,
+ gpointer user_data)
+{
+ GcrParser *self = GCR_PARSER (user_data);
+
+ parsing_begin (self, outer, n_outer);
+ parsed_attributes (self, attrs);
+ parsed_label (self, label);
+ parsed_fire (self);
+ parsing_end (self);
+}
+
+static gint
+parse_der_openssh_public (GcrParser *self,
+ const guchar *data,
+ gsize n_data)
+{
+ guint num_parsed;
+
+ num_parsed = _gcr_openssh_pub_parse (data, n_data,
+ on_openssh_public_key_parsed, self);
+
+ if (num_parsed == 0)
+ return GCR_ERROR_UNRECOGNIZED;
+ return SUCCESS;
+}
+
+/* -----------------------------------------------------------------------------
* FORMATS
*/
@@ -1581,7 +1655,8 @@ static const ParserFormat parser_normal[] = {
{ GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 },
{ 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_DER_PKCS12, parse_der_pkcs12 },
+ { GCR_FORMAT_OPENSSH_PUBLIC, parse_der_openssh_public },
};
/* Must be in format_id numeric order */
@@ -1595,6 +1670,7 @@ 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_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 23635ca..184eedd 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -71,6 +71,8 @@ typedef enum {
GCR_FORMAT_DER_PKCS12 = 500,
+ GCR_FORMAT_OPENSSH_PUBLIC = 600,
+
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 f2f3b7a..a63b090 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-openssh \
test-trust \
test-parser \
test-record \
diff --git a/gcr/tests/files/openssh_keys.pub b/gcr/tests/files/openssh_keys.pub
new file mode 100644
index 0000000..00d294b
--- /dev/null
+++ b/gcr/tests/files/openssh_keys.pub
@@ -0,0 +1,2 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAL4z+ad0ZJYzMOQuGp00UJ+AijKhrPVUEYLcxBmFQonb/KIlLSWJua4Rl9DB4tDj30Y9c/oApqC4n+FIYlUZMSnxmpvcLF6aeXOiHHPvm0EDYjjyVubyYQWI7CROrrzSc+x++ha3TuJEvF3PlKlZmTKKVYEkZNjwFqYysGyPxPalAAAAFQDtDSEF9Gvnv5fQtSbbsp7j78uVBwAAAIAtNpAg/Mbd/E2241enedB9AxAbJWZ5QYnoPe6/zx5dOmU7+qz8mG6tgvF8F7IgXPabuAKslzTDGS3zgaEhWicDS3CIYik2UR8hXdxfovIEqZKZe7u02FCEoXYCEiFUAdzDGzjI7PswgtEJWWNqKeNis3HmDDha9lMkqz/3fLZGXwAAAIEAiaRPYKZDMoJG+aVZ5A3R/m2gl+mYE2MsjPKXuBKcrZ6ItA9BMe4G/An0/+E3A+DuoGxdeNNMF8U9Dy2N8Sch/Ngtg2E/FBo5geljWobJXd1jxmPtF2WAliYJXDdIt6RBVPGL9H/KSjDmBMsVd42wxVJywawzypklVZjSUuWuBMI= dsa-key example com
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCs8z2y0cCPYRAPkq8tAt6FC/kdfnR/p8B2ZoY0oiLNt7kQEwJfexgwLqTxWYd2fSDUSSDPrsqAxZAwLLS/eF04kXiJO2VfqAWFpTLNToERHpFF1yZQe26ELTlNNfna7LqfCRvpNDwu6AqndsT3eFt7DWvBDXbbEiTLW21Z2OFAAH/J2iCFn4c0a8Myf7IaMYcy5GG3mpk39kEO4aNV/67U7kfooek24ObwD0vlXzlsi5VZIUFOIUi0UdkNEMCtUWpfkZ1STUlmwp9HVM7xb7/9PESQKDnZdxpB09S9cIjdpDecpDlMDDEbEUECM1PIas3ndhB7gAN1i2JsPHTcXZ1 rsa-key example com
diff --git a/gcr/tests/test-openssh.c b/gcr/tests/test-openssh.c
new file mode 100644
index 0000000..81634da
--- /dev/null
+++ b/gcr/tests/test-openssh.c
@@ -0,0 +1,196 @@
+/* -*- 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-openssh.h"
+
+#include "egg/egg-testing.h"
+
+#include <gcrypt.h>
+#include <glib.h>
+#include <string.h>
+
+typedef struct {
+ const gchar *expected_label;
+ const gchar *expected_options;
+} Test;
+
+#define OPENSSH_PUBLIC_RSA1 \
+ "2048 65537 19574029774826276058535216798260123376543523095248321838931" \
+ "8476099051534660565418100376122247153936738716140984293302866595208305" \
+ "7124376564328644357957081508003798389808113087527047927841196160520784" \
+ "3971799891833860159372766201922902824211581515042106928142039998651198" \
+ "7806024885997262427984841536983221992403267030558391252672804492615887" \
+ "9294713324466630490990131504557923061505441555447586185019409756877006" \
+ "5871190731807718592844942425524851665039303855329966512492845780563670" \
+ "0617451083369174928502647995734856960603065454655489558179113130210712" \
+ "74638931037011169213563881172297734240201883475566393175838117784693 r" \
+ "sa-key example com\n"
+
+#define OPENSSH_PUBLIC_RSA2 \
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCs8z2y0cCPYRAPkq8tAt6FC/kdfnR/p" \
+ "8B2ZoY0oiLNt7kQEwJfexgwLqTxWYd2fSDUSSDPrsqAxZAwLLS/eF04kXiJO2VfqAWFpTL" \
+ "NToERHpFF1yZQe26ELTlNNfna7LqfCRvpNDwu6AqndsT3eFt7DWvBDXbbEiTLW21Z2OFAA" \
+ "H/J2iCFn4c0a8Myf7IaMYcy5GG3mpk39kEO4aNV/67U7kfooek24ObwD0vlXzlsi5VZIUF" \
+ "OIUi0UdkNEMCtUWpfkZ1STUlmwp9HVM7xb7/9PESQKDnZdxpB09S9cIjdpDecpDlMDDEbE" \
+ "UECM1PIas3ndhB7gAN1i2JsPHTcXZ1 rsa-key example com\r\n" \
+ "# Comment\n"
+
+#define OPENSSH_PUBLIC_DSA2 \
+ "ssh-dss AAAAB3NzaC1kc3MAAACBAL4z+ad0ZJYzMOQuGp00UJ+AijKhrPVUEYLcxBmFQo" \
+ "nb/KIlLSWJua4Rl9DB4tDj30Y9c/oApqC4n+FIYlUZMSnxmpvcLF6aeXOiHHPvm0EDYjjy" \
+ "VubyYQWI7CROrrzSc+x++ha3TuJEvF3PlKlZmTKKVYEkZNjwFqYysGyPxPalAAAAFQDtDS" \
+ "EF9Gvnv5fQtSbbsp7j78uVBwAAAIAtNpAg/Mbd/E2241enedB9AxAbJWZ5QYnoPe6/zx5d" \
+ "OmU7+qz8mG6tgvF8F7IgXPabuAKslzTDGS3zgaEhWicDS3CIYik2UR8hXdxfovIEqZKZe7" \
+ "u02FCEoXYCEiFUAdzDGzjI7PswgtEJWWNqKeNis3HmDDha9lMkqz/3fLZGXwAAAIEAiaRP" \
+ "YKZDMoJG+aVZ5A3R/m2gl+mYE2MsjPKXuBKcrZ6ItA9BMe4G/An0/+E3A+DuoGxdeNNMF8" \
+ "U9Dy2N8Sch/Ngtg2E/FBo5geljWobJXd1jxmPtF2WAliYJXDdIt6RBVPGL9H/KSjDmBMsV" \
+ "d42wxVJywawzypklVZjSUuWuBMI= dsa-key example com \n"
+
+#define EXTRA_LINES_WITHOUT_KEY \
+ "\n# Comment\n\n" \
+ "20aa3\n" \
+ "not a key\n"
+
+static void
+setup (Test *test,
+ gconstpointer unused)
+{
+
+}
+
+static void
+teardown (Test *test,
+ gconstpointer unused)
+{
+
+}
+
+static void
+on_openssh_pub_parse (GckAttributes *attrs,
+ const gchar *label,
+ const gchar *options,
+ const gchar *outer,
+ gsize n_outer,
+ gpointer user_data)
+{
+ Test *test = user_data;
+ guint keys;
+
+ if (test->expected_label)
+ g_assert_cmpstr (label, ==, test->expected_label);
+ if (test->expected_options)
+ g_assert_cmpstr (options, ==, test->expected_options);
+
+ /* The block should parse properly */
+ keys = _gcr_openssh_pub_parse (outer, n_outer, NULL, NULL);
+ g_assert_cmpuint (keys, ==, 1);
+}
+
+static void
+test_parse_v1_rsa (Test *test,
+ gconstpointer unused)
+{
+ const gchar *data = OPENSSH_PUBLIC_RSA1 EXTRA_LINES_WITHOUT_KEY;
+ gint keys;
+
+ test->expected_label = "rsa-key example com";
+
+ keys = _gcr_openssh_pub_parse (data, strlen (data),
+ on_openssh_pub_parse, test);
+ g_assert_cmpint (keys, ==, 1);
+
+}
+
+static void
+test_parse_v2_rsa (Test *test,
+ gconstpointer unused)
+{
+ const gchar *data = OPENSSH_PUBLIC_RSA2 EXTRA_LINES_WITHOUT_KEY;
+ gint keys;
+
+ test->expected_label = "rsa-key example com";
+
+ keys = _gcr_openssh_pub_parse (data, strlen (data),
+ on_openssh_pub_parse, test);
+ g_assert_cmpint (keys, ==, 1);
+}
+
+static void
+test_parse_v2_dsa (Test *test,
+ gconstpointer unused)
+{
+ const gchar *data = OPENSSH_PUBLIC_DSA2 EXTRA_LINES_WITHOUT_KEY;
+ gint keys;
+
+ test->expected_label = "dsa-key example com";
+
+ keys = _gcr_openssh_pub_parse (data, strlen (data),
+ on_openssh_pub_parse, test);
+ g_assert_cmpint (keys, ==, 1);
+}
+
+static void
+test_parse_v1_options (Test *test,
+ gconstpointer unused)
+{
+ const gchar *data = "option1,option2=\"value 2\",option3 " OPENSSH_PUBLIC_RSA1;
+ gint keys;
+
+ test->expected_options = "option1,option2=\"value 2\",option3";
+
+ keys = _gcr_openssh_pub_parse (data, strlen (data),
+ on_openssh_pub_parse, test);
+ g_assert_cmpint (keys, ==, 1);
+}
+
+static void
+test_parse_v2_options (Test *test,
+ gconstpointer unused)
+{
+ const gchar *data = "option1,option2=\"value 2\",option3 " OPENSSH_PUBLIC_RSA2;
+ gint keys;
+
+ test->expected_options = "option1,option2=\"value 2\",option3";
+
+ keys = _gcr_openssh_pub_parse (data, strlen (data),
+ on_openssh_pub_parse, test);
+ g_assert_cmpint (keys, ==, 1);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-gnupg-process");
+
+ g_test_add ("/gcr/openssh/parse_v1_rsa", Test, NULL, setup, test_parse_v1_rsa, teardown);
+ g_test_add ("/gcr/openssh/parse_v2_rsa", Test, NULL, setup, test_parse_v2_rsa, teardown);
+ g_test_add ("/gcr/openssh/parse_v2_dsa", Test, NULL, setup, test_parse_v2_dsa, teardown);
+ g_test_add ("/gcr/openssh/parse_v1_options", Test, NULL, setup, test_parse_v1_options, teardown);
+ g_test_add ("/gcr/openssh/parse_v2_options", Test, NULL, setup, test_parse_v2_options, teardown);
+
+ return egg_tests_run_in_thread_with_loop ();
+}
diff --git a/testing/ssh-example/README b/testing/ssh-example/README
new file mode 100644
index 0000000..f3b240c
--- /dev/null
+++ b/testing/ssh-example/README
@@ -0,0 +1 @@
+The passwords for the private keys are: boooo
diff --git a/testing/ssh-example/id_dsa b/testing/ssh-example/id_dsa
new file mode 100644
index 0000000..ef23625
--- /dev/null
+++ b/testing/ssh-example/id_dsa
@@ -0,0 +1,15 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,ECBE9F6DAE948508DB1A5E51AF32B5A5
+
+2LW/70yuiadQM/tVWZ4QqxV0JZQQ3Sjqz28Soj5sUKDuKCszTBFyiRKLvI091Z6G
+NsDZ5agRr6t4e6ysne0aiJg1ex7ymx6GyVDI3PmNEstBqrhrxgrHgtfhwR0vVdSf
+go0nrftWdU/tlAd2h2JGQSwngwaW8aDlqG9rA86CYYcXLTyF9xW9ECtJMXohl3x2
+fS7t4vLZCnCP0lj36andZdRHAMwwHHvO1tgCotQdWeNksN4cIE4m3huM1kIDBcIW
+oL4z9qWM3CC4r++Sutn1I9xXpKu86QosKaOJJmObkpwcMagxz+fMvbMDIl9L0GGw
+PMM7d5Rl2Fs7H7z2tK9PnKwIpNCuHIMe29RUr65LJxqeqoEc9zgWKgZuPjarBlTa
+hob+mWJHi1WntSwoG9QE7Hj0FVuaUwf8QSPBvnNZYFZMzFR8SH4FK57yKXvtVoGI
+JFt+4aea0EClJ0X9+zBfS0aAFkwqi+Lbn99OVHhw/DL2XgZa9mjd5xDcMxseh0wQ
+Kqc8VQdOVeyfYOwLQgoiimtlgwdimzrG7UWCBQomEGf50d7HlBVAEqv9MeJCm2bb
+RJ4ERL/hpmxZulshatfwbA==
+-----END DSA PRIVATE KEY-----
diff --git a/testing/ssh-example/id_dsa.pub b/testing/ssh-example/id_dsa.pub
new file mode 100644
index 0000000..1e111d7
--- /dev/null
+++ b/testing/ssh-example/id_dsa.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAL4z+ad0ZJYzMOQuGp00UJ+AijKhrPVUEYLcxBmFQonb/KIlLSWJua4Rl9DB4tDj30Y9c/oApqC4n+FIYlUZMSnxmpvcLF6aeXOiHHPvm0EDYjjyVubyYQWI7CROrrzSc+x++ha3TuJEvF3PlKlZmTKKVYEkZNjwFqYysGyPxPalAAAAFQDtDSEF9Gvnv5fQtSbbsp7j78uVBwAAAIAtNpAg/Mbd/E2241enedB9AxAbJWZ5QYnoPe6/zx5dOmU7+qz8mG6tgvF8F7IgXPabuAKslzTDGS3zgaEhWicDS3CIYik2UR8hXdxfovIEqZKZe7u02FCEoXYCEiFUAdzDGzjI7PswgtEJWWNqKeNis3HmDDha9lMkqz/3fLZGXwAAAIEAiaRPYKZDMoJG+aVZ5A3R/m2gl+mYE2MsjPKXuBKcrZ6ItA9BMe4G/An0/+E3A+DuoGxdeNNMF8U9Dy2N8Sch/Ngtg2E/FBo5geljWobJXd1jxmPtF2WAliYJXDdIt6RBVPGL9H/KSjDmBMsVd42wxVJywawzypklVZjSUuWuBMI= dsa-key example com
diff --git a/testing/ssh-example/id_rsa b/testing/ssh-example/id_rsa
new file mode 100644
index 0000000..b3b32ab
--- /dev/null
+++ b/testing/ssh-example/id_rsa
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,2166F6D1CF1E7548690D572639503DCF
+
+vWdHuKtNO8dMYBxgQgxjVUiiek6KTZpb0nnm9tRo6KJp08Ce3TCC184LSA+AQ+zJ
+tJ54GTyHaTB4jf+BTn0LjmHT5VSFevmyWCWvQ2UbEJTmOhmEHwVpzJHcB9jVKhYG
+axHMtckUelUXlOmx7YFVU5YTbnIOyXkG8XSARk3j1NSmSGMK7S4vB0I7KpJi76gN
+LpWGFsiYjr6vUdcvjsZUB/CbyJ456N/ND41AERVM0Ecl6vQC8touN/U9+BHHWOAb
++e6I0v2Oje0TEm/qDpq834JJb6auCWmCDQLEe63WeWgceG48DmdyDwJ5sOH0kSxq
+HNGYFRB2PEOaNI4b0keSeXTjxKCxhaFs+krJZaXAfKIzGg1AJ1w9Hb7whFpvwRMv
+SUhfdFkzQW1/fj6qCgRlq78h7rAahoLroPpY9Uhd1qKH4PTpx4oD+nvAIqPN4Ch8
+vVGh+NtiGWNT7HnTG6cWkGZnWUQ4PZ9dkPVSPWsea8dVEHjpbUKGikxIx4D7abbC
+ZA2ifcAMt2rklYWoXVST53qBrKTo2hlpI9c5sn3/A7JBZuE3ljgCZL/TozuKk+ZH
+UzqbxWsGl1u3pMNc8/T8l6PuuKl+D3vczBFkQWlSjRGY3UCnQ+nQEI8zxKes61B9
+y/b1/zNYJiGqNzJG427qd3EGAlt0FS5N/5iFCGXyo80rS34i/UnJkcJcAuIQdqIX
+GKgRrekxepff/mirn58WKIxWobp9y0vOMCZm8lD53wXLCIsbbWCqxbmBttvdr6hM
+UWZ2QTbKn+3KeBm2O8PZGDooP2bhocnBP2tdm/6rC9cYbESikFUjC6IJFxFsRr7z
+Hmwnwxdkb0vJCKXLf4ww48nDODrSu3Fhc6YhRR7uIpt3VswKG1Kfm5xVbjUhu+4S
+rf0Y69sivYFi+mlpr0GD6EpQsZ9nHhd1e6pPmVprBt5s5LbOa+SO8k3iTa+/BDGZ
+Ft8PXG3alEEUYllavubkP5kLnsVZ8C+UNFEeDRzhzWjmcv3er6U1WwTEzgIxos76
+2+leOvtQ5l0wzk0U3fL0c694dOoG0rm1E2jAd6LkZwn7e/15raP9igEB72uM5bea
+ikrd2gd5AEwaDKESErRp+CCcHXJ8C1zaAhgws21qbNegV44AwtDPkYN8ID2DSwUv
+KQZX3hwNc0g3sRGlQ35lpwe7H8qTGwr5l5TPM0eKuNi/V+qmFFjCMEpDkp+/hSSu
+ThpazlWoWUg7qBlopOmTLF7wN1byfwiu5DeF56HE1+W1cPyAzhEkbuuEuzZcaJit
+6aS5pCeq2dGwyNgb65+n/jZiucCXJQToIUZvdlPXfsstABDs//iAARwqjtxmIdoZ
+uyI7tjK9MkRIvHIyCSQRKdhpelDuMiKxORhOiLLJsZ3Wd+Acr14vNk7nHJZcvaX/
+UuF6/iKFsg+smWIsSPE/OtsWJ+4g0jOg5oHphOH57m89cqOQe2njcTWpOSMGdF9P
+u9QrCVOaRnswPpFuNJQrRjte+9HIxn5Qgzw3vr+Me21NW0fvDaaKUrBm4PPPEUFg
+V4/XW2WtotyszoIAMdzUOmLNUGNh1I+GwJY7Mb16jHDQe0RjtGYlDjH3ykj1isAM
+-----END RSA PRIVATE KEY-----
diff --git a/testing/ssh-example/id_rsa.pub b/testing/ssh-example/id_rsa.pub
new file mode 100644
index 0000000..83067d4
--- /dev/null
+++ b/testing/ssh-example/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCs8z2y0cCPYRAPkq8tAt6FC/kdfnR/p8B2ZoY0oiLNt7kQEwJfexgwLqTxWYd2fSDUSSDPrsqAxZAwLLS/eF04kXiJO2VfqAWFpTLNToERHpFF1yZQe26ELTlNNfna7LqfCRvpNDwu6AqndsT3eFt7DWvBDXbbEiTLW21Z2OFAAH/J2iCFn4c0a8Myf7IaMYcy5GG3mpk39kEO4aNV/67U7kfooek24ObwD0vlXzlsi5VZIUFOIUi0UdkNEMCtUWpfkZ1STUlmwp9HVM7xb7/9PESQKDnZdxpB09S9cIjdpDecpDlMDDEbEUECM1PIas3ndhB7gAN1i2JsPHTcXZ1 rsa-key example com
diff --git a/testing/ssh-example/identity b/testing/ssh-example/identity
new file mode 100644
index 0000000..35bd574
Binary files /dev/null and b/testing/ssh-example/identity differ
diff --git a/testing/ssh-example/identity.pub b/testing/ssh-example/identity.pub
new file mode 100644
index 0000000..503486b
--- /dev/null
+++ b/testing/ssh-example/identity.pub
@@ -0,0 +1 @@
+2048 65537 19574029774826276058535216798260123376543523095248321838931847609905153466056541810037612224715393673871614098429330286659520830571243765643286443579570815080037983898081130875270479278411961605207843971799891833860159372766201922902824211581515042106928142039998651198780602488599726242798484153698322199240326703055839125267280449261588792947133244666304909901315045579230615054415554475861850194097568770065871190731807718592844942425524851665039303855329966512492845780563670061745108336917492850264799573485696060306545465548955817911313021071274638931037011169213563881172297734240201883475566393175838117784693 rsa-key example com
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]