From 85363fa6107d7a7485e2c42b1fdce7e552bf4479 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 17 Apr 2014 07:15:47 +0200 Subject: gcr: GcrParser support for EC private and public keys --- gcr/fixtures/cert-ecc521.pem | 19 ++++++++ gcr/fixtures/der-ec-256.key | Bin 0 -> 121 bytes gcr/fixtures/ecc256.pem | 37 +++++++++++++++ gcr/gcr-parser.c | 111 +++++++++++++++++++++++++++++++++++++++++++ gcr/gcr-types.h | 2 + 5 files changed, 169 insertions(+) create mode 100644 gcr/fixtures/cert-ecc521.pem create mode 100644 gcr/fixtures/der-ec-256.key create mode 100644 gcr/fixtures/ecc256.pem diff --git a/gcr/fixtures/cert-ecc521.pem b/gcr/fixtures/cert-ecc521.pem new file mode 100644 index 0000000..3fc1778 --- /dev/null +++ b/gcr/fixtures/cert-ecc521.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDJDCCAsmgAwIBAgIBBzAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G +A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y +aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0 +ZSBhdXRob3JpdHkwIhgPMjAxMjA5MDEwOTIyMjRaGA8yMDE5MTAwNTA5MjIyNFow +gbgxCzAJBgNVBAYTAkdSMRIwEAYDVQQKEwlLb2tvIGluYy4xFzAVBgNVBAsTDnNs +ZWVwaW5nIGRlcHQuMQ8wDQYDVQQIEwZBdHRpa2kxFTATBgNVBAMTDENpbmR5IExh +dXBlcjEXMBUGCgmSJomT8ixkAQETB2NsYXVwZXIxDDAKBgNVBAwTA0RyLjEPMA0G +A1UEQRMGamFja2FsMRwwGgYJKoZIhvcNAQkBFg1ub25lQG5vbmUub3JnMIGbMBAG +ByqGSM49AgEGBSuBBAAjA4GGAAQAoapA9bLQHQiI8V2mIzs9sq80VR4FBB0TBOSx +GqBOE3FSzHAejQkIKc/1pW0v0wKvapYMq/RrfhPJxPkjTPtztUsAkU//9E0/aoEW +VC6Rqf+VX3wIhe7+RS8JXdBh9SM0+Z9MCRUiM8K9qPMtpNgB2ks7T5BGFHSMlNKm +uLW1agWPy5CjgbYwgbMwDAYDVR0TAQH/BAIwADA9BgNVHREENjA0ggx3d3cubm9u +ZS5vcmeCE3d3dy5tb3JldGhhbm9uZS5vcmeCCWxvY2FsaG9zdIcEwKgBATATBgNV +HSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBTagKMW +kYyqTJk/RRjg++gqz6xX6zAfBgNVHSMEGDAWgBTwtIH+mBK/tSi5ZEADy8wfZk4o +AzAKBggqhkjOPQQDAgNJADBGAiEAoj/ZB98cG/FaA7VVU+R6+TT3icF+De61rfim +R43VMlUCIQCXjG9gRp0x+/8vCRL0/nr0a32SRPruKVDqbHnNiWchsg== +-----END CERTIFICATE----- diff --git a/gcr/fixtures/der-ec-256.key b/gcr/fixtures/der-ec-256.key new file mode 100644 index 0000000..6486af6 Binary files /dev/null and b/gcr/fixtures/der-ec-256.key differ diff --git a/gcr/fixtures/ecc256.pem b/gcr/fixtures/ecc256.pem new file mode 100644 index 0000000..75a2cfa --- /dev/null +++ b/gcr/fixtures/ecc256.pem @@ -0,0 +1,37 @@ +Public Key Info: + Public Key Algorithm: EC + Key Security Level: High + +curve: SECP256R1 +private key: + 00:fd:2b:00:80:f3:36:5f:11:32:65:e3:8d:30:33: + 3b:47:f5:ce:f8:13:e5:4c:c2:cf:fd:e8:05:6a:ca: + c9:41:b1: +x: + 3c:15:6f:1d:48:3e:64:59:13:2c:6d:04:1a:38:0d: + 30:5c:e4:3f:55:cb:d9:17:15:46:72:71:92:c1:f8: + c6:33: +y: + 3d:04:2e:c8:c1:0f:c0:50:04:7b:9f:c9:48:b5:40: + fa:6f:93:82:59:61:5e:72:57:cb:83:06:bd:cc:82: + 94:c1: + +Public Key ID: AC:FA:47:67:C6:1B:41:79:12:57:F7:AC:05:C1:50:E2:8E:D0:0E:5B +Public key's random art: ++--[ EC 256]----+ +| .o+==..| +| .+o...+.| +| o.Eo. +| +| . *.o o | +| S.o.. . | +| .. * | +| .. + o | +| . . . | +| .... | ++-----------------+ + +-----BEGIN EC PRIVATE KEY----- +MHgCAQEEIQD9KwCA8zZfETJl440wMztH9c74E+VMws/96AVqyslBsaAKBggqhkjO +PQMBB6FEA0IABDwVbx1IPmRZEyxtBBo4DTBc5D9Vy9kXFUZycZLB+MYzPQQuyMEP +wFAEe5/JSLVA+m+TgllhXnJXy4MGvcyClME= +-----END EC PRIVATE KEY----- diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c index 4c39a1a..5bb4b99 100644 --- a/gcr/gcr-parser.c +++ b/gcr/gcr-parser.c @@ -171,6 +171,7 @@ EGG_SECURE_DECLARE (parser); static GQuark PEM_CERTIFICATE; static GQuark PEM_RSA_PRIVATE_KEY; static GQuark PEM_DSA_PRIVATE_KEY; +static GQuark PEM_EC_PRIVATE_KEY; static GQuark PEM_ANY_PRIVATE_KEY; static GQuark PEM_ENCRYPTED_PRIVATE_KEY; static GQuark PEM_PRIVATE_KEY; @@ -195,6 +196,7 @@ init_quarks (void) QUARK (PEM_PRIVATE_KEY, "PRIVATE KEY"); QUARK (PEM_RSA_PRIVATE_KEY, "RSA PRIVATE KEY"); QUARK (PEM_DSA_PRIVATE_KEY, "DSA PRIVATE KEY"); + QUARK (PEM_EC_PRIVATE_KEY, "EC PRIVATE KEY"); QUARK (PEM_ANY_PRIVATE_KEY, "ANY PRIVATE KEY"); QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY"); QUARK (PEM_PKCS7, "PKCS7"); @@ -609,6 +611,70 @@ done: pop_parsed (self, parsed); return ret; } +/* ----------------------------------------------------------------------------- + * EC PRIVATE KEY + */ + +static gint +parse_der_private_key_ec (GcrParser *self, + GBytes *data) +{ + gint ret = GCR_ERROR_UNRECOGNIZED; + GNode *asn = NULL; + GBytes *value = NULL; + GBytes *pub = NULL; + GcrParsed *parsed; + guint bits; + gulong version; + + parsed = push_parsed (self, TRUE); + + asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECPrivateKey", data); + if (!asn) + goto done; + + if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version)) + goto done; + + /* We only support simple version */ + if (version != 1) { + g_message ("unsupported version of EC key: %lu", version); + goto done; + } + + parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_EC, data); + parsing_object (parsed, CKO_PRIVATE_KEY); + parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_EC); + parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE); + ret = GCR_ERROR_FAILURE; + + if (!parsed_asn1_element (parsed, asn, "parameters", CKA_EC_PARAMS)) + goto done; + + value = egg_asn1x_get_string_as_usg (egg_asn1x_node (asn, "privateKey", NULL), egg_secure_realloc); + if (!value) + goto done; + + parsed_attribute_bytes (parsed, CKA_VALUE, value); + + pub = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "publicKey", NULL), &bits); + if (pub && bits == 8 * g_bytes_get_size (pub)) + parsed_attribute_bytes (parsed, CKA_EC_POINT, pub); + parsed_fire (self, parsed); + ret = SUCCESS; + +done: + if (pub) + g_bytes_unref (pub); + if (value) + g_bytes_unref (value); + egg_asn1x_destroy (asn); + if (ret == GCR_ERROR_FAILURE) + g_message ("invalid EC key"); + + pop_parsed (self, parsed); + return ret; +} /* ----------------------------------------------------------------------------- * PRIVATE KEY @@ -623,6 +689,8 @@ parse_der_private_key (GcrParser *self, res = parse_der_private_key_rsa (self, data); if (res == GCR_ERROR_UNRECOGNIZED) res = parse_der_private_key_dsa (self, data); + if (res == GCR_ERROR_UNRECOGNIZED) + res = parse_der_private_key_ec (self, data); return res; } @@ -691,6 +759,25 @@ done: return res; } +static gint +handle_subject_public_key_ec (GcrParser *self, + GcrParsed *parsed, + GBytes *key, + GNode *params) +{ + GBytes *bytes; + + parsing_object (parsed, CKO_PUBLIC_KEY); + parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_EC); + + bytes = egg_asn1x_encode (params, g_realloc); + parsed_attribute_bytes (parsed, CKA_EC_PARAMS, bytes); + parsed_attribute_bytes (parsed, CKA_EC_POINT, key); + g_bytes_unref (bytes); + + return SUCCESS; +} + static gint parse_der_subject_public_key (GcrParser *self, GBytes *data) @@ -725,6 +812,9 @@ parse_der_subject_public_key (GcrParser *self, else if (oid == GCR_OID_PKIX1_DSA) ret = handle_subject_public_key_dsa (self, parsed, key, params); + else if (oid == GCR_OID_PKIX1_EC) + ret = handle_subject_public_key_ec (self, parsed, key, params); + else ret = GCR_ERROR_UNRECOGNIZED; @@ -773,6 +863,8 @@ parse_der_pkcs8_plain (GcrParser *self, key_type = CKK_RSA; else if (key_algo == GCR_OID_PKIX1_DSA) key_type = CKK_DSA; + else if (key_algo == GCR_OID_PKIX1_EC) + key_type = CKK_EC; if (key_type == GCK_INVALID) { ret = GCR_ERROR_UNRECOGNIZED; @@ -801,6 +893,10 @@ done: if (ret == GCR_ERROR_UNRECOGNIZED && params) ret = parse_der_private_key_dsa_parts (self, keydata, params); break; + case CKK_EC: + ret = parse_der_private_key_ec (self, keydata); + break; + default: g_message ("invalid or unsupported key type in PKCS#8 key"); ret = GCR_ERROR_UNRECOGNIZED; @@ -1723,6 +1819,9 @@ formats_for_armor_type (GQuark armor_type, } else if (armor_type == PEM_DSA_PRIVATE_KEY) { *inner_format = GCR_FORMAT_DER_PRIVATE_KEY_DSA; *outer_format = GCR_FORMAT_PEM_PRIVATE_KEY_DSA; + } else if (armor_type == PEM_EC_PRIVATE_KEY) { + *inner_format = GCR_FORMAT_DER_PRIVATE_KEY_EC; + *outer_format = GCR_FORMAT_PEM_PRIVATE_KEY_EC; } else if (armor_type == PEM_ANY_PRIVATE_KEY) { *inner_format = GCR_FORMAT_DER_PRIVATE_KEY; *outer_format = GCR_FORMAT_PEM_PRIVATE_KEY; @@ -1933,6 +2032,13 @@ parse_pem_private_key_dsa (GcrParser *self, return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data); } +static gint +parse_pem_private_key_ec (GcrParser *self, + GBytes *data) +{ + return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_EC, data); +} + static gint parse_pem_certificate (GcrParser *self, GBytes *data) @@ -2028,6 +2134,7 @@ parse_openssh_public (GcrParser *self, * @GCR_FORMAT_DER_PRIVATE_KEY: DER encoded private key * @GCR_FORMAT_DER_PRIVATE_KEY_RSA: DER encoded RSA private key * @GCR_FORMAT_DER_PRIVATE_KEY_DSA: DER encoded DSA private key + * @GCR_FORMAT_DER_PRIVATE_KEY_EC: DER encoded EC private key * @GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY: DER encoded SubjectPublicKeyInfo * @GCR_FORMAT_DER_CERTIFICATE_X509: DER encoded X.509 certificate * @GCR_FORMAT_DER_PKCS7: DER encoded PKCS\#7 container file which can contain certificates @@ -2043,6 +2150,7 @@ parse_openssh_public (GcrParser *self, * @GCR_FORMAT_PEM_PRIVATE_KEY: An OpenSSL style PEM file with a private key * @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 + * @GCR_FORMAT_PEM_PRIVATE_KEY_EC: An OpenSSL style PEM file with a private EC key * @GCR_FORMAT_PEM_CERTIFICATE_X509: An OpenSSL style PEM file with an X.509 certificate * @GCR_FORMAT_PEM_PKCS7: An OpenSSL style PEM file containing PKCS\#7 * @GCR_FORMAT_PEM_PKCS8_PLAIN: Unencrypted OpenSSL style PEM file containing PKCS\#8 @@ -2065,6 +2173,7 @@ static const ParserFormat parser_normal[] = { { GCR_FORMAT_BASE64_SPKAC, parse_base64_spkac }, { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa }, { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa }, + { GCR_FORMAT_DER_PRIVATE_KEY_EC, parse_der_private_key_ec }, { GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY, parse_der_subject_public_key }, { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate }, { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 }, @@ -2083,6 +2192,7 @@ static const ParserFormat parser_formats[] = { { GCR_FORMAT_DER_PRIVATE_KEY, parse_der_private_key }, { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa }, { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa }, + { GCR_FORMAT_DER_PRIVATE_KEY_EC, parse_der_private_key_ec }, { GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY, parse_der_subject_public_key }, { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate }, { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 }, @@ -2105,6 +2215,7 @@ static const ParserFormat parser_formats[] = { { GCR_FORMAT_PEM_PKCS8_ENCRYPTED, parse_pem_pkcs8_encrypted }, { GCR_FORMAT_PEM_PKCS12, parse_pem_pkcs12 }, { GCR_FORMAT_PEM_PKCS10, parse_pem_pkcs10 }, + { GCR_FORMAT_PEM_PRIVATE_KEY_EC, parse_pem_private_key_ec }, }; static int diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h index f600454..3711380 100644 --- a/gcr/gcr-types.h +++ b/gcr/gcr-types.h @@ -63,6 +63,7 @@ typedef enum { GCR_FORMAT_DER_PRIVATE_KEY = 100, GCR_FORMAT_DER_PRIVATE_KEY_RSA, GCR_FORMAT_DER_PRIVATE_KEY_DSA, + GCR_FORMAT_DER_PRIVATE_KEY_EC, GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY = 150, @@ -95,6 +96,7 @@ typedef enum { GCR_FORMAT_PEM_PKCS12, GCR_FORMAT_PEM_PRIVATE_KEY, GCR_FORMAT_PEM_PKCS10, + GCR_FORMAT_PEM_PRIVATE_KEY_EC, } GcrDataFormat; /* -- cgit v1.2.3