summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@redhat.com>2014-04-17 07:14:41 +0200
committerStef Walter <stefw@redhat.com>2014-04-19 22:29:49 +0200
commit490464cd4c43f6582dc29bbf7c6d1b6f49bdc30d (patch)
tree5cd88ad7bac21862ee03896f77ebff7911ffa9bf
parent4fce10b1dd8c9196ddd3e7c47aa9330227df9c6c (diff)
gcr: Implement support for parsing ecdsa OpenSSH keys
-rw-r--r--gcr/gcr-openssh.c68
-rw-r--r--gcr/test-openssh.c25
-rw-r--r--testing/ssh-example/id_ecdsa8
-rw-r--r--testing/ssh-example/id_ecdsa.pub1
4 files changed, 101 insertions, 1 deletions
diff --git a/gcr/gcr-openssh.c b/gcr/gcr-openssh.c
index b8a0b39..0219f0e 100644
--- a/gcr/gcr-openssh.c
+++ b/gcr/gcr-openssh.c
@@ -25,6 +25,10 @@
#include "gcr-internal.h"
#include "gcr-types.h"
+#include "gcr/gcr-oids.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
#include "egg/egg-buffer.h"
#include "egg/egg-decimal.h"
@@ -116,6 +120,8 @@ keytype_to_algo (const gchar *algo,
return CKK_RSA;
else if (match_word (algo, length, "ssh-dss"))
return CKK_DSA;
+ else if (length >= 6 && strncmp (algo, "ecdsa-", 6) == 0)
+ return CKK_ECDSA;
return G_MAXULONG;
}
@@ -291,6 +297,65 @@ read_v2_public_rsa (EggBuffer *buffer,
}
static gboolean
+read_v2_public_ecdsa (EggBuffer *buffer,
+ gsize *offset,
+ GckBuilder *builder)
+{
+ gconstpointer data;
+ GBytes *bytes;
+ GNode *asn;
+ GNode *node;
+ gchar *curve;
+ GQuark oid;
+ gsize len;
+
+ /* The named curve */
+ if (!egg_buffer_get_string (buffer, *offset, offset,
+ &curve, (EggBufferAllocator)g_realloc))
+ return FALSE;
+
+ if (g_strcmp0 (curve, "nistp256") == 0) {
+ oid = GCR_OID_EC_SECP256R1;
+ } else if (g_strcmp0 (curve, "nistp384") == 0) {
+ oid = GCR_OID_EC_SECP384R1;
+ } else if (g_strcmp0 (curve, "nistp521") == 0) {
+ oid = GCR_OID_EC_SECP521R1;
+ } else {
+ g_free (curve);
+ g_message ("unknown or unsupported curve in ssh public key");
+ return FALSE;
+ }
+
+ g_free (curve);
+
+ asn = egg_asn1x_create (pk_asn1_tab, "ECParameters");
+ g_return_val_if_fail (asn != NULL, FALSE);
+
+ node = egg_asn1x_node (asn, "namedCurve", NULL);
+ if (!egg_asn1x_set_choice (asn, node))
+ g_return_val_if_reached (FALSE);
+
+ if (!egg_asn1x_set_oid_as_quark (node, oid))
+ g_return_val_if_reached (FALSE);
+
+ bytes = egg_asn1x_encode (asn, g_realloc);
+ g_return_val_if_fail (bytes != NULL, FALSE);
+ egg_asn1x_destroy (asn);
+
+ data = g_bytes_get_data (bytes, &len);
+ gck_builder_add_data (builder, CKA_EC_PARAMS, data, len);
+ g_bytes_unref (bytes);
+
+ if (!read_buffer_mpi (buffer, offset, builder, CKA_EC_POINT))
+ return FALSE;
+
+ gck_builder_add_ulong (builder, CKA_KEY_TYPE, CKK_ECDSA);
+ gck_builder_add_ulong (builder, CKA_CLASS, CKO_PUBLIC_KEY);
+
+ return TRUE;
+}
+
+static gboolean
read_v2_public_key (gulong algo,
gconstpointer data,
gsize n_data,
@@ -326,6 +391,9 @@ read_v2_public_key (gulong algo,
case CKK_DSA:
ret = read_v2_public_dsa (&buffer, &offset, builder);
break;
+ case CKK_ECDSA:
+ ret = read_v2_public_ecdsa (&buffer, &offset, builder);
+ break;
default:
g_assert_not_reached ();
break;
diff --git a/gcr/test-openssh.c b/gcr/test-openssh.c
index bde412a..a48e282 100644
--- a/gcr/test-openssh.c
+++ b/gcr/test-openssh.c
@@ -67,6 +67,11 @@ typedef struct {
"U9Dy2N8Sch/Ngtg2E/FBo5geljWobJXd1jxmPtF2WAliYJXDdIt6RBVPGL9H/KSjDmBMsV" \
"d42wxVJywawzypklVZjSUuWuBMI= dsa-key@example.com \n"
+#define OPENSSH_PUBLIC_ECDSA \
+ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" \
+ "BBBMKWn4nDF3IVAB2XKK8MdlMV0r1PkwHWemNuNkKnDSLy1CA17IEBXzEFX0yDEaC/8cFG" \
+ "Bc0VblrySYCYKvJc+is= ecdsa-key@example.com \n"
+
#define EXTRA_LINES_WITHOUT_KEY \
"\n# Comment\n\n" \
"20aa3\n" \
@@ -158,6 +163,23 @@ test_parse_v2_dsa (Test *test,
}
static void
+test_parse_v2_ecdsa (Test *test,
+ gconstpointer unused)
+{
+ const gchar *data = OPENSSH_PUBLIC_ECDSA EXTRA_LINES_WITHOUT_KEY;
+ GBytes *bytes;
+ gint keys;
+
+ test->expected_label = "ecdsa-key@example.com";
+
+ bytes = g_bytes_new_static (data, strlen (data));
+ keys = _gcr_openssh_pub_parse (bytes, on_openssh_pub_parse, test);
+ g_assert_cmpint (keys, ==, 1);
+
+ g_bytes_unref (bytes);
+}
+
+static void
test_parse_v1_options (Test *test,
gconstpointer unused)
{
@@ -198,11 +220,12 @@ main (int argc, char **argv)
g_type_init ();
#endif
g_test_init (&argc, &argv, NULL);
- g_set_prgname ("test-gnupg-process");
+ g_set_prgname ("test-openssh");
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_v2_ecdsa", Test, NULL, setup, test_parse_v2_ecdsa, 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);
diff --git a/testing/ssh-example/id_ecdsa b/testing/ssh-example/id_ecdsa
new file mode 100644
index 0000000..fdfbb3c
--- /dev/null
+++ b/testing/ssh-example/id_ecdsa
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,90D5DC6AEE85FE9929F112F5E22E8295
+
+2SlRUDeauO04UsLRZMfma2vQwzv2l16l/LEyWx325JNOdEjlGAuYiycJr0b2qr7u
+vAv0pc71Re8Jg6nSVSy9O4werYnkQcb6E6MTaZCCUgqRqtGfmHtHvhIDxSqybPv7
+iCjTfzLtuJ6C6TiLH9h7OVfDW/tcWg08MJ5VP1iMHhA=
+-----END EC PRIVATE KEY-----
diff --git a/testing/ssh-example/id_ecdsa.pub b/testing/ssh-example/id_ecdsa.pub
new file mode 100644
index 0000000..119a4ad
--- /dev/null
+++ b/testing/ssh-example/id_ecdsa.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMKWn4nDF3IVAB2XKK8MdlMV0r1PkwHWemNuNkKnDSLy1CA17IEBXzEFX0yDEaC/8cFGBc0VblrySYCYKvJc+is= stef@stef.thewalter.lan