diff options
author | Stef Walter <stefw@redhat.com> | 2014-04-17 07:14:41 +0200 |
---|---|---|
committer | Stef Walter <stefw@redhat.com> | 2014-04-19 22:29:49 +0200 |
commit | 490464cd4c43f6582dc29bbf7c6d1b6f49bdc30d (patch) | |
tree | 5cd88ad7bac21862ee03896f77ebff7911ffa9bf | |
parent | 4fce10b1dd8c9196ddd3e7c47aa9330227df9c6c (diff) |
gcr: Implement support for parsing ecdsa OpenSSH keys
-rw-r--r-- | gcr/gcr-openssh.c | 68 | ||||
-rw-r--r-- | gcr/test-openssh.c | 25 | ||||
-rw-r--r-- | testing/ssh-example/id_ecdsa | 8 | ||||
-rw-r--r-- | testing/ssh-example/id_ecdsa.pub | 1 |
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 |