diff --git a/src/itest/groovy/com/hierynomus/sshj/IntegrationSpec.groovy b/src/itest/groovy/com/hierynomus/sshj/IntegrationSpec.groovy index fc4c30de8..8d55bce3f 100644 --- a/src/itest/groovy/com/hierynomus/sshj/IntegrationSpec.groovy +++ b/src/itest/groovy/com/hierynomus/sshj/IntegrationSpec.groovy @@ -15,6 +15,8 @@ */ package com.hierynomus.sshj +import com.hierynomus.sshj.key.ECDSAKeyAlgorithm +import com.hierynomus.sshj.key.EdDSAKeyAlgorithm import com.hierynomus.sshj.signature.SignatureEdDSA import net.schmizz.sshj.DefaultConfig import net.schmizz.sshj.SSHClient @@ -29,7 +31,7 @@ class IntegrationSpec extends IntegrationBaseSpec { def "should accept correct key for #signatureName"() { given: def config = new DefaultConfig() - config.setSignatureFactories(signatureFactory) + config.setKeyAlgorithms(Collections.singletonList(signatureFactory)) SSHClient sshClient = new SSHClient(config) sshClient.addHostKeyVerifier(fingerprint) // test-containers/ssh_host_ecdsa_key's fingerprint @@ -40,7 +42,7 @@ class IntegrationSpec extends IntegrationBaseSpec { sshClient.isConnected() where: - signatureFactory << [new SignatureECDSA.Factory256(), new SignatureEdDSA.Factory()] + signatureFactory << [new ECDSAKeyAlgorithm.Factory256(), new EdDSAKeyAlgorithm.Factory()] fingerprint << ["d3:6a:a9:52:05:ab:b5:48:dd:73:60:18:0c:3a:f0:a3", "dc:68:38:ce:fc:6f:2c:d6:6d:6b:34:eb:5c:f0:41:6a"] signatureName = signatureFactory.getName() } diff --git a/src/itest/groovy/com/hierynomus/sshj/signature/SignatureSpec.groovy b/src/itest/groovy/com/hierynomus/sshj/signature/SignatureSpec.groovy new file mode 100644 index 000000000..0a91482e0 --- /dev/null +++ b/src/itest/groovy/com/hierynomus/sshj/signature/SignatureSpec.groovy @@ -0,0 +1,43 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.signature + +import com.hierynomus.sshj.IntegrationBaseSpec +import com.hierynomus.sshj.key.RSAKeyAlgorithm +import net.schmizz.sshj.DefaultConfig +import net.schmizz.sshj.signature.SignatureRSA +import spock.lang.Unroll + +class SignatureSpec extends IntegrationBaseSpec { + + @Unroll + def "should correctly connect with #sig Signature"() { + given: + def cfg = new DefaultConfig() + cfg.setKeyAlgorithms(Collections.singletonList(sigFactory)) + def client = getConnectedClient(cfg) + + when: + client.authPublickey(USERNAME, KEYFILE) + + then: + client.authenticated + + where: + sigFactory << [new RSAKeyAlgorithm.FactorySSHRSA(), new RSAKeyAlgorithm.FactoryRSASHA256(), new RSAKeyAlgorithm.FactoryRSASHA512()] + sig = sigFactory.name + } +} diff --git a/src/itest/groovy/com/hierynomus/sshj/transport/mac/MacSpec.groovy b/src/itest/groovy/com/hierynomus/sshj/transport/mac/MacSpec.groovy index a5842a449..460038838 100644 --- a/src/itest/groovy/com/hierynomus/sshj/transport/mac/MacSpec.groovy +++ b/src/itest/groovy/com/hierynomus/sshj/transport/mac/MacSpec.groovy @@ -17,9 +17,6 @@ package com.hierynomus.sshj.transport.mac import com.hierynomus.sshj.IntegrationBaseSpec import net.schmizz.sshj.DefaultConfig -import net.schmizz.sshj.transport.mac.HMACRIPEMD160 -import net.schmizz.sshj.transport.mac.HMACSHA2256 -import spock.lang.AutoCleanup import spock.lang.Unroll class MacSpec extends IntegrationBaseSpec { diff --git a/src/main/java/com/hierynomus/sshj/key/AbstractKeyAlgorithm.java b/src/main/java/com/hierynomus/sshj/key/AbstractKeyAlgorithm.java new file mode 100644 index 000000000..e5d616b39 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/key/AbstractKeyAlgorithm.java @@ -0,0 +1,60 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.key; + +import net.schmizz.sshj.common.Buffer; +import net.schmizz.sshj.common.Factory; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.signature.Signature; + +import java.security.GeneralSecurityException; +import java.security.PublicKey; + +public abstract class AbstractKeyAlgorithm implements KeyAlgorithm { + private final String keyAlgorithm; + private final Factory.Named signature; + private final KeyType keyFormat; + + public AbstractKeyAlgorithm(String keyAlgorithm, Factory.Named signature, KeyType keyFormat) { + this.keyAlgorithm = keyAlgorithm; + this.signature = signature; + this.keyFormat = keyFormat; + } + + public void putPubKeyIntoBuffer(PublicKey pk, Buffer buf) { + keyFormat.putPubKeyIntoBuffer(pk, buf); + } + + @Override + public PublicKey readPubKeyFromBuffer(Buffer buf) throws GeneralSecurityException { + return keyFormat.readPubKeyFromBuffer(buf); + } + + @Override + public String getKeyAlgorithm() { + return keyAlgorithm; + } + + @Override + public KeyType getKeyFormat() { + return keyFormat; + } + + @Override + public Signature newSignature() { + return this.signature.create(); + } +} diff --git a/src/main/java/com/hierynomus/sshj/key/DSAKeyAlgorithm.java b/src/main/java/com/hierynomus/sshj/key/DSAKeyAlgorithm.java new file mode 100644 index 000000000..d7fe6f6f1 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/key/DSAKeyAlgorithm.java @@ -0,0 +1,65 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.key; + +import net.schmizz.sshj.common.Factory; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.signature.Signature; +import net.schmizz.sshj.signature.SignatureDSA; + +public class DSAKeyAlgorithm extends AbstractKeyAlgorithm { + + /** + * A named factory for the SSH-DSA key algorithm. + */ + public static class FactorySSHDSA + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new DSAKeyAlgorithm(KeyType.DSA.toString(), new SignatureDSA.Factory(), KeyType.DSA); + } + + @Override + public String getName() { + return KeyType.DSA.toString(); + } + + } + + /** + * A named factory for the SSH-DSS-CERT key algorithm + */ + public static class FactorySSHDSSCert + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new DSAKeyAlgorithm(KeyType.DSA_CERT.toString(), new SignatureDSA.Factory(), KeyType.DSA_CERT); + } + + @Override + public String getName() { + return KeyType.DSA_CERT.toString(); + } + + } + + + public DSAKeyAlgorithm(String keyAlgorithm, Factory.Named signature, KeyType keyFormat) { + super(keyAlgorithm, signature, KeyType.DSA); + } +} diff --git a/src/main/java/com/hierynomus/sshj/key/ECDSAKeyAlgorithm.java b/src/main/java/com/hierynomus/sshj/key/ECDSAKeyAlgorithm.java new file mode 100644 index 000000000..6346db2e9 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/key/ECDSAKeyAlgorithm.java @@ -0,0 +1,72 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.key; + +import net.schmizz.sshj.common.Factory; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.signature.Signature; +import net.schmizz.sshj.signature.SignatureECDSA; + +public class ECDSAKeyAlgorithm extends AbstractKeyAlgorithm { + /** A named factory for ECDSA-256 signature */ + public static class Factory256 implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new ECDSAKeyAlgorithm(KeyType.ECDSA256.toString(), new SignatureECDSA.Factory256(), KeyType.ECDSA256); + } + + @Override + public String getName() { + return KeyType.ECDSA256.toString(); + } + + } + + /** A named factory for ECDSA-384 signature */ + public static class Factory384 implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new ECDSAKeyAlgorithm(KeyType.ECDSA384.toString(), new SignatureECDSA.Factory384(), KeyType.ECDSA384); + } + + @Override + public String getName() { + return KeyType.ECDSA384.toString(); + } + + } + + /** A named factory for ECDSA-521 signature */ + public static class Factory521 implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new ECDSAKeyAlgorithm(KeyType.ECDSA521.toString(), new SignatureECDSA.Factory384(), KeyType.ECDSA521); + } + + @Override + public String getName() { + return KeyType.ECDSA521.toString(); + } + + } + + public ECDSAKeyAlgorithm(String keyAlgorithm, Factory.Named signature, KeyType keyFormat) { + super(keyAlgorithm, signature, keyFormat); + } +} diff --git a/src/main/java/com/hierynomus/sshj/key/EdDSAKeyAlgorithm.java b/src/main/java/com/hierynomus/sshj/key/EdDSAKeyAlgorithm.java new file mode 100644 index 000000000..633135482 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/key/EdDSAKeyAlgorithm.java @@ -0,0 +1,39 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.key; + +import com.hierynomus.sshj.signature.SignatureEdDSA; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.signature.Signature; + +public class EdDSAKeyAlgorithm extends AbstractKeyAlgorithm { + public static class Factory implements net.schmizz.sshj.common.Factory.Named { + + @Override + public String getName() { + return KeyType.ED25519.toString(); + } + + @Override + public KeyAlgorithm create() { + return new EdDSAKeyAlgorithm(KeyType.ED25519.toString(), new SignatureEdDSA.Factory(), KeyType.ED25519); + } + } + + public EdDSAKeyAlgorithm(String keyAlgorithm, Factory.Named signature, KeyType keyFormat) { + super(keyAlgorithm, signature, keyFormat); + } +} diff --git a/src/main/java/com/hierynomus/sshj/key/KeyAlgorithm.java b/src/main/java/com/hierynomus/sshj/key/KeyAlgorithm.java new file mode 100644 index 000000000..dbfcebd23 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/key/KeyAlgorithm.java @@ -0,0 +1,45 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.key; + +import net.schmizz.sshj.common.Buffer; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.signature.Signature; + +import java.security.GeneralSecurityException; +import java.security.PublicKey; + +/** + * In [RFC4252], the concept "public key algorithm" is used to establish + * a relationship between one algorithm name, and: + *

+ * A. procedures used to generate and validate a private/public + * keypair; + * B. a format used to encode a public key; and + * C. procedures used to calculate, encode, and verify a signature. + */ +public interface KeyAlgorithm { + + PublicKey readPubKeyFromBuffer(Buffer buf) throws GeneralSecurityException; + + void putPubKeyIntoBuffer(PublicKey pk, Buffer buf); + + String getKeyAlgorithm(); + + KeyType getKeyFormat(); + + Signature newSignature(); +} diff --git a/src/main/java/com/hierynomus/sshj/key/RSAKeyAlgorithm.java b/src/main/java/com/hierynomus/sshj/key/RSAKeyAlgorithm.java new file mode 100644 index 000000000..2f90f5c48 --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/key/RSAKeyAlgorithm.java @@ -0,0 +1,96 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.key; + +import net.schmizz.sshj.common.Factory; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.signature.Signature; +import net.schmizz.sshj.signature.SignatureRSA; + +public class RSAKeyAlgorithm extends AbstractKeyAlgorithm { + + /** + * A named factory for the SSH-RSA (SHA1) public key algorithm + */ + public static class FactorySSHRSA + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new RSAKeyAlgorithm("ssh-rsa", new SignatureRSA.FactorySSHRSA(), KeyType.RSA); + } + + @Override + public String getName() { + return "ssh-rsa"; + } + } + + /** + * A named factory for the ssh-rsa-cert-v01@openssh.com (SHA1) public key algorithm + */ + public static class FactorySSHRSACert + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new RSAKeyAlgorithm("ssh-rsa-cert-v01@openssh.com", new SignatureRSA.FactoryCERT(), KeyType.RSA_CERT); + } + + @Override + public String getName() { + return "ssh-rsa-cert-v01@openssh.com"; + } + } + + /** + * A named factory for the RSA-SHA2-256 public key algorithm + */ + public static class FactoryRSASHA256 + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new RSAKeyAlgorithm("rsa-sha2-256", new SignatureRSA.FactoryRSASHA256(), KeyType.RSA); + } + + @Override + public String getName() { + return "rsa-sha2-256"; + } + } + + /** + * A named factory for the RSA-SHA2-512 public key algorithm + */ + public static class FactoryRSASHA512 + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public KeyAlgorithm create() { + return new RSAKeyAlgorithm("rsa-sha2-512", new SignatureRSA.FactoryRSASHA512(), KeyType.RSA); + } + + @Override + public String getName() { + return "rsa-sha2-512"; + } + } + + public RSAKeyAlgorithm(String keyAlgorithm, Factory.Named signature, KeyType keyFormat) { + super(keyAlgorithm, signature, keyFormat); + } +} diff --git a/src/main/java/com/hierynomus/sshj/signature/SignatureEdDSA.java b/src/main/java/com/hierynomus/sshj/signature/SignatureEdDSA.java index 19a1da4ab..5f460b335 100644 --- a/src/main/java/com/hierynomus/sshj/signature/SignatureEdDSA.java +++ b/src/main/java/com/hierynomus/sshj/signature/SignatureEdDSA.java @@ -40,7 +40,7 @@ public Signature create() { } SignatureEdDSA() { - super(getEngine()); + super(getEngine(), KeyType.ED25519.toString()); } private static EdDSAEngine getEngine() { diff --git a/src/main/java/net/schmizz/sshj/AndroidConfig.java b/src/main/java/net/schmizz/sshj/AndroidConfig.java index 1dae34d62..77605f441 100644 --- a/src/main/java/net/schmizz/sshj/AndroidConfig.java +++ b/src/main/java/net/schmizz/sshj/AndroidConfig.java @@ -15,6 +15,9 @@ */ package net.schmizz.sshj; +import com.hierynomus.sshj.key.DSAKeyAlgorithm; +import com.hierynomus.sshj.key.EdDSAKeyAlgorithm; +import com.hierynomus.sshj.key.RSAKeyAlgorithm; import com.hierynomus.sshj.signature.SignatureEdDSA; import net.schmizz.sshj.common.SecurityUtils; @@ -23,6 +26,8 @@ import net.schmizz.sshj.transport.random.JCERandom; import net.schmizz.sshj.transport.random.SingletonRandomFactory; +import java.util.Arrays; + /** * Registers SpongyCastle as JCE provider. */ @@ -33,11 +38,14 @@ public class AndroidConfig SecurityUtils.registerSecurityProvider("org.spongycastle.jce.provider.BouncyCastleProvider"); } - // don't add ECDSA - protected void initSignatureFactories() { - setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory(), - // but add EdDSA - new SignatureEdDSA.Factory()); + + @Override + protected void initKeyAlgorithms() { + setKeyAlgorithms(Arrays.asList( + new EdDSAKeyAlgorithm.Factory(), + new RSAKeyAlgorithm.FactorySSHRSA(), + new DSAKeyAlgorithm.FactorySSHDSA() + )); } @Override diff --git a/src/main/java/net/schmizz/sshj/Config.java b/src/main/java/net/schmizz/sshj/Config.java index 4d19a5dd8..79189998b 100644 --- a/src/main/java/net/schmizz/sshj/Config.java +++ b/src/main/java/net/schmizz/sshj/Config.java @@ -15,6 +15,7 @@ */ package net.schmizz.sshj; +import com.hierynomus.sshj.key.KeyAlgorithm; import net.schmizz.keepalive.KeepAliveProvider; import net.schmizz.sshj.common.Factory; import net.schmizz.sshj.common.LoggerFactory; @@ -77,11 +78,11 @@ public interface Config { Factory getRandomFactory(); /** - * Retrieve the list of named factories for {@link Signature} + * Retrieve the list of named factories for {@link com.hierynomus.sshj.key.KeyAlgorithm} * - * @return a list of named {@link Signature} factories + * @return a list of named {@link com.hierynomus.sshj.key.KeyAlgorithm} factories */ - List> getSignatureFactories(); + List> getKeyAlgorithms(); /** * Returns the software version information for identification during SSH connection initialization. For example, @@ -132,11 +133,11 @@ public interface Config { void setRandomFactory(Factory randomFactory); /** - * Set the named factories for {@link Signature}. + * Set the named factories for {@link KeyAlgorithm}. * - * @param signatureFactories a list of named factories + * @param keyAlgorithms a list of named factories */ - void setSignatureFactories(List> signatureFactories); + void setKeyAlgorithms(List> keyAlgorithms); /** * Set the software version information for identification during SSH connection initialization. For example, {@code diff --git a/src/main/java/net/schmizz/sshj/ConfigImpl.java b/src/main/java/net/schmizz/sshj/ConfigImpl.java index 70df287cb..0bddd18e7 100644 --- a/src/main/java/net/schmizz/sshj/ConfigImpl.java +++ b/src/main/java/net/schmizz/sshj/ConfigImpl.java @@ -15,10 +15,10 @@ */ package net.schmizz.sshj; +import com.hierynomus.sshj.key.KeyAlgorithm; import net.schmizz.keepalive.KeepAliveProvider; import net.schmizz.sshj.common.Factory; import net.schmizz.sshj.common.LoggerFactory; -import net.schmizz.sshj.signature.Signature; import net.schmizz.sshj.transport.cipher.Cipher; import net.schmizz.sshj.transport.compression.Compression; import net.schmizz.sshj.transport.kex.KeyExchange; @@ -42,7 +42,7 @@ public class ConfigImpl private List> cipherFactories; private List> compressionFactories; private List> macFactories; - private List> signatureFactories; + private List> keyAlgorithms; private List> fileKeyProviderFactories; private boolean waitForServerIdentBeforeSendingClientIdent = false; @@ -78,11 +78,6 @@ public Factory getRandomFactory() { return randomFactory; } - @Override - public List> getSignatureFactories() { - return signatureFactories; - } - @Override public String getVersion() { return version; @@ -138,15 +133,6 @@ public void setRandomFactory(Factory randomFactory) { this.randomFactory = randomFactory; } - public void setSignatureFactories(Factory.Named... signatureFactories) { - setSignatureFactories(Arrays.asList(signatureFactories)); - } - - @Override - public void setSignatureFactories(List> signatureFactories) { - this.signatureFactories = signatureFactories; - } - @Override public void setVersion(String version) { this.version = version; @@ -172,6 +158,16 @@ public void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerI this.waitForServerIdentBeforeSendingClientIdent = waitForServerIdentBeforeSendingClientIdent; } + @Override + public List> getKeyAlgorithms() { + return keyAlgorithms; + } + + @Override + public void setKeyAlgorithms(List> keyAlgorithms) { + this.keyAlgorithms = keyAlgorithms; + } + @Override public LoggerFactory getLoggerFactory() { return loggerFactory; diff --git a/src/main/java/net/schmizz/sshj/DefaultConfig.java b/src/main/java/net/schmizz/sshj/DefaultConfig.java index 7f1bbf85e..b2f13f01e 100644 --- a/src/main/java/net/schmizz/sshj/DefaultConfig.java +++ b/src/main/java/net/schmizz/sshj/DefaultConfig.java @@ -15,7 +15,10 @@ */ package net.schmizz.sshj; -import com.hierynomus.sshj.signature.SignatureEdDSA; +import com.hierynomus.sshj.key.DSAKeyAlgorithm; +import com.hierynomus.sshj.key.ECDSAKeyAlgorithm; +import com.hierynomus.sshj.key.EdDSAKeyAlgorithm; +import com.hierynomus.sshj.key.RSAKeyAlgorithm; import com.hierynomus.sshj.transport.cipher.BlockCiphers; import com.hierynomus.sshj.transport.cipher.StreamCiphers; import com.hierynomus.sshj.transport.kex.DHGroups; @@ -26,10 +29,7 @@ import net.schmizz.sshj.common.Factory; import net.schmizz.sshj.common.LoggerFactory; import net.schmizz.sshj.common.SecurityUtils; -import net.schmizz.sshj.signature.SignatureDSA; -import net.schmizz.sshj.signature.SignatureECDSA; -import net.schmizz.sshj.signature.SignatureRSA; -import net.schmizz.sshj.transport.cipher.*; +import net.schmizz.sshj.transport.cipher.Cipher; import net.schmizz.sshj.transport.compression.NoneCompression; import net.schmizz.sshj.transport.kex.Curve25519SHA256; import net.schmizz.sshj.transport.kex.DHGexSHA1; @@ -56,7 +56,7 @@ *

  • {@link net.schmizz.sshj.ConfigImpl#setMACFactories MAC}: {@link net.schmizz.sshj.transport.mac.HMACSHA1}, {@link net.schmizz.sshj.transport.mac.HMACSHA196}, {@link net.schmizz.sshj.transport.mac.HMACMD5}, {@link * net.schmizz.sshj.transport.mac.HMACMD596}
  • *
  • {@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}
  • - *
  • {@link net.schmizz.sshj.ConfigImpl#setSignatureFactories Signature}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}
  • + *
  • {@link net.schmizz.sshj.ConfigImpl#setKeyAlgorithms KeyAlgorithm}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}
  • *
  • {@link net.schmizz.sshj.ConfigImpl#setRandomFactory PRNG}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}
  • *
  • {@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link * net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*
  • @@ -76,12 +76,12 @@ public DefaultConfig() { setVersion(readVersionFromProperties()); final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered(); initKeyExchangeFactories(bouncyCastleRegistered); + initKeyAlgorithms(); initRandomFactory(bouncyCastleRegistered); initFileKeyProviderFactories(bouncyCastleRegistered); initCipherFactories(); initCompressionFactories(); initMACFactories(); - initSignatureFactories(); setKeepAliveProvider(KeepAliveProvider.HEARTBEAT); } @@ -99,8 +99,8 @@ private String readVersionFromProperties() { @Override public void setLoggerFactory(LoggerFactory loggerFactory) { - super.setLoggerFactory(loggerFactory); - log = loggerFactory.getLogger(getClass()); + super.setLoggerFactory(loggerFactory); + log = loggerFactory.getLogger(getClass()); } protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) { @@ -133,6 +133,20 @@ protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) { } } + protected void initKeyAlgorithms() { + setKeyAlgorithms(Arrays.asList( + new EdDSAKeyAlgorithm.Factory(), + new ECDSAKeyAlgorithm.Factory521(), + new ECDSAKeyAlgorithm.Factory384(), + new ECDSAKeyAlgorithm.Factory256(), + new RSAKeyAlgorithm.FactoryRSASHA512(), + new RSAKeyAlgorithm.FactoryRSASHA256(), + new RSAKeyAlgorithm.FactorySSHRSACert(), + new DSAKeyAlgorithm.FactorySSHDSSCert(), + new RSAKeyAlgorithm.FactorySSHRSA(), + new DSAKeyAlgorithm.FactorySSHDSA())); + } + protected void initRandomFactory(boolean bouncyCastleRegistered) { setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered ? new BouncyCastleRandom.Factory() : new JCERandom.Factory())); @@ -207,18 +221,6 @@ protected void initCipherFactories() { log.debug("Available cipher factories: {}", avail); } - protected void initSignatureFactories() { - setSignatureFactories( - new SignatureEdDSA.Factory(), - new SignatureECDSA.Factory256(), - new SignatureECDSA.Factory384(), - new SignatureECDSA.Factory521(), - new SignatureRSA.Factory(), - new SignatureRSA.FactoryCERT(), - new SignatureDSA.Factory() - ); - } - protected void initMACFactories() { setMACFactories( Macs.HMACSHA1(), diff --git a/src/main/java/net/schmizz/sshj/signature/AbstractSignature.java b/src/main/java/net/schmizz/sshj/signature/AbstractSignature.java index 3eb9ae963..0ab6d08fd 100644 --- a/src/main/java/net/schmizz/sshj/signature/AbstractSignature.java +++ b/src/main/java/net/schmizz/sshj/signature/AbstractSignature.java @@ -29,18 +29,26 @@ public abstract class AbstractSignature @SuppressWarnings("PMD.UnnecessaryFullyQualifiedName") protected final java.security.Signature signature; + private final String signatureName; - protected AbstractSignature(String algorithm) { + protected AbstractSignature(String algorithm, String signatureName) { try { this.signature = SecurityUtils.getSignature(algorithm); + this.signatureName = signatureName; } catch (GeneralSecurityException e) { throw new SSHRuntimeException(e); } } protected AbstractSignature(@SuppressWarnings("PMD.UnnecessaryFullyQualifiedName") - java.security.Signature signatureEngine) { + java.security.Signature signatureEngine, String signatureName) { this.signature = signatureEngine; + this.signatureName = signatureName; + } + + @Override + public String getSignatureName() { + return signatureName; } @Override diff --git a/src/main/java/net/schmizz/sshj/signature/Signature.java b/src/main/java/net/schmizz/sshj/signature/Signature.java index 6ad1ac453..4338aa32a 100644 --- a/src/main/java/net/schmizz/sshj/signature/Signature.java +++ b/src/main/java/net/schmizz/sshj/signature/Signature.java @@ -21,6 +21,8 @@ /** Signature interface for SSH used to sign or verify data. Usually wraps a {@code javax.crypto.Signature} object. */ public interface Signature { + String getSignatureName(); + /** * Initialize this signature with the given public key for signature verification. * diff --git a/src/main/java/net/schmizz/sshj/signature/SignatureDSA.java b/src/main/java/net/schmizz/sshj/signature/SignatureDSA.java index 3406e609c..7179f8ccb 100644 --- a/src/main/java/net/schmizz/sshj/signature/SignatureDSA.java +++ b/src/main/java/net/schmizz/sshj/signature/SignatureDSA.java @@ -50,7 +50,7 @@ public String getName() { } public SignatureDSA() { - super("SHA1withDSA"); + super("SHA1withDSA", KeyType.DSA.toString()); } @Override @@ -72,8 +72,8 @@ public byte[] encode(byte[] sig) { // result must be 40 bytes, but length of r and s may not be 20 bytes - int r_copylen = (r.length < 20) ? r.length : 20; - int s_copylen = (s.length < 20) ? s.length : 20; + int r_copylen = Math.min(r.length, 20); + int s_copylen = Math.min(s.length, 20); System.arraycopy(r, r.length - r_copylen, result, 20 - r_copylen, r_copylen); System.arraycopy(s, s.length - s_copylen, result, 40 - s_copylen, s_copylen); diff --git a/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java b/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java index b063e393b..792836109 100644 --- a/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java +++ b/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java @@ -79,7 +79,7 @@ public String getName() { private String keyTypeName; public SignatureECDSA(String algorithm, String keyTypeName) { - super(algorithm); + super(algorithm, keyTypeName); this.keyTypeName = keyTypeName; } diff --git a/src/main/java/net/schmizz/sshj/signature/SignatureRSA.java b/src/main/java/net/schmizz/sshj/signature/SignatureRSA.java index 4fab9895d..e9695ac4a 100644 --- a/src/main/java/net/schmizz/sshj/signature/SignatureRSA.java +++ b/src/main/java/net/schmizz/sshj/signature/SignatureRSA.java @@ -22,26 +22,53 @@ import java.security.InvalidKeyException; import java.security.PublicKey; import java.security.SignatureException; -import java.util.Date; /** RSA {@link Signature} */ public class SignatureRSA extends AbstractSignature { /** A named factory for RSA {@link Signature} */ - public static class Factory + public static class FactorySSHRSA implements net.schmizz.sshj.common.Factory.Named { @Override public Signature create() { - return new SignatureRSA(KeyType.RSA.toString()); + return new SignatureRSA("SHA1withRSA", KeyType.RSA, KeyType.RSA.toString()); } @Override public String getName() { return KeyType.RSA.toString(); } + } + + /** A named factory for RSA {@link Signature} */ + public static class FactoryRSASHA256 + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public Signature create() { + return new SignatureRSA("SHA256withRSA", KeyType.RSA, "rsa-sha2-256"); + } + + @Override + public String getName() { + return "rsa-sha2-256"; + } + } + /** A named factory for RSA {@link Signature} */ + public static class FactoryRSASHA512 + implements net.schmizz.sshj.common.Factory.Named { + @Override + public Signature create() { + return new SignatureRSA("SHA512withRSA", KeyType.RSA, "rsa-sha2-512"); + } + + @Override + public String getName() { + return "rsa-sha2-512"; + } } /** A named factory for RSA {@link Signature} */ @@ -50,7 +77,7 @@ public static class FactoryCERT @Override public Signature create() { - return new SignatureRSA(KeyType.RSA_CERT.toString()); + return new SignatureRSA("SHA1withRSA", KeyType.RSA_CERT, KeyType.RSA.toString()); } @Override @@ -60,19 +87,19 @@ public String getName() { } - private String keyTypeName; + private KeyType keyType; - public SignatureRSA(String keyTypeName) { - super("SHA1withRSA"); - this.keyTypeName = keyTypeName; + public SignatureRSA(String algorithm, KeyType keyType, String name) { + super(algorithm, name); + this.keyType = keyType; } @Override @SuppressWarnings("unchecked") public void initVerify(PublicKey publicKey) { try { - if (this.keyTypeName.equals(KeyType.RSA_CERT.toString()) && publicKey instanceof Certificate) { + if (this.keyType.equals(KeyType.RSA_CERT) && publicKey instanceof Certificate) { signature.initVerify(((Certificate) publicKey).getKey()); } else { signature.initVerify(publicKey); @@ -89,7 +116,7 @@ public byte[] encode(byte[] signature) { @Override public boolean verify(byte[] sig) { - sig = extractSig(sig, KeyType.RSA.toString()); + sig = extractSig(sig, getSignatureName()); try { return signature.verify(sig); } catch (SignatureException e) { diff --git a/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java b/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java index b5b7e92a0..936862558 100644 --- a/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java +++ b/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java @@ -15,6 +15,7 @@ */ package net.schmizz.sshj.transport; +import com.hierynomus.sshj.key.KeyAlgorithm; import net.schmizz.concurrent.ErrorDeliveryUtil; import net.schmizz.concurrent.Event; import net.schmizz.sshj.common.*; @@ -30,9 +31,7 @@ import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.PublicKey; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.Queue; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -232,6 +231,13 @@ private void gotKexInit(SSHPacket buf) } kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(), negotiatedAlgs.getKeyExchangeAlgorithm()); + + List keyAlgorithms = new ArrayList(); + for (String signatureAlgorithm : negotiatedAlgs.getSignatureAlgorithms()) { + keyAlgorithms.add(Factory.Named.Util.create(transport.getConfig().getKeyAlgorithms(), signatureAlgorithm)); + } + transport.setKeyAlgorithms(keyAlgorithms); + try { kex.init(transport, transport.getServerID(), transport.getClientID(), diff --git a/src/main/java/net/schmizz/sshj/transport/NegotiatedAlgorithms.java b/src/main/java/net/schmizz/sshj/transport/NegotiatedAlgorithms.java index 5dac8056c..be78566d8 100644 --- a/src/main/java/net/schmizz/sshj/transport/NegotiatedAlgorithms.java +++ b/src/main/java/net/schmizz/sshj/transport/NegotiatedAlgorithms.java @@ -15,10 +15,12 @@ */ package net.schmizz.sshj.transport; +import java.util.List; + public final class NegotiatedAlgorithms { private final String kex; - private final String sig; + private final List availableSigs; private final String c2sCipher; private final String s2cCipher; private final String c2sMAC; @@ -26,10 +28,10 @@ public final class NegotiatedAlgorithms { private final String c2sComp; private final String s2cComp; - NegotiatedAlgorithms(String kex, String sig, String c2sCipher, String s2cCipher, String c2sMAC, String s2cMAC, + NegotiatedAlgorithms(String kex, List availableSigs, String c2sCipher, String s2cCipher, String c2sMAC, String s2cMAC, String c2sComp, String s2cComp) { this.kex = kex; - this.sig = sig; + this.availableSigs = availableSigs; this.c2sCipher = c2sCipher; this.s2cCipher = s2cCipher; this.c2sMAC = c2sMAC; @@ -42,8 +44,8 @@ public String getKeyExchangeAlgorithm() { return kex; } - public String getSignatureAlgorithm() { - return sig; + public List getSignatureAlgorithms() { + return availableSigs; } public String getClient2ServerCipherAlgorithm() { @@ -74,7 +76,7 @@ public String getServer2ClientCompressionAlgorithm() { public String toString() { return ("[ " + "kex=" + kex + "; " + - "sig=" + sig + "; " + + "availableSigs=" + availableSigs + "; " + "c2sCipher=" + c2sCipher + "; " + "s2cCipher=" + s2cCipher + "; " + "c2sMAC=" + c2sMAC + "; " + diff --git a/src/main/java/net/schmizz/sshj/transport/Proposal.java b/src/main/java/net/schmizz/sshj/transport/Proposal.java index a0a9de267..a4b0b69f2 100644 --- a/src/main/java/net/schmizz/sshj/transport/Proposal.java +++ b/src/main/java/net/schmizz/sshj/transport/Proposal.java @@ -21,6 +21,7 @@ import net.schmizz.sshj.common.Message; import net.schmizz.sshj.common.SSHPacket; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -38,7 +39,7 @@ class Proposal { public Proposal(Config config) { kex = Factory.Named.Util.getNames(config.getKeyExchangeFactories()); - sig = Factory.Named.Util.getNames(config.getSignatureFactories()); + sig = Factory.Named.Util.getNames(config.getKeyAlgorithms()); c2sCipher = s2cCipher = Factory.Named.Util.getNames(config.getCipherFactories()); c2sMAC = s2cMAC = Factory.Named.Util.getNames(config.getMACFactories()); c2sComp = s2cComp = Factory.Named.Util.getNames(config.getCompressionFactories()); @@ -126,7 +127,7 @@ public NegotiatedAlgorithms negotiate(Proposal other) throws TransportException { return new NegotiatedAlgorithms( firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()), - firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()), + allMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()), firstMatch(this.getClient2ServerCipherAlgorithms(), other.getClient2ServerCipherAlgorithms()), firstMatch(this.getServer2ClientCipherAlgorithms(), other.getServer2ClientCipherAlgorithms()), firstMatch(this.getClient2ServerMACAlgorithms(), other.getClient2ServerMACAlgorithms()), @@ -138,19 +139,36 @@ public NegotiatedAlgorithms negotiate(Proposal other) private static String firstMatch(List a, List b) throws TransportException { - for (String aa : a) - for (String bb : b) - if (aa.equals(bb)) - return aa; + for (String aa : a) { + if (b.contains(aa)) { + return aa; + } + } throw new TransportException("Unable to reach a settlement: " + a + " and " + b); } + private static List allMatch(List a, List b) throws TransportException { + List res = new ArrayList(); + for (String aa : a) { + if (b.contains(aa)) { + res.add(aa); + } + } + + if (res.isEmpty()) { + throw new TransportException("Unable to reach a settlement: " + a + " and " + b); + } + + return res; + } + private static String toCommaString(List sl) { StringBuilder sb = new StringBuilder(); int i = 0; for (String s : sl) { - if (i++ != 0) + if (i++ != 0) { sb.append(","); + } sb.append(s); } return sb.toString(); diff --git a/src/main/java/net/schmizz/sshj/transport/Transport.java b/src/main/java/net/schmizz/sshj/transport/Transport.java index 634191816..6ae9f8f17 100644 --- a/src/main/java/net/schmizz/sshj/transport/Transport.java +++ b/src/main/java/net/schmizz/sshj/transport/Transport.java @@ -15,9 +15,11 @@ */ package net.schmizz.sshj.transport; +import com.hierynomus.sshj.key.KeyAlgorithm; import net.schmizz.sshj.Config; import net.schmizz.sshj.Service; import net.schmizz.sshj.common.DisconnectReason; +import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.common.SSHPacket; import net.schmizz.sshj.common.SSHPacketHandler; import net.schmizz.sshj.transport.verification.AlgorithmsVerifier; @@ -235,4 +237,6 @@ long write(SSHPacket payload) * @param e The exception that occurred. */ void die(Exception e); + + KeyAlgorithm getKeyAlgorithm(KeyType keyType) throws TransportException; } diff --git a/src/main/java/net/schmizz/sshj/transport/TransportImpl.java b/src/main/java/net/schmizz/sshj/transport/TransportImpl.java index 37334af3c..c92ac0380 100644 --- a/src/main/java/net/schmizz/sshj/transport/TransportImpl.java +++ b/src/main/java/net/schmizz/sshj/transport/TransportImpl.java @@ -15,6 +15,7 @@ */ package net.schmizz.sshj.transport; +import com.hierynomus.sshj.key.KeyAlgorithm; import com.hierynomus.sshj.transport.IdentificationStringParser; import net.schmizz.concurrent.ErrorDeliveryUtil; import net.schmizz.concurrent.Event; @@ -30,6 +31,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -39,6 +41,7 @@ public final class TransportImpl implements Transport, DisconnectListener { + private static final class NullService extends AbstractService { @@ -86,6 +89,8 @@ static final class ConnInfo { private final Decoder decoder; + private List keyAlgorithms; + private final Event serviceAccept; private final Event close; @@ -649,4 +654,18 @@ ConnInfo getConnInfo() { return connInfo; } + @Override + public KeyAlgorithm getKeyAlgorithm(KeyType keyType) throws TransportException { + for (KeyAlgorithm ka : keyAlgorithms) { + if (ka.getKeyFormat().equals(keyType)) { + return ka; + } + } + + throw new TransportException("Cannot find an available KeyAlgorithm for type " + keyType); + } + + public void setKeyAlgorithms(List keyAlgorithms) { + this.keyAlgorithms = keyAlgorithms; + } } diff --git a/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java b/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java index 4c045e4ad..f82d45dd4 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java @@ -78,8 +78,8 @@ public boolean next(Message msg, SSHPacket packet) digest.update(buf.array(), buf.rpos(), buf.available()); H = digest.digest(); - Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(), - KeyType.fromKey(hostKey).toString()); + + Signature signature = trans.getKeyAlgorithm(KeyType.fromKey(hostKey)).newSignature(); signature.initVerify(hostKey); signature.update(H, 0, H.length); if (!signature.verify(sig)) diff --git a/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHGex.java b/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHGex.java index 5c13d4307..8a62beb48 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHGex.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHGex.java @@ -15,6 +15,7 @@ */ package net.schmizz.sshj.transport.kex; +import com.hierynomus.sshj.key.KeyAlgorithm; import net.schmizz.sshj.common.*; import net.schmizz.sshj.signature.Signature; import net.schmizz.sshj.transport.Transport; @@ -30,9 +31,9 @@ public abstract class AbstractDHGex extends AbstractDH { private final Logger log = LoggerFactory.getLogger(getClass()); - private int minBits = 1024; - private int maxBits = 8192; - private int preferredBits = 2048; + private final int minBits = 1024; + private final int maxBits = 8192; + private final int preferredBits = 2048; public AbstractDHGex(Digest digest) { super(new DH(), digest); @@ -84,8 +85,8 @@ private boolean parseGexReply(SSHPacket buffer) throws Buffer.BufferException, G .putMPInt(k); digest.update(buf.array(), buf.rpos(), buf.available()); H = digest.digest(); - Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(), - KeyType.fromKey(hostKey).toString()); + KeyAlgorithm keyAlgorithm = trans.getKeyAlgorithm(KeyType.fromKey(hostKey)); + Signature signature = keyAlgorithm.newSignature(); signature.initVerify(hostKey); signature.update(H, 0, H.length); if (!signature.verify(sig)) diff --git a/src/main/java/net/schmizz/sshj/userauth/method/KeyedAuthMethod.java b/src/main/java/net/schmizz/sshj/userauth/method/KeyedAuthMethod.java index 75ea54319..e03eb9ffa 100644 --- a/src/main/java/net/schmizz/sshj/userauth/method/KeyedAuthMethod.java +++ b/src/main/java/net/schmizz/sshj/userauth/method/KeyedAuthMethod.java @@ -15,11 +15,12 @@ */ package net.schmizz.sshj.userauth.method; +import com.hierynomus.sshj.key.KeyAlgorithm; import net.schmizz.sshj.common.Buffer; -import net.schmizz.sshj.common.Factory; import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.common.SSHPacket; import net.schmizz.sshj.signature.Signature; +import net.schmizz.sshj.transport.TransportException; import net.schmizz.sshj.userauth.UserAuthException; import net.schmizz.sshj.userauth.keyprovider.KeyProvider; @@ -47,9 +48,15 @@ protected SSHPacket putPubKey(SSHPacket reqBuf) } // public key as 2 strings: [ key type | key blob ] - reqBuf.putString(KeyType.fromKey(key).toString()) - .putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData()); - return reqBuf; + KeyType keyType = KeyType.fromKey(key); + try { + KeyAlgorithm ka = params.getTransport().getKeyAlgorithm(keyType); + reqBuf.putString(ka.getKeyAlgorithm()) + .putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData()); + return reqBuf; + } catch (IOException ioe) { + throw new UserAuthException("No KeyAlgorithm configured for key " + keyType); + } } protected SSHPacket putSig(SSHPacket reqBuf) @@ -61,17 +68,20 @@ protected SSHPacket putSig(SSHPacket reqBuf) throw new UserAuthException("Problem getting private key from " + kProv, ioe); } - final String kt = KeyType.fromKey(key).toString(); - Signature signature = Factory.Named.Util.create(params.getTransport().getConfig().getSignatureFactories(), kt); - if (signature == null) - throw new UserAuthException("Could not create signature instance for " + kt + " key"); + final KeyType kt = KeyType.fromKey(key); + Signature signature; + try { + signature = params.getTransport().getKeyAlgorithm(kt).newSignature(); + } catch (TransportException e) { + throw new UserAuthException("No KeyAlgorithm configured for key " + kt); + } signature.initSign(key); signature.update(new Buffer.PlainBuffer() .putString(params.getTransport().getSessionID()) .putBuffer(reqBuf) // & rest of the data for sig .getCompactData()); - reqBuf.putSignature(kt, signature.encode(signature.sign())); + reqBuf.putSignature(signature.getSignatureName(), signature.encode(signature.sign())); return reqBuf; }