aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2013-02-04 23:38:07 -0800
committerKenny Root <kenny@the-b.org>2013-02-04 23:43:45 -0800
commitadabbacc18acd44182702d74aa7a4eac338fc43d (patch)
tree2e9d0acd72df141e27e79c384ff8ce1f4a66de8b
parent4271e2ed172a016e9455f0e43b628a744907ce63 (diff)
downloadsshlib-adabbacc18acd44182702d74aa7a4eac338fc43d.tar.gz
sshlib-adabbacc18acd44182702d74aa7a4eac338fc43d.tar.bz2
sshlib-adabbacc18acd44182702d74aa7a4eac338fc43d.zip
Add ECDSA support
-rw-r--r--lib/src/main/java/com/trilead/ssh2/KnownHosts.java19
-rw-r--r--lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java33
-rw-r--r--lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java88
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java294
-rw-r--r--lib/src/main/java/com/trilead/ssh2/transport/KexManager.java47
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);