Commit 35a01f8c authored by Jakub Jelen's avatar Jakub Jelen Committed by Daiki Ueno

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=2799Signed-off-by: 's avatarJakub Jelen <jjelen@redhat.com>

https://bugzilla.gnome.org/show_bug.cgi?id=790910
parent f87699bc
......@@ -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) {
......
......@@ -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,
......
......@@ -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);
......
......@@ -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);
}
}
......
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