[gcr] Properly DER encode CKA_EC_POINT



commit a0c9b6ee5dbc4b7df77672ef2db02d16ecc779c5
Author: Jakub Jelen <jjelen redhat com>
Date:   Fri Jul 21 16:28:31 2017 +0200

    Properly DER encode CKA_EC_POINT
    
     * The PKCS#11 specification described this attribute as DER encoded and
       existing tools expect the value as an OCTET STRING
    
    Signed-off-by: Jakub Jelen <jjelen redhat com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=785234

 gcr/gcr-openssh.c            |   36 ++++++++++++++++++++++++++++++-
 gcr/gcr-parser.c             |   48 +++++++++++++++++++++++++++++++++++++----
 gcr/gcr-subject-public-key.c |   21 ++++++++++++++---
 3 files changed, 95 insertions(+), 10 deletions(-)
---
diff --git a/gcr/gcr-openssh.c b/gcr/gcr-openssh.c
index 0219f0e..75a196c 100644
--- a/gcr/gcr-openssh.c
+++ b/gcr/gcr-openssh.c
@@ -247,6 +247,39 @@ parse_v1_public_line (const gchar *line,
 }
 
 static gboolean
+read_buffer_mpi_to_der (EggBuffer *buffer,
+                        gsize *offset,
+                        GckBuilder *builder,
+                        gulong attribute_type)
+{
+       const guchar *data, *data_value;
+       GBytes *der_data = NULL;
+       gsize len, data_len;
+       GNode *asn = NULL;
+       gboolean rv = FALSE;
+
+       if (!egg_buffer_get_byte_array (buffer, *offset, offset, &data, &len))
+               return FALSE;
+
+       asn = egg_asn1x_create (pk_asn1_tab, "ECPoint");
+       if (!asn)
+               return FALSE;
+
+       egg_asn1x_set_string_as_raw (asn, data, len, NULL);
+       der_data = egg_asn1x_encode (asn, g_realloc);
+       if (!der_data)
+               goto out;
+
+       data_value = g_bytes_get_data (der_data, &data_len);
+       gck_builder_add_data (builder, attribute_type, data_value, data_len);
+       rv = TRUE;
+out:
+       g_bytes_unref (der_data);
+       egg_asn1x_destroy (asn);
+       return rv;
+}
+
+static gboolean
 read_buffer_mpi (EggBuffer *buffer,
                  gsize *offset,
                  GckBuilder *builder,
@@ -346,7 +379,8 @@ read_v2_public_ecdsa (EggBuffer *buffer,
        gck_builder_add_data (builder, CKA_EC_PARAMS, data, len);
        g_bytes_unref (bytes);
 
-       if (!read_buffer_mpi (buffer, offset, builder, CKA_EC_POINT))
+       /* need to convert to DER encoded OCTET STRING */
+       if (!read_buffer_mpi_to_der (buffer, offset, builder, CKA_EC_POINT))
                return FALSE;
 
        gck_builder_add_ulong (builder, CKA_KEY_TYPE, CKK_ECDSA);
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index cbea784..cf5c44e 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -279,6 +279,25 @@ parsed_asn1_element (GcrParsed *parsed,
        return TRUE;
 }
 
+static gboolean
+parsed_asn1_structure (GcrParsed *parsed,
+                      GNode *asn,
+                      CK_ATTRIBUTE_TYPE type)
+{
+       GBytes *value;
+
+       g_assert (asn);
+       g_assert (parsed);
+
+       value = egg_asn1x_encode (asn, g_realloc);
+       if (value == NULL)
+               return FALSE;
+
+       parsed_attribute_bytes (parsed, type, value);
+       g_bytes_unref (value);
+       return TRUE;
+}
+
 static void
 parsed_ulong_attribute (GcrParsed *parsed,
                         CK_ATTRIBUTE_TYPE type,
@@ -625,6 +644,7 @@ parse_der_private_key_ec (GcrParser *self,
        GNode *asn = NULL;
        GBytes *value = NULL;
        GBytes *pub = NULL;
+       GNode *asn_q = NULL;
        GcrParsed *parsed;
        guint bits;
        gulong version;
@@ -660,8 +680,16 @@ parse_der_private_key_ec (GcrParser *self,
        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);
+       if (!pub || bits != 8 * g_bytes_get_size (pub))
+               goto done;
+       asn_q = egg_asn1x_create (pk_asn1_tab, "ECPoint");
+       if (!asn_q)
+               goto done;
+       egg_asn1x_set_string_as_bytes (asn_q, pub);
+
+       if (!parsed_asn1_structure (parsed, asn_q, CKA_EC_POINT))
+               goto done;
+
        parsed_fire (self, parsed);
        ret = SUCCESS;
 
@@ -671,6 +699,7 @@ done:
        if (value)
                g_bytes_unref (value);
        egg_asn1x_destroy (asn);
+       egg_asn1x_destroy (asn_q);
        if (ret == GCR_ERROR_FAILURE)
                g_message ("invalid EC key");
 
@@ -767,17 +796,26 @@ handle_subject_public_key_ec (GcrParser *self,
                               GBytes *key,
                               GNode *params)
 {
-       GBytes *bytes;
+       gint ret = GCR_ERROR_FAILURE;
+       GBytes *bytes = NULL;
+       GNode *asn = NULL;
 
        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;
+       asn = egg_asn1x_create (pk_asn1_tab, "ECPoint");
+       if (!asn)
+               goto done;
+       egg_asn1x_set_string_as_bytes (asn, key);
+       parsed_asn1_structure (parsed, asn, CKA_EC_POINT);
+       ret = SUCCESS;
+done:
+       egg_asn1x_destroy (asn);
+       return ret;
 }
 
 static gint
diff --git a/gcr/gcr-subject-public-key.c b/gcr/gcr-subject-public-key.c
index 0335dc0..1621d95 100644
--- a/gcr/gcr-subject-public-key.c
+++ b/gcr/gcr-subject-public-key.c
@@ -750,8 +750,8 @@ ec_subject_public_key_from_attributes (GckAttributes *attrs,
                                        GNode *info_asn)
 {
        const GckAttribute *ec_params, *ec_point;
-       GNode *params_asn;
-       GBytes *bytes;
+       GNode *params_asn, *point_asn;
+       GBytes *bytes, *key_bytes;
 
        ec_params = gck_attributes_find (attrs, CKA_EC_PARAMS);
        ec_point = gck_attributes_find (attrs, CKA_EC_POINT);
@@ -770,14 +770,27 @@ ec_subject_public_key_from_attributes (GckAttributes *attrs,
 
        bytes = g_bytes_new_with_free_func (ec_point->value, ec_point->length,
                                            gck_attributes_unref, gck_attributes_ref (attrs));
+       point_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECPoint", bytes);
+       g_bytes_unref (bytes);
+
+       if (point_asn == NULL) {
+               egg_asn1x_destroy (params_asn);
+               return FALSE;
+       }
+       key_bytes = egg_asn1x_get_string_as_bytes (point_asn);
+       egg_asn1x_destroy (point_asn);
+       if (key_bytes == NULL) {
+               egg_asn1x_destroy (params_asn);
+               return FALSE;
+       }
 
        egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
-                                  bytes, g_bytes_get_size (bytes) * 8);
+                                  key_bytes, g_bytes_get_size (key_bytes) * 8);
        egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
 
        egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), 
GCR_OID_PKIX1_EC);
 
-       g_bytes_unref (bytes);
+       g_bytes_unref (key_bytes);
        egg_asn1x_destroy (params_asn);
        return TRUE;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]