summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2017-11-27 17:25:34 +0100
committerDaiki Ueno <dueno@src.gnome.org>2017-11-29 17:22:17 +0100
commit35a01f8c6eaf3c991aaeb3f66449f41d3f0580bc (patch)
treeaede6c9492a3b8444bbc4e58e31a443a92cb1613
parentf87699bc53a70b63423e7bf122ade29ed6d113e3 (diff)
downloadgnome-keyring-35a01f8c6eaf3c991aaeb3f66449f41d3f0580bc.tar.gz
ssh-agent: Support SHA2 extension for RSA signatures
* Includes the test adjustments IETF draft: https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-12 This will be most probably needed for OpenSSH 7.7p1: https://bugzilla.mindrot.org/show_bug.cgi?id=2799 Signed-off-by: Jakub Jelen <jjelen@redhat.com> https://bugzilla.gnome.org/show_bug.cgi?id=790910
-rw-r--r--daemon/ssh-agent/gkd-ssh-agent-ops.c63
-rw-r--r--daemon/ssh-agent/gkd-ssh-agent-private.h11
-rw-r--r--daemon/ssh-agent/gkd-ssh-agent-proto.c72
-rw-r--r--daemon/ssh-agent/test-keytypes.c47
4 files changed, 129 insertions, 64 deletions
diff --git a/daemon/ssh-agent/gkd-ssh-agent-ops.c b/daemon/ssh-agent/gkd-ssh-agent-ops.c
index ab4becaf..e1cba2d5 100644
--- a/daemon/ssh-agent/gkd-ssh-agent-ops.c
+++ b/daemon/ssh-agent/gkd-ssh-agent-ops.c
@@ -884,6 +884,17 @@ op_v1_request_identities (GkdSshAgentCall *call)
return TRUE;
}
+/* XXX we should create it using asn1x ... */
+static const guchar SHA512_ASN[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */
+ { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04,
+ 0x40 };
+
+static const guchar SHA256_ASN[] = /* Object ID is 2.16.840.1.101.3.4.2.1 */
+ { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
+ 0x20 };
+
static const guchar SHA1_ASN[15] = /* Object ID is 1.3.14.3.2.26 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
@@ -910,9 +921,17 @@ make_pkcs1_sign_hash (GChecksumType algo, const guchar *data, gsize n_data,
if (algo == G_CHECKSUM_SHA1) {
asn = SHA1_ASN;
n_asn = sizeof (SHA1_ASN);
+ } else if (algo == G_CHECKSUM_SHA256) {
+ asn = SHA256_ASN;
+ n_asn = sizeof (SHA256_ASN);
+ } else if (algo == G_CHECKSUM_SHA512) {
+ asn = SHA512_ASN;
+ n_asn = sizeof (SHA512_ASN);
} else if (algo == G_CHECKSUM_MD5) {
asn = MD5_ASN;
n_asn = sizeof (MD5_ASN);
+ } else {
+ g_assert_not_reached();
}
n_hash = n_algo + n_asn;
@@ -1013,6 +1032,7 @@ op_sign_request (GkdSshAgentCall *call)
GChecksumType halgo;
gsize n_hash = 0;
GQuark oid = 0;
+ gint rv;
offset = 5;
@@ -1056,21 +1076,44 @@ op_sign_request (GkdSshAgentCall *call)
return TRUE;
}
- if (mech == CKM_ECDSA) {
+ /* Usually we hash the data with SHA1 */
+ halgo = G_CHECKSUM_SHA1;
+ if (flags & GKD_SSH_FLAG_OLD_SIGNATURE) {
+ halgo = G_CHECKSUM_MD5;
+ }
+ switch (algo) {
+ case CKK_RSA:
+ /* draft-ietf-curdle-rsa-sha2-12 */
+ if (flags & GKD_SSH_FLAG_RSA_SHA2_256) {
+ halgo = G_CHECKSUM_SHA256;
+ } else if (flags & GKD_SSH_FLAG_RSA_SHA2_512) {
+ halgo = G_CHECKSUM_SHA512;
+ }
+ salgo = gkd_ssh_agent_proto_rsa_algo_to_keytype (halgo);
+ break;
+
+ case CKK_EC:
/* 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) {
+ rv = gkd_ssh_agent_proto_curve_oid_to_hash_algo (oid);
+ if (rv == -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;
- } else {
- /* Usually we hash the data with SHA1 */
- halgo = G_CHECKSUM_SHA1;
+ halgo = (GChecksumType) rv;
+ salgo = gkd_ssh_agent_proto_ecc_algo_to_keytype (oid);
+ break;
+
+ case CKK_DSA:
+ /* DSA is using default values */
+ salgo = gkd_ssh_agent_proto_dsa_algo_to_keytype ();
+ break;
+
+ default:
+ g_assert_not_reached ();
}
+ g_assert (salgo);
+
/* Build the hash */
if (mech == CKM_RSA_PKCS)
hash = make_pkcs1_sign_hash (halgo, data, n_data, &n_hash);
@@ -1101,8 +1144,6 @@ op_sign_request (GkdSshAgentCall *call)
blobpos = call->resp->len;
egg_buffer_add_uint32 (call->resp, 0);
- salgo = gkd_ssh_agent_proto_algo_to_keytype (algo, oid);
- g_assert (salgo);
egg_buffer_add_string (call->resp, salgo);
switch (algo) {
diff --git a/daemon/ssh-agent/gkd-ssh-agent-private.h b/daemon/ssh-agent/gkd-ssh-agent-private.h
index 28a1faf2..a6c35a44 100644
--- a/daemon/ssh-agent/gkd-ssh-agent-private.h
+++ b/daemon/ssh-agent/gkd-ssh-agent-private.h
@@ -79,6 +79,8 @@ typedef struct _GkdSshAgentCall {
#define GKD_SSH_DSA_SIGNATURE_PADDING 20
#define GKD_SSH_FLAG_OLD_SIGNATURE 0x01
+#define GKD_SSH_FLAG_RSA_SHA2_256 0x02
+#define GKD_SSH_FLAG_RSA_SHA2_512 0x04
/* -----------------------------------------------------------------------------
* gkd-ssh-agent-ops.c
@@ -103,8 +105,11 @@ void gkd_ssh_agent_checkin_main_session (GckSession*
gulong gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo);
-const gchar* gkd_ssh_agent_proto_algo_to_keytype (gulong algo,
- GQuark oid);
+const gchar* gkd_ssh_agent_proto_rsa_algo_to_keytype (GChecksumType halgo);
+
+const gchar* gkd_ssh_agent_proto_dsa_algo_to_keytype (void);
+
+const gchar* gkd_ssh_agent_proto_ecc_algo_to_keytype (GQuark oid);
GQuark gkd_ssh_agent_proto_curve_to_oid (const gchar *salgo);
@@ -112,8 +117,6 @@ 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,
diff --git a/daemon/ssh-agent/gkd-ssh-agent-proto.c b/daemon/ssh-agent/gkd-ssh-agent-proto.c
index 034bfb9a..522733d1 100644
--- a/daemon/ssh-agent/gkd-ssh-agent-proto.c
+++ b/daemon/ssh-agent/gkd-ssh-agent-proto.c
@@ -66,7 +66,9 @@ gulong
gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo)
{
g_return_val_if_fail (salgo, G_MAXULONG);
- if (strcmp (salgo, "ssh-rsa") == 0)
+ if (strcmp (salgo, "ssh-rsa") == 0 ||
+ strcmp (salgo, "rsa-sha2-256") == 0 ||
+ strcmp (salgo, "rsa-sha2-512") == 0)
return CKK_RSA;
else if (strcmp (salgo, "ssh-dss") == 0)
return CKK_DSA;
@@ -130,9 +132,26 @@ gkd_ssh_agent_proto_curve_oid_to_hash_algo (GQuark oid)
}
const gchar*
-gkd_ssh_agent_proto_curve_oid_to_keytype (GQuark oid)
+gkd_ssh_agent_proto_dsa_algo_to_keytype (void)
{
- g_return_val_if_fail (oid, NULL);
+ return "ssh-dss";
+}
+
+const gchar*
+gkd_ssh_agent_proto_rsa_algo_to_keytype (GChecksumType halgo)
+{
+ if (halgo == G_CHECKSUM_SHA256)
+ return "rsa-sha2-256";
+ else if (halgo == G_CHECKSUM_SHA512)
+ return "rsa-sha2-512";
+
+ return "ssh-rsa";
+}
+
+const gchar*
+gkd_ssh_agent_proto_ecc_algo_to_keytype (GQuark oid)
+{
+ g_return_val_if_fail (oid != 0, NULL);
init_quarks ();
@@ -146,24 +165,6 @@ gkd_ssh_agent_proto_curve_oid_to_keytype (GQuark oid)
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";
- } else if (algo == CKK_DSA) {
- g_return_val_if_fail (curve_oid == 0, NULL);
- 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;
-}
-
-
GQuark
gkd_ssh_agent_proto_find_curve_oid (GckAttributes *attrs)
{
@@ -660,8 +661,6 @@ gboolean
gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs)
{
gboolean ret = FALSE;
- const gchar *salgo;
- GQuark oid = 0;
gulong algo;
g_assert (resp);
@@ -669,15 +668,6 @@ gkd_ssh_agent_proto_write_public (EggBuffer *resp, GckAttributes *attrs)
if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &algo))
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, oid);
- g_assert (salgo);
- egg_buffer_add_string (resp, salgo);
switch (algo) {
case CKK_RSA:
@@ -704,10 +694,16 @@ gboolean
gkd_ssh_agent_proto_write_public_rsa (EggBuffer *resp, GckAttributes *attrs)
{
const GckAttribute *attr;
+ const gchar *salgo;
g_assert (resp);
g_assert (attrs);
+ /* write algorithm identification */
+ salgo = gkd_ssh_agent_proto_rsa_algo_to_keytype (G_CHECKSUM_SHA1);
+ g_assert (salgo);
+ egg_buffer_add_string (resp, salgo);
+
attr = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
g_return_val_if_fail (attr, FALSE);
@@ -727,10 +723,16 @@ gboolean
gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, GckAttributes *attrs)
{
const GckAttribute *attr;
+ const gchar *salgo;
g_assert (resp);
g_assert (attrs);
+ /* write algorithm identification */
+ salgo = gkd_ssh_agent_proto_dsa_algo_to_keytype ();
+ g_assert (salgo);
+ egg_buffer_add_string (resp, salgo);
+
attr = gck_attributes_find (attrs, CKA_PRIME);
g_return_val_if_fail (attr, FALSE);
@@ -769,6 +771,7 @@ gkd_ssh_agent_proto_write_public_ecdsa (EggBuffer *resp, GckAttributes *attrs)
GBytes *bytes, *q;
gboolean rv;
gsize q_len;
+ const gchar *salgo;
g_assert (resp);
g_assert (attrs);
@@ -777,6 +780,11 @@ gkd_ssh_agent_proto_write_public_ecdsa (EggBuffer *resp, GckAttributes *attrs)
oid = gkd_ssh_agent_proto_find_curve_oid (attrs);
g_return_val_if_fail (oid, FALSE);
+ /* write algorithm identification */
+ salgo = gkd_ssh_agent_proto_ecc_algo_to_keytype (oid);
+ g_assert (salgo);
+ egg_buffer_add_string (resp, salgo);
+
curve = gkd_ssh_agent_proto_oid_to_curve (oid);
g_return_val_if_fail (curve != NULL, FALSE);
diff --git a/daemon/ssh-agent/test-keytypes.c b/daemon/ssh-agent/test-keytypes.c
index 0c315b43..e8ed127b 100644
--- a/daemon/ssh-agent/test-keytypes.c
+++ b/daemon/ssh-agent/test-keytypes.c
@@ -39,15 +39,18 @@ struct alg {
gchar *name;
CK_KEY_TYPE id;
gchar *curve_oid;
+ GChecksumType hash;
};
/* known algorithms */
static struct alg algs_known[] = {
- { "ssh-rsa", CKK_RSA, NULL },
- { "ssh-dss", CKK_DSA, NULL },
- { "ecdsa-sha2-nistp256", CKK_EC, GKD_SSH_OID_ANSI_SECP256R1 },
- { "ecdsa-sha2-nistp384", CKK_EC, GKD_SSH_OID_ANSI_SECP384R1 },
- { "ecdsa-sha2-nistp521", CKK_EC, GKD_SSH_OID_ANSI_SECP521R1 },
+ { "ssh-rsa", CKK_RSA, NULL, 0 },
+ { "rsa-sha2-256", CKK_RSA, NULL, G_CHECKSUM_SHA256 },
+ { "rsa-sha2-512", CKK_RSA, NULL, G_CHECKSUM_SHA512 },
+ { "ssh-dss", CKK_DSA, NULL, 0},
+ { "ecdsa-sha2-nistp256", CKK_EC, GKD_SSH_OID_ANSI_SECP256R1, 0 },
+ { "ecdsa-sha2-nistp384", CKK_EC, GKD_SSH_OID_ANSI_SECP384R1, 0 },
+ { "ecdsa-sha2-nistp521", CKK_EC, GKD_SSH_OID_ANSI_SECP521R1, 0 },
/* terminator */
{ NULL, 0, 0 }
@@ -56,16 +59,14 @@ static struct alg algs_known[] = {
/* unknown algorithms */
static struct alg algs_parse_unknown[] = {
/* no certificates */
- { "ssh-rsa-cert-v01@openssh.com", G_MAXULONG, NULL },
- { "ssh-dss-cert-v01@openssh.com", G_MAXULONG, NULL },
- { "ecdsa-sha2-nistp256-cert-v01@openssh.com", G_MAXULONG, NULL },
- { "ecdsa-sha2-nistp384-cert-v01@openssh.com", G_MAXULONG, NULL },
- { "ecdsa-sha2-nistp521-cert-v01@openssh.com", G_MAXULONG, NULL },
+ { "ssh-rsa-cert-v01@openssh.com", G_MAXULONG, NULL, 0 },
+ { "ssh-dss-cert-v01@openssh.com", G_MAXULONG, NULL, 0 },
+ { "ecdsa-sha2-nistp256-cert-v01@openssh.com", G_MAXULONG, NULL, 0 },
+ { "ecdsa-sha2-nistp384-cert-v01@openssh.com", G_MAXULONG, NULL, 0 },
+ { "ecdsa-sha2-nistp521-cert-v01@openssh.com", G_MAXULONG, NULL, 0 },
/* no new signatures/algorithms */
- { "rsa-sha2-256", G_MAXULONG, NULL },
- { "rsa-sha2-512", G_MAXULONG, NULL },
- { "ssh-ed25519", G_MAXULONG, NULL },
- { "ssh-ed25519-cert-v01@openssh.com", G_MAXULONG, NULL },
+ { "ssh-ed25519", G_MAXULONG, NULL, 0 },
+ { "ssh-ed25519-cert-v01@openssh.com", G_MAXULONG, NULL, 0 },
/* terminator */
{ NULL, 0, 0 }
@@ -128,8 +129,20 @@ test_generate (Test *test, gconstpointer unused)
const struct alg *a;
for (a = test->algs_known; a->name != NULL; a++) {
- GQuark oid = g_quark_from_string (a->curve_oid);
- const gchar *alg_name = gkd_ssh_agent_proto_algo_to_keytype (a->id, oid);
+ const gchar *alg_name = NULL;
+ GQuark oid;
+ switch (a->id) {
+ case CKK_RSA:
+ alg_name = gkd_ssh_agent_proto_rsa_algo_to_keytype (a->hash);
+ break;
+ case CKK_EC:
+ oid = g_quark_from_string (a->curve_oid);
+ alg_name = gkd_ssh_agent_proto_ecc_algo_to_keytype (oid);
+ break;
+ case CKK_DSA:
+ alg_name = gkd_ssh_agent_proto_dsa_algo_to_keytype ();
+ break;
+ }
g_assert_cmpstr (a->name, ==, alg_name);
}
}
@@ -143,7 +156,7 @@ test_curve_from_ssh (Test *test, gconstpointer unused)
/* known */
for (a = test->curves; a->name != NULL; a++) {
GQuark oid = g_quark_from_string (a->curve_oid);
- alg_name = gkd_ssh_agent_proto_curve_oid_to_keytype (oid);
+ alg_name = gkd_ssh_agent_proto_ecc_algo_to_keytype (oid);
g_assert_cmpstr (a->name, ==, alg_name);
}
}