summaryrefslogtreecommitdiff
path: root/pkcs11/gkm
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2017-08-08 18:34:01 +0200
committerDaiki Ueno <ueno@gnu.org>2017-10-13 08:51:04 +0200
commit32680d2667410c8d1802e10746084253daee65d0 (patch)
tree5871b40b69533179204fd9c2f6c72012dadf53e3 /pkcs11/gkm
parentd96bb48a91bdd2075c08b781dc0b1c49db6f89c6 (diff)
downloadgnome-keyring-32680d2667410c8d1802e10746084253daee65d0.tar.gz
ASN.1 definitions of ECDSA and helper functions for DER encoding and decoding
https://bugzilla.gnome.org/show_bug.cgi?id=641082
Diffstat (limited to 'pkcs11/gkm')
-rw-r--r--pkcs11/gkm/gkm-data-asn1.c121
-rw-r--r--pkcs11/gkm/gkm-data-asn1.h26
-rw-r--r--pkcs11/gkm/gkm-data-der.c165
-rw-r--r--pkcs11/gkm/gkm-data-der.h20
4 files changed, 326 insertions, 6 deletions
diff --git a/pkcs11/gkm/gkm-data-asn1.c b/pkcs11/gkm/gkm-data-asn1.c
index e063dd48..591bbe88 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 12826dab..822fd08b 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 78c16ca1..b21049c6 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 e4968623..f0587db5 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);