Commit 32680d26 authored by Jakub Jelen's avatar Jakub Jelen Committed by Daiki Ueno

ASN.1 definitions of ECDSA and helper functions for DER encoding and decoding

https://bugzilla.gnome.org/show_bug.cgi?id=641082
parent d96bb48a
......@@ -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
......@@ -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 }
};
......@@ -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);
}
......@@ -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_*/
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment