[gnome-keyring/wip/dueno/ecdsa-support: 2/10] ECDSA support in GKM internals
- From: Daiki Ueno <dueno src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring/wip/dueno/ecdsa-support: 2/10] ECDSA support in GKM internals
- Date: Fri, 13 Oct 2017 07:22:49 +0000 (UTC)
commit cf34a4ed346c88938021ee5ed6e2114856e3c998
Author: Jakub Jelen <jjelen redhat com>
Date: Tue Aug 8 19:01:55 2017 +0200
ECDSA support in GKM internals
https://bugzilla.gnome.org/show_bug.cgi?id=641082
pkcs11/gkm/Makefile.am | 2 +
pkcs11/gkm/gkm-attributes.c | 35 ++++++++++
pkcs11/gkm/gkm-attributes.h | 8 ++
pkcs11/gkm/gkm-crypto.c | 12 ++++
pkcs11/gkm/gkm-dsa-mechanism.c | 2 +-
pkcs11/gkm/gkm-ecdsa-mechanism.c | 133 ++++++++++++++++++++++++++++++++++++++
pkcs11/gkm/gkm-ecdsa-mechanism.h | 50 ++++++++++++++
pkcs11/gkm/gkm-module.c | 6 ++
pkcs11/gkm/gkm-private-xsa-key.c | 99 ++++++++++++++++++++++++++++-
pkcs11/gkm/gkm-private-xsa-key.h | 9 +++
pkcs11/gkm/gkm-public-xsa-key.c | 53 +++++++++++++++
pkcs11/gkm/gkm-public-xsa-key.h | 9 +++
pkcs11/gkm/gkm-sexp-key.c | 78 +++++++++++++++++++++-
pkcs11/gkm/gkm-sexp-key.h | 8 ++
pkcs11/gkm/gkm-sexp.c | 82 +++++++++++++++++++++++
pkcs11/gkm/gkm-sexp.h | 9 +++
16 files changed, 589 insertions(+), 6 deletions(-)
---
diff --git a/pkcs11/gkm/Makefile.am b/pkcs11/gkm/Makefile.am
index 949aec3..d940ff2 100644
--- a/pkcs11/gkm/Makefile.am
+++ b/pkcs11/gkm/Makefile.am
@@ -44,6 +44,8 @@ libgkm_la_SOURCES = \
pkcs11/gkm/gkm-dh-public-key.h \
pkcs11/gkm/gkm-dsa-mechanism.c \
pkcs11/gkm/gkm-dsa-mechanism.h \
+ pkcs11/gkm/gkm-ecdsa-mechanism.c \
+ pkcs11/gkm/gkm-ecdsa-mechanism.h \
pkcs11/gkm/gkm-factory.c \
pkcs11/gkm/gkm-factory.h \
pkcs11/gkm/gkm-generic-key.c \
diff --git a/pkcs11/gkm/gkm-attributes.c b/pkcs11/gkm/gkm-attributes.c
index 996028b..fb185bc 100644
--- a/pkcs11/gkm/gkm-attributes.c
+++ b/pkcs11/gkm/gkm-attributes.c
@@ -21,6 +21,7 @@
#include "config.h"
#include "gkm-attributes.h"
+#include "gkm-data-der.h"
#include "gkm-util.h"
#include "egg/egg-timegm.h"
@@ -118,6 +119,24 @@ gkm_attribute_get_string (CK_ATTRIBUTE_PTR attr, gchar **value)
}
CK_RV
+gkm_attribute_get_bytes (CK_ATTRIBUTE_PTR attr, GBytes **value)
+{
+ g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (value, CKR_GENERAL_ERROR);
+
+ if (attr->ulValueLen == 0) {
+ *value = NULL;
+ return CKR_OK;
+ }
+
+ if (!attr->pValue)
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+
+ *value = g_bytes_new (attr->pValue, attr->ulValueLen);
+ return CKR_OK;
+}
+
+CK_RV
gkm_attribute_get_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t *value)
{
gcry_error_t gcry;
@@ -555,6 +574,22 @@ gkm_attributes_find_string (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
return gkm_attribute_get_string (attr, value) == CKR_OK;
}
+/* Need to get DER encoded EC parameters and point */
+gboolean
+gkm_attributes_find_bytes (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type, GBytes **value)
+{
+ CK_ATTRIBUTE_PTR attr;
+
+ g_return_val_if_fail (attrs || !n_attrs, FALSE);
+
+ attr = gkm_attributes_find (attrs, n_attrs, type);
+ if (attr == NULL)
+ return FALSE;
+
+ return gkm_attribute_get_bytes (attr, value) == CKR_OK;
+}
+
GArray*
gkm_template_new (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
{
diff --git a/pkcs11/gkm/gkm-attributes.h b/pkcs11/gkm/gkm-attributes.h
index 7f63928..8f2f9cb 100644
--- a/pkcs11/gkm/gkm-attributes.h
+++ b/pkcs11/gkm/gkm-attributes.h
@@ -39,6 +39,9 @@ CK_RV gkm_attribute_get_time (CK_ATTRI
CK_RV gkm_attribute_get_string (CK_ATTRIBUTE_PTR attr,
gchar **value);
+CK_RV gkm_attribute_get_bytes (CK_ATTRIBUTE_PTR attr,
+ GBytes **value);
+
CK_RV gkm_attribute_get_mpi (CK_ATTRIBUTE_PTR attr,
gcry_mpi_t *value);
@@ -122,6 +125,11 @@ gboolean gkm_attributes_find_string (CK_ATTRI
CK_ATTRIBUTE_TYPE type,
gchar **value);
+gboolean gkm_attributes_find_bytes (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type,
+ GBytes **value);
+
GArray* gkm_template_new (CK_ATTRIBUTE_PTR attrs,
CK_ULONG n_attrs);
diff --git a/pkcs11/gkm/gkm-crypto.c b/pkcs11/gkm/gkm-crypto.c
index 0d46bbb..7195e0a 100644
--- a/pkcs11/gkm/gkm-crypto.c
+++ b/pkcs11/gkm/gkm-crypto.c
@@ -24,6 +24,7 @@
#include "gkm-aes-mechanism.h"
#include "gkm-dh-mechanism.h"
#include "gkm-dsa-mechanism.h"
+#include "gkm-ecdsa-mechanism.h"
#include "gkm-hkdf-mechanism.h"
#include "gkm-null-mechanism.h"
#include "gkm-rsa-mechanism.h"
@@ -262,6 +263,7 @@ gkm_crypto_sign (GkmSession *session, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
case CKM_RSA_PKCS:
case CKM_RSA_X_509:
case CKM_DSA:
+ case CKM_ECDSA:
sexp = gkm_session_get_crypto_state (session);
g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
return gkm_crypto_sign_xsa (gkm_sexp_get (sexp), mech, data, n_data, signature, n_signature);
@@ -303,6 +305,10 @@ gkm_crypto_sign_xsa (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
g_return_val_if_fail (algorithm == GCRY_PK_DSA, CKR_GENERAL_ERROR);
rv = gkm_dsa_mechanism_sign (sexp, data, n_data, signature, n_signature);
break;
+ case CKM_ECDSA:
+ g_return_val_if_fail (algorithm == GCRY_PK_ECC, CKR_GENERAL_ERROR);
+ rv = gkm_ecdsa_mechanism_sign (sexp, data, n_data, signature, n_signature);
+ break;
default:
/* Again shouldn't be reached */
g_return_val_if_reached (CKR_GENERAL_ERROR);
@@ -321,6 +327,7 @@ gkm_crypto_verify (GkmSession *session, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data
case CKM_RSA_PKCS:
case CKM_RSA_X_509:
case CKM_DSA:
+ case CKM_ECDSA:
sexp = gkm_session_get_crypto_state (session);
g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
return gkm_crypto_verify_xsa (gkm_sexp_get (sexp), mech, data, n_data, signature,
n_signature);
@@ -362,6 +369,10 @@ gkm_crypto_verify_xsa (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR dat
g_return_val_if_fail (algorithm == GCRY_PK_DSA, CKR_GENERAL_ERROR);
rv = gkm_dsa_mechanism_verify (sexp, data, n_data, signature, n_signature);
break;
+ case CKM_ECDSA:
+ g_return_val_if_fail (algorithm == GCRY_PK_ECC, CKR_GENERAL_ERROR);
+ rv = gkm_ecdsa_mechanism_verify (sexp, data, n_data, signature, n_signature);
+ break;
default:
/* Again shouldn't be reached */
g_return_val_if_reached (CKR_GENERAL_ERROR);
@@ -506,6 +517,7 @@ gkm_crypto_prepare (GkmSession *session, CK_MECHANISM_TYPE mech, GkmObject *key)
switch (mech) {
case CKM_RSA_PKCS:
case CKM_RSA_X_509:
+ case CKM_ECDSA:
case CKM_DSA:
return gkm_crypto_prepare_xsa (session, mech, key);
default:
diff --git a/pkcs11/gkm/gkm-dsa-mechanism.c b/pkcs11/gkm/gkm-dsa-mechanism.c
index f7a4f9e..ee8b025 100644
--- a/pkcs11/gkm/gkm-dsa-mechanism.c
+++ b/pkcs11/gkm/gkm-dsa-mechanism.c
@@ -90,7 +90,7 @@ gkm_dsa_mechanism_sign (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
}
gcry_sexp_release (ssig);
- return CKR_OK;
+ return rv;
}
CK_RV
diff --git a/pkcs11/gkm/gkm-ecdsa-mechanism.c b/pkcs11/gkm/gkm-ecdsa-mechanism.c
new file mode 100644
index 0000000..2ef0c5a
--- /dev/null
+++ b/pkcs11/gkm/gkm-ecdsa-mechanism.c
@@ -0,0 +1,133 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gkm-crypto.h"
+#include "gkm-ecdsa-mechanism.h"
+#include "gkm-session.h"
+#include "gkm-sexp.h"
+#include "gkm-sexp-key.h"
+
+#include "egg/egg-libgcrypt.h"
+#include "egg/egg-secure-memory.h"
+
+/* ----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+CK_RV
+gkm_ecdsa_mechanism_sign (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
+{
+ gcry_sexp_t ssig, splain;
+ gcry_error_t gcry;
+ CK_ULONG size, key_bytes, key_bits;
+ CK_RV rv;
+
+ g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (n_signature, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
+
+ /* If no output, then don't process */
+ key_bits = gcry_pk_get_nbits(sexp);
+ key_bytes = (key_bits + 7)/8;
+ if (!signature) {
+ *n_signature = key_bytes * 2;
+ return CKR_OK;
+ } else if (*n_signature < (key_bytes * 2)) {
+ *n_signature = key_bytes * 2;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ /* Prepare the input s-expression */
+ gcry = gcry_sexp_build (&splain, NULL, "(data (flags raw) (value %b))",
+ n_data, data);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ /* Do the magic */
+ gcry = gcry_pk_sign (&ssig, splain, sexp);
+ gcry_sexp_release (splain);
+
+ /* TODO: Certain codes should be returned (data too big etc... ) */
+ if (gcry) {
+ g_message ("signing of the data failed: %s", gcry_strerror (gcry));
+ return CKR_FUNCTION_FAILED;
+ }
+
+ /* signature consists of two mpint values concatenated */
+ size = key_bytes;
+ rv = gkm_crypto_sexp_to_data (ssig, key_bits, signature, &size, NULL, "ecdsa", "r", NULL);
+ if (rv == CKR_OK) {
+ g_return_val_if_fail (size == key_bytes, CKR_GENERAL_ERROR);
+ rv = gkm_crypto_sexp_to_data (ssig, key_bits, signature + key_bytes, &size, NULL, "ecdsa",
"s", NULL);
+ if (rv == CKR_OK) {
+ g_return_val_if_fail (size == key_bytes, CKR_GENERAL_ERROR);
+ *n_signature = key_bytes * 2;
+ }
+ }
+
+ gcry_sexp_release (ssig);
+ return rv;
+}
+
+CK_RV
+gkm_ecdsa_mechanism_verify (gcry_sexp_t sexp, CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG n_signature)
+{
+ gcry_sexp_t ssig, splain;
+ gcry_error_t gcry;
+ CK_ULONG key_bytes;
+
+ g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (signature, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (data, CKR_ARGUMENTS_BAD);
+
+ key_bytes = gcry_pk_get_nbits(sexp)/8;
+ if (n_signature != key_bytes*2)
+ return CKR_SIGNATURE_LEN_RANGE;
+
+ /* Prepare the input s-expressions */
+ gcry = gcry_sexp_build (&splain, NULL, "(data (flags raw) (value %b))",
+ n_data, data);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ gcry = gcry_sexp_build (&ssig, NULL, "(sig-val (ecdsa (r %b) (s %b)))",
+ key_bytes, signature, key_bytes, signature + key_bytes);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ /* Do the magic */
+ gcry = gcry_pk_verify (ssig, splain, sexp);
+ gcry_sexp_release (splain);
+ gcry_sexp_release (ssig);
+
+ /* TODO: See if any other codes should be mapped */
+ if (gcry_err_code (gcry) == GPG_ERR_BAD_SIGNATURE) {
+ return CKR_SIGNATURE_INVALID;
+ } else if (gcry) {
+ g_message ("verifying of the data failed: %s", gcry_strerror (gcry));
+ return CKR_FUNCTION_FAILED;
+ }
+
+ return CKR_OK;
+}
+
diff --git a/pkcs11/gkm/gkm-ecdsa-mechanism.h b/pkcs11/gkm/gkm-ecdsa-mechanism.h
new file mode 100644
index 0000000..9964034
--- /dev/null
+++ b/pkcs11/gkm/gkm-ecdsa-mechanism.h
@@ -0,0 +1,50 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GKM_ECDSA_MECHANISM_H_
+#define GKM_ECDSA_MECHANISM_H_
+
+#include "gkm-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+static const CK_MECHANISM_TYPE GKM_ECDSA_MECHANISMS[] = {
+ CKM_ECDSA
+};
+
+CK_RV gkm_ecdsa_mechanism_sign (gcry_sexp_t sexp,
+ CK_BYTE_PTR data,
+ CK_ULONG n_data,
+ CK_BYTE_PTR signature,
+ CK_ULONG_PTR n_signature);
+
+CK_RV gkm_ecdsa_mechanism_verify (gcry_sexp_t sexp,
+ CK_BYTE_PTR data,
+ CK_ULONG n_data,
+ CK_BYTE_PTR signature,
+ CK_ULONG n_signature);
+
+#endif /* GKM_ECDSA_MECHANISM_H_ */
diff --git a/pkcs11/gkm/gkm-module.c b/pkcs11/gkm/gkm-module.c
index 47477aa..f8177d2 100644
--- a/pkcs11/gkm/gkm-module.c
+++ b/pkcs11/gkm/gkm-module.c
@@ -162,6 +162,12 @@ static const MechanismAndInfo mechanism_list[] = {
{ CKM_DH_PKCS_DERIVE, { 1, 255, CKF_DERIVE } },
/*
+ * CKM_ECDSA
+ * For ECDSA, min and max are the minimum and maximum modulus in bits
+ */
+ { CKM_ECDSA, { 256, 521, CKF_SIGN | CKF_VERIFY } },
+
+ /*
* CKM_G_HKDF_DERIVE
* For HKDF derivation the min and max are sizes of prime in bits.
*/
diff --git a/pkcs11/gkm/gkm-private-xsa-key.c b/pkcs11/gkm/gkm-private-xsa-key.c
index de8c937..3dbbd12 100644
--- a/pkcs11/gkm/gkm-private-xsa-key.c
+++ b/pkcs11/gkm/gkm-private-xsa-key.c
@@ -28,6 +28,7 @@
#include "gkm-debug.h"
#include "gkm-factory.h"
#include "gkm-private-xsa-key.h"
+#include "gkm-data-der.h"
#include "gkm-session.h"
#include "gkm-transaction.h"
#include "gkm-util.h"
@@ -42,6 +43,47 @@ G_DEFINE_TYPE (GkmPrivateXsaKey, gkm_private_xsa_key, GKM_TYPE_SEXP_KEY);
* INTERNAL
*/
+/* Can't be defined in gkm_attributes, because it does not know anything about
+ * DER encoding nor OIDs
+ */
+gboolean
+gkm_attributes_find_ecc_oid (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GQuark *value)
+{
+ GBytes *bytes;
+ CK_ATTRIBUTE_PTR attr;
+ GQuark oid;
+
+ g_return_val_if_fail (attrs || !n_attrs, FALSE);
+
+ attr = gkm_attributes_find (attrs, n_attrs, CKA_EC_PARAMS);
+ if (attr == NULL)
+ return FALSE;
+
+ bytes = g_bytes_new (attr->pValue, attr->ulValueLen);
+ g_return_val_if_fail (bytes != NULL, FALSE);
+
+ oid = gkm_data_der_oid_from_ec_params (bytes);
+ g_return_val_if_fail (oid != 0, FALSE);
+ *value = oid;
+
+ g_bytes_unref (bytes);
+ return TRUE;
+}
+
+gboolean
+gkm_attributes_find_ecc_q (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type, GBytes **value)
+{
+ GBytes *data;
+ gboolean rv;
+
+ rv = gkm_attributes_find_bytes (attrs, n_attrs, type, &data);
+ g_return_val_if_fail (rv, FALSE);
+
+ rv = gkm_data_der_decode_ecdsa_q (data, value);
+
+ return rv;
+}
static CK_RV
create_rsa_private (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
@@ -144,6 +186,52 @@ done:
return ret;
}
+static CK_RV
+create_ecdsa_private (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+ gcry_error_t gcry;
+ gcry_mpi_t d = NULL;
+ const gchar *curve_name, *q_data;
+ GBytes *q = NULL;
+ gsize q_size;
+ GQuark oid;
+ CK_RV ret;
+
+ if (!gkm_attributes_find_ecc_oid (attrs, n_attrs, &oid) ||
+ !gkm_attributes_find_ecc_q (attrs, n_attrs, CKA_EC_POINT, &q) ||
+ !gkm_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &d)) {
+ ret = CKR_TEMPLATE_INCOMPLETE;
+ goto done;
+ }
+
+ curve_name = gkm_data_der_oid_to_curve (oid);
+ if (curve_name == NULL) {
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ q_data = g_bytes_get_data (q, &q_size);
+
+ gcry = gcry_sexp_build (skey, NULL,
+ "(private-key (ecdsa (curve %s) (q %b) (d %m)))",
+ curve_name, q_size, q_data, d);
+
+ if (gcry != 0) {
+ g_message ("couldn't create ECDSA key from passed attributes: %s", gcry_strerror (gcry));
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ gkm_attributes_consume (attrs, n_attrs, CKA_EC_PARAMS,
+ CKA_EC_POINT, CKA_VALUE, G_MAXULONG);
+ ret = CKR_OK;
+
+done:
+ g_bytes_unref (q);
+ gcry_mpi_release (d);
+ return ret;
+}
+
static GkmObject*
factory_create_private_xsa_key (GkmSession *session, GkmTransaction *transaction,
CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
@@ -272,7 +360,13 @@ gkm_private_xsa_key_real_get_attribute (GkmObject *base, GkmSession *session, CK
case CKA_BASE:
return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_DSA, "g", attr);
- /* DSA private parts */
+ case CKA_EC_POINT:
+ return gkm_sexp_key_set_ec_q (GKM_SEXP_KEY (self), GCRY_PK_ECC, attr);
+
+ case CKA_EC_PARAMS:
+ return gkm_sexp_key_set_ec_params (GKM_SEXP_KEY (self), GCRY_PK_ECC, attr);
+
+ /* (EC)DSA private parts */
case CKA_VALUE:
return CKR_ATTRIBUTE_SENSITIVE;
};
@@ -396,6 +490,9 @@ gkm_private_xsa_key_create_sexp (GkmSession *session, GkmTransaction *transactio
case CKK_DSA:
ret = create_dsa_private (attrs, n_attrs, &sexp);
break;
+ case CKK_EC:
+ ret = create_ecdsa_private (attrs, n_attrs, &sexp);
+ break;
default:
ret = CKR_ATTRIBUTE_VALUE_INVALID;
break;
diff --git a/pkcs11/gkm/gkm-private-xsa-key.h b/pkcs11/gkm/gkm-private-xsa-key.h
index af10c3d..d6af4a8 100644
--- a/pkcs11/gkm/gkm-private-xsa-key.h
+++ b/pkcs11/gkm/gkm-private-xsa-key.h
@@ -63,4 +63,13 @@ GkmSexp* gkm_private_xsa_key_create_sexp (GkmSession *s
CK_ATTRIBUTE_PTR attrs,
CK_ULONG n_attrs);
+gboolean gkm_attributes_find_ecc_oid (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ GQuark *value);
+
+gboolean gkm_attributes_find_ecc_q (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type,
+ GBytes **value);
+
#endif /* __GKM_PRIVATE_XSA_KEY_H__ */
diff --git a/pkcs11/gkm/gkm-public-xsa-key.c b/pkcs11/gkm/gkm-public-xsa-key.c
index a823e8a..5cc93f3 100644
--- a/pkcs11/gkm/gkm-public-xsa-key.c
+++ b/pkcs11/gkm/gkm-public-xsa-key.c
@@ -27,6 +27,7 @@
#include "gkm-debug.h"
#include "gkm-factory.h"
#include "gkm-public-xsa-key.h"
+#include "gkm-data-der.h"
#include "gkm-session.h"
#include "gkm-sexp.h"
#include "gkm-transaction.h"
@@ -140,6 +141,49 @@ done:
return ret;
}
+static CK_RV
+create_ecdsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+ gcry_error_t gcry;
+ const gchar *curve_name, *q_data;
+ GBytes *q = NULL;
+ gsize q_size;
+ GQuark oid;
+ CK_RV ret;
+
+ if (!gkm_attributes_find_ecc_oid (attrs, n_attrs, &oid) ||
+ !gkm_attributes_find_ecc_q (attrs, n_attrs, CKA_EC_POINT, &q)) {
+ ret = CKR_TEMPLATE_INCOMPLETE;
+ goto done;
+ }
+
+ curve_name = gkm_data_der_oid_to_curve (oid);
+ if (curve_name == NULL) {
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ q_data = g_bytes_get_data (q, &q_size);
+
+ gcry = gcry_sexp_build (skey, NULL,
+ "(public-key (ecdsa (curve %s) (q %b)))",
+ curve_name, q_size, q_data);
+
+ if (gcry != 0) {
+ g_message ("couldn't create ECDSA key from passed attributes: %s", gcry_strerror (gcry));
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ gkm_attributes_consume (attrs, n_attrs, CKA_EC_POINT, CKA_EC_PARAMS,
+ G_MAXULONG);
+ ret = CKR_OK;
+
+done:
+ g_bytes_unref (q);
+ return ret;
+}
+
static GkmObject*
factory_create_public_xsa_key (GkmSession *session, GkmTransaction *transaction,
CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
@@ -221,6 +265,12 @@ gkm_public_xsa_key_real_get_attribute (GkmObject *base, GkmSession *session, CK_
/* DSA public value */
case CKA_VALUE:
return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_DSA, "y", attr);
+
+ case CKA_EC_POINT:
+ return gkm_sexp_key_set_ec_q (GKM_SEXP_KEY (self), GCRY_PK_ECC, attr);
+
+ case CKA_EC_PARAMS:
+ return gkm_sexp_key_set_ec_params (GKM_SEXP_KEY (self), GCRY_PK_ECC, attr);
};
return GKM_OBJECT_CLASS (gkm_public_xsa_key_parent_class)->get_attribute (base, session, attr);
@@ -286,6 +336,9 @@ gkm_public_xsa_key_create_sexp (GkmSession *session, GkmTransaction *transaction
case CKK_DSA:
ret = create_dsa_public (attrs, n_attrs, &sexp);
break;
+ case CKK_EC:
+ ret = create_ecdsa_public (attrs, n_attrs, &sexp);
+ break;
default:
ret = CKR_ATTRIBUTE_VALUE_INVALID;
break;
diff --git a/pkcs11/gkm/gkm-public-xsa-key.h b/pkcs11/gkm/gkm-public-xsa-key.h
index bc1bbee..f2c0f25 100644
--- a/pkcs11/gkm/gkm-public-xsa-key.h
+++ b/pkcs11/gkm/gkm-public-xsa-key.h
@@ -56,4 +56,13 @@ GkmSexp* gkm_public_xsa_key_create_sexp (GkmSession *ses
CK_ATTRIBUTE_PTR attrs,
CK_ULONG n_attrs);
+extern gboolean gkm_attributes_find_ecc_oid (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ GQuark *value);
+
+extern gboolean gkm_attributes_find_ecc_q (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type,
+ GBytes **value);
+
#endif /* __GKM_PUBLIC_XSA_KEY_H__ */
diff --git a/pkcs11/gkm/gkm-sexp-key.c b/pkcs11/gkm/gkm-sexp-key.c
index fa48b9a..8b98bdc 100644
--- a/pkcs11/gkm/gkm-sexp-key.c
+++ b/pkcs11/gkm/gkm-sexp-key.c
@@ -26,8 +26,10 @@
#define DEBUG_FLAG GKM_DEBUG_OBJECT
#include "gkm-debug.h"
#include "gkm-dsa-mechanism.h"
+#include "gkm-ecdsa-mechanism.h"
#include "gkm-rsa-mechanism.h"
#include "gkm-sexp-key.h"
+#include "gkm-data-der.h"
#include "gkm-util.h"
enum {
@@ -63,6 +65,8 @@ gkm_sexp_key_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIB
return gkm_attribute_set_ulong (attr, CKK_RSA);
case GCRY_PK_DSA:
return gkm_attribute_set_ulong (attr, CKK_DSA);
+ case GCRY_PK_ECC:
+ return gkm_attribute_set_ulong (attr, CKK_ECDSA);
default:
g_return_val_if_reached (CKR_GENERAL_ERROR);
};
@@ -100,6 +104,9 @@ gkm_sexp_key_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIB
case GCRY_PK_DSA:
return gkm_attribute_set_data (attr, (CK_VOID_PTR)GKM_DSA_MECHANISMS,
sizeof (GKM_DSA_MECHANISMS));
+ case GCRY_PK_ECC:
+ return gkm_attribute_set_data (attr, (CK_VOID_PTR)GKM_ECDSA_MECHANISMS,
+ sizeof (GKM_ECDSA_MECHANISMS));
default:
g_return_val_if_reached (CKR_GENERAL_ERROR);
};
@@ -224,8 +231,9 @@ gkm_sexp_key_get_algorithm (GkmSexpKey *self)
return algorithm;
}
-CK_RV
-gkm_sexp_key_set_part (GkmSexpKey *self, int algo, const char *part, CK_ATTRIBUTE_PTR attr)
+static CK_RV
+gkm_sexp_key_set_part_encode (GkmSexpKey *self, int algo, const char *part,
+ CK_ATTRIBUTE_PTR attr, int der_encode)
{
gcry_sexp_t numbers;
gcry_mpi_t mpi;
@@ -236,7 +244,7 @@ gkm_sexp_key_set_part (GkmSexpKey *self, int algo, const char *part, CK_ATTRIBUT
g_return_val_if_fail (self->pv->base_sexp, CKR_GENERAL_ERROR);
if (!gkm_sexp_parse_key (gkm_sexp_get (self->pv->base_sexp),
- &algorithm, NULL, &numbers))
+ &algorithm, NULL, &numbers))
g_return_val_if_reached (CKR_GENERAL_ERROR);
if (algorithm != algo) {
@@ -248,13 +256,75 @@ gkm_sexp_key_set_part (GkmSexpKey *self, int algo, const char *part, CK_ATTRIBUT
if (!gkm_sexp_extract_mpi (numbers, &mpi, part, NULL))
g_return_val_if_reached (CKR_GENERAL_ERROR);
- rv = gkm_attribute_set_mpi (attr, mpi);
+
+ if (der_encode) {
+ /* convert mpi to DER encoded OCTET string */
+ GBytes *data;
+
+ rv = gkm_data_der_encode_ecdsa_q (mpi, &data);
+ g_return_val_if_fail (rv, CKR_GENERAL_ERROR);
+
+ rv = gkm_attribute_set_bytes (attr, data);
+ g_bytes_unref (data);
+ } else {
+ rv = gkm_attribute_set_mpi (attr, mpi);
+ }
+
gcry_sexp_release (numbers);
gcry_mpi_release (mpi);
return rv;
}
+CK_RV
+gkm_sexp_key_set_part (GkmSexpKey *self, int algo, const char *part, CK_ATTRIBUTE_PTR attr)
+{
+ return gkm_sexp_key_set_part_encode (self, algo, part, attr, 0);
+}
+
+CK_RV
+gkm_sexp_key_set_ec_q (GkmSexpKey *self, int algo, CK_ATTRIBUTE_PTR attr)
+{
+ return gkm_sexp_key_set_part_encode (self, algo, "q", attr, 1);
+}
+
+CK_RV
+gkm_sexp_key_set_ec_params (GkmSexpKey *self, int algo, CK_ATTRIBUTE_PTR attr)
+{
+ CK_RV rv;
+ gchar *curve_name;
+ GBytes *data;
+ int algorithm;
+ gcry_sexp_t numbers;
+
+ g_return_val_if_fail (GKM_IS_SEXP_KEY (self), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (self->pv->base_sexp, CKR_GENERAL_ERROR);
+
+ if (!gkm_sexp_parse_key (gkm_sexp_get (self->pv->base_sexp),
+ &algorithm, NULL, &numbers))
+ g_return_val_if_reached (CKR_GENERAL_ERROR);
+
+ if (algorithm != algo) {
+ gcry_sexp_release (numbers);
+ gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: attribute %s not valid for key algorithm: %s",
+ gkm_log_attr_type (attr->type), gcry_pk_algo_name (algo));
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ }
+
+ rv = gkm_sexp_extract_string (numbers, &curve_name, "curve", NULL);
+ g_return_val_if_fail (rv, CKR_GENERAL_ERROR);
+
+ data = gkm_data_der_curve_to_ec_params (curve_name);
+ g_return_val_if_fail (data != NULL, CKR_GENERAL_ERROR);
+
+ rv = gkm_attribute_set_bytes (attr, data);
+ g_bytes_unref (data);
+ gcry_sexp_release (numbers);
+ g_free (curve_name);
+
+ return rv;
+}
+
GkmSexp*
gkm_sexp_key_acquire_crypto_sexp (GkmSexpKey *self, GkmSession *session)
{
diff --git a/pkcs11/gkm/gkm-sexp-key.h b/pkcs11/gkm/gkm-sexp-key.h
index 7400167..99e0042 100644
--- a/pkcs11/gkm/gkm-sexp-key.h
+++ b/pkcs11/gkm/gkm-sexp-key.h
@@ -64,6 +64,14 @@ CK_RV gkm_sexp_key_set_part (GkmSexpKey *self,
const char *part,
CK_ATTRIBUTE_PTR attr);
+CK_RV gkm_sexp_key_set_ec_params (GkmSexpKey *self,
+ int algo,
+ CK_ATTRIBUTE_PTR attr);
+
+CK_RV gkm_sexp_key_set_ec_q (GkmSexpKey *self,
+ int algo,
+ CK_ATTRIBUTE_PTR attr);
+
GkmSexp* gkm_sexp_key_acquire_crypto_sexp (GkmSexpKey *self,
GkmSession *session);
diff --git a/pkcs11/gkm/gkm-sexp.c b/pkcs11/gkm/gkm-sexp.c
index 28d7ce2..287f874 100644
--- a/pkcs11/gkm/gkm-sexp.c
+++ b/pkcs11/gkm/gkm-sexp.c
@@ -194,6 +194,31 @@ done:
return pubkey;
}
+static gcry_sexp_t
+ecdsa_numbers_to_public (gcry_sexp_t ecdsa)
+{
+ gchar *curve_name = NULL, *q = NULL;
+ gsize q_len;
+ gcry_sexp_t pubkey = NULL;
+ gcry_error_t gcry;
+
+ if (!gkm_sexp_extract_string (ecdsa, &curve_name, "curve", NULL) ||
+ !gkm_sexp_extract_buffer (ecdsa, &q, &q_len, "q", NULL))
+ goto done;
+
+ gcry = gcry_sexp_build (&pubkey, NULL, "(public-key (ecdsa (curve %s) (q %b)))",
+ curve_name, q_len, q);
+ if (gcry)
+ goto done;
+ g_assert (pubkey);
+
+done:
+ g_free (curve_name);
+ g_free (q);
+
+ return pubkey;
+}
+
gboolean
gkm_sexp_key_to_public (gcry_sexp_t privkey, gcry_sexp_t *pubkey)
{
@@ -210,6 +235,9 @@ gkm_sexp_key_to_public (gcry_sexp_t privkey, gcry_sexp_t *pubkey)
case GCRY_PK_DSA:
*pubkey = dsa_numbers_to_public (numbers);
break;
+ case GCRY_PK_ECC:
+ *pubkey = ecdsa_numbers_to_public (numbers);
+ break;
default:
g_return_val_if_reached (FALSE);
}
@@ -240,6 +268,60 @@ gkm_sexp_extract_mpi (gcry_sexp_t sexp, gcry_mpi_t *mpi, ...)
return (*mpi) ? TRUE : FALSE;
}
+/* ECDSA s-exp lists the curve name as a string */
+gboolean
+gkm_sexp_extract_string (gcry_sexp_t sexp, gchar **buf, ...)
+{
+ gcry_sexp_t at = NULL;
+ va_list va;
+
+ g_assert (sexp);
+ g_assert (buf);
+
+ va_start (va, buf);
+ at = gkm_sexp_get_childv (sexp, va);
+ va_end (va);
+
+ *buf = NULL;
+ if (at) {
+ size_t len;
+ const char *data;
+
+ data = gcry_sexp_nth_data (at, 1, &len);
+ *buf = g_strndup (data, len);
+ gcry_sexp_release (at);
+ }
+
+ return (*buf) ? TRUE : FALSE;
+}
+
+gboolean
+gkm_sexp_extract_buffer (gcry_sexp_t sexp, gchar **buf, gsize *bufsize, ...)
+{
+ gcry_sexp_t at = NULL;
+ va_list va;
+
+ g_assert (sexp);
+ g_assert (buf);
+
+ va_start (va, bufsize);
+ at = gkm_sexp_get_childv (sexp, va);
+ va_end (va);
+
+ *buf = NULL;
+ if (at) {
+ size_t len;
+ const char *data;
+
+ data = gcry_sexp_nth_data (at, 1, &len);
+ *buf = g_memdup (data, len);
+ *bufsize = len;
+ gcry_sexp_release (at);
+ }
+
+ return (*buf) ? TRUE : FALSE;
+}
+
gcry_sexp_t
gkm_sexp_get_childv (gcry_sexp_t sexp, va_list va)
{
diff --git a/pkcs11/gkm/gkm-sexp.h b/pkcs11/gkm/gkm-sexp.h
index ff1aa34..0e44d80 100644
--- a/pkcs11/gkm/gkm-sexp.h
+++ b/pkcs11/gkm/gkm-sexp.h
@@ -52,6 +52,15 @@ gboolean gkm_sexp_extract_mpi (gcry_sexp_t sexp,
gcry_mpi_t *mpi,
...) G_GNUC_NULL_TERMINATED;
+gboolean gkm_sexp_extract_string (gcry_sexp_t sexp,
+ gchar **buf,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gkm_sexp_extract_buffer (gcry_sexp_t sexp,
+ gchar **buf,
+ gsize *bufsize,
+ ...) G_GNUC_NULL_TERMINATED;
+
gcry_sexp_t gkm_sexp_get_childv (gcry_sexp_t sexp,
va_list va);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]