[gnome-keyring/wip/dueno/ecdsa-support: 1/10] ASN.1 definitions of ECDSA and helper functions for DER encoding and decoding
- From: Daiki Ueno <dueno src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring/wip/dueno/ecdsa-support: 1/10] ASN.1 definitions of ECDSA and helper functions for DER encoding and decoding
- Date: Fri, 13 Oct 2017 07:22:44 +0000 (UTC)
commit 32680d2667410c8d1802e10746084253daee65d0
Author: Jakub Jelen <jjelen redhat com>
Date: Tue Aug 8 18:34:01 2017 +0200
ASN.1 definitions of ECDSA and helper functions for DER encoding and decoding
https://bugzilla.gnome.org/show_bug.cgi?id=641082
egg/pk.asn | 22 ++++++
egg/pk.asn.h | 20 +++++-
pkcs11/gkm/gkm-data-asn1.c | 121 ++++++++++++++++++++++++++++++--
pkcs11/gkm/gkm-data-asn1.h | 26 +++++++
pkcs11/gkm/gkm-data-der.c | 165 ++++++++++++++++++++++++++++++++++++++++++++
pkcs11/gkm/gkm-data-der.h | 20 +++++
6 files changed, 367 insertions(+), 7 deletions(-)
---
diff --git a/egg/pk.asn b/egg/pk.asn
index 347323c..17e3a5b 100644
--- a/egg/pk.asn
+++ b/egg/pk.asn
@@ -101,5 +101,27 @@ DHParameter ::= SEQUENCE {
privateValueLength INTEGER OPTIONAL
}
+-- FROM New PKIX ASN.1 [RFC5912], RFC5915
+
+Parameters ::= CHOICE {
+ namedCurve OBJECT IDENTIFIER,
+ implicitlyCA NULL
+}
+
+-- bogus attribute used to encode Q into CKA_EC_POINT
+ECKeyQ ::= OCTET STRING
+
+ECPrivateKey ::= SEQUENCE {
+ version INTEGER { ecPrivkeyVer1(1) }, -- should be 1
+ d OCTET STRING, -- private key
+ parameters [0] Parameters OPTIONAL, -- OID
+ q [1] BIT STRING OPTIONAL -- public key
+}
+
+-- can't find definition anywhere, but works
+ECPublicKey ::= SEQUENCE {
+ parameters [0] Parameters OPTIONAL, -- OID
+ q [1] BIT STRING -- public key
+}
END
diff --git a/egg/pk.asn.h b/egg/pk.asn.h
index 618ccca..53d547a 100644
--- a/egg/pk.asn.h
+++ b/egg/pk.asn.h
@@ -2,6 +2,7 @@
# include "config.h"
#endif
+/* Generated using asn1Parser pk.asn -o pk.asn.h */
/* #include <libtasn1.h> */
const ASN1_ARRAY_TYPE pk_asn1_tab[] = {
@@ -63,9 +64,26 @@ const ASN1_ARRAY_TYPE pk_asn1_tab[] = {
{ "g", 1073741827, NULL },
{ "Y", 1073741827, NULL },
{ "priv", 3, NULL },
- { "DHParameter", 536870917, NULL },
+ { "DHParameter", 1610612741, NULL },
{ "prime", 1073741827, NULL },
{ "base", 1073741827, NULL },
{ "privateValueLength", 16387, NULL },
+ { "Parameters", 1610612754, NULL },
+ { "namedCurve", 1073741836, NULL },
+ { "implicitlyCA", 20, NULL },
+ { "ECKeyQ", 1073741831, NULL },
+ { "ECPrivateKey", 1610612741, NULL },
+ { "version", 1610874883, NULL },
+ { "ecPrivkeyVer1", 1, "1"},
+ { "d", 1073741831, NULL },
+ { "parameters", 1610637314, "Parameters"},
+ { NULL, 2056, "0"},
+ { "q", 536895494, NULL },
+ { NULL, 2056, "1"},
+ { "ECPublicKey", 536870917, NULL },
+ { "parameters", 1610637314, "Parameters"},
+ { NULL, 2056, "0"},
+ { "q", 536879110, NULL },
+ { NULL, 2056, "1"},
{ NULL, 0, NULL }
};
diff --git a/pkcs11/gkm/gkm-data-asn1.c b/pkcs11/gkm/gkm-data-asn1.c
index e063dd4..591bbe8 100644
--- a/pkcs11/gkm/gkm-data-asn1.c
+++ b/pkcs11/gkm/gkm-data-asn1.c
@@ -26,8 +26,8 @@
#include "egg/egg-asn1x.h"
-gboolean
-gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi)
+static gboolean
+gkm_data_asn1_read_mpi_internal (GNode *asn, gcry_mpi_t *mpi, GBytes *(*asn1_get)(GNode *))
{
gcry_error_t gcry;
GBytes *buf;
@@ -36,7 +36,7 @@ gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi)
g_return_val_if_fail (asn, FALSE);
g_return_val_if_fail (mpi, FALSE);
- buf = egg_asn1x_get_integer_as_raw (asn);
+ buf = asn1_get (asn);
if (!buf)
return FALSE;
@@ -50,8 +50,8 @@ gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi)
return TRUE;
}
-gboolean
-gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi)
+static gboolean
+gkm_data_asn1_write_mpi_internal (GNode *asn, gcry_mpi_t mpi, void (*asn1_set)(GNode *, GBytes *))
{
gcry_error_t gcry;
GBytes *bytes;
@@ -72,8 +72,117 @@ gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi)
g_return_val_if_fail (gcry == 0, FALSE);
bytes = g_bytes_new_with_free_func (buf, len, gcry_free, buf);
- egg_asn1x_set_integer_as_raw (asn, bytes);
+ asn1_set (asn, bytes);
g_bytes_unref (bytes);
return TRUE;
}
+
+/* ECDSA private key (d) is OCTET STRING encoded MPI */
+gboolean
+gkm_data_asn1_read_string_mpi (GNode *asn, gcry_mpi_t *mpi)
+{
+ return gkm_data_asn1_read_mpi_internal (asn, mpi, egg_asn1x_get_string_as_bytes);
+}
+
+gboolean
+gkm_data_asn1_write_string_mpi (GNode *asn, gcry_mpi_t mpi)
+{
+ return gkm_data_asn1_write_mpi_internal (asn, mpi, egg_asn1x_set_string_as_bytes);
+}
+
+gboolean
+gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi)
+{
+ return gkm_data_asn1_read_mpi_internal (asn, mpi, egg_asn1x_get_integer_as_raw);
+}
+
+gboolean
+gkm_data_asn1_write_mpi (GNode *asn, gcry_mpi_t mpi)
+{
+ return gkm_data_asn1_write_mpi_internal (asn, mpi, egg_asn1x_set_integer_as_raw);
+}
+
+/* ECDSA CKA_EC_POINT encodes q value as a OCTET STRING in PKCS#11 */
+gboolean
+gkm_data_asn1_read_string (GNode *asn, GBytes **data)
+{
+ GBytes *buf;
+
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (data, FALSE);
+
+ buf = egg_asn1x_get_string_as_bytes (asn);
+ if (!buf)
+ return FALSE;
+
+ *data = buf;
+ return TRUE;
+}
+
+gboolean
+gkm_data_asn1_write_string (GNode *asn, GBytes *data)
+{
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (data, FALSE);
+
+ egg_asn1x_set_string_as_bytes (asn, data);
+
+ return TRUE;
+}
+
+/* ECDSA public key (q) is encoded as a bit string in PEM files */
+gboolean
+gkm_data_asn1_read_bit_string (GNode *asn, GBytes **data, gsize *data_bits)
+{
+ GBytes *buf;
+ guint n_bits;
+
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (data, FALSE);
+
+ buf = egg_asn1x_get_bits_as_raw (asn, &n_bits);
+ if (!buf)
+ return FALSE;
+
+ *data = buf;
+ *data_bits = n_bits;
+ return TRUE;
+}
+
+gboolean
+gkm_data_asn1_write_bit_string (GNode *asn, GBytes *data, gsize data_bits)
+{
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (data, FALSE);
+
+ egg_asn1x_set_bits_as_raw (asn, data, data_bits);
+
+ return TRUE;
+}
+
+/* ECDSA differentiates curves based on the OID */
+gboolean
+gkm_data_asn1_read_oid (GNode *asn, GQuark *oid)
+{
+ GQuark q;
+
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (oid, FALSE);
+
+ q = egg_asn1x_get_oid_as_quark (asn);
+ if (!q)
+ return FALSE;
+
+ *oid = q;
+ return TRUE;
+}
+
+gboolean
+gkm_data_asn1_write_oid (GNode *asn, GQuark oid)
+{
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (oid, FALSE);
+
+ return egg_asn1x_set_oid_as_quark (asn, oid);
+}
diff --git a/pkcs11/gkm/gkm-data-asn1.h b/pkcs11/gkm/gkm-data-asn1.h
index 12826da..822fd08 100644
--- a/pkcs11/gkm/gkm-data-asn1.h
+++ b/pkcs11/gkm/gkm-data-asn1.h
@@ -32,4 +32,30 @@ gboolean gkm_data_asn1_read_mpi (GNode *asn,
gboolean gkm_data_asn1_write_mpi (GNode *asn,
gcry_mpi_t mpi);
+gboolean gkm_data_asn1_read_string_mpi (GNode *asn,
+ gcry_mpi_t *mpi);
+
+gboolean gkm_data_asn1_write_string_mpi (GNode *asn,
+ gcry_mpi_t mpi);
+
+gboolean gkm_data_asn1_read_string (GNode *asn,
+ GBytes **data);
+
+gboolean gkm_data_asn1_write_string (GNode *asn,
+ GBytes *data);
+
+gboolean gkm_data_asn1_read_bit_string (GNode *asn,
+ GBytes **data,
+ gsize *data_bits);
+
+gboolean gkm_data_asn1_write_bit_string (GNode *asn,
+ GBytes *data,
+ gsize data_bits);
+
+gboolean gkm_data_asn1_read_oid (GNode *asn,
+ GQuark *oid);
+
+gboolean gkm_data_asn1_write_oid (GNode *asn,
+ GQuark oid);
+
#endif /*GKM_DATA_ASN_H_*/
diff --git a/pkcs11/gkm/gkm-data-der.c b/pkcs11/gkm/gkm-data-der.c
index 78c16ca..b21049c 100644
--- a/pkcs11/gkm/gkm-data-der.c
+++ b/pkcs11/gkm/gkm-data-der.c
@@ -43,7 +43,11 @@ EGG_SECURE_DECLARE (data_der);
static GQuark OID_PKIX1_RSA;
static GQuark OID_PKIX1_DSA;
+static GQuark OID_PKIX1_ECDSA;
static GQuark OID_PKCS12_PBE_3DES_SHA1;
+static GQuark OID_ANSI_SECP256R1;
+static GQuark OID_ANSI_SECP384R1;
+static GQuark OID_ANSI_SECP521R1;
static void
init_quarks (void)
@@ -57,7 +61,11 @@ init_quarks (void)
QUARK (OID_PKIX1_RSA, "1.2.840.113549.1.1.1");
QUARK (OID_PKIX1_DSA, "1.2.840.10040.4.1");
+ QUARK (OID_PKIX1_ECDSA, "1.2.840.10045.2.1");
QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3");
+ QUARK (OID_ANSI_SECP256R1, "1.2.840.10045.3.1.7");
+ QUARK (OID_ANSI_SECP384R1, "1.3.132.0.34");
+ QUARK (OID_ANSI_SECP521R1, "1.3.132.0.35");
#undef QUARK
@@ -65,6 +73,161 @@ init_quarks (void)
}
}
+const gchar *
+gkm_data_der_oid_to_curve (GQuark oid)
+{
+ if (oid == OID_ANSI_SECP256R1)
+ return "NIST P-256";
+ else if (oid == OID_ANSI_SECP384R1)
+ return "NIST P-384";
+ else if (oid == OID_ANSI_SECP521R1)
+ return "NIST P-521";
+ return NULL;
+}
+
+/*
+ * Convert ecc->curve values from libgcrypt representation to internal one.
+ * Ignore duplicates and alternative names, since S-expressions are created
+ * only by us throught this code.
+ */
+static GQuark
+gkm_data_der_curve_to_oid (const gchar *curve)
+{
+ if (g_str_equal (curve, "NIST P-256"))
+ return OID_ANSI_SECP256R1;
+ else if (g_str_equal (curve, "NIST P-384"))
+ return OID_ANSI_SECP384R1;
+ else if (g_str_equal (curve, "NIST P-521"))
+ return OID_ANSI_SECP521R1;
+ return 0;
+}
+
+
+GQuark
+gkm_data_der_oid_from_ec_params (GBytes *params)
+{
+ GNode *asn;
+ GQuark oid;
+
+ init_quarks ();
+
+ asn = egg_asn1x_create_and_decode (pk_asn1_tab, "Parameters", params);
+ if (!asn)
+ return 0;
+
+ oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "namedCurve", NULL));
+
+ egg_asn1x_destroy (asn);
+ return oid;
+}
+
+GBytes *
+gkm_data_der_get_ec_params (GQuark oid)
+{
+ GNode *asn;
+ GBytes *params = NULL;
+ GNode *named_curve;
+
+ asn = egg_asn1x_create (pk_asn1_tab, "Parameters");
+ if (!asn)
+ goto done;
+
+ named_curve = egg_asn1x_node (asn, "namedCurve", NULL);
+
+ if (!egg_asn1x_set_oid_as_quark (named_curve, oid))
+ goto done;
+
+ if (!egg_asn1x_set_choice (asn, named_curve))
+ goto done;
+
+ params = egg_asn1x_encode (asn, NULL);
+
+done:
+ egg_asn1x_destroy (asn);
+ return params;
+}
+
+/* wrapper so we do not have to export the GQuark magic */
+GBytes *
+gkm_data_der_curve_to_ec_params (const gchar *curve_name)
+{
+ GQuark oid;
+
+ init_quarks ();
+
+ oid = gkm_data_der_curve_to_oid (curve_name);
+ if (oid == 0)
+ return NULL;
+
+ return gkm_data_der_get_ec_params (oid);
+}
+
+GBytes *
+gkm_data_der_encode_ecdsa_q_str (const guchar *data, gsize data_len)
+{
+ GNode *asn = NULL;
+ GBytes *bytes, *result = NULL;
+
+ asn = egg_asn1x_create (pk_asn1_tab, "ECKeyQ");
+ g_return_val_if_fail (asn, FALSE);
+
+ bytes = g_bytes_new_static (data, data_len);
+
+ /* "consumes" bytes */
+ if (!gkm_data_asn1_write_string (asn, bytes))
+ goto done;
+
+ result = egg_asn1x_encode (asn, g_realloc);
+ if (result == NULL)
+ g_warning ("couldn't encode Q into the PKCS#11 structure: %s", egg_asn1x_message (asn));
+done:
+ egg_asn1x_destroy (asn);
+ return result;
+}
+
+gboolean
+gkm_data_der_encode_ecdsa_q (gcry_mpi_t q, GBytes **result)
+{
+ gcry_error_t gcry;
+ guchar data[1024];
+ gsize data_len = 1024;
+ gboolean rv = TRUE;
+
+ g_assert (q);
+ g_assert (result);
+
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, data, data_len, &data_len, q);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ *result = gkm_data_der_encode_ecdsa_q_str (data, data_len);
+ if (*result == NULL)
+ rv = FALSE;
+
+ return rv;
+}
+
+gboolean
+gkm_data_der_decode_ecdsa_q (GBytes *data, GBytes **result)
+{
+ GNode *asn = NULL;
+ gboolean rv = TRUE;
+
+ g_assert (data);
+ g_assert (result);
+
+ asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECKeyQ", data);
+ /* workaround a bug in gcr (not DER encoding the MPI) */
+ if (!asn) {
+ *result = data;
+ return rv;
+ }
+
+ rv = gkm_data_asn1_read_string (asn, result);
+
+ egg_asn1x_destroy (asn);
+ return rv;
+}
+
/* -----------------------------------------------------------------------------
* KEY PARSING
*/
@@ -518,6 +681,8 @@ gkm_data_der_read_private_pkcs8_plain (GBytes *data,
algorithm = GCRY_PK_RSA;
else if (key_algo == OID_PKIX1_DSA)
algorithm = GCRY_PK_DSA;
+ else if (key_algo == OID_PKIX1_ECDSA)
+ algorithm = GCRY_PK_ECC;
if (!algorithm) {
ret = GKM_DATA_UNRECOGNIZED;
diff --git a/pkcs11/gkm/gkm-data-der.h b/pkcs11/gkm/gkm-data-der.h
index e496862..f0587db 100644
--- a/pkcs11/gkm/gkm-data-der.h
+++ b/pkcs11/gkm/gkm-data-der.h
@@ -44,6 +44,26 @@ GkmDataResult gkm_data_der_read_private_key_dsa_parts (GBytes *keydata,
GBytes *params,
gcry_sexp_t *s_key);
+const gchar * gkm_data_der_oid_to_curve (GQuark oid);
+
+GQuark gkm_data_der_oid_from_ec_params (GBytes *params);
+
+GBytes * gkm_data_der_get_ec_params (GQuark oid);
+
+GBytes * gkm_data_der_encode_ecdsa_q_str (const guchar *data,
+ gsize data_len);
+
+gboolean gkm_data_der_encode_ecdsa_q (gcry_mpi_t q,
+ GBytes **result);
+
+gboolean gkm_data_der_decode_ecdsa_q (GBytes *data,
+ GBytes **result);
+
+GBytes * gkm_data_der_curve_to_ec_params (const gchar *curve_name);
+
+GkmDataResult gkm_data_der_read_private_key_ecdsa (GBytes *data,
+ gcry_sexp_t *s_key);
+
GkmDataResult gkm_data_der_read_private_key (GBytes *data,
gcry_sexp_t *s_key);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]