summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@redhat.com>2014-04-17 07:15:47 +0200
committerStef Walter <stefw@redhat.com>2014-04-19 22:29:49 +0200
commit85363fa6107d7a7485e2c42b1fdce7e552bf4479 (patch)
tree8c22ccbd2f42b1406aaef85ee60945b32e5860ae
parent490464cd4c43f6582dc29bbf7c6d1b6f49bdc30d (diff)
gcr: GcrParser support for EC private and public keys
-rw-r--r--gcr/fixtures/cert-ecc521.pem19
-rw-r--r--gcr/fixtures/der-ec-256.keybin0 -> 121 bytes
-rw-r--r--gcr/fixtures/ecc256.pem37
-rw-r--r--gcr/gcr-parser.c111
-rw-r--r--gcr/gcr-types.h2
5 files changed, 169 insertions, 0 deletions
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
--- /dev/null
+++ b/gcr/fixtures/der-ec-256.key
Binary files 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;
}
@@ -692,6 +760,25 @@ done:
}
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;
@@ -1934,6 +2033,13 @@ parse_pem_private_key_dsa (GcrParser *self,
}
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;
/*