Commit cf34a4ed authored by Jakub Jelen's avatar Jakub Jelen Committed by Daiki Ueno

ECDSA support in GKM internals

https://bugzilla.gnome.org/show_bug.cgi?id=641082
parent 32680d26
......@@ -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 \
......
......@@ -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"
......@@ -117,6 +118,24 @@ gkm_attribute_get_string (CK_ATTRIBUTE_PTR attr, gchar **value)
return CKR_OK;
}
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)
{
......@@ -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)
{
......
......@@ -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);
......
......@@ -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:
......
......@@ -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
......
/*
* 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;
}
/*
* 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_ */
......@@ -161,6 +161,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.
......
......@@ -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;
......
......@@ -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__ */
......@@ -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;
......
......@@ -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__ */
......@@ -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)
{
......
......@@ -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);
......
......@@ -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;