diff options
Diffstat (limited to 'lib/src')
5 files changed, 433 insertions, 48 deletions
| diff --git a/lib/src/main/java/com/trilead/ssh2/KnownHosts.java b/lib/src/main/java/com/trilead/ssh2/KnownHosts.java index c68b852..b88c1b9 100644 --- a/lib/src/main/java/com/trilead/ssh2/KnownHosts.java +++ b/lib/src/main/java/com/trilead/ssh2/KnownHosts.java @@ -17,6 +17,7 @@ import java.security.NoSuchAlgorithmException;  import java.security.PublicKey;
  import java.security.SecureRandom;
  import java.security.interfaces.DSAPublicKey;
 +import java.security.interfaces.ECPublicKey;
  import java.security.interfaces.RSAPublicKey;
  import java.util.Iterator;
  import java.util.LinkedList;
 @@ -28,6 +29,7 @@ import javax.crypto.spec.SecretKeySpec;  import com.trilead.ssh2.crypto.Base64;
  import com.trilead.ssh2.signature.DSASHA1Verify;
 +import com.trilead.ssh2.signature.ECDSASHA2Verify;
  import com.trilead.ssh2.signature.RSASHA1Verify;
 @@ -115,6 +117,14 @@ public class KnownHosts  				publicKeys.add(new KnownHostsEntry(hostnames, dpk));
  			}
  		}
 +		else if ("ecdsa-sha2-nistp256".equals(serverHostKeyAlgorithm))
 +		{
 +			ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey);
 +
 +			synchronized (publicKeys) {
 +				publicKeys.add(new KnownHostsEntry(hostnames, epk));
 +			}
 +		}
  		else
  			throw new IOException("Unknwon host key type (" + serverHostKeyAlgorithm + ")");
  	}
 @@ -590,6 +600,10 @@ public class KnownHosts  		{
  			remoteKey = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey);
  		}
 +		else if ("ecdsa-sha2-nistp256".equals(serverHostKeyAlgorithm))
 +		{
 +		    remoteKey = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey);
 +		}
  		else
  			throw new IllegalArgumentException("Unknown hostkey type " + serverHostKeyAlgorithm);
 @@ -705,7 +719,10 @@ public class KnownHosts  			throw new IllegalArgumentException("Unknown hash type " + type);
  		}
 -		if ("ssh-rsa".equals(keyType))
 +		if ("ecdsa-sha2-nistp256".equals(keyType))
 +		{
 +		}
 +		else if ("ssh-rsa".equals(keyType))
  		{
  		}
  		else if ("ssh-dss".equals(keyType))
 diff --git a/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java b/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java index e1e416e..ed50c30 100644 --- a/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java +++ b/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java @@ -7,6 +7,8 @@ import java.security.PrivateKey;  import java.security.SecureRandom;
  import java.security.interfaces.DSAPrivateKey;
  import java.security.interfaces.DSAPublicKey;
 +import java.security.interfaces.ECPrivateKey;
 +import java.security.interfaces.ECPublicKey;
  import java.security.interfaces.RSAPrivateKey;
  import java.security.interfaces.RSAPublicKey;
  import java.util.Vector;
 @@ -26,6 +28,7 @@ import com.trilead.ssh2.packets.PacketUserauthRequestPublicKey;  import com.trilead.ssh2.packets.Packets;
  import com.trilead.ssh2.packets.TypesWriter;
  import com.trilead.ssh2.signature.DSASHA1Verify;
 +import com.trilead.ssh2.signature.ECDSASHA2Verify;
  import com.trilead.ssh2.signature.RSASHA1Verify;
  import com.trilead.ssh2.transport.MessageHandler;
  import com.trilead.ssh2.transport.TransportManager;
 @@ -239,7 +242,37 @@ public class AuthenticationManager implements MessageHandler  						"ssh-rsa", pk_enc, rsa_sig_enc);
  				tm.sendMessage(ua.getPayload());
 +			}
 +			else if (key instanceof ECPrivateKey)
 +			{
 +				ECPrivateKey pk = (ECPrivateKey) key;
 +
 +				byte[] pk_enc = ECDSASHA2Verify.encodeSSHECDSAPublicKey((ECPublicKey) pair.getPublic());
 +
 +				TypesWriter tw = new TypesWriter();
 +				{
 +					byte[] H = tm.getSessionIdentifier();
 +					tw.writeString(H, 0, H.length);
 +					tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
 +					tw.writeString(user);
 +					tw.writeString("ssh-connection");
 +					tw.writeString("publickey");
 +					tw.writeBoolean(true);
 +					tw.writeString("ecdsa-sha2-nistp256");
 +					tw.writeString(pk_enc, 0, pk_enc.length);
 +				}
 +
 +				byte[] msg = tw.getBytes();
 +
 +				byte[] ds = ECDSASHA2Verify.generateSignature(msg, pk);
 +
 +				byte[] ec_sig_enc = ECDSASHA2Verify.encodeSSHECDSASignature(ds);
 +
 +				PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
 +						"ecdsa-sha2-nistp256", pk_enc, ec_sig_enc);
 +
 +				tm.sendMessage(ua.getPayload());
  			}
  			else
  			{
 diff --git a/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java b/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java index d3f10a3..f04c412 100644 --- a/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java +++ b/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java @@ -31,6 +31,10 @@ import java.security.interfaces.DSAPrivateKey;  import java.security.interfaces.RSAPrivateKey;  import java.security.spec.DSAPrivateKeySpec;  import java.security.spec.DSAPublicKeySpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec;  import java.security.spec.InvalidKeySpecException;  import java.security.spec.KeySpec;  import java.security.spec.RSAPrivateKeySpec; @@ -43,6 +47,7 @@ import com.trilead.ssh2.log.Logger;  import com.trilead.ssh2.packets.TypesReader;  import com.trilead.ssh2.packets.TypesWriter;  import com.trilead.ssh2.signature.DSASHA1Verify; +import com.trilead.ssh2.signature.ECDSASHA2Verify;  import com.trilead.ssh2.signature.RSASHA1Verify;  /** @@ -277,10 +282,14 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  			String type = tr.readString(); -			KeyPair pair;  			String comment; +			String keyType; +			KeySpec pubSpec; +			KeySpec privSpec;  			if (type.equals("ssh-rsa")) { +				keyType = "RSA"; +  				BigInteger n = tr.readMPINT();  				BigInteger e = tr.readMPINT();  				BigInteger d = tr.readMPINT(); @@ -289,25 +298,11 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  				tr.readMPINT(); // q  				comment = tr.readString(); -				KeySpec pubSpec = new RSAPublicKeySpec(n, e); -				KeySpec privSpec = new RSAPrivateKeySpec(n, d); - -				PublicKey pubKey; -				PrivateKey privKey; -				try { -					KeyFactory kf = KeyFactory.getInstance("RSA"); -					pubKey = kf.generatePublic(pubSpec); -					privKey = kf.generatePrivate(privSpec); -				} catch (NoSuchAlgorithmException ex) { -					// TODO: log error -					return; -				} catch (InvalidKeySpecException ex) { -					// TODO: log error -					return; -				} - -				pair = new KeyPair(pubKey, privKey); +				pubSpec = new RSAPublicKeySpec(n, e); +				privSpec = new RSAPrivateKeySpec(n, d);  			} else if (type.equals("ssh-dss")) { +				keyType = "DSA"; +  				BigInteger p = tr.readMPINT();  				BigInteger q = tr.readMPINT();  				BigInteger g = tr.readMPINT(); @@ -315,29 +310,56 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  				BigInteger x = tr.readMPINT();  				comment = tr.readString(); -				KeySpec pubSpec = new DSAPublicKeySpec(y, p, q, g); -				KeySpec privSpec = new DSAPrivateKeySpec(x, p, q, g); - -				PublicKey pubKey; -				PrivateKey privKey; -				try { -					KeyFactory kf = KeyFactory.getInstance("DSA"); -					pubKey = kf.generatePublic(pubSpec); -					privKey = kf.generatePrivate(privSpec); -				} catch (NoSuchAlgorithmException ex) { -					// TODO: log error +				pubSpec = new DSAPublicKeySpec(y, p, q, g); +				privSpec = new DSAPrivateKeySpec(x, p, q, g); +			} else if (type.equals("ecdsa-sha2-nistp256")) { +				keyType = "EC"; + +				String curveName = tr.readString(); +				byte[] groupBytes = tr.readByteString(); +				BigInteger exponent = tr.readMPINT(); +				comment = tr.readString(); + +				if (!"nistp256".equals(curveName)) { +					log.log(2, "Invalid curve name for ecdsa-sha2-nistp256: " + curveName); +					os.write(SSH_AGENT_FAILURE);  					return; -				} catch (InvalidKeySpecException ex) { -					// TODO: log error +				} + +				ECParameterSpec nistp256 = ECDSASHA2Verify.EllipticCurves.nistp256; +				ECPoint group = ECDSASHA2Verify.decodeECPoint(groupBytes, nistp256.getCurve()); +				if (group == null) { +					// TODO log error +					os.write(SSH_AGENT_FAILURE);  					return;  				} -				pair = new KeyPair(pubKey, privKey); +				pubSpec = new ECPublicKeySpec(group, nistp256); +				privSpec = new ECPrivateKeySpec(exponent, nistp256);  			} else { +				log.log(2, "Unknown key type: " + type);  				os.write(SSH_AGENT_FAILURE);  				return;  			} +			PublicKey pubKey; +			PrivateKey privKey; +			try { +				KeyFactory kf = KeyFactory.getInstance(keyType); +				pubKey = kf.generatePublic(pubSpec); +				privKey = kf.generatePrivate(privSpec); +			} catch (NoSuchAlgorithmException ex) { +				// TODO: log error +				 os.write(SSH_AGENT_FAILURE); +				return; +			} catch (InvalidKeySpecException ex) { +				// TODO: log error +				 os.write(SSH_AGENT_FAILURE); +				return; +			} + +			KeyPair pair = new KeyPair(pubKey, privKey); +  			boolean confirmUse = false;  			int lifetime = 0; diff --git a/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java b/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java new file mode 100644 index 0000000..c9c237f --- /dev/null +++ b/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java @@ -0,0 +1,294 @@ +/** + * + */ +package com.trilead.ssh2.signature; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECFieldFp; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import com.trilead.ssh2.log.Logger; +import com.trilead.ssh2.packets.TypesReader; +import com.trilead.ssh2.packets.TypesWriter; + +/** + * @author Kenny Root + * + */ +public class ECDSASHA2Verify { +	private static final Logger log = Logger.getLogger(ECDSASHA2Verify.class); + +	public static ECPublicKey decodeSSHECDSAPublicKey(byte[] key) throws IOException +	{ +		TypesReader tr = new TypesReader(key); + +		String key_format = tr.readString(); + +		if (key_format.equals("ecdsa-sha2-nistp256") == false) +			throw new IllegalArgumentException("This is not an ecdsa-sha2-nistp256 public key"); + +		String curveName = tr.readString(); +		byte[] groupBytes = tr.readByteString(); + +		if (tr.remain() != 0) +			throw new IOException("Padding in ECDSA public key!"); + +		if (!"nistp256".equals(curveName)) { +			throw new IOException("Curve is not nistp256"); +		} + +		ECParameterSpec nistp256 = ECDSASHA2Verify.EllipticCurves.nistp256; +		ECPoint group = ECDSASHA2Verify.decodeECPoint(groupBytes, nistp256.getCurve()); +		if (group == null) { +			throw new IOException("Invalid ECDSA group"); +		} + +		KeySpec keySpec = new ECPublicKeySpec(group, nistp256); + +		try { +			KeyFactory kf = KeyFactory.getInstance("EC"); +			return (ECPublicKey) kf.generatePublic(keySpec); +		} catch (NoSuchAlgorithmException nsae) { +			IOException ioe = new IOException("No RSA KeyFactory available"); +			ioe.initCause(nsae); +			throw ioe; +		} catch (InvalidKeySpecException ikse) { +			IOException ioe = new IOException("No RSA KeyFactory available"); +			ioe.initCause(ikse); +			throw ioe; +		} +	} + +	public static byte[] encodeSSHECDSAPublicKey(ECPublicKey key) throws IOException { +		TypesWriter tw = new TypesWriter(); + +		tw.writeString("ecdsa-sha2-nistp256"); + +		tw.writeString("nistp256"); + +		tw.writeBytes(encodeECPoint(key.getW(), key.getParams().getCurve())); + +		return tw.getBytes(); +	} + +	public static byte[] decodeSSHECDSASignature(byte[] sig) throws IOException { +		byte[] rsArray = null; + +		/* Hopefully a server obeying the standard... */ +		TypesReader tr = new TypesReader(sig); + +		String sig_format = tr.readString(); +		if (sig_format.equals("ecdsa-sha2-nistp256") == false) +			throw new IOException("Peer sent wrong signature format"); + +		rsArray = tr.readByteString(); + +		if (tr.remain() != 0) +			throw new IOException("Padding in ECDSA signature!"); + +		byte[] rArray; +		byte[] sArray; +		{ +			TypesReader rsReader = new TypesReader(rsArray); +			rArray = rsReader.readMPINT().toByteArray(); +			sArray = rsReader.readMPINT().toByteArray(); +		} + +		int first = rArray.length; +		int second = sArray.length; + +		/* We can't have the high bit set, so add an extra zero at the beginning if so. */ +		if ((rArray[0] & 0x80) != 0) { +			first++; +		} +		if ((sArray[0] & 0x80) != 0) { +			second++; +		} + +		/* Calculate total output length */ +		int length = 6 + first + second; +		byte[] asn1 = new byte[length]; + +		/* ASN.1 SEQUENCE tag */ +		asn1[0] = (byte) 0x30; + +		/* Size of SEQUENCE */ +		asn1[1] = (byte) (4 + first + second); + +		/* ASN.1 INTEGER tag */ +		asn1[2] = (byte) 0x02; + +		/* "r" INTEGER length */ +		asn1[3] = (byte) first; + +		/* Copy in the "r" INTEGER */ +		System.arraycopy(rArray, 0, asn1, (4 + first) - rArray.length, rArray.length); + +		/* ASN.1 INTEGER tag */ +		asn1[rArray.length + 4] = (byte) 0x02; + +		/* "s" INTEGER length */ +		asn1[rArray.length + 5] = (byte) second; + +		/* Copy in the "s" INTEGER */ +		System.arraycopy(sArray, 0, asn1, (6 + first + second) - sArray.length, sArray.length); + +		return asn1; +	} + +	public static byte[] encodeSSHECDSASignature(byte[] sig) throws IOException +	{ +		TypesWriter tw = new TypesWriter(); + +		tw.writeString("ecdsa-sha2-nistp256"); + +		int rLength = sig[3]; +		int sLength = sig[5 + rLength]; + +		byte[] rArray = new byte[rLength]; +		byte[] sArray = new byte[sLength]; + +		System.arraycopy(sig, 4, rArray, 0, rLength); +		System.arraycopy(sig, 6 + rLength, sArray, 0, sLength); + +		BigInteger r = new BigInteger(rArray); +		BigInteger s = new BigInteger(sArray); + +		// Write the <r,s> to its own types writer. +		TypesWriter rsWriter = new TypesWriter(); +		rsWriter.writeMPInt(r); +		rsWriter.writeMPInt(s); +		tw.writeBytes(rsWriter.getBytes()); + +		return tw.getBytes(); +	} + +	public static byte[] generateSignature(byte[] message, ECPrivateKey pk) throws IOException +	{ +		try { +			Signature s = Signature.getInstance("SHA256withECDSA"); +			s.initSign(pk); +			s.update(message); +			return s.sign(); +		} catch (NoSuchAlgorithmException e) { +			IOException ex = new IOException(); +			ex.initCause(e); +			throw ex; +		} catch (InvalidKeyException e) { +			IOException ex = new IOException(); +			ex.initCause(e); +			throw ex; +		} catch (SignatureException e) { +			IOException ex = new IOException(); +			ex.initCause(e); +			throw ex; +		} +	} + +	public static boolean verifySignature(byte[] message, byte[] ds, ECPublicKey dpk) throws IOException +	{ +		try { +			Signature s = Signature.getInstance("SHA256withECDSA"); +			s.initVerify(dpk); +			s.update(message); +			return s.verify(ds); +		} catch (NoSuchAlgorithmException e) { +			IOException ex = new IOException("No such algorithm"); +			ex.initCause(e); +			throw ex; +		} catch (InvalidKeyException e) { +			IOException ex = new IOException("No such algorithm"); +			ex.initCause(e); +			throw ex; +		} catch (SignatureException e) { +			IOException ex = new IOException(); +			ex.initCause(e); +			throw ex; +		} +	} + +	/** +	 * Decode an OctetString to EllipticCurvePoint according to SECG 2.3.4 +	 */ +	public static ECPoint decodeECPoint(byte[] M, EllipticCurve curve) { +		if (M.length == 0) { +			return null; +		} + +		// M has len 2 ceil(log_2(q)/8) + 1 ? +		int elementSize = (curve.getField().getFieldSize() + 7) / 8; +		if (M.length != 2 * elementSize + 1) { +			return null; +		} + +		// step 3.2 +		if (M[0] != 0x04) { +			return null; +		} + +		// Step 3.3 +		byte[] xp = new byte[elementSize]; +		System.arraycopy(M, 1, xp, 0, elementSize); + +		// Step 3.4 +		byte[] yp = new byte[elementSize]; +		System.arraycopy(M, 1 + elementSize, yp, 0, elementSize); + +		ECPoint P = new ECPoint(new BigInteger(1, xp), new BigInteger(1, yp)); + +		// TODO check point 3.5 + +		// Step 3.6 +		return P; +	} + +	/** +	 * Encode EllipticCurvePoint to an OctetString +	 */ +	public static byte[] encodeECPoint(ECPoint group, EllipticCurve curve) +	{ +		// M has len 2 ceil(log_2(q)/8) + 1 ? +		int elementSize = (curve.getField().getFieldSize() + 7) / 8; +		byte[] M = new byte[2 * elementSize + 1]; + +		// Uncompressed format +		M[0] = 0x04; + +		{ +			byte[] affineX = group.getAffineX().toByteArray(); +			System.arraycopy(affineX, 0, M, 1, elementSize - affineX.length); +		} + +		{ +			byte[] affineY = group.getAffineY().toByteArray(); +			System.arraycopy(affineY, 0, M, 1 + elementSize, elementSize - affineY.length); +		} + +		return M; +	} + +	public static class EllipticCurves { +		public static ECParameterSpec nistp256 = new ECParameterSpec( +				new EllipticCurve( +						new ECFieldFp(new BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16)), +						new BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16), +						new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)), +				new ECPoint(new BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16), +							new BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16)), +				new BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16), +				1); +	} +} diff --git a/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java b/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java index 43a5267..1a32a39 100644 --- a/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java +++ b/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java @@ -4,7 +4,10 @@ package com.trilead.ssh2.transport;  import java.io.IOException;
  import java.security.SecureRandom;
  import java.security.interfaces.DSAPublicKey;
 +import java.security.interfaces.ECPublicKey;
  import java.security.interfaces.RSAPublicKey;
 +import java.util.Set;
 +import java.util.TreeSet;
  import com.trilead.ssh2.ConnectionInfo;
  import com.trilead.ssh2.DHGexParameters;
 @@ -30,6 +33,7 @@ import com.trilead.ssh2.packets.PacketKexInit;  import com.trilead.ssh2.packets.PacketNewKeys;
  import com.trilead.ssh2.packets.Packets;
  import com.trilead.ssh2.signature.DSASHA1Verify;
 +import com.trilead.ssh2.signature.ECDSASHA2Verify;
  import com.trilead.ssh2.signature.RSASHA1Verify;
 @@ -43,6 +47,20 @@ public class KexManager  {
  	private static final Logger log = Logger.getLogger(KexManager.class);
 +	private static final Set<String> HOSTKEY_ALGS = new TreeSet<String>();
 +	static {
 +		HOSTKEY_ALGS.add("ecdsa-sha2-nistp256");
 +		HOSTKEY_ALGS.add("ssh-rsa");
 +		HOSTKEY_ALGS.add("ssh-dsa");
 +	}
 +
 +	private static final Set<String> KEX_ALGS = new TreeSet<String>();
 +	static {
 +		KEX_ALGS.add("diffie-hellman-group-exchange-sha1");
 +		KEX_ALGS.add("diffie-hellman-group14-sha1");
 +		KEX_ALGS.add("diffie-hellman-group1-sha1");
 +	}
 +
  	KexState kxs;
  	int kexCount = 0;
  	KeyMaterial km;
 @@ -307,43 +325,44 @@ public class KexManager  	public static final String[] getDefaultServerHostkeyAlgorithmList()
  	{
 -		return new String[] { "ssh-rsa", "ssh-dss" };
 +		return HOSTKEY_ALGS.toArray(new String[HOSTKEY_ALGS.size()]);
  	}
  	public static final void checkServerHostkeyAlgorithmsList(String[] algos)
  	{
  		for (int i = 0; i < algos.length; i++)
  		{
 -			if (("ssh-rsa".equals(algos[i]) == false) && ("ssh-dss".equals(algos[i]) == false))
 +			if (!HOSTKEY_ALGS.contains(algos[i]))
  				throw new IllegalArgumentException("Unknown server host key algorithm '" + algos[i] + "'");
  		}
  	}
  	public static final String[] getDefaultKexAlgorithmList()
  	{
 -		return new String[] { "diffie-hellman-group-exchange-sha1", "diffie-hellman-group14-sha1",
 -				"diffie-hellman-group1-sha1" };
 +		return KEX_ALGS.toArray(new String[KEX_ALGS.size()]);
  	}
  	public static final void checkKexAlgorithmList(String[] algos)
  	{
  		for (int i = 0; i < algos.length; i++)
  		{
 -			if ("diffie-hellman-group-exchange-sha1".equals(algos[i]))
 -				continue;
 -
 -			if ("diffie-hellman-group14-sha1".equals(algos[i]))
 -				continue;
 -
 -			if ("diffie-hellman-group1-sha1".equals(algos[i]))
 -				continue;
 -
 -			throw new IllegalArgumentException("Unknown kex algorithm '" + algos[i] + "'");
 +			if (!KEX_ALGS.contains(algos[i]))
 +				throw new IllegalArgumentException("Unknown kex algorithm '" + algos[i] + "'");
  		}
  	}
  	private boolean verifySignature(byte[] sig, byte[] hostkey) throws IOException
  	{
 +		if (kxs.np.server_host_key_algo.equals("ecdsa-sha2-nistp256"))
 +		{
 +			byte[] rs = ECDSASHA2Verify.decodeSSHECDSASignature(sig);
 +			ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(hostkey);
 +
 +			log.log(50, "Verifying ecdsa-sha2-nistp256");
 +
 +			return ECDSASHA2Verify.verifySignature(kxs.H, rs, epk);
 +		}
 +
  		if (kxs.np.server_host_key_algo.equals("ssh-rsa"))
  		{
  			byte[] rs = RSASHA1Verify.decodeSSHRSASignature(sig);
 | 
