[gnome-keyring] ssh-agent: Support SHA2 extension for RSA signatures



commit 35a01f8c6eaf3c991aaeb3f66449f41d3f0580bc
Author: Jakub Jelen <jjelen redhat com>
Date:   Mon Nov 27 17:25:34 2017 +0100

    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

 daemon/ssh-agent/gkd-ssh-agent-ops.c     |   63 +++++++++++++++++++++-----
 daemon/ssh-agent/gkd-ssh-agent-private.h |   11 +++--
 daemon/ssh-agent/gkd-ssh-agent-proto.c   |   72 ++++++++++++++++-------------
 daemon/ssh-agent/test-keytypes.c         |   47 ++++++++++++-------
 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 ab4beca..e1cba2d 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 28a1faf..a6c35a4 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 034bfb9..522733d 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 0c315b4..e8ed127 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);
        }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]