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

Support ECDSA in ssh-agent interface

https://bugzilla.gnome.org/show_bug.cgi?id=641082
parent b0a2020b
...@@ -28,4 +28,5 @@ gkd_ssh_agent_standalone_LDADD = \ ...@@ -28,4 +28,5 @@ gkd_ssh_agent_standalone_LDADD = \
libgkd-ssh-agent.la \ libgkd-ssh-agent.la \
libegg-buffer.la \ libegg-buffer.la \
libegg-secure.la \ libegg-secure.la \
libgkm.la \
$(DAEMON_LIBS) $(DAEMON_LIBS)
...@@ -112,6 +112,11 @@ build_like_attributes (GckAttributes *attrs, CK_OBJECT_CLASS klass) ...@@ -112,6 +112,11 @@ build_like_attributes (GckAttributes *attrs, CK_OBJECT_CLASS klass)
copy_attribute (attrs, CKA_VALUE, &builder); copy_attribute (attrs, CKA_VALUE, &builder);
break; break;
case CKK_EC:
copy_attribute (attrs, CKA_EC_PARAMS, &builder);
copy_attribute (attrs, CKA_EC_POINT, &builder);
break;
default: default:
g_return_val_if_reached (NULL); g_return_val_if_reached (NULL);
break; break;
...@@ -306,7 +311,8 @@ load_identity_v2_attributes (GckObject *object, gpointer user_data) ...@@ -306,7 +311,8 @@ load_identity_v2_attributes (GckObject *object, gpointer user_data)
attrs = gck_object_get (object, NULL, &error, CKA_ID, CKA_LABEL, CKA_KEY_TYPE, CKA_MODULUS, attrs = gck_object_get (object, NULL, &error, CKA_ID, CKA_LABEL, CKA_KEY_TYPE, CKA_MODULUS,
CKA_PUBLIC_EXPONENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PUBLIC_EXPONENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE,
CKA_VALUE, CKA_CLASS, CKA_MODULUS_BITS, CKA_TOKEN, GCK_INVALID); CKA_VALUE, CKA_CLASS, CKA_MODULUS_BITS, CKA_TOKEN,
CKA_EC_POINT, CKA_EC_PARAMS, GCK_INVALID);
if (error) { if (error) {
g_warning ("error retrieving attributes for public key: %s", egg_error_message (error)); g_warning ("error retrieving attributes for public key: %s", egg_error_message (error));
g_clear_error (&error); g_clear_error (&error);
...@@ -643,6 +649,9 @@ op_add_identity (GkdSshAgentCall *call) ...@@ -643,6 +649,9 @@ op_add_identity (GkdSshAgentCall *call)
case CKK_DSA: case CKK_DSA:
ret = gkd_ssh_agent_proto_read_pair_dsa (call->req, &offset, &priv, &pub); ret = gkd_ssh_agent_proto_read_pair_dsa (call->req, &offset, &priv, &pub);
break; break;
case CKK_EC:
ret = gkd_ssh_agent_proto_read_pair_ecdsa (call->req, &offset, &priv, &pub);
break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
return FALSE; return FALSE;
...@@ -982,6 +991,7 @@ unlock_and_sign (GckSession *session, GckObject *key, gulong mech_type, const gu ...@@ -982,6 +991,7 @@ unlock_and_sign (GckSession *session, GckObject *key, gulong mech_type, const gu
return gck_session_sign (session, key, mech_type, input, n_input, n_result, NULL, err); return gck_session_sign (session, key, mech_type, input, n_input, n_result, NULL, err);
} }
static gboolean static gboolean
op_sign_request (GkdSshAgentCall *call) op_sign_request (GkdSshAgentCall *call)
{ {
...@@ -1002,6 +1012,7 @@ op_sign_request (GkdSshAgentCall *call) ...@@ -1002,6 +1012,7 @@ op_sign_request (GkdSshAgentCall *call)
gulong algo, mech; gulong algo, mech;
GChecksumType halgo; GChecksumType halgo;
gsize n_hash = 0; gsize n_hash = 0;
GQuark oid = 0;
offset = 5; offset = 5;
...@@ -1022,7 +1033,12 @@ op_sign_request (GkdSshAgentCall *call) ...@@ -1022,7 +1033,12 @@ op_sign_request (GkdSshAgentCall *call)
mech = CKM_RSA_PKCS; mech = CKM_RSA_PKCS;
else if (algo == CKK_DSA) else if (algo == CKK_DSA)
mech = CKM_DSA; mech = CKM_DSA;
else else if (algo == CKK_EC) {
mech = CKM_ECDSA;
oid = gkd_ssh_agent_proto_find_curve_oid (attrs);
if (!oid)
return FALSE;
} else
g_return_val_if_reached (FALSE); g_return_val_if_reached (FALSE);
if (!egg_buffer_get_byte_array (call->req, offset, &offset, &data, &n_data) || if (!egg_buffer_get_byte_array (call->req, offset, &offset, &data, &n_data) ||
...@@ -1040,11 +1056,20 @@ op_sign_request (GkdSshAgentCall *call) ...@@ -1040,11 +1056,20 @@ op_sign_request (GkdSshAgentCall *call)
return TRUE; return TRUE;
} }
/* Usually we hash the data with SHA1 */ if (mech == CKM_ECDSA) {
if (flags & GKD_SSH_FLAG_OLD_SIGNATURE) /* ECDSA is using SHA-2 hash algorithms based on key size */
gint ret = gkd_ssh_agent_proto_curve_oid_to_hash_algo (oid);
if (ret == -1) {
egg_buffer_add_byte (call->resp, GKD_SSH_RES_FAILURE);
return FALSE;
}
halgo = (GChecksumType) ret;
} else if (flags & GKD_SSH_FLAG_OLD_SIGNATURE) {
halgo = G_CHECKSUM_MD5; halgo = G_CHECKSUM_MD5;
else } else {
/* Usually we hash the data with SHA1 */
halgo = G_CHECKSUM_SHA1; halgo = G_CHECKSUM_SHA1;
}
/* Build the hash */ /* Build the hash */
if (mech == CKM_RSA_PKCS) if (mech == CKM_RSA_PKCS)
...@@ -1076,7 +1101,7 @@ op_sign_request (GkdSshAgentCall *call) ...@@ -1076,7 +1101,7 @@ op_sign_request (GkdSshAgentCall *call)
blobpos = call->resp->len; blobpos = call->resp->len;
egg_buffer_add_uint32 (call->resp, 0); egg_buffer_add_uint32 (call->resp, 0);
salgo = gkd_ssh_agent_proto_algo_to_keytype (algo); salgo = gkd_ssh_agent_proto_algo_to_keytype (algo, oid);
g_assert (salgo); g_assert (salgo);
egg_buffer_add_string (call->resp, salgo); egg_buffer_add_string (call->resp, salgo);
...@@ -1089,6 +1114,10 @@ op_sign_request (GkdSshAgentCall *call) ...@@ -1089,6 +1114,10 @@ op_sign_request (GkdSshAgentCall *call)
ret = gkd_ssh_agent_proto_write_signature_dsa (call->resp, result, n_result); ret = gkd_ssh_agent_proto_write_signature_dsa (call->resp, result, n_result);
break; break;
case CKK_EC:
ret = gkd_ssh_agent_proto_write_signature_ecdsa (call->resp, result, n_result);
break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
} }
......
...@@ -103,7 +103,18 @@ void gkd_ssh_agent_checkin_main_session (GckSession* ...@@ -103,7 +103,18 @@ void gkd_ssh_agent_checkin_main_session (GckSession*
gulong gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo); gulong gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo);
const gchar* gkd_ssh_agent_proto_algo_to_keytype (gulong algo); const gchar* gkd_ssh_agent_proto_algo_to_keytype (gulong algo,
GQuark oid);
GQuark gkd_ssh_agent_proto_curve_to_oid (const gchar *salgo);
const gchar* gkd_ssh_agent_proto_oid_to_curve (GQuark oid);
gint gkd_ssh_agent_proto_curve_oid_to_hash_algo (GQuark oid);
const gchar* gkd_ssh_agent_proto_curve_oid_to_keytype (GQuark oid);
GQuark gkd_ssh_agent_proto_find_curve_oid (GckAttributes *attrs);
gboolean gkd_ssh_agent_proto_read_mpi (EggBuffer *req, gboolean gkd_ssh_agent_proto_read_mpi (EggBuffer *req,
gsize *offset, gsize *offset,
...@@ -119,12 +130,24 @@ const guchar* gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer * ...@@ -119,12 +130,24 @@ const guchar* gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer *
gsize *offset, gsize *offset,
gsize *n_challenge); gsize *n_challenge);
gboolean gkd_ssh_agent_proto_read_string_to_der (EggBuffer *req,
gsize *offset,
GckBuilder *attrs,
CK_ATTRIBUTE_TYPE type);
gboolean gkd_ssh_agent_proto_read_ecdsa_curve (EggBuffer *req,
gsize *offset,
GckBuilder *attrs);
gboolean gkd_ssh_agent_proto_write_mpi (EggBuffer *resp, gboolean gkd_ssh_agent_proto_write_mpi (EggBuffer *resp,
const GckAttribute *attr); const GckAttribute *attr);
gboolean gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp, gboolean gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp,
const GckAttribute *attr); const GckAttribute *attr);
gboolean gkd_ssh_agent_proto_write_string (EggBuffer *resp,
const GckAttribute *attr);
gboolean gkd_ssh_agent_proto_read_public (EggBuffer *req, gboolean gkd_ssh_agent_proto_read_public (EggBuffer *req,
gsize *offset, gsize *offset,
GckBuilder *attrs, GckBuilder *attrs,
...@@ -138,6 +161,10 @@ gboolean gkd_ssh_agent_proto_read_public_dsa (EggBuffer * ...@@ -138,6 +161,10 @@ gboolean gkd_ssh_agent_proto_read_public_dsa (EggBuffer *
gsize *offset, gsize *offset,
GckBuilder *attrs); GckBuilder *attrs);
gboolean gkd_ssh_agent_proto_read_public_ecdsa (EggBuffer *req,
gsize *offset,
GckBuilder *attrs);
gboolean gkd_ssh_agent_proto_read_public_v1 (EggBuffer *req, gboolean gkd_ssh_agent_proto_read_public_v1 (EggBuffer *req,
gsize *offset, gsize *offset,
GckBuilder *attrs); GckBuilder *attrs);
...@@ -152,6 +179,11 @@ gboolean gkd_ssh_agent_proto_read_pair_dsa (EggBuffer * ...@@ -152,6 +179,11 @@ gboolean gkd_ssh_agent_proto_read_pair_dsa (EggBuffer *
GckBuilder *priv, GckBuilder *priv,
GckBuilder *pub); GckBuilder *pub);
gboolean gkd_ssh_agent_proto_read_pair_ecdsa (EggBuffer *req,
gsize *offset,
GckBuilder *priv,
GckBuilder *pub);
gboolean gkd_ssh_agent_proto_read_pair_v1 (EggBuffer *req, gboolean gkd_ssh_agent_proto_read_pair_v1 (EggBuffer *req,
gsize *offset, gsize *offset,
GckBuilder *priv, GckBuilder *priv,
...@@ -166,6 +198,9 @@ gboolean gkd_ssh_agent_proto_write_public_rsa (EggBuffer * ...@@ -166,6 +198,9 @@ gboolean gkd_ssh_agent_proto_write_public_rsa (EggBuffer *
gboolean gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, gboolean gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp,
GckAttributes *attrs); GckAttributes *attrs);
gboolean gkd_ssh_agent_proto_write_public_ecdsa (EggBuffer *resp,
GckAttributes *attrs);
gboolean gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp, gboolean gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp,
GckAttributes *attrs); GckAttributes *attrs);
...@@ -177,4 +212,8 @@ gboolean gkd_ssh_agent_proto_write_signature_dsa (EggBuffer * ...@@ -177,4 +212,8 @@ gboolean gkd_ssh_agent_proto_write_signature_dsa (EggBuffer *
CK_BYTE_PTR signature, CK_BYTE_PTR signature,
CK_ULONG n_signature); CK_ULONG n_signature);
gboolean gkd_ssh_agent_proto_write_signature_ecdsa (EggBuffer *resp,
CK_BYTE_PTR signature,
CK_ULONG n_signature);
#endif /*GKDSSHPRIVATE_H_*/ #endif /*GKDSSHPRIVATE_H_*/
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "gkd-ssh-agent-private.h" #include "gkd-ssh-agent-private.h"
#include "gkm/gkm-data-der.h"
#include "egg/egg-buffer.h" #include "egg/egg-buffer.h"
#include <gck/gck.h> #include <gck/gck.h>
...@@ -32,6 +34,34 @@ ...@@ -32,6 +34,34 @@
#include <string.h> #include <string.h>
/* -----------------------------------------------------------------------------
* QUARKS
*/
static GQuark OID_ANSI_SECP256R1;
static GQuark OID_ANSI_SECP384R1;
static GQuark OID_ANSI_SECP521R1;
static void
init_quarks (void)
{
static volatile gsize quarks_inited = 0;
if (g_once_init_enter (&quarks_inited)) {
#define QUARK(name, value) \
name = g_quark_from_static_string(value)
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
g_once_init_leave (&quarks_inited, 1);
}
}
gulong gulong
gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo) gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo)
{ {
...@@ -40,19 +70,122 @@ gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo) ...@@ -40,19 +70,122 @@ gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo)
return CKK_RSA; return CKK_RSA;
else if (strcmp (salgo, "ssh-dss") == 0) else if (strcmp (salgo, "ssh-dss") == 0)
return CKK_DSA; return CKK_DSA;
else if (strcmp (salgo, "ecdsa-sha2-nistp256") == 0 ||
strcmp (salgo, "ecdsa-sha2-nistp384") == 0 ||
strcmp (salgo, "ecdsa-sha2-nistp521") == 0)
return CKK_EC;
return G_MAXULONG; return G_MAXULONG;
} }
GQuark
gkd_ssh_agent_proto_curve_to_oid (const gchar *salgo)
{
g_return_val_if_fail (salgo, 0);
init_quarks ();
if (g_str_equal (salgo, "nistp256"))
return OID_ANSI_SECP256R1;
else if (g_str_equal (salgo, "nistp384"))
return OID_ANSI_SECP384R1;
else if (g_str_equal (salgo, "nistp521"))
return OID_ANSI_SECP521R1;
return 0;
}
const gchar* const gchar*
gkd_ssh_agent_proto_algo_to_keytype (gulong algo) gkd_ssh_agent_proto_oid_to_curve (GQuark oid)
{ {
if (algo == CKK_RSA) g_return_val_if_fail (oid, NULL);
init_quarks ();
if (oid == OID_ANSI_SECP256R1)
return "nistp256";
else if (oid == OID_ANSI_SECP384R1)
return "nistp384";
else if (oid == OID_ANSI_SECP521R1)
return "nistp521";
return NULL;
}
gint
gkd_ssh_agent_proto_curve_oid_to_hash_algo (GQuark oid)
{
g_return_val_if_fail (oid, -1);
init_quarks ();
/* from rfc5656 */
if (oid == OID_ANSI_SECP256R1)
return G_CHECKSUM_SHA256;
else if (oid == OID_ANSI_SECP384R1)
return G_CHECKSUM_SHA384;
else if (oid == OID_ANSI_SECP521R1)
return G_CHECKSUM_SHA512;
return -1;
}
const gchar*
gkd_ssh_agent_proto_curve_oid_to_keytype (GQuark oid)
{
g_return_val_if_fail (oid, NULL);
init_quarks ();
if (oid == OID_ANSI_SECP256R1)
return "ecdsa-sha2-nistp256";
else if (oid == OID_ANSI_SECP384R1)
return "ecdsa-sha2-nistp384";
else if (oid == OID_ANSI_SECP521R1)
return "ecdsa-sha2-nistp521";
return NULL;
}
const gchar*
gkd_ssh_agent_proto_algo_to_keytype (gulong algo, GQuark curve_oid)
{
if (algo == CKK_RSA) {
g_return_val_if_fail (curve_oid == 0, NULL);
return "ssh-rsa"; return "ssh-rsa";
else if (algo == CKK_DSA) } else if (algo == CKK_DSA) {
g_return_val_if_fail (curve_oid == 0, NULL);
return "ssh-dss"; return "ssh-dss";
} else if (algo == CKK_EC) {
g_return_val_if_fail (curve_oid != 0, NULL);
return gkd_ssh_agent_proto_curve_oid_to_keytype (curve_oid);
}
return NULL; return NULL;
} }
GQuark
gkd_ssh_agent_proto_find_curve_oid (GckAttributes *attrs)
{
GBytes *bytes;
const GckAttribute *attr;
GQuark oid;
g_assert (attrs);
attr = gck_attributes_find (attrs, CKA_EC_PARAMS);
if (attr == NULL)
g_return_val_if_reached (0);
bytes = g_bytes_new (attr->value, attr->length);
oid = gkm_data_der_oid_from_ec_params (bytes);
g_bytes_unref (bytes);
return oid;
}
gboolean gboolean
gkd_ssh_agent_proto_read_mpi (EggBuffer *req, gsize *offset, gkd_ssh_agent_proto_read_mpi (EggBuffer *req, gsize *offset,
GckBuilder *builder, GckBuilder *builder,
...@@ -103,6 +236,27 @@ gkd_ssh_agent_proto_read_mpi_v1 (EggBuffer *req, ...@@ -103,6 +236,27 @@ gkd_ssh_agent_proto_read_mpi_v1 (EggBuffer *req,
return TRUE; return TRUE;
} }
gboolean
gkd_ssh_agent_proto_read_string_to_der (EggBuffer *req,
gsize *offset,
GckBuilder *attrs,
CK_ATTRIBUTE_TYPE type)
{
const guchar *data, *q_data;
gsize len, q_len;
GBytes *bytes;
if (!egg_buffer_get_byte_array (req, *offset, offset, &data, &len))
return FALSE;
bytes = gkm_data_der_encode_ecdsa_q_str (data, len);
q_data = g_bytes_get_data (bytes, &q_len);
gck_builder_add_data (attrs, type, q_data, q_len);
return TRUE;
}
gboolean gboolean
gkd_ssh_agent_proto_write_mpi (EggBuffer *resp, gkd_ssh_agent_proto_write_mpi (EggBuffer *resp,
const GckAttribute *attr) const GckAttribute *attr)
...@@ -147,6 +301,23 @@ gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp, ...@@ -147,6 +301,23 @@ gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp,
return TRUE; return TRUE;
} }
gboolean
gkd_ssh_agent_proto_write_string (EggBuffer *resp,
const GckAttribute *attr)
{
guchar *data;
g_assert (resp);
g_assert (attr);
data = egg_buffer_add_byte_array_empty (resp, attr->length);
if (data == NULL)
return FALSE;
memcpy (data, attr->value, attr->length);
return TRUE;
}
const guchar* const guchar*
gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer *req, gsize *offset, gsize *n_challenge) gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer *req, gsize *offset, gsize *n_challenge)
{ {
...@@ -204,6 +375,9 @@ gkd_ssh_agent_proto_read_public (EggBuffer *req, ...@@ -204,6 +375,9 @@ gkd_ssh_agent_proto_read_public (EggBuffer *req,
case CKK_DSA: case CKK_DSA:
ret = gkd_ssh_agent_proto_read_public_dsa (req, offset, attrs); ret = gkd_ssh_agent_proto_read_public_dsa (req, offset, attrs);
break; break;
case CKK_EC:
ret = gkd_ssh_agent_proto_read_public_ecdsa (req, offset, attrs);
break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
return FALSE; return FALSE;
...@@ -395,11 +569,99 @@ gkd_ssh_agent_proto_read_public_dsa (EggBuffer *req, ...@@ -395,11 +569,99 @@ gkd_ssh_agent_proto_read_public_dsa (EggBuffer *req,
return TRUE; return TRUE;
} }
gboolean
gkd_ssh_agent_proto_read_ecdsa_curve (EggBuffer *req,
gsize *offset,
GckBuilder *attrs)
{
GBytes *params;
gchar *curve_name;
const guchar *params_data;
GQuark oid;
gsize params_len;
g_assert (req);
g_assert (offset);
g_assert (attrs);
/* first part is the curve name (nistp* part of key name) and needs
* to be converted to CKA_EC_PARAMS
*/
if (!egg_buffer_get_string (req, *offset, offset, &curve_name,
(EggBufferAllocator)g_realloc))
return FALSE;
oid = gkd_ssh_agent_proto_curve_to_oid (curve_name);
g_return_val_if_fail (oid, FALSE);
params = gkm_data_der_get_ec_params (oid);
g_return_val_if_fail (params != NULL, FALSE);
params_data = g_bytes_get_data (params, &params_len);
gck_builder_add_data (attrs, CKA_EC_PARAMS, params_data, params_len);
return TRUE;
}
gboolean
gkd_ssh_agent_proto_read_pair_ecdsa (EggBuffer *req,
gsize *offset,
GckBuilder *priv_attrs,
GckBuilder *pub_attrs)
{
const GckAttribute *attr;
g_assert (req);
g_assert (offset);
g_assert (priv_attrs);
g_assert (pub_attrs);
if (!gkd_ssh_agent_proto_read_ecdsa_curve (req, offset, priv_attrs) ||
!gkd_ssh_agent_proto_read_string_to_der (req, offset, priv_attrs, CKA_EC_POINT) ||
!gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_VALUE))
return FALSE;
/* Copy attributes to the public key */
attr = gck_builder_find (priv_attrs, CKA_EC_POINT);
gck_builder_add_attribute (pub_attrs, attr);
attr = gck_builder_find (priv_attrs, CKA_EC_PARAMS);
gck_builder_add_attribute (pub_attrs, attr);
/* Add in your basic other required attributes */
gck_builder_add_ulong (priv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
gck_builder_add_ulong (priv_attrs, CKA_KEY_TYPE, CKK_EC);
gck_builder_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
gck_builder_add_ulong (pub_attrs, CKA_KEY_TYPE, CKK_EC);
return TRUE;
}
gboolean
gkd_ssh_agent_proto_read_public_ecdsa (EggBuffer *req,
gsize *offset,
GckBuilder *attrs)
{
g_assert (req);
g_assert (offset);
g_assert (attrs);
if (!gkd_ssh_agent_proto_read_ecdsa_curve (req, offset, attrs) ||
!gkd_ssh_agent_proto_read_string_to_der (req, offset, attrs, CKA_EC_POINT))
return FALSE;
/* Add in your basic other required attributes */
gck_builder_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY);
gck_builder_add_ulong (attrs, CKA_KEY_TYPE, CKK_EC);
return TRUE;
}
gboolean gboolean
gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs) gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
const gchar *salgo; const gchar *salgo;
GQuark oid = 0;
gulong algo; gulong algo;
g_assert (resp); g_assert (resp);
...@@ -407,8 +669,13 @@ gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs) ...@@ -407,8 +669,13 @@ gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs)
if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &algo)) if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &algo))
g_return_val_if_reached (FALSE); g_return_val_if_reached (FALSE);
if (algo == CKK_EC) {
oid = gkd_ssh_agent_proto_find_curve_oid (attrs);
if (!oid)
return FALSE;
}
salgo = gkd_ssh_agent_proto_algo_to_keytype (algo); salgo = gkd_ssh_agent_proto_algo_to_keytype (algo, oid);
g_assert (salgo); g_assert (salgo);
egg_buffer_add_string (resp, salgo); egg_buffer_add_string (resp, salgo);
...@@ -421,6 +688,10 @@ gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs) ...@@ -421,6 +688,10 @@ gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs)
ret = gkd_ssh_agent_proto_write_public_dsa (resp, attrs); ret = gkd_ssh_agent_proto_write_public_dsa (resp, attrs);
break; break;
case CKK_EC:
ret = gkd_ssh_agent_proto_write_public_ecdsa (resp, attrs);
break;
default: default:
g_return_val_if_reached (FALSE); g_return_val_if_reached (FALSE);
break; break;
...@@ -487,6 +758,55 @@ gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, GckAttributes *attrs) ...@@ -487,6 +758,55 @@ gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, GckAttributes *attrs)
return TRUE; return TRUE;
} }
gboolean
gkd_ssh_agent_proto_write_public_ecdsa (EggBuffer *resp, GckAttributes *attrs)
{
const GckAttribute *attr;
GQuark oid;
const gchar *curve;
guchar *data;
const guchar *q_data;
GBytes *bytes, *q;
gboolean rv;
gsize q_len;
g_assert (resp);
g_assert (attrs);
/* decode curve name from EC_PARAMS */
oid = gkd_ssh_agent_proto_find_curve_oid (attrs);
g_return_val_if_fail (oid, FALSE);
curve = gkd_ssh_agent_proto_oid_to_curve (oid);
g_return_val_if_fail (curve != NULL, FALSE);
data = egg_buffer_add_byte_array_empty (resp, strlen (curve));
if (data == NULL)
return FALSE;
memcpy (data, curve, strlen(curve));
/* decode DER-encoded value Q */
attr = gck_attributes_find (attrs, CKA_EC_POINT);
g_return_val_if_fail (attr, FALSE);
bytes = g_bytes_new_static (attr->value, attr->length);
rv = gkm_data_der_decode_ecdsa_q (bytes, &q);
g_return_val_if_fail (rv, FALSE);
g_bytes_unref (bytes);
q_data = g_bytes_get_data (q, &q_len);
data = egg_buffer_add_byte_array_empty (resp, q_len);
if (data == NULL)
return FALSE;
memcpy (data, q_data, q_len);
g_bytes_unref (q);
return TRUE;
}
gboolean gboolean
gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp, GckAttributes *attrs)