Try all public key algorithms available for a specific key type in SSH_MSG_USERAUTH_REQUEST. (#763)

This commit is contained in:
Yves Langisch
2022-02-04 09:08:30 +01:00
committed by GitHub
parent 32329e547e
commit aabb1be52e
3 changed files with 31 additions and 7 deletions

View File

@@ -28,6 +28,7 @@ import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** Transport layer of the SSH protocol. */ /** Transport layer of the SSH protocol. */
@@ -224,5 +225,5 @@ public interface Transport
void die(Exception e); void die(Exception e);
KeyAlgorithm getHostKeyAlgorithm(); KeyAlgorithm getHostKeyAlgorithm();
KeyAlgorithm getClientKeyAlgorithm(KeyType keyType) throws TransportException; List<KeyAlgorithm> getClientKeyAlgorithms(KeyType keyType) throws TransportException;
} }

View File

@@ -33,6 +33,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@@ -637,15 +638,18 @@ public final class TransportImpl
} }
@Override @Override
public KeyAlgorithm getClientKeyAlgorithm(KeyType keyType) throws TransportException { public List<KeyAlgorithm> getClientKeyAlgorithms(KeyType keyType) throws TransportException {
List<Factory.Named<KeyAlgorithm>> factories = getConfig().getKeyAlgorithms(); List<Factory.Named<KeyAlgorithm>> factories = getConfig().getKeyAlgorithms();
List<KeyAlgorithm> available = new ArrayList<>();
if (factories != null) if (factories != null)
for (Factory.Named<KeyAlgorithm> f : factories) for (Factory.Named<KeyAlgorithm> f : factories)
if ( if (
f instanceof KeyAlgorithms.Factory && ((KeyAlgorithms.Factory) f).getKeyType().equals(keyType) f instanceof KeyAlgorithms.Factory && ((KeyAlgorithms.Factory) f).getKeyType().equals(keyType)
|| !(f instanceof KeyAlgorithms.Factory) && f.getName().equals(keyType.toString()) || !(f instanceof KeyAlgorithms.Factory) && f.getName().equals(keyType.toString())
) )
return f.create(); available.add(f.create());
throw new TransportException("Cannot find an available KeyAlgorithm for type " + keyType); if (available.isEmpty())
throw new TransportException("Cannot find an available KeyAlgorithm for type " + keyType);
return available;
} }
} }

View File

@@ -27,17 +27,36 @@ import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
import java.io.IOException; import java.io.IOException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.LinkedList;
import java.util.Queue;
public abstract class KeyedAuthMethod public abstract class KeyedAuthMethod
extends AbstractAuthMethod { extends AbstractAuthMethod {
protected final KeyProvider kProv; protected final KeyProvider kProv;
private Queue<KeyAlgorithm> available;
public KeyedAuthMethod(String name, KeyProvider kProv) { public KeyedAuthMethod(String name, KeyProvider kProv) {
super(name); super(name);
this.kProv = kProv; this.kProv = kProv;
} }
private KeyAlgorithm getPublicKeyAlgorithm(KeyType keyType) throws TransportException {
if (available == null) {
available = new LinkedList<>(params.getTransport().getClientKeyAlgorithms(keyType));
}
return available.peek();
}
@Override
public boolean shouldRetry() {
if (available != null) {
available.poll();
return !available.isEmpty();
}
return false;
}
protected SSHPacket putPubKey(SSHPacket reqBuf) protected SSHPacket putPubKey(SSHPacket reqBuf)
throws UserAuthException { throws UserAuthException {
PublicKey key; PublicKey key;
@@ -50,7 +69,7 @@ public abstract class KeyedAuthMethod
// public key as 2 strings: [ key type | key blob ] // public key as 2 strings: [ key type | key blob ]
KeyType keyType = KeyType.fromKey(key); KeyType keyType = KeyType.fromKey(key);
try { try {
KeyAlgorithm ka = params.getTransport().getClientKeyAlgorithm(keyType); KeyAlgorithm ka = getPublicKeyAlgorithm(keyType);
if (ka != null) { if (ka != null) {
reqBuf.putString(ka.getKeyAlgorithm()) reqBuf.putString(ka.getKeyAlgorithm())
.putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData()); .putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData());
@@ -74,7 +93,7 @@ public abstract class KeyedAuthMethod
final KeyType kt = KeyType.fromKey(key); final KeyType kt = KeyType.fromKey(key);
Signature signature; Signature signature;
try { try {
signature = params.getTransport().getClientKeyAlgorithm(kt).newSignature(); signature = getPublicKeyAlgorithm(kt).newSignature();
} catch (TransportException e) { } catch (TransportException e) {
throw new UserAuthException("No KeyAlgorithm configured for key " + kt); throw new UserAuthException("No KeyAlgorithm configured for key " + kt);
} }