Skip to content

Commit cac340d

Browse files
authored
Add support for other keytypes to openssh-key-v1 keyfiles (#485)
* Added support for RSA to openssh-key-v1 keyfile * Fixed exception * Added ECDSA support to openssh-key-v1 * Added integration tests for different keytypes
1 parent 00cd335 commit cac340d

File tree

20 files changed

+288
-23
lines changed

20 files changed

+288
-23
lines changed

src/itest/docker-image/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM sickp/alpine-sshd:7.5-r2
22

3-
ADD id_rsa.pub /home/sshj/.ssh/authorized_keys
3+
ADD authorized_keys /home/sshj/.ssh/authorized_keys
44

55
ADD test-container/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key
66
ADD test-container/ssh_host_ecdsa_key.pub /etc/ssh/ssh_host_ecdsa_key.pub
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOEQcvowiV3igdRO7rKPrZrao1hCQrnC4tgsxqSJdQCbABI+vHrdbJRfWZNuSk48aAtARJzJVmkn/r63EPJgkh8= root@itgcpkerberosstack-cbgateway-0-20151117031915
2+
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHQiZm0wBbmI8gohA/N9ir1O+egikL6S9FjZS8GHbx4rTHI1V+vbXxx2O9bFWtep1PFb4iowtZkxf6gvRjGkL6M= ajvanerp@Heimdall.local
3+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDAdJiRkkBM8yC8seTEoAn2PfwbLKrkcahZ0xxPoWICJ root@sshj
4+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8ww4hJG/gHJYdkjTTBDF1GNz+228nuWprPV+NbQauA ajvanerp@Heimdall.local
5+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOaWrwt3drIOjeBq2LSHRavxAT7ja2f+5soOUJl/zKSI ajvanerp@Heimdall.xebialabs.com
6+
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAoZ9l6Tkm2aL1tSBy2yw4xU5s8BE9MfqS/4J7DzvsYJxF6oQmTIjmStuhH/CT7UjuDtKXdXZUsIhKtafiizxGO8kHSzKDeitpth2RSr8ddMzZKyD6RNs7MfsgjA3UTtrrSrCXEY6O43S2cnuJrWzkPxtwxaQ3zOvDbS2tiulzyq0VzYmuhA/a4CyuQtJBuu+P2oqmu6pU/VB6IzONpvBvYbNPsH1WDmP7zko5wHPihXPCliztspKxS4DRtOZ7BGXyvg44UmIy0Kf4jOkaBV/eCCA4qH7ZHz71/5ceMOpszPcNOEmLGGYhwI+P3OuGMpkrSAv1f8IY6R8spZNncP6UaQ== no-passphrase
7+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKRyZAtOJJfAhPU6xE6ZXY564vwErAI3n3Yn4lTHL9bxev9Ily6eCqPLcV0WbSV04pztngFn9MjT7yb8mcXheHpIaWEH569sMpmpOtyfn4p68SceuXBGyyPGMIcfOTknkASd1JYSD4EPkd9rZmCzcx3vEnLu8ChnA/G221xSVQ5VC/jD/c/CgNUayhQ+xbn57qHKKtZwfTa21QmwIabGYJNwlVjlKTCdddeVnZfKqKrG7cxHQApsxd21rhM9IT/C/f4Y/Tx3WUUVeam0iZ265oiPHoPALqJIWSQIUheRYAxYAQqJwSQ0Or9MM8XXun2Iy3RUSGk6eIvrCsFbNURsHNs7Pu0UnpYv6FZ3vCkFep/1pAT6fQvY7pDOOWDHKXArD4watc9gIWaQBH73wDW/KgBcnMRSoGWgQjsYqIamP4oV1+HqUI3lRAsXZaX+eiBGt3+3A5KebP27UJ1YUwhwlzs7wzTKaCu0OaL+hOsP1F2AxAa995bgFksMd23645ux3YCJKXG4sGpJ1Z/Hs49K72gv+QjLZVxXqY623c8+3OUhlixqoEFd4iG7UMc5a552ch/VA+jaspmLZoFhPz99aBRVb1oCSPxSwLw+Q/wxv6pZmT+14rqTzY2farjU53hM+CsUPh7dnWXhGG7RuA5wCdeOXOYjuksfzAoHIZhPqTgQ== ajvanerp@Heimdall.local

src/itest/docker-image/id_rsa.pub

-1
This file was deleted.

src/itest/groovy/com/hierynomus/sshj/IntegrationBaseSpec.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import spock.lang.Specification
2424
class IntegrationBaseSpec extends Specification {
2525
protected static final int DOCKER_PORT = 2222
2626
protected static final String USERNAME = "sshj"
27-
protected static final String KEYFILE = "src/test/resources/id_rsa"
27+
protected static final String KEYFILE = "src/itest/resources/keyfiles/id_rsa"
2828
protected final static String SERVER_IP = System.getProperty("serverIP", "127.0.0.1")
2929

3030
protected static SSHClient getConnectedClient(Config config) {

src/itest/groovy/com/hierynomus/sshj/IntegrationSpec.groovy

+15-3
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,35 @@ class IntegrationSpec extends IntegrationBaseSpec {
5757
thrown(TransportException.class)
5858
}
5959

60-
def "should authenticate"() {
60+
@Unroll
61+
def "should authenticate with key #key"() {
6162
given:
6263
SSHClient client = getConnectedClient()
6364

6465
when:
65-
client.authPublickey(USERNAME, KEYFILE)
66+
def keyProvider = passphrase != null ? client.loadKeys("src/itest/resources/keyfiles/$key", passphrase) : client.loadKeys("src/itest/resources/keyfiles/$key")
67+
client.authPublickey(USERNAME, keyProvider)
6668

6769
then:
6870
client.isAuthenticated()
71+
72+
where:
73+
key | passphrase
74+
// "id_ecdsa_nistp256" | null // TODO: Need to improve PKCS8 key support.
75+
"id_ecdsa_opensshv1" | null
76+
"id_ed25519_opensshv1" | null
77+
"id_ed25519_opensshv1_aes256cbc.pem" | "foobar"
78+
"id_ed25519_opensshv1_protected" | "sshjtest"
79+
"id_rsa" | null
80+
"id_rsa_opensshv1" | null
6981
}
7082

7183
def "should not authenticate with wrong key"() {
7284
given:
7385
SSHClient client = getConnectedClient()
7486

7587
when:
76-
client.authPublickey("sshj", "src/test/resources/id_dsa")
88+
client.authPublickey("sshj", "src/itest/resources/keyfiles/id_unknown_key")
7789

7890
then:
7991
thrown(UserAuthException.class)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-----BEGIN EC PRIVATE KEY-----
2+
MHcCAQEEIJUMlsSlXqCZmCjlN4kV7hzP+p9pu0fwJ8r4m1qle58SoAoGCCqGSM49
3+
AwEHoUQDQgAE4RBy+jCJXeKB1E7uso+tmtqjWEJCucLi2CzGpIl1AJsAEj68et1s
4+
lF9Zk25KTjxoC0BEnMlWaSf+vrcQ8mCSHw==
5+
-----END EC PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
3+
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR0ImZtMAW5iPIKIQPzfYq9TvnoIpC+
4+
kvRY2UvBh28eK0xyNVfr218cdjvWxVrXqdTxW+IqMLWZMX+oL0YxpC+jAAAAsD+6Oow/uj
5+
qMAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHQiZm0wBbmI8goh
6+
A/N9ir1O+egikL6S9FjZS8GHbx4rTHI1V+vbXxx2O9bFWtep1PFb4iowtZkxf6gvRjGkL6
7+
MAAAAgXNC11pInVAOd3xNphiHMoISeitf6h1IKbDM+niLrL5kAAAAXYWp2YW5lcnBASGVp
8+
bWRhbGwubG9jYWwB
9+
-----END OPENSSH PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3+
QyNTUxOQAAACAwHSYkZJATPMgvLHkxKAJ9j38Gyyq5HGoWdMcT6FiAiQAAAJDimgR84poE
4+
fAAAAAtzc2gtZWQyNTUxOQAAACAwHSYkZJATPMgvLHkxKAJ9j38Gyyq5HGoWdMcT6FiAiQ
5+
AAAECmsckQycWnfGQK6XtQpaMGODbAkMQOdJNK6XJSipB7dDAdJiRkkBM8yC8seTEoAn2P
6+
fwbLKrkcahZ0xxPoWICJAAAACXJvb3RAc3NoagECAwQ=
7+
-----END OPENSSH PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBLQVXV9f
3+
Wpw8AL9RTpAr//AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIJ8ww4hJG/gHJYdk
4+
jTTBDF1GNz+228nuWprPV+NbQauAAAAAoGHEO7x3fSRBohvrIR52U4XD3uqRnhrPYm01k1
5+
f4HHNNv46m92Zw6JKIB9Trrvp0sdMI8MVb79bN45rbn6mvpABtWl6T5TOTyMnKzDfAOx9c
6+
FTaasWFmgtgkXOsu5pLrYBAQgCHWbzjjz6KoV1DmD4SAn9Ojf9Oh+YdAEKZcsvklgpu+Kj
7+
nzN/DR0jt7Nzep2kNCLAS24QEkvQeATVSDiL8=
8+
-----END OPENSSH PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB/aWL0WG
3+
iYPOTxGlFwvaCNAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIOaWrwt3drIOjeBq
4+
2LSHRavxAT7ja2f+5soOUJl/zKSIAAAAsKplAiFbOhzcOJYFYBYm8sqYbvhPF8jKdQFkbo
5+
LAOeq+vQ0YBV9XUWQQM2tmL+RPjykPJZ2thcHLpVp3PfUEgo4bImCt939b3Ji3cEwD3QuK
6+
MIhjhx1KvSJNF/uhjwPJnttwHG+ld8F5Gv7LpTOUmOzXKGLIgYRuwonhs5ezdNv5ERs+Cq
7+
M9p/SW5ehL5KPJhGa5a+ZQXRojwEH7J4Q5xztH1gviTdIEpFWWQBH8rX6y
8+
-----END OPENSSH PRIVATE KEY-----

src/itest/resources/keyfiles/id_rsa

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEoAIBAAKCAQEAoZ9l6Tkm2aL1tSBy2yw4xU5s8BE9MfqS/4J7DzvsYJxF6oQm
3+
TIjmStuhH/CT7UjuDtKXdXZUsIhKtafiizxGO8kHSzKDeitpth2RSr8ddMzZKyD6
4+
RNs7MfsgjA3UTtrrSrCXEY6O43S2cnuJrWzkPxtwxaQ3zOvDbS2tiulzyq0VzYmu
5+
hA/a4CyuQtJBuu+P2oqmu6pU/VB6IzONpvBvYbNPsH1WDmP7zko5wHPihXPClizt
6+
spKxS4DRtOZ7BGXyvg44UmIy0Kf4jOkaBV/eCCA4qH7ZHz71/5ceMOpszPcNOEmL
7+
GGYhwI+P3OuGMpkrSAv1f8IY6R8spZNncP6UaQIBIwKCAQBXvO4uJlbrLJQDPYAt
8+
1i1ybGcF+rrR/Q34a2dgCpZDEwFiDTlcv1hxx689OXTf5cMPXGDZXX5udd9p7Wxa
9+
NqnIrvVUtQWLdqcZuEeO+gitHr8IyMJf5Lm8C/u5vl1PYOYhO0qxwmrTP1u6fZPh
10+
zWX2X1p5626/sy+TCisCRDeLRyes+Dtfs3bDjUq+zF3D/DmeYY55LUx0XS27uXNS
11+
QuUDMSnymFyj4o+jPK0q/j5w4bB+0rbsij+EP7S//jOFrSEcZgBhhIj0rHA5fo6w
12+
NrgtgRKD3HKFBM3b4VM8TdMbHsmf+nT9DjiDqcs+IxXMGlb1XTjtQFIN2eyRtNLd
13+
eQ0bAoGBAMwgv3rGytRjVbR4TT77eF81svzitOJWRdfXuKB5gqM3jsPR08f1MEtZ
14+
44kaI5ByJ3mBDt/EwNgLRdmBddPrLu3so9VLdRmWKI+KNGxwkcxzJv1xXdicgw+w
15+
S5WgigJryuUbtdylXQTlRArLUKsXULk/MndhGiD+a4fZ3dUtktF9AoGBAMqxh6tr
16+
S0ao0rN4hc9I92gwPubD1+XQr9TJQEEqGv3g5O3BdfDrTvizfaeNArahrIqyO5SK
17+
7iDg0xcHqdxmVmmCJ8CkIWBPXLU6erQ1QNlBJmnzYn5lR0Ksx2h/myjeXztvJKEM
18+
q4xUjAEzWjmwxxU3Y6l3FokvgIU4kOVoE4JdAoGARfyZa+xizHnUPeAae/5yaclE
19+
rnmdGma43En2KGQsyj7vHpEVaSDdW6nKWuRj9wKRMPkMafpQvxnOzjsD06EXZ4RV
20+
bbN4mw7pVcj8B+wUuyAqoAmchMfya8dqXy+6SfkSXS4Sd4knNODkIPVAOqjoegcJ
21+
/QtZamXbuYyGkjuCy3sCgYBLSUEFJ9ohjymwX/cvvAQfYmCBmTLu9b2mzmhSt94j
22+
yI+Lgl8BtnxrANbmdjQ1NLxuB6+61IRVWtIP3kZnzj1aY4sbqq1PqHLkOkrVOFnq
23+
S2YKGJJMND8KIur67ZFm84J1KUgej61uow9uKQRBUEnx8AByJOsdAwPZteys+sVq
24+
7wKBgAc3BL6ttDVYlL8U8fgvTCGuIajItvOQQj1n8RKyRLblYXBKAtY+pbULzmF+
25+
HscRgJMcwEIosEbTzzBNEVQm6dS6R/Q534C00Fpsw1z/PFTI8AOdUzTROGjuN8Fg
26+
YZoqMQLhk/PB8V4l7yJmPrE971RmJBBDlLDt6hZwOYEI2yF4
27+
-----END RSA PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
3+
NhAAAAAwEAAQAAAgEAykcmQLTiSXwIT1OsROmV2OeuL8BKwCN592J+JUxy/W8Xr/SJcung
4+
qjy3FdFm0ldOKc7Z4BZ/TI0+8m/JnF4Xh6SGlhB+evbDKZqTrcn5+KevEnHrlwRssjxjCH
5+
Hzk5J5AEndSWEg+BD5Hfa2Zgs3Md7xJy7vAoZwPxtttcUlUOVQv4w/3PwoDVGsoUPsW5+e
6+
6hyirWcH02ttUJsCGmxmCTcJVY5SkwnXXXlZ2Xyqiqxu3MR0AKbMXdta4TPSE/wv3+GP08
7+
d1lFFXmptImduuaIjx6DwC6iSFkkCFIXkWAMWAEKicEkNDq/TDPF17p9iMt0VEhpOniL6w
8+
rBWzVEbBzbOz7tFJ6WL+hWd7wpBXqf9aQE+n0L2O6QzjlgxylwKw+MGrXPYCFmkAR+98A1
9+
vyoAXJzEUqBloEI7GKiGpj+KFdfh6lCN5UQLF2Wl/nogRrd/twOSnmz9u1CdWFMIcJc7O8
10+
M0ymgrtDmi/oTrD9RdgMQGvfeW4BZLDHdt+uObsd2AiSlxuLBqSdWfx7OPSu9oL/kIy2Vc
11+
V6mOtt3PPtzlIZYsaqBBXeIhu1DHOWuednIf1QPo2rKZi2aBYT8/fWgUVW9aAkj8UsC8Pk
12+
P8Mb+qWZk/teK6k82Nn2q41Od4TPgrFD4e3Z1l4Rhu0bgOcAnXjlzmI7pLH8wKByGYT6k4
13+
EAAAdQ3L5mFty+ZhYAAAAHc3NoLXJzYQAAAgEAykcmQLTiSXwIT1OsROmV2OeuL8BKwCN5
14+
92J+JUxy/W8Xr/SJcungqjy3FdFm0ldOKc7Z4BZ/TI0+8m/JnF4Xh6SGlhB+evbDKZqTrc
15+
n5+KevEnHrlwRssjxjCHHzk5J5AEndSWEg+BD5Hfa2Zgs3Md7xJy7vAoZwPxtttcUlUOVQ
16+
v4w/3PwoDVGsoUPsW5+e6hyirWcH02ttUJsCGmxmCTcJVY5SkwnXXXlZ2Xyqiqxu3MR0AK
17+
bMXdta4TPSE/wv3+GP08d1lFFXmptImduuaIjx6DwC6iSFkkCFIXkWAMWAEKicEkNDq/TD
18+
PF17p9iMt0VEhpOniL6wrBWzVEbBzbOz7tFJ6WL+hWd7wpBXqf9aQE+n0L2O6Qzjlgxylw
19+
Kw+MGrXPYCFmkAR+98A1vyoAXJzEUqBloEI7GKiGpj+KFdfh6lCN5UQLF2Wl/nogRrd/tw
20+
OSnmz9u1CdWFMIcJc7O8M0ymgrtDmi/oTrD9RdgMQGvfeW4BZLDHdt+uObsd2AiSlxuLBq
21+
SdWfx7OPSu9oL/kIy2VcV6mOtt3PPtzlIZYsaqBBXeIhu1DHOWuednIf1QPo2rKZi2aBYT
22+
8/fWgUVW9aAkj8UsC8PkP8Mb+qWZk/teK6k82Nn2q41Od4TPgrFD4e3Z1l4Rhu0bgOcAnX
23+
jlzmI7pLH8wKByGYT6k4EAAAADAQABAAACAEeOg+nAE40LY6UsZHS8bVYeH3ClBcySwELT
24+
hOyM7uDYu/hy+Wy9b8zJTbtaKJWgbPY9RrYPP1lFXk9FXH0EjC5f9XyAuT2mrcO5+yQvn0
25+
5ng3dy9XSnDAzBcAc8yH4cAtInTzD2O0OGPZpr/Hp83Tm3NHg4EjVCedLZUSZMZ7cGaFpa
26+
svzp9wE/M2KZNLP087K+Do5pNEuGZVVugH/4eOApqBOsFWoOwTFADJjzkSEdftp6ZM8WMp
27+
XBU5T3UAnh3M3GbartlJqza9o1tKk5Ham9SFZvZFiQMvBaAr6kpzP+qh86hnuvb/EU1Tw1
28+
ldj6skzjJCq3cTzeuIEn7BiUL1qEECjpjx7OG6L9/lWyOy27nU/tiQ1MCUDMs/u/Kpnm8X
29+
1kvEYzq1iEQVjqEaKHQBA35GB5krXzVLK2XNMYzZDM4+bGbffX04t4CpVbJHY7mFrbO584
30+
JlqsCxKvhDDJpNuWhT4HUrAMPCJRvFC57n12+wjLrDsBKMOGRwo1NqnaR75QOR5gtboav+
31+
6P/o35U/gATyiePDF3HD/213gJcOwRXpH9oFleRStqiU2OsfcULlrjD6gIXCAQOOrt4l15
32+
uEh8fnUdFbgmFfuTapKHHm6nVGs6K0JWpqlqlsiwsJxSBwRhRFO3G/iAsmxKDvWaq1yBIJ
33+
yhDRTeA7fyCw8k+wsBAAABAGeNiRwkVyn/iUA61drLC5Y/0Gd+a540VrLMwyV3LGlDZPH3
34+
RQFHH+HldhLqmp2ikHZWFq36vjTDr/ubCuwQNlJo4TAo5/RQk1/ChBqXj2IdT+vBysH+bK
35+
IuZQoWXsfISMfQ7o+F5vv7WdItS9w44HpXayH12Q8D1Qr4Qnt0CeMIhrrV7MPsGVTIOpOU
36+
FxH4xu9ovBWDnyloC4rWkBmeAzLCFtO1V1iGN7Six/OXvnxnbif+BsfdQt+OxHIYBOue5G
37+
+Dkss+1xR8l8xrZsOpN2uY1QFIaE6UyElFleAEhtYL2vvuXTrL3EJKqRtIcWenL/wxYlkt
38+
X1CJQS02JW+PtNUAAAEBAPWFstL1hWK4Fp5ipJSGSkDNvGGuzamAYEgqr6n5Zzb1R1HPyE
39+
x6uEMB7ELQjOG4FENIQYBBnBRnMOWWFJp0V5UjFKDft1FabLiozqBtLCRnHnIGllFIWJK+
40+
u/h9OL4OWXGUJx2Em4XdJBPqp0g56VI237AsnTbTGS0tGLOErLWbQY7npZeBFct/501RTP
41+
M5i7F0QEDLjEDZbDxvCz8a5tjfvyP1awK2SyluiE4VPeYr5Op1JNPTJMz5U3YFsIZxdZHJ
42+
AK5mX8hNzTHpTApkS7o0DvExn5DVB8OHOQFdc+BjBIqQwa953f3FaAw9V3o6Dt1zXe9OJR
43+
tBUiBeurvDFk0AAAEBANLpAv9NDf3c8k0PAYhwu+SWoo0OclOWQSZes/93UeB0ch57LD+v
44+
KVPR3hw2AzAsgZn/PcMbIC3SPLNnAlNftfTa98avQOEfmYqrH499zVPuMb7fieS/eQZ4LF
45+
rsZ0o+W4CDVmzImgOe1hENWcfSeUKajEwpgtj440mJlBls37G/zHMMe5DkA2TAxKldiHOR
46+
fmHOtFKT3fnKFa6PWbwlLFnWIod4zheWrwV7E1coBhh+CA5SlgQANRFs7J8zxPznOtIK2O
47+
cF2+/92cM0TijlBk8u5jnN44cUmk4V1nYboCVb0JD2B7yF9ZYP6IB03jt5GEZSfHHCrZP8
48+
vCxMmXDxtAUAAAAXYWp2YW5lcnBASGVpbWRhbGwubG9jYWwBAgME
49+
-----END OPENSSH PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN DSA PRIVATE KEY-----
2+
Proc-Type: 4,ENCRYPTED
3+
DEK-Info: DES-EDE3-CBC,9B6744BB12A8EA8F
4+
5+
pzZw5s3zDVHYdejZxdTpaRx00Yd1grbJe6mIJGvZRB0Jm0hKXoOX71PUI814mc5+
6+
a5pzbyO98aciL/Eat5m3P692WQ0yOPMuphRnklsM3s4qrCjp2aRRbWvbyV/QV9bp
7+
Xz2yYvNqU3WJC3UJIaFFMvRo/lC/Wsz9OvHSSl3LnsXXhiOCeaE32etoOYdlk9ro
8+
N9NqDdaw28t9//iiHhuQK4afK6TZkU6DatFljJHILCC416Xh9+DDK9E+CDKzmlcw
9+
jSwtzgFKEhgrT0XKoZR9LJZDolT1YpFy7M3cFRYIuYvJfuLcjxVEldJE900QlaJS
10+
ybb6RxV6SRVwQYXTbIClcXes+oNJMv59DivAfajxECQC5sAynW/FnY1sz0igmz6D
11+
scclJuJIbawqiuV/Lv6bvgzMa/ZXL4b9JeJPuQELa7tCpvj4fpNk1IiftYISlwoT
12+
iG5pL8yLhPL4/fxGnKJzUPCA9mbwiloW2cAZZxTd+Utqmhemcl9gF0JGNR2XeYwS
13+
3obEjbkqMF0WR3AcVZU9B5d9SKUaAzTp4vu5yZtNVEIaiVlnI3hMwWMs2Jgahswo
14+
QF9MCPsRYsxLs7/u4a4qoQ==
15+
-----END DSA PRIVATE KEY-----

src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java

+59-16
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,27 @@
2121
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
2222
import net.schmizz.sshj.common.*;
2323
import net.schmizz.sshj.common.Buffer.PlainBuffer;
24-
import net.schmizz.sshj.transport.cipher.BlockCipher;
2524
import net.schmizz.sshj.transport.cipher.Cipher;
2625
import net.schmizz.sshj.userauth.keyprovider.BaseFileKeyProvider;
2726
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
2827
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
28+
import org.bouncycastle.asn1.nist.NISTNamedCurves;
29+
import org.bouncycastle.asn1.x9.X9ECParameters;
30+
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
2931
import org.mindrot.jbcrypt.BCrypt;
3032
import org.slf4j.Logger;
3133
import org.slf4j.LoggerFactory;
3234

3335
import java.io.BufferedReader;
3436
import java.io.IOException;
37+
import java.math.BigInteger;
3538
import java.nio.ByteBuffer;
3639
import java.nio.CharBuffer;
3740
import java.nio.charset.Charset;
38-
import java.security.GeneralSecurityException;
39-
import java.security.KeyPair;
40-
import java.security.PublicKey;
41+
import java.security.*;
42+
import java.security.spec.ECPrivateKeySpec;
43+
import java.security.spec.InvalidKeySpecException;
44+
import java.security.spec.RSAPrivateKeySpec;
4145
import java.util.Arrays;
4246

4347
/**
@@ -125,10 +129,12 @@ private PlainBuffer decryptBuffer(PlainBuffer privateKeyBuffer, String cipherNam
125129
private void initializeCipher(String kdfName, byte[] kdfOptions, Cipher cipher) throws Buffer.BufferException {
126130
if (kdfName.equals(BCRYPT)) {
127131
PlainBuffer opts = new PlainBuffer(kdfOptions);
128-
CharBuffer charBuffer = CharBuffer.wrap(pwdf.reqPassword(null));
129-
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
130-
byte[] passphrase = Arrays.copyOfRange(byteBuffer.array(),
131-
byteBuffer.position(), byteBuffer.limit());
132+
byte[] passphrase = new byte[0];
133+
if (pwdf != null) {
134+
CharBuffer charBuffer = CharBuffer.wrap(pwdf.reqPassword(null));
135+
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
136+
passphrase = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
137+
}
132138
byte[] keyiv = new byte[48];
133139
new BCrypt().pbkdf(passphrase, opts.readBytes(), opts.readUInt32AsInt(), keyiv);
134140
byte[] key = Arrays.copyOfRange(keyiv, 0, 32);
@@ -183,13 +189,40 @@ private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey pub
183189
}
184190
// The private key section contains both the public key and the private key
185191
String keyType = keyBuffer.readString(); // string keytype
186-
logger.info("Read key type: {}", keyType);
187-
188-
byte[] pubKey = keyBuffer.readBytes(); // string publickey (again...)
189-
keyBuffer.readUInt32();
190-
byte[] privKey = new byte[32];
191-
keyBuffer.readRawBytes(privKey); // string privatekey
192-
keyBuffer.readRawBytes(new byte[32]); // string publickey (again...)
192+
KeyType kt = KeyType.fromString(keyType);
193+
logger.info("Read key type: {}", keyType, kt);
194+
KeyPair kp;
195+
switch (kt) {
196+
case ED25519:
197+
byte[] pubKey = keyBuffer.readBytes(); // string publickey (again...)
198+
keyBuffer.readUInt32(); // length of privatekey+publickey
199+
byte[] privKey = new byte[32];
200+
keyBuffer.readRawBytes(privKey); // string privatekey
201+
keyBuffer.readRawBytes(new byte[32]); // string publickey (again...)
202+
kp = new KeyPair(publicKey, new EdDSAPrivateKey(new EdDSAPrivateKeySpec(privKey, EdDSANamedCurveTable.getByName("Ed25519"))));
203+
break;
204+
case RSA:
205+
BigInteger n = keyBuffer.readMPInt(); // Modulus
206+
BigInteger e = keyBuffer.readMPInt(); // Public Exponent
207+
BigInteger d = keyBuffer.readMPInt(); // Private Exponent
208+
keyBuffer.readMPInt(); // iqmp (q^-1 mod p)
209+
keyBuffer.readMPInt(); // p (Prime 1)
210+
keyBuffer.readMPInt(); // q (Prime 2)
211+
kp = new KeyPair(publicKey, SecurityUtils.getKeyFactory("RSA").generatePrivate(new RSAPrivateKeySpec(n, d)));
212+
break;
213+
case ECDSA256:
214+
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-256"));
215+
break;
216+
case ECDSA384:
217+
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-384"));
218+
break;
219+
case ECDSA521:
220+
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-521"));
221+
break;
222+
223+
default:
224+
throw new IOException("Cannot decode keytype " + keyType + " in openssh-key-v1 files (yet).");
225+
}
193226
String comment = keyBuffer.readString(); // string comment
194227
byte[] padding = new byte[keyBuffer.available()];
195228
keyBuffer.readRawBytes(padding); // char[] padding
@@ -198,6 +231,16 @@ private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey pub
198231
throw new IOException("Padding of key format contained wrong byte at position: " + i);
199232
}
200233
}
201-
return new KeyPair(publicKey, new EdDSAPrivateKey(new EdDSAPrivateKeySpec(privKey, EdDSANamedCurveTable.getByName("Ed25519"))));
234+
return kp;
235+
}
236+
237+
private PrivateKey createECDSAPrivateKey(KeyType kt, PlainBuffer buffer, String name) throws GeneralSecurityException, Buffer.BufferException {
238+
PublicKey pk = kt.readPubKeyFromBuffer(buffer); // Public key
239+
BigInteger s = new BigInteger(1, buffer.readBytes());
240+
X9ECParameters ecParams = NISTNamedCurves.getByName(name);
241+
ECNamedCurveSpec ecCurveSpec = new ECNamedCurveSpec(name, ecParams.getCurve(), ecParams.getG(), ecParams.getN());
242+
ECPrivateKeySpec pks = new ECPrivateKeySpec(s, ecCurveSpec);
243+
return SecurityUtils.getKeyFactory("ECDSA").generatePrivate(pks);
244+
202245
}
203246
}

src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private static String readHeader(Reader privateKey) throws IOException {
8989

9090
private static KeyFormat keyFormatFromHeader(String header, boolean separatePubKey) {
9191
if (header.startsWith("-----BEGIN") && header.endsWith("PRIVATE KEY-----")) {
92-
if (separatePubKey && header.contains(OpenSSHKeyV1KeyFile.OPENSSH_PRIVATE_KEY)) {
92+
if (header.contains(OpenSSHKeyV1KeyFile.OPENSSH_PRIVATE_KEY)) {
9393
return KeyFormat.OpenSSHv1;
9494
} else if (separatePubKey) {
9595
// Can delay asking for password since have unencrypted pubkey

src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,22 @@ public void shouldLoadProtectedED25519PrivateKeyAes256CBC() throws IOException {
197197
checkOpenSSHKeyV1("src/test/resources/keytypes/ed25519_aes256cbc.pem", "foobar");
198198
}
199199

200+
@Test
201+
public void shouldLoadRSAPrivateKeyAsOpenSSHV1() throws IOException {
202+
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
203+
keyFile.init(new File("src/test/resources/keyformats/rsa_opensshv1"));
204+
PrivateKey aPrivate = keyFile.getPrivate();
205+
assertThat(aPrivate.getAlgorithm(), equalTo("RSA"));
206+
}
207+
208+
@Test
209+
public void shouldLoadECDSAPrivateKeyAsOpenSSHV1() throws IOException {
210+
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
211+
keyFile.init(new File("src/test/resources/keyformats/ecdsa_opensshv1"));
212+
PrivateKey aPrivate = keyFile.getPrivate();
213+
assertThat(aPrivate.getAlgorithm(), equalTo("ECDSA"));
214+
}
215+
200216
private void checkOpenSSHKeyV1(String key, final String password) throws IOException {
201217
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
202218
keyFile.init(new File(key), new PasswordFinder() {

0 commit comments

Comments
 (0)