From adabbacc18acd44182702d74aa7a4eac338fc43d Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 4 Feb 2013 23:38:07 -0800 Subject: Add ECDSA support --- lib/src/main/java/com/trilead/ssh2/KnownHosts.java | 19 +- .../trilead/ssh2/auth/AuthenticationManager.java | 33 +++ .../ssh2/channel/AuthAgentForwardThread.java | 88 +++--- .../trilead/ssh2/signature/ECDSASHA2Verify.java | 294 +++++++++++++++++++++ .../com/trilead/ssh2/transport/KexManager.java | 47 +++- 5 files changed, 433 insertions(+), 48 deletions(-) create mode 100644 lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java 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 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 HOSTKEY_ALGS = new TreeSet(); + static { + HOSTKEY_ALGS.add("ecdsa-sha2-nistp256"); + HOSTKEY_ALGS.add("ssh-rsa"); + HOSTKEY_ALGS.add("ssh-dsa"); + } + + private static final Set KEX_ALGS = new TreeSet(); + 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); -- cgit v1.2.3