org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
druhm opened this issue · 5 comments
Hi,
I have a problem with SSJ when I connect to an OpenSSH server (6.6.1) with ECDSA keys (ecdsa-sha2-nistp256). While RSA and DSA keys work without any problems, ECDSA keys fail to authenticate a user. OpenSSH is well configured; using the very same keys with other tools (e.g. putty) I can successfully connect with ECDSA as well. Therefore I think its an SSHJ issue.
The problem is a bad cast from a private key to a public key in KeyType.java:133
@Override
protected boolean isMyType(Key key) {
return ("ECDSA".equals(key.getAlgorithm()) && ECDSAVariationsAdapter.fieldSizeFromKey((ECPublicKey) key) == 256);
}
which results in the folloing error message.
org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
Root cause is that in KeyedAuthMethod.java:64 a call to KeyType.fromKey() uses a private key as parameter (created in KeyedAuthMethod.java:59), which basically leads to the ClassCastException later on.
[main] INFO net.schmizz.sshj.transport.random.BouncyCastleRandom - Generating random seed from SecureRandom.
[main] INFO net.schmizz.sshj.transport.TransportImpl - Client identity string: SSH-2.0-SSHJ_0.22.0
[main] INFO net.schmizz.sshj.transport.TransportImpl - Server identity string: SSH-2.0-OpenSSH_6.6.1
[reader] ERROR net.schmizz.sshj.transport.TransportImpl - Dying because - org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
java.lang.ClassCastException: org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
at net.schmizz.sshj.common.KeyType$3.isMyType(KeyType.java:133)
at net.schmizz.sshj.common.KeyType.fromKey(KeyType.java:297)
at net.schmizz.sshj.userauth.method.KeyedAuthMethod.putSig(KeyedAuthMethod.java:64)
at net.schmizz.sshj.userauth.method.AuthPublickey.sendSignedReq(AuthPublickey.java:74)
at net.schmizz.sshj.userauth.method.AuthPublickey.handle(AuthPublickey.java:45)
at net.schmizz.sshj.userauth.UserAuthImpl.handle(UserAuthImpl.java:142)
at net.schmizz.sshj.transport.TransportImpl.handle(TransportImpl.java:500)
at net.schmizz.sshj.transport.Decoder.decode(Decoder.java:102)
at net.schmizz.sshj.transport.Decoder.received(Decoder.java:170)
at net.schmizz.sshj.transport.Reader.run(Reader.java:59)
[reader] INFO net.schmizz.sshj.transport.TransportImpl - Disconnected - UNKNOWN
[main] ERROR net.schmizz.concurrent.Promise - <<authenticated>> woke to: net.schmizz.sshj.userauth.UserAuthException: org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
Exception in thread "main" net.schmizz.sshj.userauth.UserAuthException: Exhausted available authentication methods
at net.schmizz.sshj.SSHClient.auth(SSHClient.java:230)
at net.schmizz.sshj.SSHClient.authPublickey(SSHClient.java:345)
at net.schmizz.sshj.SSHClient.authPublickey(SSHClient.java:364)
at ecdsatester.EcdsaTesterMain.main(EcdsaTesterMain.java:46)
Caused by: net.schmizz.sshj.userauth.UserAuthException: org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
at net.schmizz.sshj.userauth.UserAuthException$1.chain(UserAuthException.java:33)
at net.schmizz.sshj.userauth.UserAuthException$1.chain(UserAuthException.java:26)
at net.schmizz.concurrent.Promise.deliverError(Promise.java:96)
at net.schmizz.sshj.userauth.UserAuthImpl.notifyError(UserAuthImpl.java:156)
at net.schmizz.sshj.transport.TransportImpl.die(TransportImpl.java:601)
at net.schmizz.sshj.transport.Reader.run(Reader.java:67)
Caused by: net.schmizz.sshj.common.SSHException: org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
at net.schmizz.sshj.common.SSHException$1.chain(SSHException.java:36)
at net.schmizz.sshj.common.SSHException$1.chain(SSHException.java:29)
at net.schmizz.sshj.transport.TransportImpl.die(TransportImpl.java:595)
... 1 more
Caused by: java.lang.ClassCastException: org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey cannot be cast to java.security.interfaces.ECPublicKey
at net.schmizz.sshj.common.KeyType$3.isMyType(KeyType.java:133)
at net.schmizz.sshj.common.KeyType.fromKey(KeyType.java:297)
at net.schmizz.sshj.userauth.method.KeyedAuthMethod.putSig(KeyedAuthMethod.java:64)
at net.schmizz.sshj.userauth.method.AuthPublickey.sendSignedReq(AuthPublickey.java:74)
at net.schmizz.sshj.userauth.method.AuthPublickey.handle(AuthPublickey.java:45)
at net.schmizz.sshj.userauth.UserAuthImpl.handle(UserAuthImpl.java:142)
at net.schmizz.sshj.transport.TransportImpl.handle(TransportImpl.java:500)
at net.schmizz.sshj.transport.Decoder.decode(Decoder.java:102)
at net.schmizz.sshj.transport.Decoder.received(Decoder.java:170)
at net.schmizz.sshj.transport.Reader.run(Reader.java:59)
There is a good change that I am using your API incorrectly here, since I have not found anything about this issue online and I somehow doubt that I would be the first to stumble across this.
If so please advise how to connect with a given private ECDSA key. But even if there is something wrong with the keys themselves (encoding etc), the code path that causes the exception is at least dubious, or am I wrong?
The keys in the sample below have been created for this issue and can be thrown away. I have locally updated java.security for BC and replaced local_policy.jar and US_export_policy.jar with their unlimited version.
I am using JRE1.8.0_144, SSHJ-0.22.0 and BC-158.
Here is a minimal sample that illustrates the problem.
package tester.sshj;
import java.net.Inet4Address;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
public class EcdsaTesterMain
{
public static void main(final String[] args) throws Exception
{
final SSHClient sshClient = new SSHClient();
sshClient.addHostKeyVerifier( new PromiscuousVerifier() );
sshClient.connect( Inet4Address.getByName( "10.2.2.20" ) );
final String publicKey =
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
+ "NTYAAABBBA1ANSWFQ+1EUqDhncD8Y3mvhEw+iAATA/Qln5NzVUzZHbvyrJ+7l3"
+ "C00IceDdes9SIFtm0W0m7JjPvlCl5nlso= SSH Key";
final String privateKey =
"-----BEGIN EC PRIVATE KEY-----\n" +
"MHcCAQEEIGhcvG8anyHew/xZJfozh5XIc1kmZZs6o2f0l3KFs4jgoAoGCCqGSM49\n" +
"AwEHoUQDQgAEDUA1JYVD7URSoOGdwPxjea+ETD6IABMD9CWfk3NVTNkdu/Ksn7uX\n" +
"cLTQhx4N16z1IgW2bRbSbsmM++UKXmeWyg==\n" +
"-----END EC PRIVATE KEY-----\n";
final OpenSSHKeyFile keyFile = new OpenSSHKeyFile();
keyFile.init( privateKey, publicKey );
final KeyProvider keyProvider = new KeyPairWrapper( keyFile.getPublic(), keyFile.getPrivate());
sshClient.authPublickey
( "username"
, keyProvider
);
System.out.println( sshClient.isAuthenticated() );
sshClient.disconnect();
}
}
Thanks for your time
Thomas
THanks for the carefully described issue! Which version of SSHJ are you using? (Just to check :))
That was fast :). sshj-0.22.0.jar
I did not build this myself, but used the jar from http://repo1.maven.org/maven2/com/hierynomus/sshj/0.22.0/
Fixed it ;)
Nice. Thanks a lot!