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

[PATCH] Support for private keys in OpenSSH format


Hello all,
the attached patch set provides support and tests for all the supported
key types in new OpenSSH format, which is default since OpenSSH 7.8. It
is also available in gitlab mirror:

https://gitlab.com/jjelen/libssh-mirror/tree/openssh-keys

Applying this patch set will allow us to revert commit 100c9c98, which
modified the pkd test to generate keys in old format, but it is not a
requirement.

The code is generally functional, but in crypto backend, I did not
implement calculation of additional RSA parameters, that are not part
of the key format, but can be calculated from others. OpenSSL can work
without these parameters, but might be slower.

We can inspire in OpenSSH code, which calculates these parameters the
following way:

https://github.com/openssh/openssh-portable/blob/master/ssh-rsa.c#L107

I will be on vacation until next Tuesday, so I will address potential
review comments later.

Regards,
-- 
Jakub Jelen
Software Engineer
Security Technologies
Red Hat, Inc.
From d7bf545cf9079a3a978aa0031fd3dcc195bf33a9 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Wed, 29 Aug 2018 19:16:37 +0200
Subject: [PATCH 1/5] tests: Drop duplicate ed25519 key creation

---
 tests/torture.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/tests/torture.c b/tests/torture.c
index 5f9f67b3..e442b425 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -652,13 +652,6 @@ static void torture_setup_create_sshd_config(void **state)
     torture_write_file(ecdsa_hostkey,
                        torture_get_testkey(SSH_KEYTYPE_ECDSA, 521, 0));
 
-    snprintf(ed25519_hostkey,
-             sizeof(ed25519_hostkey),
-             "%s/sshd/ssh_host_ed25519_key",
-             s->socket_dir);
-    torture_write_file(ed25519_hostkey,
-                       torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 0));
-
     snprintf(trusted_ca_pubkey,
              sizeof(trusted_ca_pubkey),
              "%s/sshd/user_ca.pub",
-- 
2.17.1


From 351040a0f235d4c7b027e8d4019719360daaac55 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 6 Sep 2018 10:46:36 +0200
Subject: [PATCH 2/5] buffer: typo

---
 src/buffer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/buffer.c b/src/buffer.c
index 8cc01c74..32ab9139 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1217,7 +1217,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
     }
 
     if (rc != SSH_ERROR){
-        /* Check if our canary is intact, if not somthing really bad happened */
+        /* Check if our canary is intact, if not something really bad happened */
         uint32_t canary = va_arg(ap, uint32_t);
         if (canary != SSH_BUFFER_PACK_END){
             if (argc == -1){
-- 
2.17.1


From 0b820526f8b74013fef760ab543cc1db12ab83c2 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 6 Sep 2018 16:52:32 +0200
Subject: [PATCH 3/5] tests: Provide testing keys also in OpenSSH format

This extends the torture API to provide a way to request
keys in different formats. This extends the keys with
private keys in the new OpenSSH format (default since
OpenSSH 7.8).

This also needs modifications to the ed25519 tests, which
do not support PEM format and expected the new format out of the
box.

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/torture.c                       |   2 +-
 tests/torture_key.c                   | 249 +++++++++++++++++++++++++-
 tests/torture_key.h                   |   6 +
 tests/unittests/torture_pki_ed25519.c |  33 ++--
 4 files changed, 272 insertions(+), 18 deletions(-)

diff --git a/tests/torture.c b/tests/torture.c
index e442b425..95da3c67 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -629,7 +629,7 @@ static void torture_setup_create_sshd_config(void **state)
              "%s/sshd/ssh_host_ed25519_key",
              s->socket_dir);
     torture_write_file(ed25519_hostkey,
-                       torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 0));
+                       torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 0));
 
 #ifdef HAVE_DSA
     snprintf(dsa_hostkey,
diff --git a/tests/torture_key.c b/tests/torture_key.c
index c0ec845a..b0cce335 100644
--- a/tests/torture_key.c
+++ b/tests/torture_key.c
@@ -91,6 +91,70 @@ static const char torture_rsa_private_testkey_passphrase[] =
         "JSvUyxoaZUjQkT7iF94HsF+FVVJdI55UjgnMiZ0d5vKffWyTHYcYHkFYaSloAMWN\n"
         "-----END RSA PRIVATE KEY-----\n";
 
+static const char torture_rsa_private_openssh_testkey_passphrase[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "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\n"
+        "FBRkf+Jj9eVXieT4PJKtWuvxNNrJVA==\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+static const char torture_rsa_private_openssh_testkey[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "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\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+
 static const char torture_rsa_public_testkey[] =
         "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsA5ERRaUFckApnmEAFjLGdFrIN"
         "k/Vsl4ts9Ur6enF6auEfJmCN1tjcAOi34lHJaO+WXbDYYj7duW3SP7H9lbCMwq79B"
@@ -161,6 +225,55 @@ static const char torture_dsa_private_testkey_passphrase[] =
         "wHBOL6HrOnD+gGs6DUFwzA==\n"
         "-----END DSA PRIVATE KEY-----\n";
 
+static const char torture_dsa_private_openssh_testkey_passphrase[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBC\n"
+        "UZK61oXs3uKMs4l7G0cpAAAAEAAAAAEAAAGxAAAAB3NzaC1kc3MAAACBAJTK9U8S\n"
+        "SfdSdkOPMLNLNIelOW3OvQRz7WbP8kAKMcwEn0L9b8/C8ffKOR+gWGFES+hjsg+f\n"
+        "AC7ltzHDxOQhKrthE5DjT0+rDA+/LQ3cZSn/6QpLbrwEgn5Uo3nXddF/t4vV7hod\n"
+        "Qn5qX3HUnFOZzpPQYGrWXK74JNRTKHblo0MXAAAAFQCvOI9tBplPs3sI0MLCF7lW\n"
+        "+gvzxwAAAIBeG4hWwnFRAnmdZBEt/ujdcQZD4RxWYc7MwHXEKweNiekSGFyj6v8c\n"
+        "NlIPfWTMN4BlTJzPfVaoYvzJev45lEuoSwYLt3AQDM+JcO6XTMdyXTKIo+tGsuA0\n"
+        "kd4pxPol+UGeAruNBEhVSDcXfXTh9tVravBqeIuXgZIFk9cylR2eDwAAAIB4roDQ\n"
+        "Bfgf8AoSAJAb7y8OVvxt5cT7iqaRMQX2XgtW09Nu9RbUIVS7n2mw3iqZG0xnG3iv\n"
+        "1oL9gwNXMLlf+gLmsqU3788jaEZ9IhZ8VdgHAoHm6UWM7b2uADmhirI6dRZUVO+/\n"
+        "iMGUvDxa66OI4hDV055pbwQhtxupUatThyDzIgAAAeAtGFEW6JZTeSumizZJI4T2\n"
+        "Kha05Ze3juTeW+BMjqTcf77yAL2jvsljogCtu4+5CWWO4g+cr80vyVytji6IYTNM\n"
+        "MPn1qe6dHXnfmgtiegHXxrjr5v5/i1cvD32Bxffy+yjR9kbV9GJYF+K5pfYVpQBa\n"
+        "XVmq6AJUPd/yxKw6jRGZJi8GTcrKbCZAL+VYSPwc0veCrmGPjeeMCgYcEXPvhSui\n"
+        "P0JnG1Ap12FeK+61rIbZBAr7qbTGJi5Z5HlDlgon2tmMZOkIuL1Oytgut4MpmYjP\n"
+        "ph+qrzgwfSwOsjVIuHlb1L0phWRlgbT8lmysEE7McGKWiCOabxgl3NF9lClhDBb9\n"
+        "nzupkK1cg/4p17USYMOdeNhTmJ0DkQT+8UenfBOmzV7kamLlEYXJdDZBN//dZ8UR\n"
+        "KEzAzpaAVIyJQ+wvCUIh/VO8sJP+3q4XQUkv0QcIRlc0+r9qbW2Tqv3vajFcFtK6\n"
+        "nrTmIJVL0pG+z/93Ncpy5susD+JvhJ4yfl7Jet3jy4fWwm3qkLl0WsobJ7Om+GyH\n"
+        "DzHH9RgDk3XuUHS/fz+kTwmtyIH/Rq1jIt+s+T8iA9CzKSX6sBu2yfMo1w2/LbCx\n"
+        "Xy1rHS42TePw28m1cQuUfjqdOC3IBgQ1m3x2f1on7hk=\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+static const char torture_dsa_private_openssh_testkey[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdz\n"
+        "c2gtZHNzAAAAgQCUyvVPEkn3UnZDjzCzSzSHpTltzr0Ec+1mz/JACjHMBJ9C/W/P\n"
+        "wvH3yjkfoFhhREvoY7IPnwAu5bcxw8TkISq7YROQ409PqwwPvy0N3GUp/+kKS268\n"
+        "BIJ+VKN513XRf7eL1e4aHUJ+al9x1JxTmc6T0GBq1lyu+CTUUyh25aNDFwAAABUA\n"
+        "rziPbQaZT7N7CNDCwhe5VvoL88cAAACAXhuIVsJxUQJ5nWQRLf7o3XEGQ+EcVmHO\n"
+        "zMB1xCsHjYnpEhhco+r/HDZSD31kzDeAZUycz31WqGL8yXr+OZRLqEsGC7dwEAzP\n"
+        "iXDul0zHcl0yiKPrRrLgNJHeKcT6JflBngK7jQRIVUg3F3104fbVa2rwaniLl4GS\n"
+        "BZPXMpUdng8AAACAeK6A0AX4H/AKEgCQG+8vDlb8beXE+4qmkTEF9l4LVtPTbvUW\n"
+        "1CFUu59psN4qmRtMZxt4r9aC/YMDVzC5X/oC5rKlN+/PI2hGfSIWfFXYBwKB5ulF\n"
+        "jO29rgA5oYqyOnUWVFTvv4jBlLw8WuujiOIQ1dOeaW8EIbcbqVGrU4cg8yIAAAHY\n"
+        "tbI937WyPd8AAAAHc3NoLWRzcwAAAIEAlMr1TxJJ91J2Q48ws0s0h6U5bc69BHPt\n"
+        "Zs/yQAoxzASfQv1vz8Lx98o5H6BYYURL6GOyD58ALuW3McPE5CEqu2ETkONPT6sM\n"
+        "D78tDdxlKf/pCktuvASCflSjedd10X+3i9XuGh1CfmpfcdScU5nOk9BgatZcrvgk\n"
+        "1FModuWjQxcAAAAVAK84j20GmU+zewjQwsIXuVb6C/PHAAAAgF4biFbCcVECeZ1k\n"
+        "ES3+6N1xBkPhHFZhzszAdcQrB42J6RIYXKPq/xw2Ug99ZMw3gGVMnM99Vqhi/Ml6\n"
+        "/jmUS6hLBgu3cBAMz4lw7pdMx3JdMoij60ay4DSR3inE+iX5QZ4Cu40ESFVINxd9\n"
+        "dOH21Wtq8Gp4i5eBkgWT1zKVHZ4PAAAAgHiugNAF+B/wChIAkBvvLw5W/G3lxPuK\n"
+        "ppExBfZeC1bT0271FtQhVLufabDeKpkbTGcbeK/Wgv2DA1cwuV/6AuaypTfvzyNo\n"
+        "Rn0iFnxV2AcCgebpRYztva4AOaGKsjp1FlRU77+IwZS8PFrro4jiENXTnmlvBCG3\n"
+        "G6lRq1OHIPMiAAAAFQCNR3fP4j87IO2086Db40C/jaMosgAAAAABAg==\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
 static const char torture_dsa_public_testkey[] =
         "ssh-dss AAAAB3NzaC1kc3MAAACBAJTK9U8SSfdSdkOPMLNLNIelOW3OvQRz7WbP8k"
         "AKMcwEn0L9b8/C8ffKOR+gWGFES+hjsg+fAC7ltzHDxOQhKrthE5DjT0+rDA+/LQ3c"
@@ -222,6 +335,29 @@ static const char torture_ecdsa256_private_testkey_passphrase[] =
         "8VZn2VJDaitLy8ARqA/lMGQfqHSa3EOqti9FzWG/P6s=\n"
         "-----END EC PRIVATE KEY-----\n";
 
+static const char torture_ecdsa256_private_openssh_testkey[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNl\n"
+        "Y2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTH7253zxDkZa0t37Iy\n"
+        "1hpqkLzmD7ZkuntW0UcDQRs0eoFRDGiH4iTz0yWvsBTFwU936QKj40TrKr+Y1Bwv\n"
+        "sTqJAAAAmOuDchHrg3IRAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy\n"
+        "NTYAAABBBMfvbnfPEORlrS3fsjLWGmqQvOYPtmS6e1bRRwNBGzR6gVEMaIfiJPPT\n"
+        "Ja+wFMXBT3fpAqPjROsqv5jUHC+xOokAAAAgEIN55hgC1fcSew/Stq3BWk1NoD/g\n"
+        "rU3pW8cyJRmVV2EAAAAA\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+static const char torture_ecdsa256_private_openssh_testkey_pasphrase[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABA+\n"
+        "O0w3yPZF2q0FjVBhQjn2AAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAy\n"
+        "NTYAAAAIbmlzdHAyNTYAAABBBMfvbnfPEORlrS3fsjLWGmqQvOYPtmS6e1bRRwNB\n"
+        "GzR6gVEMaIfiJPPTJa+wFMXBT3fpAqPjROsqv5jUHC+xOokAAACghvb4EX8M06UB\n"
+        "zigxOn9bg5cZkZ2yWY8jzxtOWH4YJXsuhON/jePDJuI2ro5u4iKFD1u2JLfcshdh\n"
+        "vKZyjixU9KdewykQQt/wFkrCfNUyCH8jFiQsAqhBfopRFyDJV9pmcUBL/3fJqwut\n"
+        "ZeBSfA7tXORp3xrwFI1tXiiUCM+/nhxiCsFaCJXeiM3tN+kFtwQ8kamINqwaC8Vj\n"
+        "lFLKHDfwJQ==\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
 static const char torture_ecdsa256_public_testkey[] =
         "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNT"
         "YAAABBBMfvbnfPEORlrS3fsjLWGmqQvOYPtmS6e1bRRwNBGzR6gVEMaIfiJPPTJa+w"
@@ -245,6 +381,31 @@ static const char torture_ecdsa384_private_testkey_passphrase[] =
         "8VZn2VJDaitLy8ARqA/lMGQfqHSa3EOqti9FzWG/P6s=\n"
         "-----END EC PRIVATE KEY-----\n";
 
+static const char torture_ecdsa384_private_openssh_testkey[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNl\n"
+        "Y2RzYS1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRXc4BN6BrVo1QMi3+i\n"
+        "/B85Lu7SMuzBi+1PbJti8xz+Szgq64gaBGOK9o+WOdLAd/w7p7DJLdztJ0bYoyT4\n"
+        "V3B3ZqR9RyGq6mYCjkXlc5YbYHjueBbp0oeNXqsXHNAWQZoAAADIITfDfiE3w34A\n"
+        "AAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEEV3OATega1aNU\n"
+        "DIt/ovwfOS7u0jLswYvtT2ybYvMc/ks4KuuIGgRjivaPljnSwHf8O6ewyS3c7SdG\n"
+        "2KMk+Fdwd2akfUchqupmAo5F5XOWG2B47ngW6dKHjV6rFxzQFkGaAAAAMFjyMRrk\n"
+        "O1HLgBV5NaE8n9Mrbntt6GILe5p8SLpgDagc5GJupfnkQM3DPb0xPjSZBAAAAAA=\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+static const char torture_ecdsa384_private_openssh_testkey_passphrase[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB4N\n"
+        "dKGEoxFeg6dqiR2vTl6AAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzOD\n"
+        "QAAAAIbmlzdHAzODQAAABhBFdzgE3oGtWjVAyLf6L8Hzku7tIy7MGL7U9sm2LzHP5\n"
+        "LOCrriBoEY4r2j5Y50sB3/DunsMkt3O0nRtijJPhXcHdmpH1HIarqZgKOReVzlhtg\n"
+        "eO54FunSh41eqxcc0BZBmgAAANDOL7sWcylFf8SsjGVFvr36mpyUBpAJ/e7o4RbQg\n"
+        "H8FDu1IxscOfbLDoB3CV7UEIgG58nVsDamfL6rXV/tzWnPxYxi6jUHcKT1BugO/Jt\n"
+        "/ncelMeoAS6MAZhElaGKzU1cJMlMTV9ofmuKuAwllQULG7L8lwHs9whBK4JmWPaGL\n"
+        "pU3i9ZoT33/g6pcvA83vicCNqj7ggl6Vb9MeO/zGW1+oV2HC3WiLTqBsYxEJu4YCM\n"
+        "ewfx9pWeWaCllNy/F1rCBu3cxqzcge9hqIlNtpT7Dq3k\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
 static const char torture_ecdsa384_public_testkey[] =
         "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzOD"
         "QAAABhBFdzgE3oGtWjVAyLf6L8Hzku7tIy7MGL7U9sm2LzHP5LOCrriBoEY4r2j5Y5"
@@ -272,6 +433,36 @@ static const char torture_ecdsa521_private_testkey_passphrase[] =
         "uRzL95L05ctOBGYNYqpPNIX3UdQU07kzwNC+yaHOb2s=\n"
         "-----END EC PRIVATE KEY-----\n";
 
+static const char torture_ecdsa521_private_openssh_testkey[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNl\n"
+        "Y2RzYS1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQBzoPvbx1tpCQedI+3\n"
+        "O1pHAnDrcIGXXlzKQHhJde7BZ0060/MGKNRQsxNO8FdutryAvgBN311Ce7CfwpBS\n"
+        "HZP/P4EBGNY8qFwdwbHntelcISRrDMxhodRSdF14USY1GxtfKmx/SYkoBNTeHyDN\n"
+        "MyRuvHwMlMUcQiNcFKGzjgexJhWXdfIAAAEAt6sYz7erGM8AAAATZWNkc2Etc2hh\n"
+        "Mi1uaXN0cDUyMQAAAAhuaXN0cDUyMQAAAIUEAc6D728dbaQkHnSPtztaRwJw63CB\n"
+        "l15cykB4SXXuwWdNOtPzBijUULMTTvBXbra8gL4ATd9dQnuwn8KQUh2T/z+BARjW\n"
+        "PKhcHcGx57XpXCEkawzMYaHUUnRdeFEmNRsbXypsf0mJKATU3h8gzTMkbrx8DJTF\n"
+        "HEIjXBShs44HsSYVl3XyAAAAQgC83nSJ2SLoiBvEku1JteQKWx/Xt6THksgC7rrI\n"
+        "aTUmNzk+60f0sCCmGll0dgrZLmeIw+TtnG1E20VZflCKq+IdkQAAAAABAg==\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+static const char torture_ecdsa521_private_openssh_testkey_passphrase[] =
+        "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+        "b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAj\n"
+        "9WBFa/piJcPFEE4CGZTKAAAAEAAAAAEAAACsAAAAE2VjZHNhLXNoYTItbmlzdHA1\n"
+        "MjEAAAAIbmlzdHA1MjEAAACFBAHOg+9vHW2kJB50j7c7WkcCcOtwgZdeXMpAeEl1\n"
+        "7sFnTTrT8wYo1FCzE07wV262vIC+AE3fXUJ7sJ/CkFIdk/8/gQEY1jyoXB3Bsee1\n"
+        "6VwhJGsMzGGh1FJ0XXhRJjUbG18qbH9JiSgE1N4fIM0zJG68fAyUxRxCI1wUobOO\n"
+        "B7EmFZd18gAAAQDLjaKp+DLEHFb98f5WnVFg6LgDN847sfeuPZVfVjeSAiIv016O\n"
+        "ld7DXb137B2xYVsuce6sHbypr10dJOvgMTLdzTl+crYNJL+8UufJP0rOIFaDenzQ\n"
+        "RW8wydwiQxwt1ZqtD8ASqFmadxngufJKZzPLGfjCbCz3uATKa2sXN66nRXRZJbVA\n"
+        "IlNYDY8ivAStNhfItUMqyM6PkYlKJECtJw7w7TYKpvts7t72JmtgqVjS45JI/YZ+\n"
+        "kitIG0YmG8rzL9d1vBB5m+MH/fnFz2uJqbQYCH9Ctc8HZodAVoTNDzXHU2mYF9PE\n"
+        "Z6+gi3jd+kOyUk3NifHcre9K6ie7LL33JayM\n"
+        "-----END OPENSSH PRIVATE KEY-----\n";
+
+
 static const char torture_ecdsa521_public_testkey[] =
         "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1Mj"
         "EAAACFBAHOg+9vHW2kJB50j7c7WkcCcOtwgZdeXMpAeEl17sFnTTrT8wYo1FCzE07w"
@@ -308,53 +499,92 @@ static const char torture_ed25519_public_testkey[] =
 static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
                                                 int bits,
                                                 int with_passphrase,
-                                                int pubkey)
+                                                int pubkey,
+                                                int format)
 {
     switch (type) {
         case SSH_KEYTYPE_DSS:
             if (pubkey) {
                 return torture_dsa_public_testkey;
             } else if (with_passphrase) {
+                if (format == 1) {
+                    return torture_dsa_private_openssh_testkey_passphrase;
+                }
                 return torture_dsa_private_testkey_passphrase;
             }
+            if (format == 1) {
+                return torture_dsa_private_openssh_testkey;
+            }
             return torture_dsa_private_testkey;
         case SSH_KEYTYPE_RSA:
             if (pubkey) {
                 return torture_rsa_public_testkey;
             } else if (with_passphrase) {
+                if (format == 1) {
+                    return torture_rsa_private_openssh_testkey_passphrase;
+                }
                 return torture_rsa_private_testkey_passphrase;
             }
+            if (format == 1) {
+                return torture_rsa_private_openssh_testkey;
+            }
             return torture_rsa_private_testkey;
         case SSH_KEYTYPE_ECDSA:
             if (bits == 521) {
                 if (pubkey) {
                     return torture_ecdsa521_public_testkey;
                 } else if (with_passphrase) {
+                    if (format == 1) {
+                        return torture_ecdsa521_private_openssh_testkey_passphrase;
+                    }
                     return torture_ecdsa521_private_testkey_passphrase;
                 }
+                if (format == 1) {
+                    return torture_ecdsa521_private_openssh_testkey;
+                }
                 return torture_ecdsa521_private_testkey;
             } else if (bits == 384) {
                 if (pubkey) {
                     return torture_ecdsa384_public_testkey;
                 } else if (with_passphrase){
+                    if (format == 1) {
+                        return torture_ecdsa384_private_openssh_testkey_passphrase;
+                    }
                     return torture_ecdsa384_private_testkey_passphrase;
                 }
+                if (format == 1) {
+                    return torture_ecdsa384_private_openssh_testkey;
+                }
                 return torture_ecdsa384_private_testkey;
             }
 
             if (pubkey) {
                 return torture_ecdsa256_public_testkey;
             } else if (with_passphrase){
+                if (format == 1) {
+                    return torture_ecdsa256_private_openssh_testkey_pasphrase;
+                }
                 return torture_ecdsa256_private_testkey_passphrase;
             }
+            if (format == 1) {
+                return torture_ecdsa256_private_openssh_testkey;
+            }
             return torture_ecdsa256_private_testkey;
         case SSH_KEYTYPE_ED25519:
             if (pubkey) {
                 return torture_ed25519_public_testkey;
             } else if (with_passphrase) {
-                return torture_ed25519_private_testkey_passphrase;
+                if (format == 1) {
+                    return torture_ed25519_private_testkey_passphrase;
+                }
+                /* ed25519 keys are not available in legacy PEM format */
+                return NULL;
             }
-            return torture_ed25519_private_testkey;
+            if (format == 1) {
+                return torture_ed25519_private_testkey;
+            }
+            /* ed25519 keys are not available in legacy PEM format */
+            return NULL;
         case SSH_KEYTYPE_DSS_CERT01:
             return torture_dsa_testkey_cert;
         case SSH_KEYTYPE_RSA_CERT01:
@@ -367,16 +597,25 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
     return NULL;
 }
 
+/* Return the encrypted private key in a new OpenSSH format */
+const char *torture_get_openssh_testkey(enum ssh_keytypes_e type,
+                                        int ecda_bits,
+                                        int with_passphrase)
+{
+    return torture_get_testkey_internal(type, ecda_bits, with_passphrase, 0, 1);
+}
+
+/* Return the private key in the legacy PEM format */
 const char *torture_get_testkey(enum ssh_keytypes_e type,
                                 int ecda_bits,
                                 int with_passphrase)
 {
-    return torture_get_testkey_internal(type, ecda_bits, with_passphrase, 0);
+    return torture_get_testkey_internal(type, ecda_bits, with_passphrase, 0, 0);
 }
 
 const char *torture_get_testkey_pub(enum ssh_keytypes_e type, int ecda_bits)
 {
-    return torture_get_testkey_internal(type, ecda_bits, 0, 1);
+    return torture_get_testkey_internal(type, ecda_bits, 0, 1, 0);
 }
 
 const char *torture_get_testkey_passphrase(void)
diff --git a/tests/torture_key.h b/tests/torture_key.h
index f5f54250..5ad85d0f 100644
--- a/tests/torture_key.h
+++ b/tests/torture_key.h
@@ -26,6 +26,12 @@
 
 #define TORTURE_TESTKEY_PASSWORD "libssh-rocks"
 
+/* Return the encrypted private key in a new OpenSSH format */
+const char *torture_get_openssh_testkey(enum ssh_keytypes_e type,
+                                        int ecdsa_bits,
+                                        int with_passphrase);
+
+/* Return the private key in the legacy PEM format */
 const char *torture_get_testkey(enum ssh_keytypes_e type,
                                 int ecdsa_bits,
                                 int with_passphrase);
diff --git a/tests/unittests/torture_pki_ed25519.c b/tests/unittests/torture_pki_ed25519.c
index 98c96a59..b21641b9 100644
--- a/tests/unittests/torture_pki_ed25519.c
+++ b/tests/unittests/torture_pki_ed25519.c
@@ -21,16 +21,18 @@ const uint8_t ref_signature[ED25519_SIG_LEN]=
 
 static int setup_ed25519_key(void **state)
 {
+    const char *keystring = NULL;
+
     (void) state; /* unused */
 
     unlink(LIBSSH_ED25519_TESTKEY);
     unlink(LIBSSH_ED25519_TESTKEY_PASSPHRASE);
     unlink(LIBSSH_ED25519_TESTKEY ".pub");
 
-    torture_write_file(LIBSSH_ED25519_TESTKEY,
-                       torture_get_testkey(SSH_KEYTYPE_ED25519, 0,0));
-    torture_write_file(LIBSSH_ED25519_TESTKEY_PASSPHRASE,
-                       torture_get_testkey(SSH_KEYTYPE_ED25519, 0,0));
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 0);
+    torture_write_file(LIBSSH_ED25519_TESTKEY, keystring);
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 1);
+    torture_write_file(LIBSSH_ED25519_TESTKEY_PASSPHRASE, keystring);
 
     torture_write_file(LIBSSH_ED25519_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_ED25519,0));
@@ -84,10 +86,12 @@ static void torture_pki_ed25519_publickey_from_privatekey(void **state)
     ssh_key key = NULL;
     ssh_key pubkey = NULL;
     const char *passphrase = NULL;
+    const char *keystring = NULL;
 
     (void) state; /* unused */
 
-    rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 0),
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 0);
+    rc = ssh_pki_import_privkey_base64(keystring,
                                        passphrase,
                                        NULL,
                                        NULL,
@@ -319,10 +323,12 @@ static void torture_pki_ed25519_write_privkey(void **state)
     ssh_key_free(privkey);
 }
 
-static void torture_pki_ed25519_sign(void **state){
+static void torture_pki_ed25519_sign(void **state)
+{
     ssh_key privkey = NULL;
     ssh_signature sig = NULL;
     ssh_string blob = NULL;
+    const char *keystring = NULL;
     int rc;
 
     (void)state;
@@ -330,9 +336,8 @@ static void torture_pki_ed25519_sign(void **state){
     sig = ssh_signature_new();
     assert_non_null(sig);
 
-    rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519,
-                                                           0,
-                                                           0),
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 0);
+    rc = ssh_pki_import_privkey_base64(keystring,
                                        NULL,
                                        NULL,
                                        NULL,
@@ -429,11 +434,13 @@ static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state)
     int rc;
     ssh_key key = NULL;
     const char *passphrase = torture_get_testkey_passphrase();
+    const char *testkey = NULL;
 
     (void) state; /* unused */
 
     /* same for ED25519 */
-    rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 1),
+    testkey = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 1);
+    rc = ssh_pki_import_privkey_base64(testkey,
                                        passphrase,
                                        NULL,
                                        NULL,
@@ -447,7 +454,7 @@ static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state)
     key = NULL;
 
     /* test if it returns -1 if passphrase is wrong */
-    rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 1),
+    rc = ssh_pki_import_privkey_base64(testkey,
                                        "wrong passphrase !!",
                                        NULL,
                                        NULL,
@@ -461,11 +468,13 @@ static void torture_pki_ed25519_privkey_dup(void **state)
     const char *passphrase = torture_get_testkey_passphrase();
     ssh_key key = NULL;
     ssh_key dup = NULL;
+    const char *testkey = NULL;
     int rc;
 
     (void) state; /* unused */
 
-    rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 1),
+    testkey = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0, 1);
+    rc = ssh_pki_import_privkey_base64(testkey,
                                        passphrase,
                                        NULL,
                                        NULL,
-- 
2.17.1


From df0101ee48c1f8ad2614cb8a282fc4ad6b9ac346 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 6 Sep 2018 17:53:19 +0200
Subject: [PATCH 4/5] pki: Allow reading keys in new OpenSSH format

This implements reading the OpenSSH key format accross the
cryptographic backends. Most of the code is shared and moved
to pki.c, just the building of the keys is implemented in
pki_privkey_build_*() functions.

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 include/libssh/pki_priv.h   |  26 ++++
 src/pki.c                   | 269 ++++++++++++++++++++++++++++++++++++
 src/pki_container_openssh.c |  56 +-------
 src/pki_crypto.c            | 146 +++++++++++++++++++
 src/pki_ed25519.c           |  22 +++
 src/pki_gcrypt.c            |  63 +++++++++
 src/pki_mbedcrypto.c        | 140 +++++++++++++++++++
 7 files changed, 670 insertions(+), 52 deletions(-)

diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h
index fe7e92a8..f8d94616 100644
--- a/include/libssh/pki_priv.h
+++ b/include/libssh/pki_priv.h
@@ -72,6 +72,9 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
                                   const char *passphrase,
                                   ssh_auth_callback auth_fn,
                                   void *auth_data);
+int pki_import_privkey_buffer(enum ssh_keytypes_e type,
+                              ssh_buffer buffer,
+                              ssh_key *pkey);
 
 /* SSH Public Key Functions */
 int pki_pubkey_build_dss(ssh_key key,
@@ -85,6 +88,26 @@ int pki_pubkey_build_rsa(ssh_key key,
 int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
 ssh_string pki_publickey_to_blob(const ssh_key key);
 
+/* SSH Private Key Functions */
+int pki_privkey_build_dss(ssh_key key,
+                          ssh_string p,
+                          ssh_string q,
+                          ssh_string g,
+                          ssh_string pubkey,
+                          ssh_string privkey);
+int pki_privkey_build_rsa(ssh_key key,
+                          ssh_string n,
+                          ssh_string e,
+                          ssh_string d,
+                          ssh_string iqmp,
+                          ssh_string p,
+                          ssh_string q);
+int pki_privkey_build_ecdsa(ssh_key key,
+                            int nid,
+                            ssh_string e,
+                            ssh_string exp);
+ssh_string pki_publickey_to_blob(const ssh_key key);
+
 /* SSH Signature Functions */
 ssh_string pki_signature_to_blob(const ssh_signature sign);
 ssh_signature pki_signature_from_blob(const ssh_key pubkey,
@@ -121,6 +144,9 @@ int pki_ed25519_key_dup(ssh_key new, const ssh_key key);
 int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
 ssh_string pki_ed25519_sig_to_blob(ssh_signature sig);
 int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
+int pki_privkey_build_ed25519(ssh_key key,
+                              ssh_string pubkey,
+                              ssh_string privkey);
 
 /* PKI Container OpenSSH */
 ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
diff --git a/src/pki.c b/src/pki.c
index 821df576..51410bdd 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -810,6 +810,275 @@ ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key) {
     return privkey;
 }
 
+int pki_import_privkey_buffer(enum ssh_keytypes_e type,
+                              ssh_buffer buffer,
+                              ssh_key *pkey)
+{
+    ssh_key key;
+    int rc;
+
+    key = ssh_key_new();
+    if (key == NULL) {
+        return SSH_ERROR;
+    }
+
+    key->type = type;
+    key->type_c = ssh_key_type_to_char(type);
+    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
+
+    switch (type) {
+        case SSH_KEYTYPE_DSS:
+            {
+                ssh_string p;
+                ssh_string q;
+                ssh_string g;
+                ssh_string pubkey;
+                ssh_string privkey;
+
+                p = ssh_buffer_get_ssh_string(buffer);
+                if (p == NULL) {
+                    goto fail;
+                }
+                q = ssh_buffer_get_ssh_string(buffer);
+                if (q == NULL) {
+                    ssh_string_burn(p);
+                    ssh_string_free(p);
+
+                    goto fail;
+                }
+                g = ssh_buffer_get_ssh_string(buffer);
+                if (g == NULL) {
+                    ssh_string_burn(p);
+                    ssh_string_free(p);
+                    ssh_string_burn(q);
+                    ssh_string_free(q);
+
+                    goto fail;
+                }
+                pubkey = ssh_buffer_get_ssh_string(buffer);
+                if (pubkey == NULL) {
+                    ssh_string_burn(p);
+                    ssh_string_free(p);
+                    ssh_string_burn(q);
+                    ssh_string_free(q);
+                    ssh_string_burn(g);
+                    ssh_string_free(g);
+
+                    goto fail;
+                }
+                privkey = ssh_buffer_get_ssh_string(buffer);
+                if (pubkey == NULL) {
+                    ssh_string_burn(p);
+                    ssh_string_free(p);
+                    ssh_string_burn(q);
+                    ssh_string_free(q);
+                    ssh_string_burn(g);
+                    ssh_string_free(g);
+                    ssh_string_burn(pubkey);
+                    ssh_string_free(pubkey);
+
+                    goto fail;
+                }
+
+                rc = pki_privkey_build_dss(key, p, q, g, pubkey, privkey);
+#ifdef DEBUG_CRYPTO
+                ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
+                ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
+                ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
+                ssh_print_hexa("pubkey", ssh_string_data(pubkey),
+                               ssh_string_len(pubkey));
+                ssh_print_hexa("privkey", ssh_string_data(privkey),
+                               ssh_string_len(privkey));
+#endif
+                ssh_string_burn(p);
+                ssh_string_free(p);
+                ssh_string_burn(q);
+                ssh_string_free(q);
+                ssh_string_burn(g);
+                ssh_string_free(g);
+                ssh_string_burn(pubkey);
+                ssh_string_free(pubkey);
+                ssh_string_burn(privkey);
+                ssh_string_free(privkey);
+                if (rc == SSH_ERROR) {
+                    goto fail;
+                }
+            }
+            break;
+        case SSH_KEYTYPE_RSA:
+            {
+                ssh_string n;
+                ssh_string e;
+                ssh_string d;
+                ssh_string iqmp;
+                ssh_string p;
+                ssh_string q;
+
+                n = ssh_buffer_get_ssh_string(buffer);
+                if (n == NULL) {
+                    goto fail;
+                }
+                e = ssh_buffer_get_ssh_string(buffer);
+                if (e == NULL) {
+                    ssh_string_burn(n);
+                    ssh_string_free(n);
+
+                    goto fail;
+                }
+                d = ssh_buffer_get_ssh_string(buffer);
+                if (d == NULL) {
+                    ssh_string_burn(n);
+                    ssh_string_free(n);
+                    ssh_string_burn(e);
+                    ssh_string_free(e);
+
+                    goto fail;
+                }
+                iqmp = ssh_buffer_get_ssh_string(buffer);
+                if (iqmp == NULL) {
+                    ssh_string_burn(n);
+                    ssh_string_free(n);
+                    ssh_string_burn(e);
+                    ssh_string_free(e);
+                    ssh_string_burn(d);
+                    ssh_string_free(d);
+
+                    goto fail;
+                }
+                p = ssh_buffer_get_ssh_string(buffer);
+                if (p == NULL) {
+                    ssh_string_burn(n);
+                    ssh_string_free(n);
+                    ssh_string_burn(e);
+                    ssh_string_free(e);
+                    ssh_string_burn(d);
+                    ssh_string_free(d);
+                    ssh_string_burn(iqmp);
+                    ssh_string_free(iqmp);
+
+                    goto fail;
+                }
+                q = ssh_buffer_get_ssh_string(buffer);
+                if (q == NULL) {
+                    ssh_string_burn(n);
+                    ssh_string_free(n);
+                    ssh_string_burn(e);
+                    ssh_string_free(e);
+                    ssh_string_burn(d);
+                    ssh_string_free(d);
+                    ssh_string_burn(iqmp);
+                    ssh_string_free(iqmp);
+                    ssh_string_burn(p);
+                    ssh_string_free(p);
+
+                    goto fail;
+                }
+
+                rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
+#ifdef DEBUG_CRYPTO
+                ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
+                ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
+                ssh_print_hexa("d", ssh_string_data(d), ssh_string_len(d));
+                ssh_print_hexa("iqmp", ssh_string_data(iqmp),
+                               ssh_string_len(iqmp));
+                ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
+                ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
+#endif
+                ssh_string_burn(n);
+                ssh_string_free(n);
+                ssh_string_burn(e);
+                ssh_string_free(e);
+                ssh_string_burn(d);
+                ssh_string_free(d);
+                ssh_string_burn(iqmp);
+                ssh_string_free(iqmp);
+                ssh_string_burn(p);
+                ssh_string_free(p);
+                ssh_string_burn(q);
+                ssh_string_free(q);
+                if (rc == SSH_ERROR) {
+                    goto fail;
+                }
+            }
+            break;
+#ifdef HAVE_ECC
+        case SSH_KEYTYPE_ECDSA:
+            {
+                ssh_string e;
+                ssh_string exp;
+                ssh_string i;
+                int nid;
+
+                i = ssh_buffer_get_ssh_string(buffer);
+                if (i == NULL) {
+                    goto fail;
+                }
+                nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
+                ssh_string_free(i);
+                if (nid == -1) {
+                    goto fail;
+                }
+
+                e = ssh_buffer_get_ssh_string(buffer);
+                if (e == NULL) {
+                    goto fail;
+                }
+
+                exp = ssh_buffer_get_ssh_string(buffer);
+                if (e == NULL) {
+                    goto fail;
+                }
+
+                rc = pki_privkey_build_ecdsa(key, nid, e, exp);
+                ssh_string_burn(e);
+                ssh_string_free(e);
+                ssh_string_burn(exp);
+                ssh_string_free(exp);
+                if (rc < 0) {
+                    goto fail;
+                }
+
+                /* Update key type */
+                key->type_c = ssh_pki_key_ecdsa_name(key);
+            }
+            break;
+#endif
+        case SSH_KEYTYPE_ED25519:
+            {
+                ssh_string pubkey = NULL, privkey = NULL;
+
+                rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
+                if (rc != SSH_OK){
+                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
+                    goto fail;
+                }
+
+                rc = pki_privkey_build_ed25519(key, pubkey, privkey);
+                ssh_string_burn(privkey);
+                ssh_string_free(privkey);
+                ssh_string_free(pubkey);
+                if (rc != SSH_OK) {
+                    goto fail;
+                }
+            }
+            break;
+        case SSH_KEYTYPE_DSS_CERT01:
+        case SSH_KEYTYPE_RSA_CERT01:
+        case SSH_KEYTYPE_RSA1:
+        case SSH_KEYTYPE_UNKNOWN:
+        default:
+            SSH_LOG(SSH_LOG_WARN, "Unknown private key type (%d)", type);
+            goto fail;
+    }
+
+    *pkey = key;
+    return SSH_OK;
+fail:
+    ssh_key_free(key);
+
+    return SSH_ERROR;
+}
+
 static int pki_import_pubkey_buffer(ssh_buffer buffer,
                                     enum ssh_keytypes_e type,
                                     ssh_key *pkey) {
diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c
index 2c4b6c46..4154b424 100644
--- a/src/pki_container_openssh.c
+++ b/src/pki_container_openssh.c
@@ -60,7 +60,6 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
     enum ssh_keytypes_e type;
     char *type_s = NULL;
     ssh_key key = NULL;
-    ssh_string pubkey = NULL, privkey = NULL;
     int rc;
 
     if (pkey == NULL) {
@@ -75,57 +74,14 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
 
     type = ssh_key_type_from_name(type_s);
     if (type == SSH_KEYTYPE_UNKNOWN) {
-        SSH_LOG(SSH_LOG_WARN, "Unknown key type found!");
+        SSH_LOG(SSH_LOG_WARN, "Unknown key type '%s' found!", type_s);
         return SSH_ERROR;
     }
     SAFE_FREE(type_s);
 
-    key = ssh_key_new();
-    if (key == NULL) {
-        SSH_LOG(SSH_LOG_WARN, "Out of memory");
-        return SSH_ERROR;
-    }
-
-    key->type = type;
-    key->type_c = ssh_key_type_to_char(type);
-    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
-
-    switch (type) {
-    case SSH_KEYTYPE_ED25519:
-        rc = ssh_buffer_unpack(key_blob_buffer, "SS", &pubkey, &privkey);
-        if (rc != SSH_OK){
-            SSH_LOG(SSH_LOG_WARN, "Unpack error");
-            goto fail;
-        }
-        if(ssh_string_len(pubkey) != ED25519_PK_LEN ||
-                ssh_string_len(privkey) != ED25519_SK_LEN){
-            SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
-            goto fail;
-        }
-        key->ed25519_privkey = malloc(ED25519_SK_LEN);
-        key->ed25519_pubkey = malloc(ED25519_PK_LEN);
-        if(key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL){
-            goto fail;
-        }
-        memcpy(key->ed25519_privkey, ssh_string_data(privkey), ED25519_SK_LEN);
-        memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN);
-        explicit_bzero(ssh_string_data(privkey), ED25519_SK_LEN);
-        SAFE_FREE(privkey);
-        SAFE_FREE(pubkey);
-        break;
-    case SSH_KEYTYPE_DSS_CERT01:
-    case SSH_KEYTYPE_DSS:
-        /* p,q,g,pub_key,priv_key */
-    case SSH_KEYTYPE_RSA_CERT01:
-    case SSH_KEYTYPE_RSA:
-        /* n,e,d,iqmp,p,q */
-    case SSH_KEYTYPE_ECDSA:
-        /* curve_name, group, privkey */
-        SSH_LOG(SSH_LOG_WARN, "Unsupported private key method %s", key->type_c);
-        goto fail;
-    case SSH_KEYTYPE_RSA1:
-    case SSH_KEYTYPE_UNKNOWN:
-        SSH_LOG(SSH_LOG_WARN, "Unknown private key protocol %s", key->type_c);
+    rc = pki_import_privkey_buffer(type, key_blob_buffer, &key);
+    if (rc != SSH_OK) {
+        SSH_LOG(SSH_LOG_WARN, "Failed to read key in OpenSSH format");
         goto fail;
     }
 
@@ -134,10 +90,6 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
 fail:
     ssh_key_free(key);
 
-    ssh_string_burn(privkey);
-    ssh_string_free(privkey);
-    ssh_string_free(pubkey);
-
     return SSH_ERROR;
 }
 
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 082f84ff..8deb9edb 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -172,6 +172,61 @@ static ssh_string make_ecpoint_string(const EC_GROUP *g,
     return s;
 }
 
+int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
+{
+    EC_POINT *p;
+    const EC_GROUP *g;
+    int ok;
+    BIGNUM *bexp = NULL;
+
+    key->ecdsa_nid = nid;
+    key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+    key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
+    if (key->ecdsa == NULL) {
+        return -1;
+    }
+
+    g = EC_KEY_get0_group(key->ecdsa);
+
+    p = EC_POINT_new(g);
+    if (p == NULL) {
+        return -1;
+    }
+
+    ok = EC_POINT_oct2point(g,
+                            p,
+                            ssh_string_data(e),
+                            ssh_string_len(e),
+                            NULL);
+    if (!ok) {
+        EC_POINT_free(p);
+        return -1;
+    }
+
+    /* EC_KEY_set_public_key duplicates p */
+    ok = EC_KEY_set_public_key(key->ecdsa, p);
+    EC_POINT_free(p);
+    if (!ok) {
+        return -1;
+    }
+
+    bexp = ssh_make_string_bn(exp);
+    if (bexp == NULL) {
+        EC_KEY_free(key->ecdsa);
+        return -1;
+    }
+    /* EC_KEY_set_private_key duplicates exp */
+    ok = EC_KEY_set_private_key(key->ecdsa, bexp);
+    BN_free(bexp);
+    if (!ok) {
+        EC_KEY_free(key->ecdsa);
+        return -1;
+    }
+
+    return 0;
+}
+
 int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
 {
     EC_POINT *p;
@@ -888,6 +943,47 @@ fail:
     return NULL;
 }
 
+int pki_privkey_build_dss(ssh_key key,
+                          ssh_string p,
+                          ssh_string q,
+                          ssh_string g,
+                          ssh_string pubkey,
+                          ssh_string privkey)
+{
+    int rc;
+    BIGNUM *bp, *bq, *bg, *bpub_key, *bpriv_key;
+
+    key->dsa = DSA_new();
+    if (key->dsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    bp = ssh_make_string_bn(p);
+    bq = ssh_make_string_bn(q);
+    bg = ssh_make_string_bn(g);
+    bpub_key = ssh_make_string_bn(pubkey);
+    bpriv_key = ssh_make_string_bn(privkey);
+    if (bp == NULL || bq == NULL ||
+        bg == NULL || bpub_key == NULL) {
+        goto fail;
+    }
+
+    rc = DSA_set0_pqg(key->dsa, bp, bq, bg);
+    if (rc == 0) {
+        goto fail;
+    }
+
+    rc = DSA_set0_key(key->dsa, bpub_key, bpriv_key);
+    if (rc == 0) {
+        goto fail;
+    }
+
+    return SSH_OK;
+fail:
+    DSA_free(key->dsa);
+    return SSH_ERROR;
+}
+
 int pki_pubkey_build_dss(ssh_key key,
                          ssh_string p,
                          ssh_string q,
@@ -926,6 +1022,56 @@ fail:
     return SSH_ERROR;
 }
 
+int pki_privkey_build_rsa(ssh_key key,
+                          ssh_string n,
+                          ssh_string e,
+                          ssh_string d,
+                          ssh_string iqmp,
+                          ssh_string p,
+                          ssh_string q)
+{
+    int rc;
+    BIGNUM *be, *bn, *bd/*, *biqmp*/, *bp, *bq;
+
+    key->rsa = RSA_new();
+    if (key->rsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    bn = ssh_make_string_bn(n);
+    be = ssh_make_string_bn(e);
+    bd = ssh_make_string_bn(d);
+    /*biqmp = ssh_make_string_bn(iqmp);*/
+    bp = ssh_make_string_bn(p);
+    bq = ssh_make_string_bn(q);
+    if (be == NULL || bn == NULL || bd == NULL ||
+        /*biqmp == NULL ||*/ bp == NULL || bq == NULL) {
+        goto fail;
+    }
+
+    rc = RSA_set0_key(key->rsa, bn, be, bd);
+    if (rc == 0) {
+        goto fail;
+    }
+
+    rc = RSA_set0_factors(key->rsa, bp, bq);
+    if (rc == 0) {
+        goto fail;
+    }
+
+    /* p, q, dmp1, dmq1 and iqmp may be NULL in private keys, but the RSA
+     * operations are much faster when these values are available.
+     * https://www.openssl.org/docs/man1.0.2/crypto/rsa.html
+     */
+    /* RSA_set0_crt_params(key->rsa, biqmp, NULL, NULL);
+    TODO calculate missing crt_params */
+
+    return SSH_OK;
+fail:
+    RSA_free(key->rsa);
+    return SSH_ERROR;
+}
+
 int pki_pubkey_build_rsa(ssh_key key,
                          ssh_string e,
                          ssh_string n) {
diff --git a/src/pki_ed25519.c b/src/pki_ed25519.c
index 45362c4f..981a74b6 100644
--- a/src/pki_ed25519.c
+++ b/src/pki_ed25519.c
@@ -56,6 +56,28 @@ error:
     return SSH_ERROR;
 }
 
+int pki_privkey_build_ed25519(ssh_key key,
+                              ssh_string pubkey,
+                              ssh_string privkey)
+{
+    if (ssh_string_len(pubkey) != ED25519_PK_LEN ||
+            ssh_string_len(privkey) != ED25519_SK_LEN) {
+        SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
+        return SSH_ERROR;
+    }
+    key->ed25519_privkey = malloc(ED25519_SK_LEN);
+    key->ed25519_pubkey = malloc(ED25519_PK_LEN);
+    if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
+        return SSH_ERROR;
+    }
+    memcpy(key->ed25519_privkey, ssh_string_data(privkey),
+           ED25519_SK_LEN);
+    memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
+           ED25519_PK_LEN);
+
+    return SSH_OK;
+}
+
 int pki_ed25519_sign(const ssh_key privkey,
                      ssh_signature sig,
                      const unsigned char *hash,
diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c
index a988d805..7084ca51 100644
--- a/src/pki_gcrypt.c
+++ b/src/pki_gcrypt.c
@@ -1030,6 +1030,27 @@ fail:
     return NULL;
 }
 
+int pki_privkey_build_dss(ssh_key key,
+                          ssh_string p,
+                          ssh_string q,
+                          ssh_string g,
+                          ssh_string pubkey,
+                          ssh_string privkey)
+{
+    gcry_sexp_build(&key->dsa, NULL,
+            "(private-key(dsa(p %b)(q %b)(g %b)(y %b)(x %b)))",
+            ssh_string_len(p), ssh_string_data(p),
+            ssh_string_len(q), ssh_string_data(q),
+            ssh_string_len(g), ssh_string_data(g),
+            ssh_string_len(pubkey), ssh_string_data(pubkey),
+            ssh_string_len(privkey), ssh_string_data(privkey));
+    if (key->dsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    return SSH_OK;
+}
+
 int pki_pubkey_build_dss(ssh_key key,
                          ssh_string p,
                          ssh_string q,
@@ -1048,6 +1069,29 @@ int pki_pubkey_build_dss(ssh_key key,
     return SSH_OK;
 }
 
+int pki_privkey_build_rsa(ssh_key key,
+                          ssh_string n,
+                          ssh_string e,
+                          ssh_string d,
+                          ssh_string iqmp,
+                          ssh_string p,
+                          ssh_string q)
+{
+    gcry_sexp_build(&key->rsa, NULL,
+            "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
+            ssh_string_len(n), ssh_string_data(n),
+            ssh_string_len(e),ssh_string_data(e),
+            ssh_string_len(d),ssh_string_data(d),
+            ssh_string_len(p),ssh_string_data(p),
+            ssh_string_len(q),ssh_string_data(q),
+            ssh_string_len(iqmp),ssh_string_data(iqmp));
+    if (key->rsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    return SSH_OK;
+}
+
 int pki_pubkey_build_rsa(ssh_key key,
                          ssh_string e,
                          ssh_string n) {
@@ -1063,6 +1107,25 @@ int pki_pubkey_build_rsa(ssh_key key,
 }
 
 #ifdef HAVE_GCRYPT_ECC
+int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
+{
+    gpg_error_t err;
+
+    key->ecdsa_nid = nid;
+    key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+    err = gcry_sexp_build(&key->ecdsa, NULL,
+                          "(private-key(ecdsa(curve %s)(d %b)(q %b)))",
+                          pki_key_ecdsa_nid_to_gcrypt_name(nid),
+                          ssh_string_len(exp), ssh_string_data(exp),
+                          ssh_string_len(e), ssh_string_data(e));
+    if (err) {
+        return SSH_ERROR;
+    }
+
+    return SSH_OK;
+}
+
 int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
 {
     gpg_error_t err;
diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c
index 534e375d..16660b27 100644
--- a/src/pki_mbedcrypto.c
+++ b/src/pki_mbedcrypto.c
@@ -214,6 +214,68 @@ fail:
     return NULL;
 }
 
+int pki_privkey_build_rsa(ssh_key key,
+                          ssh_string n,
+                          ssh_string e,
+                          ssh_string d,
+                          ssh_string iqmp,
+                          ssh_string p,
+                          ssh_string q)
+{
+    mbedtls_rsa_context *rsa = NULL;
+    const mbedtls_pk_info_t *pk_info = NULL;
+    int rc;
+
+    key->rsa = malloc(sizeof(mbedtls_pk_context));
+    if (key->rsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_pk_init(key->rsa);
+    pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
+    mbedtls_pk_setup(key->rsa, pk_info);
+
+    if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) {
+        rsa = mbedtls_pk_rsa(*key->rsa);
+        rc = mbedtls_mpi_read_binary(&rsa->N, ssh_string_data(n),
+                                     ssh_string_len(n));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+        rc = mbedtls_mpi_read_binary(&rsa->E, ssh_string_data(e),
+                                     ssh_string_len(e));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+        rc = mbedtls_mpi_read_binary(&rsa->D, ssh_string_data(d),
+                                     ssh_string_len(d));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+        rc = mbedtls_mpi_read_binary(&rsa->P, ssh_string_data(p),
+                                     ssh_string_len(p));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+        rc = mbedtls_mpi_read_binary(&rsa->Q, ssh_string_data(q),
+                                     ssh_string_len(q));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+        rc = mbedtls_mpi_read_binary(&rsa->QP, ssh_string_data(iqmp),
+                                     ssh_string_len(iqmp));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+
+        rsa->len = (mbedtls_mpi_bitlen(&rsa->N) + 7) >> 3;
+    } else {
+        return SSH_ERROR;
+    }
+
+    return SSH_OK;
+}
+
 int pki_pubkey_build_rsa(ssh_key key, ssh_string e, ssh_string n)
 {
     mbedtls_rsa_context *rsa = NULL;
@@ -1237,6 +1299,72 @@ static mbedtls_ecp_group_id pki_key_ecdsa_nid_to_mbed_gid(int nid)
     return MBEDTLS_ECP_DP_NONE;
 }
 
+int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
+{
+    int rc;
+    mbedtls_ecp_keypair keypair;
+    mbedtls_ecp_group group;
+    mbedtls_ecp_point Q;
+
+    key->ecdsa_nid = nid;
+    key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+    key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
+    if (key->ecdsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_ecdsa_init(key->ecdsa);
+    mbedtls_ecp_keypair_init(&keypair);
+    mbedtls_ecp_group_init(&group);
+    mbedtls_ecp_point_init(&Q);
+
+    rc = mbedtls_ecp_group_load(&group,
+                                pki_key_ecdsa_nid_to_mbed_gid(nid));
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_ecp_point_read_binary(&group, &Q, ssh_string_data(e),
+                                       ssh_string_len(e));
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_ecp_copy(&keypair.Q, &Q);
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_ecp_group_copy(&keypair.grp, &group);
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_mpi_read_binary(&keypair.d, ssh_string_data(exp),
+                                 ssh_string_len(exp));
+    if (rc != 0) {
+        return SSH_ERROR;
+    }
+
+    rc = mbedtls_ecdsa_from_keypair(key->ecdsa, &keypair);
+    if (rc != 0) {
+        goto fail;
+    }
+
+    mbedtls_ecp_point_free(&Q);
+    mbedtls_ecp_group_free(&group);
+    mbedtls_ecp_keypair_free(&keypair);
+    return SSH_OK;
+fail:
+    mbedtls_ecdsa_free(key->ecdsa);
+    mbedtls_ecp_point_free(&Q);
+    mbedtls_ecp_group_free(&group);
+    mbedtls_ecp_keypair_free(&keypair);
+    SAFE_FREE(key->ecdsa);
+    return SSH_ERROR;
+}
+
 int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
 {
     int rc;
@@ -1341,6 +1469,18 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter)
     return SSH_OK;
 }
 
+int pki_privkey_build_dss(ssh_key key, ssh_string p, ssh_string q, ssh_string g,
+        ssh_string pubkey, ssh_string privkey)
+{
+    (void) key;
+    (void) p;
+    (void) q;
+    (void) g;
+    (void) pubkey;
+    (void) privkey;
+    return SSH_ERROR;
+}
+
 int pki_pubkey_build_dss(ssh_key key, ssh_string p, ssh_string q, ssh_string g,
         ssh_string pubkey)
 {
-- 
2.17.1


From bd13671748c6479a6a05aafe8c59423961fbc0fe Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 6 Sep 2018 17:58:04 +0200
Subject: [PATCH 5/5] tests: Verify the keys loaded from new OpenSSH format

This runs the same test that are ran on the legacy PEM files
also with the new OpenSSH key files.

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_pki_dsa.c   | 100 +++++++++++++++++++++++++++-
 tests/unittests/torture_pki_ecdsa.c |  55 ++++++++++++++-
 tests/unittests/torture_pki_rsa.c   |  71 ++++++++++++++++++++
 3 files changed, 224 insertions(+), 2 deletions(-)

diff --git a/tests/unittests/torture_pki_dsa.c b/tests/unittests/torture_pki_dsa.c
index 1d98ccb4..6343f6da 100644
--- a/tests/unittests/torture_pki_dsa.c
+++ b/tests/unittests/torture_pki_dsa.c
@@ -28,7 +28,28 @@ static int setup_dsa_key(void **state)
     torture_write_file(LIBSSH_DSA_TESTKEY,
                        torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0));
     torture_write_file(LIBSSH_DSA_TESTKEY_PASSPHRASE,
-                       torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0));
+                       torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1));
+    torture_write_file(LIBSSH_DSA_TESTKEY ".pub",
+                       torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0));
+    torture_write_file(LIBSSH_DSA_TESTKEY "-cert.pub",
+                       torture_get_testkey_pub(SSH_KEYTYPE_DSS_CERT01, 0));
+
+    return 0;
+}
+
+static int setup_openssh_dsa_key(void **state)
+{
+    (void) state; /* unused */
+
+    unlink(LIBSSH_DSA_TESTKEY);
+    unlink(LIBSSH_DSA_TESTKEY_PASSPHRASE);
+    unlink(LIBSSH_DSA_TESTKEY ".pub");
+    unlink(LIBSSH_DSA_TESTKEY "-cert.pub");
+
+    torture_write_file(LIBSSH_DSA_TESTKEY,
+                       torture_get_openssh_testkey(SSH_KEYTYPE_DSS, 0, 0));
+    torture_write_file(LIBSSH_DSA_TESTKEY_PASSPHRASE,
+                       torture_get_openssh_testkey(SSH_KEYTYPE_DSS, 0, 1));
     torture_write_file(LIBSSH_DSA_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0));
     torture_write_file(LIBSSH_DSA_TESTKEY "-cert.pub",
@@ -217,6 +238,79 @@ static void torture_pki_dsa_import_privkey_base64_passphrase(void **state)
 #endif /* HAVE_LIBCRYPTO */
 }
 
+static void
+torture_pki_dsa_import_openssh_privkey_base64_passphrase(void **state)
+{
+    int rc;
+    ssh_key key = NULL;
+    const char *passphrase = torture_get_testkey_passphrase();
+    const char *keystring = NULL;
+
+    (void) state; /* unused */
+
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_DSS, 0, 1);
+    assert_true(keystring != NULL);
+
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       passphrase,
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_return_code(rc, errno);
+
+    rc = ssh_key_is_private(key);
+    assert_true(rc == 1);
+
+    ssh_key_free(key);
+    key = NULL;
+
+    /* test if it returns -1 if passphrase is wrong */
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       "wrong passphrase !!",
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_true(rc == -1);
+
+    /* test if it returns -1 if passphrase is NULL */
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       NULL,
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_true(rc == -1);
+
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       passphrase,
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_return_code(rc, errno);
+
+    rc = ssh_key_is_private(key);
+    assert_true(rc == 1);
+
+    ssh_key_free(key);
+    key = NULL;
+
+    /* test if it returns -1 if passphrase is wrong */
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       "wrong passphrase !!",
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_true(rc == -1);
+
+    /* test if it returns -1 if passphrase is NULL */
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       NULL,
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_true(rc == -1);
+}
+
+
 static void torture_pki_dsa_publickey_from_privatekey(void **state)
 {
     int rc;
@@ -451,6 +545,9 @@ int torture_run_tests(void)
         cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
                                  setup_dsa_key,
                                  teardown_dsa_key),
+        cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
+                                 setup_openssh_dsa_key,
+                                 teardown_dsa_key),
         cmocka_unit_test_setup_teardown(torture_pki_dsa_publickey_from_privatekey,
                                  setup_dsa_key,
                                  teardown_dsa_key),
@@ -463,6 +560,7 @@ int torture_run_tests(void)
                                  teardown_dsa_key),
 #endif
         cmocka_unit_test(torture_pki_dsa_import_privkey_base64_passphrase),
+        cmocka_unit_test(torture_pki_dsa_import_openssh_privkey_base64_passphrase),
 
         /* public key */
         cmocka_unit_test_setup_teardown(torture_pki_dsa_publickey_base64,
diff --git a/tests/unittests/torture_pki_ecdsa.c b/tests/unittests/torture_pki_ecdsa.c
index 2e89ba4d..5c66d81a 100644
--- a/tests/unittests/torture_pki_ecdsa.c
+++ b/tests/unittests/torture_pki_ecdsa.c
@@ -26,7 +26,30 @@ static int setup_ecdsa_key(void **state, int ecdsa_bits)
     torture_write_file(LIBSSH_ECDSA_TESTKEY,
                        torture_get_testkey(SSH_KEYTYPE_ECDSA, ecdsa_bits, 0));
     torture_write_file(LIBSSH_ECDSA_TESTKEY_PASSPHRASE,
-                       torture_get_testkey(SSH_KEYTYPE_ECDSA, ecdsa_bits, 0));
+                       torture_get_testkey(SSH_KEYTYPE_ECDSA, ecdsa_bits, 1));
+    torture_write_file(LIBSSH_ECDSA_TESTKEY ".pub",
+                       torture_get_testkey_pub(SSH_KEYTYPE_ECDSA, ecdsa_bits));
+
+    return 0;
+}
+
+static int setup_openssh_ecdsa_key(void **state, int ecdsa_bits)
+{
+    const char *keystring = NULL;
+
+    (void) state; /* unused */
+
+    unlink(LIBSSH_ECDSA_TESTKEY);
+    unlink(LIBSSH_ECDSA_TESTKEY_PASSPHRASE);
+    unlink(LIBSSH_ECDSA_TESTKEY ".pub");
+
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ECDSA, ecdsa_bits, 0);
+    torture_write_file(LIBSSH_ECDSA_TESTKEY,
+                       keystring);
+
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ECDSA, ecdsa_bits, 1);
+    torture_write_file(LIBSSH_ECDSA_TESTKEY_PASSPHRASE,
+                       keystring);
     torture_write_file(LIBSSH_ECDSA_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_ECDSA, ecdsa_bits));
 
@@ -54,6 +77,27 @@ static int setup_ecdsa_key_256(void **state)
     return 0;
 }
 
+static int setup_openssh_ecdsa_key_521(void **state)
+{
+    setup_openssh_ecdsa_key(state, 521);
+
+    return 0;
+}
+
+static int setup_openssh_ecdsa_key_384(void **state)
+{
+    setup_openssh_ecdsa_key(state, 384);
+
+    return 0;
+}
+
+static int setup_openssh_ecdsa_key_256(void **state)
+{
+    setup_openssh_ecdsa_key(state, 256);
+
+    return 0;
+}
+
 static int teardown(void **state)
 {
     (void) state; /* unused */
@@ -461,6 +505,15 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
                                         setup_ecdsa_key_521,
                                         teardown),
+        cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
+                                        setup_openssh_ecdsa_key_256,
+                                        teardown),
+        cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
+                                        setup_openssh_ecdsa_key_384,
+                                        teardown),
+        cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
+                                        setup_openssh_ecdsa_key_521,
+                                        teardown),
         cmocka_unit_test_setup_teardown(torture_pki_ecdsa_publickey_from_privatekey,
                                         setup_ecdsa_key_256,
                                         teardown),
diff --git a/tests/unittests/torture_pki_rsa.c b/tests/unittests/torture_pki_rsa.c
index 1e61906a..9025495c 100644
--- a/tests/unittests/torture_pki_rsa.c
+++ b/tests/unittests/torture_pki_rsa.c
@@ -34,6 +34,25 @@ static int setup_rsa_key(void **state)
                        torture_get_testkey(SSH_KEYTYPE_RSA, 0, 1));
     torture_write_file(LIBSSH_RSA_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0));
+    torture_write_file(LIBSSH_RSA_TESTKEY "-cert.pub",
+                       torture_get_testkey_pub(SSH_KEYTYPE_RSA_CERT01, 0));
+
+    return 0;
+}
+
+static int setup_rsa_openssh_key(void **state)
+{
+    (void) state; /* unused */
+
+    unlink(LIBSSH_RSA_TESTKEY);
+    unlink(LIBSSH_RSA_TESTKEY_PASSPHRASE);
+    unlink(LIBSSH_RSA_TESTKEY ".pub");
+    unlink(LIBSSH_RSA_TESTKEY "-cert.pub");
+
+    torture_write_file(LIBSSH_RSA_TESTKEY,
+                       torture_get_openssh_testkey(SSH_KEYTYPE_RSA, 0, 0));
+    torture_write_file(LIBSSH_RSA_TESTKEY_PASSPHRASE,
+                       torture_get_openssh_testkey(SSH_KEYTYPE_RSA, 0, 1));
     torture_write_file(LIBSSH_RSA_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0));
     torture_write_file(LIBSSH_RSA_TESTKEY "-cert.pub",
@@ -568,6 +587,54 @@ static void torture_pki_rsa_import_privkey_base64_passphrase(void **state)
 #endif
 }
 
+static void
+torture_pki_rsa_import_openssh_privkey_base64_passphrase(void **state)
+{
+    int rc;
+    ssh_key key = NULL;
+    const char *passphrase = torture_get_testkey_passphrase();
+    const char *keystring = NULL;
+
+    (void) state; /* unused */
+
+    keystring = torture_get_openssh_testkey(SSH_KEYTYPE_RSA, 0, 1);
+    assert_true(keystring != NULL);
+
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       passphrase,
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_return_code(rc, errno);
+
+    rc = ssh_key_is_private(key);
+    assert_true(rc == 1);
+
+    ssh_key_free(key);
+    key = NULL;
+
+    /* test if it returns -1 if passphrase is wrong */
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       "wrong passphrase !!",
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_true(rc == -1);
+    ssh_key_free(key);
+    key = NULL;
+
+    /* test if it returns -1 if passphrase is NULL */
+    /* libcrypto asks for a passphrase, so skip this test */
+    rc = ssh_pki_import_privkey_base64(keystring,
+                                       NULL,
+                                       NULL,
+                                       NULL,
+                                       &key);
+    assert_true(rc == -1);
+    ssh_key_free(key);
+    key = NULL;
+}
+
 int torture_run_tests(void) {
     int rc;
     struct CMUnitTest tests[] = {
@@ -583,10 +650,14 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
                                         setup_rsa_key,
                                         teardown),
+        cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
+                                        setup_rsa_openssh_key,
+                                        teardown),
         cmocka_unit_test_setup_teardown(torture_pki_rsa_publickey_from_privatekey,
                                         setup_rsa_key,
                                         teardown),
         cmocka_unit_test(torture_pki_rsa_import_privkey_base64_passphrase),
+        cmocka_unit_test(torture_pki_rsa_import_openssh_privkey_base64_passphrase),
         cmocka_unit_test_setup_teardown(torture_pki_rsa_copy_cert_to_privkey,
                                         setup_rsa_key,
                                         teardown),
-- 
2.17.1


Follow-Ups:
Re: [PATCH] Support for private keys in OpenSSH formatAndreas Schneider <asn@xxxxxxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org