From d0fe35bb1837a076b868f8d843c4a585ef0785c9 Mon Sep 17 00:00:00 2001 From: dma Date: Tue, 14 Oct 2014 20:16:39 -0400 Subject: [PATCH] SSLProbe --- .../com.subgraph.vega.sslprobe/.classpath | 7 + platform/com.subgraph.vega.sslprobe/.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../.settings/org.eclipse.pde.core.prefs | 3 + .../META-INF/MANIFEST.MF | 14 + .../build.properties | 4 + .../sslprobe/CertificateAnalyzer.java | 104 +++++ .../vega/internal/sslprobe/CipherSuites.java | 409 ++++++++++++++++++ .../vega/internal/sslprobe/ProbeBase.java | 150 +++++++ .../vega/internal/sslprobe/SSL2Protocol.java | 90 ++++ .../internal/sslprobe/SSLScanTaskManager.java | 137 ++++++ .../sslprobe/SSLServerScanResult.java | 164 +++++++ .../internal/sslprobe/SSLv2CipherSpec.java | 60 +++ .../vega/internal/sslprobe/SSLv2Probe.java | 86 ++++ .../internal/sslprobe/TLSAlertException.java | 24 + .../internal/sslprobe/TLSCipherProbeTask.java | 149 +++++++ .../vega/internal/sslprobe/TLSCipherSpec.java | 48 ++ .../internal/sslprobe/TLSProbeResult.java | 74 ++++ .../vega/internal/sslprobe/TLSProtocol.java | 269 ++++++++++++ .../TLSServerCipherPreferenceProbe.java | 87 ++++ .../internal/sslprobe/TLSVersionProbe.java | 76 ++++ .../com/subgraph/vega/sslprobe/Activator.java | 30 ++ .../com/subgraph/vega/sslprobe/SSLProbe.java | 277 ++++++++++++ 23 files changed, 2297 insertions(+) create mode 100644 platform/com.subgraph.vega.sslprobe/.classpath create mode 100644 platform/com.subgraph.vega.sslprobe/.project create mode 100644 platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.jdt.core.prefs create mode 100644 platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.pde.core.prefs create mode 100644 platform/com.subgraph.vega.sslprobe/META-INF/MANIFEST.MF create mode 100644 platform/com.subgraph.vega.sslprobe/build.properties create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CertificateAnalyzer.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CipherSuites.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/ProbeBase.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSL2Protocol.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLScanTaskManager.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLServerScanResult.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2CipherSpec.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2Probe.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSAlertException.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherProbeTask.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherSpec.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProbeResult.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProtocol.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSServerCipherPreferenceProbe.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSVersionProbe.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/Activator.java create mode 100644 platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/SSLProbe.java diff --git a/platform/com.subgraph.vega.sslprobe/.classpath b/platform/com.subgraph.vega.sslprobe/.classpath new file mode 100644 index 00000000..eca7bdba --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platform/com.subgraph.vega.sslprobe/.project b/platform/com.subgraph.vega.sslprobe/.project new file mode 100644 index 00000000..d43b7b6c --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/.project @@ -0,0 +1,28 @@ + + + com.subgraph.vega.sslprobe + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.jdt.core.prefs b/platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..0c68a61d --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.pde.core.prefs b/platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000..f29e940a --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/platform/com.subgraph.vega.sslprobe/META-INF/MANIFEST.MF b/platform/com.subgraph.vega.sslprobe/META-INF/MANIFEST.MF new file mode 100644 index 00000000..a708767f --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Sslprobe +Bundle-SymbolicName: com.subgraph.vega.sslprobe +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: com.subgraph.vega.sslprobe.Activator +Bundle-Vendor: SUBGRAPH +Bundle-RequiredExecutionEnvironment: JavaSE-1.8, + JavaSE-1.7 +Import-Package: com.google.common.collect, + com.subgraph.vega.api.model.alerts, + org.apache.http;version="4.2.3", + org.osgi.framework;version="1.3.0" +Export-Package: com.subgraph.vega.sslprobe diff --git a/platform/com.subgraph.vega.sslprobe/build.properties b/platform/com.subgraph.vega.sslprobe/build.properties new file mode 100644 index 00000000..34d2e4d2 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CertificateAnalyzer.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CertificateAnalyzer.java new file mode 100644 index 00000000..6ab468d9 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CertificateAnalyzer.java @@ -0,0 +1,104 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.interfaces.RSAPublicKey; + +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + +public class CertificateAnalyzer { + + private X509Certificate certificate; + private boolean error = false; + + CertificateAnalyzer () { + + } + + public void addCert(X509Certificate certificate) { + this.certificate = certificate; + } + + + public boolean selfSigned() { + + PublicKey k = certificate.getPublicKey(); + try { + certificate.verify(k); + } catch (InvalidKeyException e) { + System.out.println("Invalid key, not self signed"); + return false; + } catch (NoSuchAlgorithmException e) { + return false; + } catch (NoSuchProviderException e) { + return false; + } catch (SignatureException e) { + return false; + } catch (CertificateException e) { + return false; + } + return true; + } + + public boolean isSignedSHA1() { + return certificate.getSigAlgName().startsWith("SHA1"); + } + + public boolean isSignedMD5() { + return certificate.getSigAlgName().startsWith("MD5"); + } + + public boolean isRSA() { + return "RSA".equals(certificate.getPublicKey().getAlgorithm()); + } + + public int getRSAModulusBitLength() { + if (this.isRSA()) { + RSAPublicKey r = (RSAPublicKey) certificate.getPublicKey(); + return r.getModulus().bitLength(); + } + else return -1; + } + + public void setError(boolean error) { + this.error = error; + } + + public X509Certificate getCertificate() { + return this.certificate; + } + + public boolean isError() { + return this.error; + } + + @Override + public int hashCode() { + return (certificate == null) ? 0 : certificate.getSerialNumber().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null || getClass() != obj.getClass()) { + return false; + } + + final CertificateAnalyzer other = (CertificateAnalyzer) obj; + + if (certificate == null) { + return other.certificate == null; + } + + if(certificate.getSerialNumber() == null) { + return other.certificate.getSerialNumber() == null; + } + + return certificate.getSerialNumber().equals(other.certificate.getSerialNumber()); + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CipherSuites.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CipherSuites.java new file mode 100644 index 00000000..3bc0264c --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/CipherSuites.java @@ -0,0 +1,409 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Lists; + +public class CipherSuites { + + static private final List TLS_CIPHERS = new ArrayList(); + static private final Map TLS_CIPHER_MAP = new HashMap(); + static private final List SSLv2_CIPHERS = new ArrayList(); + static private final Map SSLv2_CIPHER_MAP = new HashMap(); + + + static public List> paritionTLSCiphers(int maxSize) { + return Lists.partition(TLS_CIPHERS, maxSize); + } + + static TLSCipherSpec lookupTLSCipher(int constant) { + return TLS_CIPHER_MAP.get(constant); + } + + + static public List getV2CipherSuites() { + return Collections.unmodifiableList(new ArrayList(SSLv2_CIPHERS)); + } + + static public SSLv2CipherSpec lookupSSLv2Cipher(int constant) { + return SSLv2_CIPHER_MAP.get(constant); + } + + static private void addCipher(String name, int number, TLSCipherSpec.keyStrength strength, boolean anonDH, boolean pfs, boolean rc4) { + final TLSCipherSpec cipherSpec = new TLSCipherSpec(name, number, strength, anonDH, pfs, rc4); + TLS_CIPHER_MAP.put(number, cipherSpec); + TLS_CIPHERS.add(cipherSpec); + } + + static private void addCipher(String name, byte[] number, SSLv2CipherSpec.keyStrength strength, boolean rc4) { + final SSLv2CipherSpec spec = new SSLv2CipherSpec(name, number, strength, rc4); + SSLv2_CIPHER_MAP.put(spec.getNum(), spec); + SSLv2_CIPHERS.add(spec); + } + + + + static { + + /* Initialize cipher list: http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml */ + + addCipher("TLS_NULL_WITH_NULL_NULL", 0x00, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_WITH_NULL_MD5", 0x01, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_WITH_NULL_SHA", 0x02, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_EXPORT_WITH_RC4_40_MD5", 0x03, TLSCipherSpec.keyStrength.EXPORT, false, false, true); + addCipher("TLS_RSA_WITH_RC4_128_MD5", 0x04, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_RSA_WITH_RC4_128_SHA", 0x05, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x06, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_RSA_WITH_IDEA_CBC_SHA", 0x07, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x08, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_RSA_WITH_DES_CBC_SHA", 0x09, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_RSA_WITH_3DES_EDE_CBC_SHA", 0x0A, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0B, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_DH_DSS_WITH_DES_CBC_SHA", 0x0C, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x0D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0E, TLSCipherSpec.keyStrength.EXPORT, false, false,false); + addCipher("TLS_DH_RSA_WITH_DES_CBC_SHA", 0x0F, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x10, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x11, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_DHE_DSS_WITH_DES_CBC_SHA", 0x12, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x013, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x14, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_DHE_RSA_WITH_DES_CBC_SHA", 0x15, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x16, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_EXPORT_WITH_RC4_40_MD5", 0x17, TLSCipherSpec.keyStrength.EXPORT, true, false, true); + addCipher("TLS_DH_Anon_WITH_RC4_128_MD5", 0x18, TLSCipherSpec.keyStrength.HIGH, true, false, true); + addCipher("TLS_DH_Anon_EXPORT_WITH_DES40_CBC_SHA", 0x19, TLSCipherSpec.keyStrength.EXPORT, true, false, false); + addCipher("TLS_DH_Anon_WITH_DES_CBC_SHA", 0x1A, TLSCipherSpec.keyStrength.LOW, true, false, false); + addCipher("TLS_DH_Anon_WITH_3DES_EDE_CBC_SHA", 0x1B, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_KRB5_WITH_DES_CBC_SHA", 0x1E, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x1F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_KRB5_WITH_RC4_128_SHA", 0x20, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x21, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_KRB5_WITH_DES_CBC_MD5", 0x22, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x23, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_KRB5_WITH_RC4_128_MD5", 0x24, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x25, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x26, TLSCipherSpec.keyStrength.LOW, false, false, false); + addCipher("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x27, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x28, TLSCipherSpec.keyStrength.EXPORT, false, false, true); + addCipher("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x29, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x2A, TLSCipherSpec.keyStrength.EXPORT, false, false, false); + addCipher("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x2B, TLSCipherSpec.keyStrength.EXPORT, false, false, true); + addCipher("TLS_PSK_WITH_NULL_SHA", 0x2C, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_DHE_PSK_WITH_NULL_SHA", 0x2D, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_PSK_WITH_NULL_SHA", 0x2E, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_WITH_AES_128_CBC_SHA", 0x2F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x30, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x31, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x32, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x33, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_AES_128_CBC_SHA", 0x34, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_RSA_WITH_AES_256_CBC_SHA", 0x35, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x36, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x37, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_AES_265_CBC_SHA", 0x38, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x39, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_AES_256_CBC_SHA", 0x3A, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_RSA_WITH_NULL_SHA256", 0x3B, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x3C, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x3D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x3E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x3F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x40, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x41, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x42, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x43, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x44, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x45, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_CAMELLIA_128_CBC_SHA", 0x46, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x67, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x68, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x69, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x6A, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x6B, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_AES_128_CBC_SHA256", 0x6C, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_DH_Anon_WITH_AES_256_CBC_SHA256", 0x6D, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x84, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x85, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x86, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x87, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x88, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_CAMELLIA_256_CBC_SHA", 0x89, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_PSK_WITH_RC4_128_SHA", 0x8A, TLSCipherSpec.keyStrength.HIGH, false, false, true); /* pre-shared key */ + addCipher("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x8B, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_128_CBC_SHA", 0x8C, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_256_CBC_SHA", 0x8D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x8E, TLSCipherSpec.keyStrength.HIGH, false, true, true); + addCipher("DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x8F, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x90, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x91, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x92, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x93, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x94, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x95, TLSCipherSpec.keyStrength.HIGH, false, false, false); + + addCipher("TLS_RSA_WITH_SEED_CBC_SHA", 0x96, TLSCipherSpec.keyStrength.HIGH, false, false, false); /* SEED / 128-bit key block cipher */ + addCipher("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x97, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x98, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x99, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x9A, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_SEED_CBC_SHA", 0x9B, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x9C, TLSCipherSpec.keyStrength.HIGH, false, false, false); /* Galois counter mode */ + addCipher("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x9D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x9E, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x9F, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0xA0, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0xA1, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0xA2, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0xA3, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0xA4, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0xA5, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_Anon_WITH_AES_128_GCM_SHA256", 0xA6, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0xA7, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_PSK_WITH_AES_128_GCM_SHA256", 0xA8, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_256_GCM_SHA384", 0xA9, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0xAA, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0xAB, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0xAC, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0xAD, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_128_CBC_SHA256", 0xAE, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_256_CBC_SHA384", 0xAF, TLSCipherSpec.keyStrength.HIGH, false, false, false); + + addCipher("TLS_PSK_WITH_NULL_SHA256", 0xB0, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_PSK_WITH_NULL_SHA384", 0xB1, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0xB2, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0xB3, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_NULL_SHA256", 0xB4, TLSCipherSpec.keyStrength.NONE, false, true, false); + addCipher("TLS_DHE_PSK_WITH_NULL_SHA384", 0xB5, TLSCipherSpec.keyStrength.NONE, false, true, false); + addCipher("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0xB6, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0xB7, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_NULL_SHA256", 0xB8, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_RSA_PSK_WITH_NULL_SHA384", 0xB9, TLSCipherSpec.keyStrength.NONE, false, false, false); + + addCipher("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xBA, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0xBB, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xBC, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0xBD, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xBE, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_Anon_WITH_CAMELLIA_128_CBC_SHA256", 0xBF, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0xC0, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0xC1, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0xC2, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0xC3, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0xC4, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0xC5, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + /* TODO: 0xFF TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ + + addCipher("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xC001, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xC002, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC003, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xC004, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xC005, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xC006, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xC007, TLSCipherSpec.keyStrength.HIGH, false, true, true); + addCipher("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC008, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xC009, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xC00A, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_NULL_SHA", 0xC00B, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xC00C, TLSCipherSpec.keyStrength.HIGH, false, false, true); + addCipher("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xC00D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xC00E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xC00F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xC010, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xC011, TLSCipherSpec.keyStrength.HIGH, false, true, true); + addCipher("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xC012, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xC013, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xC014, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_Anon_WITH_NULL_SHA", 0xC015, TLSCipherSpec.keyStrength.NONE, true, false, false); + addCipher("TLS_ECDH_Anon_WITH_RC4_128_SHA", 0xC016, TLSCipherSpec.keyStrength.HIGH, true, false, true); + addCipher("TLS_ECDH_Anon_WITH_3DES_EDE_CBC_SHA", 0xC017, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_ECDH_Anon_WITH_AES_128_CBC_SHA", 0xC018, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_ECDH_Anon_WITH_AES_256_CBC_SHA", 0xC019, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xC01A, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xC01B, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xC01C, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xC01D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xC01E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xC01F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xC020, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xC021, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xC022, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xC023, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xC024, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xC025, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xC026, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xC027, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xC028, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xC029, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xC02A, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xC02B, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xC02C, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xC02D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xC02E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xC02F, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xC030, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xC031, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xC032, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xC033, TLSCipherSpec.keyStrength.HIGH, false, true, true); + addCipher("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xC034, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xC035, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xC036, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xC037, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xC038, TLSCipherSpec.keyStrength.HIGH, false, true, false); + + addCipher("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xC039, TLSCipherSpec.keyStrength.NONE, false, false, false); /* EC DHE/PSK + null cipher */ + addCipher("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xC03A, TLSCipherSpec.keyStrength.NONE, false, false, false); + addCipher("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xC03B, TLSCipherSpec.keyStrength.NONE, false, false, false); + + addCipher("TLS_RSA_WITH_ARIA_128_CBC_SHA256", 0xC03C, TLSCipherSpec.keyStrength.HIGH, false, false, false); /* ARIA */ + addCipher("TLS_RSA_WITH_ARIA_256_CBC_SHA384", 0xC03D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 0xC03E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 0xC03F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 0xC040, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 0xC041, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 0xC042, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 0xC043, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xC044, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xC045, TLSCipherSpec.keyStrength.HIGH, false, true, false); + + addCipher("TLS_DH_Anon_WITH_ARIA_128_CBC_SHA256", 0xC046, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_DH_Anon_WITH_ARIA_256_CBC_SHA384", 0xC047, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xC048, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xC049, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xC04A, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xC04B, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xC04C, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xC04D, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 0xC04E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 0xC04F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_WITH_ARIA_128_GCM_SHA256", 0xC050, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_WITH_ARIA_256_GCM_SHA384", 0xC051, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xC052, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xC053, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 0xC054, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 0xC055, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 0xC056, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 0xC057, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 0xC058, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 0xC059, TLSCipherSpec.keyStrength.HIGH, false, false, false); + + addCipher("TLS_DH_Anon_WITH_ARIA_128_GCM_SHA256", 0xC05A, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_DH_Anon_WITH_ARIA_256_GCM_SHA384", 0xC05B, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xC05C, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xC05D, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xC05E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xC05F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xC060, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xC061, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 0xC062, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 0xC063, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_ARIA_128_CBC_SHA256", 0xC064, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_ARIA_256_CBC_SHA384", 0xC065, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xC066, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xC067, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 0xC068, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 0xC069, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_ARIA_128_GCM_SHA256", 0xC06A, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_ARIA_256_GCM_SHA384", 0xC06B, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 0xC06C, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 0xC06D, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 0xC06E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 0xC06F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xC070, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xC071, TLSCipherSpec.keyStrength.HIGH, false, true, false); + + addCipher("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xC072, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xC073, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xC074, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xC075, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc076, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xC077, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xC078, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xC079, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC07A, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC07B, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC07C, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC07D, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC07E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC07F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xC080, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xC081, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xC082, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xC083, TLSCipherSpec.keyStrength.HIGH, false, false, false); + + addCipher("TLS_DH_Anon_WITH_CAMELLIA_128_GCM_SHA256", 0xC084, TLSCipherSpec.keyStrength.HIGH, true, false, false); + addCipher("TLS_DH_Anon_WITH_CAMELLIA_256_GCM_SHA384", 0xC085, TLSCipherSpec.keyStrength.HIGH, true, false, false); + + addCipher("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC086, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC087, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC088, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC089, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC08A, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC08B, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xC08C, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xC08D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xC08E, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xC08F, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xC090, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xC091, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xC092, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xC093, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xC094, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xC095, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xC096, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xC097, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xC098, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xC099, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xC09A, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xC09B, TLSCipherSpec.keyStrength.HIGH, false, true, false); + + addCipher("TLS_RSA_WITH_AES_128_CCM", 0xC09C, TLSCipherSpec.keyStrength.HIGH, false, false, false); /* AES CCM */ + addCipher("TLS_RSA_WITH_AES_256_CCM", 0xC09D, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_RSA_WITH_AES_128_CCM", 0xC09E, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_AES_256_CCM", 0xC09F, TLSCipherSpec.keyStrength.HIGH, false, true, false); + + addCipher("TLS_RSA_WITH_AES_128_CCM_8", 0xC0A0, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_RSA_WITH_AES_256_CCM_8", 0xC0A1, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_RSA_WITH_AES_128_CCM_8", 0xC0A2, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_RSA_WITH_AES_256_CCM_8", 0xC0A3, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_PSK_WITH_AES_128_CCM", 0xC0A4, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_256_CCM", 0xC0A5, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_DHE_PSK_WITH_AES_128_CCM", 0xC0A6, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_DHE_PSK_WITH_AES_256_CCM", 0xC0A7, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_PSK_WITH_AES_128_CCM_8", 0xC0A8, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_WITH_AES_256_CCM_8", 0xC0A9, TLSCipherSpec.keyStrength.HIGH, false, false, false); + addCipher("TLS_PSK_DHE_WITH_AES_128_CCM_8", 0xC0AA, TLSCipherSpec.keyStrength.HIGH, false, true, false); + addCipher("TLS_PSK_DHE_WITH_AES_256_CCM_8", 0xC0AB, TLSCipherSpec.keyStrength.HIGH, false, true, false); + + /* 0xC0, 0xAC-0xFF unassigned */ + /* 0xC1-FD, * unassigned */ + /* 0xFE, 0xFE-FF reserved to avoid conflicts */ + /* 0xFF, 0x00-FF reserved for private use */ + addCipher("SSL2_DES_192_EDE3_CBC_WITH_MD5", new byte[]{0x07, 0x00, (byte)0xc0}, SSLv2CipherSpec.keyStrength.HIGH, false); + addCipher("SSL2_DES_192_EDE3_CBC_WITH_SHA", new byte[]{0x07, 0x01, (byte)0xc0}, SSLv2CipherSpec.keyStrength.HIGH, false); + addCipher("SSL2_DES_64_CBC_WITH_MD5", new byte[]{0x06, 0x00, 0x40}, SSLv2CipherSpec.keyStrength.LOW, false); + addCipher("SSL2_DES_64_CBC_WITH_SHA", new byte[]{0x06, 0x01, 0x40}, SSLv2CipherSpec.keyStrength.LOW, false); + addCipher("SSL2_IDEA_128_CBC_WITH_MD5", new byte[]{0x05, 0x00, (byte) 0x80}, SSLv2CipherSpec.keyStrength.HIGH, false); + addCipher("SSL2_RC2_CBC_WITH_MD5", new byte[]{0x03, 0x00, (byte) 0x80}, SSLv2CipherSpec.keyStrength.HIGH, false); + addCipher("SSL2_RC4_128_WITH_MD5", new byte[]{0x01, 0x00, (byte) 0x80}, SSLv2CipherSpec.keyStrength.HIGH, true); + addCipher("SSL2_DES_64_CBC_WITH_MD5", new byte[]{0x06, 0x00, 0x40}, SSLv2CipherSpec.keyStrength.LOW, false); + addCipher("SSL2_RC2_CBC_128_CBC_WITH_MD5", new byte[]{0x04, 0x00, (byte)0x80}, SSLv2CipherSpec.keyStrength.HIGH, false); + addCipher("SSL2_RC4_128_EXPORT40_WITH_MD5", new byte[]{0x02, 0x00, (byte)0x80}, SSLv2CipherSpec.keyStrength.EXPORT, true); + addCipher("SSL2_NULL_WITH_MD5", new byte[]{0x00, 0x00, 0x00}, SSLv2CipherSpec.keyStrength.NONE, false); + addCipher("SSL2_NULL", new byte[]{(byte)0xff, 0x08, 0x10}, SSLv2CipherSpec.keyStrength.NONE, false); + addCipher("SSL2_DES_64_CFB64_WITH_MD5_1", new byte[]{(byte)0xff, 0x08, 0x00}, SSLv2CipherSpec.keyStrength.LOW, false); + addCipher("SSL2_RC4_64_WITH_MD5", new byte[]{0x08, 0x00, (byte)0x80}, SSLv2CipherSpec.keyStrength.LOW, true); + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/ProbeBase.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/ProbeBase.java new file mode 100644 index 00000000..0480b674 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/ProbeBase.java @@ -0,0 +1,150 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.SocketFactory; + +abstract public class ProbeBase implements Callable, Runnable { + private final static Logger logger = Logger.getLogger(ProbeBase.class.getName()); + private final SocketFactory socketFactory; + private Socket socket; + private InputStream input; + private OutputStream output; + + + + protected final SSLServerScanResult scanResult; + + ProbeBase(SSLServerScanResult scanResult) { + this(scanResult, SocketFactory.getDefault()); + } + + ProbeBase(SSLServerScanResult scanResult, SocketFactory socketFactory) { + this.scanResult = scanResult; + this.scanResult.incrementOutstandingProbeCount(); + this.socketFactory = socketFactory; + } + + + + protected void skip(ByteBuffer bb, int n) { + bb.position(bb.position() + n); + } + + protected void hexDump(ByteBuffer bb) { + int n = 0; + while(bb.hasRemaining()) { + int b = bb.get() & 0xFF; + n += 1; + if(n % 16 == 0) { + System.out.print("\n"); + } + System.out.printf("%02X ", b); + } + System.out.println(); + bb.rewind(); + } + + @Override + public void run() { + try { + call(); + } catch (Exception e) { + logger.log(Level.WARNING, "Unexpected exception during probe: "+ e, e); + } + } + + @Override + public T call() throws Exception { + try { + return runProbe(); + } catch (UnknownHostException e) { + logger.warning("Unknown host exception executing probe."); + scanResult.setTLSProbeFailure("Unknown host"); + return null; + } catch (IOException e) { + logger.warning("I/O error while executing probe: "+ e); + //scanResult.setTLSProbeFailure("I/O error: "+ e); + return null; + } finally { + scanResult.decrementOutstandingProbeCount(); + if(socket != null) { + closeQuietly(socket); + } + } + } + + protected abstract T runProbe() throws Exception; + + protected void closeConnection() { + if(socket != null) { + closeQuietly(socket); + socket = null; + input = null; + output = null; + } + } + + protected Socket getSocket() throws UnknownHostException, IOException { + if(socket == null) { + if (System.getProperty("socksEnabled") != null) { + if (System.getProperty("socksEnabled").equals("true")) { + InetSocketAddress unresolved = InetSocketAddress.createUnresolved(scanResult.getTargetHost(), scanResult.getTargetPort()); + socket = socketFactory.createSocket(); + socket.connect(unresolved); + } else { + socket = socketFactory.createSocket(scanResult.getTargetHost(), scanResult.getTargetPort()); + } + } else + { + socket = socketFactory.createSocket(scanResult.getTargetHost(), scanResult.getTargetPort()); + } + } + return socket; + } + + protected InputStream getInputStream() throws IOException { + if(input == null) { + input = getSocket().getInputStream(); + } + return input; + } + + protected OutputStream getOutputStream() throws IOException { + if(output == null) { + output = getSocket().getOutputStream(); + } + return output; + } + + protected boolean readAll(byte[] buffer) throws IOException { + int remaining = buffer.length; + int offset = 0; + while(remaining > 0) { + int n = getInputStream().read(buffer, offset, remaining); + if(n == -1) { + return false; + } + remaining -= n; + offset += n; + } + return true; + } + + private void closeQuietly(Closeable closeable){ + try { + closeable.close(); + } catch (IOException e) {} + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSL2Protocol.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSL2Protocol.java new file mode 100644 index 00000000..a3d1f6e6 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSL2Protocol.java @@ -0,0 +1,90 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; + +public class SSL2Protocol { + + public final static int SSLV2_CLIENT_HELLO = 0x01; + public final static int SSLV2_SERVER_HELLO = 0x04; + + private final static int SSLV2_HEADER_LENGTH = 2; + private final static int SSLV2_VERSION = 0x0002; + private final static int SSLV2_CHALLENGE_LENGTH = 0x10; + private final static int SSLV2_CLIENT_HELLO_BASE_LENGTH = 9 + SSLV2_CHALLENGE_LENGTH; + + private final InputStream input; + private final OutputStream output; + + public SSL2Protocol(InputStream input, OutputStream output) { + this.input = input; + this.output = output; + } + + public ByteBuffer getNextHandshakeMessage() throws IOException { + final int len = readRecordLength(); + if(len == -1) { + return null; + } + final ByteBuffer buffer = ByteBuffer.allocate(len); + if(!readAll(buffer)) { + return null; + } + return buffer; + } + + private int readRecordLength() throws IOException { + final byte[] bs = new byte[2]; + if(input.read(bs, 0, bs.length) != bs.length) { + return -1; + } + return ((bs[0] & 0x7F) << 8) | (bs[1] & 0xFF); + } + + private boolean readAll(ByteBuffer buffer) throws IOException { + while(buffer.hasRemaining()) { + int n = input.read(buffer.array(), buffer.position(), buffer.remaining()); + if(n == -1) { + return false; + } + buffer.position(buffer.position() + n); + } + buffer.rewind(); + return true; + } + + public void sendClientHello(List ciphers) throws IOException { + final ByteBuffer hello = createClientHello(ciphers); + writeAll(hello); + } + + private ByteBuffer createClientHello(List ciphers) { + final int length = SSLV2_HEADER_LENGTH + SSLV2_CLIENT_HELLO_BASE_LENGTH + (3 * ciphers.size()); + final ByteBuffer buffer = ByteBuffer.allocate(length); + buffer.putShort((short) (0x8000 | (length - SSLV2_HEADER_LENGTH))); + + buffer.put((byte) SSLV2_CLIENT_HELLO); + buffer.putShort((short) SSLV2_VERSION); + buffer.putShort((short) (ciphers.size() * 3)); + buffer.putShort((short) 0); // SID length + buffer.putShort((short) SSLV2_CHALLENGE_LENGTH); + for(SSLv2CipherSpec c: ciphers) { + buffer.put(c.getNumber()); + } + final byte[] challenge = new byte[SSLV2_CHALLENGE_LENGTH]; + Arrays.fill(challenge, (byte)0x01); + buffer.put(challenge); + buffer.flip(); + return buffer; + } + + private void writeAll(ByteBuffer buffer) throws IOException { + output.write(buffer.array(), buffer.position(), buffer.remaining()); + buffer.position(buffer.position() + buffer.remaining()); + output.flush(); + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLScanTaskManager.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLScanTaskManager.java new file mode 100644 index 00000000..940fabbb --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLScanTaskManager.java @@ -0,0 +1,137 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.util.List; +import java.util.concurrent.CompletionService; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import com.subgraph.vega.internal.sslprobe.SSLServerScanResult.Flag; + + +public class SSLScanTaskManager { + private final static Logger logger = Logger.getLogger(SSLScanTaskManager.class.getName()); + + private final ExecutorService executor; + + private static int CIPHERS_PER_REQUEST = 300; + + public SSLScanTaskManager(ExecutorService executor) { + this.executor = executor; + } + + public void shutdown() throws InterruptedException { + executor.shutdown(); + executor.awaitTermination(120, TimeUnit.SECONDS); + } + + public SSLServerScanResult scanServer(String host, int port) throws InterruptedException { + logger.info("Starting scan of "+ host + ":" + port); + final SSLServerScanResult scanResult = new SSLServerScanResult(host, port); + + if(probeServerSupportedTLSCiphers(scanResult)) { + probeSupportedVersions(scanResult); + probeCipherPreference(scanResult); + } + + probeSSLv2Support(scanResult); + + scanResult.waitForOutstandingProbes(); + + return scanResult; + } + + private void probeSSLv2Support(SSLServerScanResult scanResult) { + executor.execute(new SSLv2Probe(scanResult)); + } + + private boolean probeServerSupportedTLSCiphers(SSLServerScanResult scanResult) { + + final CompletionService completionService = new ExecutorCompletionService(executor); + + int outstandingProbes = sendInitialCipherProbes(completionService, scanResult); + + while(outstandingProbes > 0) { + TLSProbeResult result = getNextCompletedCipherProbe(completionService); + if(result == null) { + return false; + } else if(result.isError()) { + scanResult.setTLSProbeFailure(result.getErrorMessage()); + return false; + } + if(result == null || result.isError()) { + return false; + } + outstandingProbes -= 1; + if(processTLSCipherProbeResult(completionService, scanResult, result)) { + outstandingProbes += 1; + } + } + return true; + } + + private int sendInitialCipherProbes(CompletionService cs, SSLServerScanResult scanResult) { + int taskCount = 0; + for(List ciphers: CipherSuites.paritionTLSCiphers(CIPHERS_PER_REQUEST)) { + taskCount += 1; + TLSCipherProbeTask task = new TLSCipherProbeTask(scanResult, ciphers); + cs.submit(task); + } + return taskCount; + } + + private TLSProbeResult getNextCompletedCipherProbe(CompletionService cs) { + try { + final Future future = cs.take(); + return future.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } catch (ExecutionException e) { + logger.warning("Unexpected exception encountered sending TLS cipher probe: "+ e.getCause()); + e.printStackTrace(); + return null; + } + } + + private boolean processTLSCipherProbeResult(CompletionService completionService, SSLServerScanResult scanResult, TLSProbeResult probeResult) { + if(probeResult.getAcceptedCipher() == null) { + return false; + } + + scanResult.addServerTLSCipher(probeResult.getAcceptedCipher()); + for(CertificateAnalyzer probeCert: probeResult.getServerCertificates()) { + scanResult.addServerCertificate(probeCert); + } + + if(probeResult.getTLSCompressionSupport()) { + scanResult.setFlag(Flag.TLS_COMPRESSION); + } + + if(probeResult.getRejectedCiphers().size() == 0) { + return false; + } + + final TLSCipherProbeTask task = new TLSCipherProbeTask(scanResult, probeResult.getRejectedCiphers()); + completionService.submit(task); + return true; + } + + /* Enumerate supported versions of TLS + SSLv3 */ + private void probeSupportedVersions(SSLServerScanResult scanResult) { + final List serverTLSCiphers = scanResult.getServerTLSCiphers(); + + if (!serverTLSCiphers.isEmpty()) { + for(Runnable task: TLSVersionProbe.getVersionProbes(scanResult)) { + executor.execute(task); + } + } + } + + private void probeCipherPreference(SSLServerScanResult scanResult) { + executor.execute(new TLSServerCipherPreferenceProbe(scanResult)); + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLServerScanResult.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLServerScanResult.java new file mode 100644 index 00000000..208f50d0 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLServerScanResult.java @@ -0,0 +1,164 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.net.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.subgraph.vega.internal.sslprobe.TLSCipherSpec.keyStrength; + +public class SSLServerScanResult { + + private final String targetHost; + private final int targetPort; + + public enum Flag { + PFS_SUPPORTED, PFS_SERVER_PREFERENCE, RC4_SERVER_PREFERENCE, RC4_SUPPORTED, WEAK_CIPHERS_SUPPORTED, + EXPORT_CIPHERS_SUPPORTED, TLS_COMPRESSION, ANON_DH, SMALL_RSA_KEY, SELF_SIGNED_CERTIFICATE, + SERVER_PREFERENCE, SSLV2, SSLV3, TLS1, TLS11, TLS12, MD5_SIGNED_CERTIFICATE, SHA1_SIGNED_CERTIFICATE + }; + + private Set flags = Collections.synchronizedSet(EnumSet.noneOf(Flag.class)); + + private boolean TLSProbeFailure; + private String errorMessage; + + private Set certs; + private List serverTLSCiphers; + private List serverSSLv2Ciphers; + private List serverPreferenceOrder; + + private int outstandingProbeCount; + + SSLServerScanResult(String targetHost, int targetPort) { + this.targetHost = targetHost; + this.targetPort = targetPort; + this.certs = new HashSet(); + this.serverTLSCiphers = new ArrayList(); + } + + public String getTargetHost() { + return targetHost; + } + + public int getTargetPort() { + return targetPort; + } + + public synchronized void setTLSProbeFailure(String message) { + errorMessage = message; + TLSProbeFailure = true; + } + + public synchronized void setServerTLSCiphersServerPreferenceOrder(List ciphers) { + this.serverPreferenceOrder = ciphers; + } + public synchronized void setServerSSLv2Ciphers(List ciphers) { + this.serverSSLv2Ciphers = ciphers; + } + + public void addServerTLSCipher(TLSCipherSpec cipher) { + analyzeCipher(cipher); + serverTLSCiphers.add(cipher); + } + + public List getServerTLSCiphers() { + return Collections.unmodifiableList(new ArrayList(serverTLSCiphers)); + } + + + public void addServerCertificate(CertificateAnalyzer certificate) { + if(certs.add(certificate)) { + analyzeCertificate(certificate); + } + } + + private void analyzeCipher(TLSCipherSpec cipher) { + if(cipher.getStrength() == keyStrength.EXPORT) { + flags.add(Flag.EXPORT_CIPHERS_SUPPORTED); + } else if(cipher.getStrength() == keyStrength.LOW) { + flags.add(Flag.WEAK_CIPHERS_SUPPORTED); + } + if(cipher.isAnonDH()) { + flags.add(Flag.ANON_DH); + } + if(cipher.isRC4()) { + flags.add(Flag.RC4_SUPPORTED); + } + if(cipher.isPFS()){ + flags.add(Flag.PFS_SUPPORTED); + } + } + + private void analyzeCertificate(CertificateAnalyzer certificate) { + if(certificate.selfSigned()) { + flags.add(Flag.SELF_SIGNED_CERTIFICATE); + } + + if(certificate.isRSA() && certificate.getRSAModulusBitLength() <= 1024) { + flags.add(Flag.SMALL_RSA_KEY); + } + + if(certificate.isSignedMD5()) { + flags.add(Flag.MD5_SIGNED_CERTIFICATE); + } + + if (certificate.isSignedSHA1()) { + flags.add(Flag.SHA1_SIGNED_CERTIFICATE); + } + } + + public synchronized void setServerTLSCiphers(ArrayList ciphers) { + this.serverTLSCiphers = ciphers; + } + + public void setFlag(Flag flag) { + flags.add(flag); + } + + public boolean isSet(Flag flag) { + return flags.contains(flag); + } + + public boolean getTLSProbeFailure() { + return this.TLSProbeFailure; + } + + public String getErrorMessage() { + return errorMessage; + } + + public List getServerTLSCiphersServerPreferenceOrder() { + return serverPreferenceOrder; + } + + public Collection getServerCertificates() { + return certs; + } + + public List getServerSSLv2Ciphers() { + return serverSSLv2Ciphers; + } + + public synchronized void incrementOutstandingProbeCount() { + outstandingProbeCount += 1; + } + + public synchronized void decrementOutstandingProbeCount() { + outstandingProbeCount -= 1; + if(outstandingProbeCount == 0) { + notifyAll(); + } + } + + public synchronized void waitForOutstandingProbes() throws InterruptedException { + while(outstandingProbeCount > 0) { + this.wait(); + } + } +} + diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2CipherSpec.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2CipherSpec.java new file mode 100644 index 00000000..e8b800b8 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2CipherSpec.java @@ -0,0 +1,60 @@ +package com.subgraph.vega.internal.sslprobe; + +public class SSLv2CipherSpec { + + public enum keyStrength { HIGH, LOW, EXPORT, NONE }; + + private String name; + private byte[] number; + private int num; + private keyStrength strength; + private boolean RC4; + + SSLv2CipherSpec(String name, byte[] number, keyStrength strength, boolean RC4) { + this.setNumber(number); + this.setName(name); + this.setStrength(strength); + this.setNum((number[2] & 0xFF) | ((number[1] & 0xFF) << 8) | ((number[0] & 0x0F) << 16)); + this.setRC4(RC4); + } + + public int getNum() { + return num; + } + + public void setNum(int num) { + this.num = num; + } + + public byte[] getNumber() { + return number; + } + + public void setNumber(byte[] number) { + this.number = number; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public keyStrength getStrength() { + return strength; + } + + public void setStrength(keyStrength strength) { + this.strength = strength; + } + + public boolean isRC4() { + return RC4; + } + + public void setRC4(boolean rC4) { + RC4 = rC4; + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2Probe.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2Probe.java new file mode 100644 index 00000000..be16995c --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/SSLv2Probe.java @@ -0,0 +1,86 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + +import com.subgraph.vega.internal.sslprobe.SSLServerScanResult.Flag; + +public class SSLv2Probe extends ProbeBase { + + private final static Logger logger = Logger.getLogger(SSLv2Probe.class.getName()); + + SSLv2Probe(SSLServerScanResult scanResult) { + super(scanResult); + } + + public Void runProbe() throws IOException { + final SSL2Protocol proto = new SSL2Protocol(getInputStream(), getOutputStream()); + proto.sendClientHello(CipherSuites.getV2CipherSuites()); + final ByteBuffer msg = proto.getNextHandshakeMessage(); + if(msg != null) { + processResponse(msg); + } else { + logger.warning("Got EOF receiving SSLv2 Server Hello message"); + } + return null; + } + + private void processResponse(ByteBuffer msg) { + int type = msg.get() & 0xFF; + if(type != SSL2Protocol.SSLV2_SERVER_HELLO) { + logger.warning("Expecting SSLv2 Server Hello message (type = 0x04), but got type = "+ type); + return; + } + + msg.get(); // session id hit + msg.get(); // certificate type + msg.getShort(); // version + int certificateLength = msg.getShort() & 0xFFFF; + int ciphersLength = msg.getShort() & 0xFFFF; + msg.getShort(); // connection id length + + processCertificate(msg, certificateLength); + processCiphers(msg, ciphersLength); + } + + private void processCertificate(ByteBuffer msg, int length) { + final byte[] certData = new byte[length]; + msg.get(certData); + final CertificateAnalyzer cert = new CertificateAnalyzer(); + try { + final X509Certificate serverCertificate = X509Certificate.getInstance(certData); + cert.addCert(serverCertificate); + } catch (CertificateException e) { + cert.setError(true); + } + scanResult.addServerCertificate(cert); + + } + + private void processCiphers(ByteBuffer msg, int length) { + final List ciphers = new ArrayList(); + for(int n = 0; n < length; n += 3) { + int cc = unpackCipherConstant(msg); + SSLv2CipherSpec spec = CipherSuites.lookupSSLv2Cipher(cc); + if(spec != null) { + ciphers.add(spec); + } + } + scanResult.setFlag(Flag.SSLV2); + scanResult.setServerSSLv2Ciphers(ciphers); + } + + private int unpackCipherConstant(ByteBuffer msg) { + byte[] bs = new byte[3]; + msg.get(bs); + return ((bs[0] & 0xFF) << 16) | ((bs[1] & 0xFF) << 8) | (bs[2] & 0xFF); + } +} + + diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSAlertException.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSAlertException.java new file mode 100644 index 00000000..a648e42e --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSAlertException.java @@ -0,0 +1,24 @@ +package com.subgraph.vega.internal.sslprobe; + +public class TLSAlertException extends Exception { + private static final long serialVersionUID = 1L; + private final int level; + private final int description; + + public TLSAlertException(int level, int description) { + this.level = level; + this.description = description; + } + + public int getLevel() { + return level; + } + + public int getDescription() { + return description; + } + + public String toString() { + return "TLSAlertException("+ level + ", "+ description + ")"; + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherProbeTask.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherProbeTask.java new file mode 100644 index 00000000..693b05bf --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherProbeTask.java @@ -0,0 +1,149 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.IOException; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + + +public class TLSCipherProbeTask extends ProbeBase implements Callable { + private final Logger logger = Logger.getLogger(TLSCipherProbeTask.class.getName()); + + + private List partition; + + TLSCipherProbeTask(SSLServerScanResult scanResult, List partition) { + super(scanResult); + this.partition = partition; + } + + @Override + public TLSProbeResult runProbe() throws Exception { + try { + TLSProtocol proto = new TLSProtocol(getInputStream(), getOutputStream()); + proto.sendTLSClientHello(partition); + return analyzeServerResponses(proto); + } catch (TLSAlertException e) { + final TLSProbeResult result = new TLSProbeResult(); + result.addCiphers(partition, null); + return result; + } catch (UnknownHostException e) { + return createErrorResult("Unknown host"); + } catch (IOException e) { + return createErrorResult("I/O error: "+ e); + } + } + + + private TLSProbeResult createErrorResult(String message) { + final TLSProbeResult result = new TLSProbeResult(); + result.setError(true, message); + return result; + } + + private TLSProbeResult analyzeServerResponses(TLSProtocol proto) throws IOException, TLSAlertException { + final TLSProbeResult result = new TLSProbeResult(); + while(true) { + ByteBuffer msg = proto.getNextHandshakeMessage(); + if(msg == null) { + //result.setError(true, "EOF received reading TLS handshake message, adding to rejected list"); + addDroppedRejected(result); + return result; + } + final int type = msg.get() & 0xFF; + final int len = proto.getInt24(msg); + if(msg.remaining() < len) { + logger.info("Ignoring short handshake message"); + } else { + if(analyzeHandshakeResponse(proto, type, msg, result)) { + return result; + } + } + } + } + + private boolean analyzeHandshakeResponse(TLSProtocol proto, int type, ByteBuffer msg, TLSProbeResult result) { + switch(type) { + case 0x02: + analyzeServerHello(proto, msg, result); + break; + + case 0x0B: + analyzeCertificateMessage(proto, msg, result); + break; + + case 0x0E: + return true; + + case 0x0C: + break; + + default: + logger.info("Unexpected handshake message received with type = "+ type); + break; + } + return false; + } + + private void addDroppedRejected(TLSProbeResult result) { + final List rejected = new ArrayList(); + for(TLSCipherSpec c: partition) { + rejected.add(c); + } + result.addRejectedCiphersOnly(rejected); + } + + private void analyzeServerHello(TLSProtocol tls, ByteBuffer msg, TLSProbeResult result) { + if(tls.extractCompressionFromServerHello(msg) != 0) { + result.setTLSCompressionSupport(true); + } + final int cipherConst = tls.extractCipherFromServerHello(msg); + TLSCipherSpec cipher = CipherSuites.lookupTLSCipher(cipherConst); + if(cipher == null) { + logger.warning("Could not find cipher constant "+ cipherConst); + return; + } + final List rejected = new ArrayList(); + for(TLSCipherSpec c: partition) { + if(cipher != c) { + rejected.add(c); + } + } + result.addCiphers(rejected, cipher); + } + + private void analyzeCertificateMessage(TLSProtocol proto, ByteBuffer msg, TLSProbeResult result) { + final int chainLength = proto.getInt24(msg); + if(msg.remaining() < chainLength) { + logger.warning("Message length is less than expected length of certificate chain"); + return; + } + + final CertificateAnalyzer ca = new CertificateAnalyzer(); + + while(msg.hasRemaining()) { + X509Certificate certificate = readCertificate(proto, msg); + ca.addCert(certificate); + } + result.addCertificate(ca); + } + + private X509Certificate readCertificate(TLSProtocol proto, ByteBuffer msg) { + final int certLength = proto.getInt24(msg); + byte[] certBytes = new byte[certLength]; + msg.get(certBytes); + try { + return X509Certificate.getInstance(certBytes); + } catch (CertificateException e) { + logger.log(Level.WARNING, "Error creating certificate from message bytes", e); + return null; + } + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherSpec.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherSpec.java new file mode 100644 index 00000000..3ad9f822 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSCipherSpec.java @@ -0,0 +1,48 @@ +package com.subgraph.vega.internal.sslprobe; + +public class TLSCipherSpec { + + public enum keyStrength { HIGH, LOW, EXPORT, NONE }; + + private final String name; + private final int number; + private final keyStrength strength; + private final boolean anonDH; + private final boolean PFS; + private final boolean RC4; + + TLSCipherSpec(String name, int number, keyStrength strength, boolean anonDH, boolean PFS, boolean RC4) { + + this.name = name; + this.number = number; + this.strength = strength; + this.anonDH = anonDH; + this.PFS = PFS; + this.RC4 = RC4; + } + + public int getNumber() { + return number; + } + + public keyStrength getStrength() { + return strength; + } + + public boolean isAnonDH() { + return anonDH; + } + + public boolean isRC4() { + return RC4; + } + + public boolean isPFS() { + return PFS; + } + + public String getName() { + return name; + } + +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProbeResult.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProbeResult.java new file mode 100644 index 00000000..b097f1c0 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProbeResult.java @@ -0,0 +1,74 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.util.ArrayList; +import java.util.List; + +public class TLSProbeResult { + + private List rejectedCiphers; + private TLSCipherSpec acceptedCipher; + private ArrayList serverCertificates; + private boolean TLScompressionSupport; + private boolean error; + private String errorMessage = ""; + + + TLSProbeResult() { + serverCertificates = new ArrayList(); + } + + public void addCiphers(List rejected, TLSCipherSpec accepted) { + this.setRejectedCiphers(rejected); + this.acceptedCipher = accepted; + } + + public void addRejectedCiphersOnly(List rejected) { + this.setRejectedCiphers(rejected); + } + + public void addServerCertificate(CertificateAnalyzer cert) { + serverCertificates.add(cert); + } + + public void setTLSCompressionSupport(boolean tf) { + this.TLScompressionSupport = tf; + } + + public void setError(boolean error, String message) { + this.error = error; + this.errorMessage = message; + } + + public void addCertificate(CertificateAnalyzer ca) { + this.serverCertificates.add(ca); + } + + public boolean isError() { + return this.error; + } + + public String getErrorMessage() { + return errorMessage; + } + + public TLSCipherSpec getAcceptedCipher() { + return this.acceptedCipher; + } + + public ArrayList getServerCertificates() { + return this.serverCertificates; + } + + public List getRejectedCiphers() { + return rejectedCiphers; + } + + public void setRejectedCiphers(List rejectedCiphers) { + this.rejectedCiphers = rejectedCiphers; + } + + public boolean getTLSCompressionSupport() { + return this.TLScompressionSupport; + } + +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProtocol.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProtocol.java new file mode 100644 index 00000000..dc7842a5 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSProtocol.java @@ -0,0 +1,269 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Random; + +public class TLSProtocol { + private final static int TLS_RECORD_HEADER_LENGTH = 5; + private final static int TLS_MAXIMUM_RECORD_LENGTH = 16 * 1024; + private final static int MAXIMUM_HANDSHAKE_MESSAGE_LENGTH = 64 * 1024; + private final static int TLS_RECORD_ALERT = 0x15; + public final static int TLS_RECORD_HANDSHAKE = 0x16; + + private final static byte TLS_HANDSHAKE_CLIENTHELLO = 0x01; + private final static byte[] DEFAULT_VERSION = { 0x03, 0x01 }; + private final static Random random = new Random(); + + + private final InputStream input; + private final OutputStream output; + + private final ByteBuffer recordBuffer; + private final ByteBuffer handshakeBuffer; + + + TLSProtocol(InputStream input, OutputStream output) { + this.input = input; + this.output = output; + this.recordBuffer = ByteBuffer.allocate(TLS_RECORD_HEADER_LENGTH + TLS_MAXIMUM_RECORD_LENGTH); + this.handshakeBuffer = ByteBuffer.allocate(MAXIMUM_HANDSHAKE_MESSAGE_LENGTH); + handshakeBuffer.flip(); + } + + + ByteBuffer getNextHandshakeMessage() throws IOException, TLSAlertException { + while(!hasFullHandshakeMessage()) { + if(!readNextRecord()) { + return null; + } + } + return extractNextHandshakeMessage(); + } + + private boolean hasFullHandshakeMessage() { + final int r = handshakeBuffer.remaining(); + return !(r < 4 || r < (peekHandshakeLength() + 4)); + } + + private int peekHandshakeLength() { + // read 32 bits from current location and mask off first byte (type) + return handshakeBuffer.getInt(handshakeBuffer.position()) & 0x00FFFFFF; + } + + private ByteBuffer extractNextHandshakeMessage() { + final int length = peekHandshakeLength(); + final byte[] msg = new byte[length + 4]; + handshakeBuffer.get(msg); + handshakeBuffer.compact().flip(); + return ByteBuffer.wrap(msg); + } + + private void appendMessageBytes(byte[] messageBytes) { + handshakeBuffer.mark(); + handshakeBuffer.position(handshakeBuffer.limit()); + handshakeBuffer.limit(handshakeBuffer.capacity()); + + handshakeBuffer.put(messageBytes); + + handshakeBuffer.limit(handshakeBuffer.position()); + handshakeBuffer.reset(); + } + + private boolean readNextRecord() throws IOException, TLSAlertException { + while(!hasFullRecord()) { + if(!readToRecordBuffer()) { + return false; + } + } + recordBuffer.flip(); + int type = recordBuffer.get() & 0xFF; + recordBuffer.getShort(); /* version */ + int length = recordBuffer.getShort() & 0xFFFF; + byte[] messageBytes = new byte[length]; + recordBuffer.get(messageBytes); + recordBuffer.compact(); + + if(type == TLS_RECORD_HANDSHAKE) { + appendMessageBytes(messageBytes); + } else if (type == TLS_RECORD_ALERT) { + if(messageBytes.length != 2) { + + } + throw new TLSAlertException(messageBytes[0] & 0xFF, messageBytes[1] & 0xFF); + } else { + + } + return true; + } + + private boolean readToRecordBuffer() throws IOException { + final byte[] array = recordBuffer.array(); + final int offset = recordBuffer.position(); + final int len = recordBuffer.remaining(); + + final int n = input.read(array, offset, len); + if(n == -1) { + return false; + } + recordBuffer.position(recordBuffer.position() + n); + return true; + } + + boolean hasFullRecord() { + if(recordBuffer.position() < 5) { + return false; + } + int length = recordBuffer.getShort(3) & 0xFFFF; + return recordBuffer.position() >= (length + 5); + } + + void createTLSClientHello(ByteBuffer buffer, List ciphers, byte[] versionBytes) { + buffer.clear(); + skip(buffer, 5); + final int recordStart = buffer.position(); + + buffer.put(TLS_HANDSHAKE_CLIENTHELLO); + buffer.mark(); + skip(buffer, 3); + int len = packClientHello(buffer, ciphers, versionBytes); + int end = buffer.position(); + buffer.reset(); + buffer.put(packInt24(len)); + + buffer.rewind(); + packRecordHeader(buffer, versionBytes, end - recordStart); + buffer.flip(); + } + + int packClientHello(ByteBuffer buffer, List ciphers, byte[] versionBytes) { + final int start = buffer.position(); + buffer.put(versionBytes); + buffer.putInt(getTimeSeconds()); + buffer.put(getRandomBytes()); + buffer.put((byte) 0); + buffer.putShort((short) (2 * ciphers.size())); + for(TLSCipherSpec c: ciphers) { + buffer.putShort((short) c.getNumber()); + } + buffer.put((byte) 0x02); + buffer.put((byte) 0); + buffer.put((byte) 0x01); + return buffer.position() - start; + } + + int extractCipherFromServerHello(ByteBuffer helloMessage) { + skipStartOfServerHello(helloMessage); + return helloMessage.getShort() & 0xFFFF; + } + + int extractCompressionFromServerHello(ByteBuffer helloMessage) { + skipStartOfServerHello(helloMessage); + helloMessage.getShort(); // Cipher + return helloMessage.get() & 0xFF; + } + + private void skipStartOfServerHello(ByteBuffer helloMessage) { + helloMessage.rewind(); + final int type = helloMessage.get() & 0xFF; + if(type != 0x02) { + + } + final int length = getInt24(helloMessage); + if(helloMessage.remaining() < length) { + + } + skip(helloMessage, 2); // version + skip(helloMessage, 32); // random; + final int sessionIdLength = helloMessage.get() & 0xFF; + skip(helloMessage, sessionIdLength); + } + + public int getInt24(ByteBuffer bb) { + int val = 0; + for(int i = 0; i < 3; i++) { + val <<= 8; + val |= (bb.get() & 0xFF); + } + return val; + } + + void packRecordHeader(ByteBuffer buffer, byte[] versionBytes, int length) { + buffer.put((byte) TLS_RECORD_HANDSHAKE); + buffer.put(versionBytes); + buffer.putShort((short) length); + } + + + private int skip(ByteBuffer buffer, int n) { + final int pos = buffer.position(); + buffer.position(pos + n); + return pos; + } + + public void sendTLSClientHello(List ciphers) throws IOException { + sendTLSClientHello(ciphers, null); + } + + public void sendTLSClientHello(List ciphers, byte[] versionBytes) throws IOException { + writeAll(createTLSClientHello(ciphers, versionBytes)); + } + + protected void writeAll(ByteBuffer buffer) throws IOException { + output.write(buffer.array(), buffer.position(), buffer.remaining()); + buffer.position(buffer.position() + buffer.remaining()); + output.flush(); + } + + private static ByteBuffer createTLSClientHello(List ciphers, byte[] versionBytes) { + final byte[] vb = (versionBytes == null) ? (DEFAULT_VERSION) : (versionBytes); + final ByteBuffer buffer = ByteBuffer.allocate(getTLSHelloLength(ciphers.size())); + + final int tlsRecordLength = 44 + (2 * ciphers.size()); + final int tlsHandshakeLength = tlsRecordLength - 4; + + buffer.put((byte) TLS_RECORD_HANDSHAKE); + buffer.put(vb); + buffer.putShort((short) tlsRecordLength); + buffer.put(TLS_HANDSHAKE_CLIENTHELLO); + buffer.put(packInt24(tlsHandshakeLength)); + buffer.put(vb); + buffer.putInt(getTimeSeconds()); + buffer.put(getRandomBytes()); + buffer.put((byte) 0); + buffer.putShort((short) (2 * ciphers.size())); + for(TLSCipherSpec c: ciphers) { + buffer.putShort((short) c.getNumber()); + } + buffer.put((byte) 0x02); + buffer.put((byte) 0x00); + buffer.put((byte) 0x01); + buffer.flip(); + return buffer; + } + + static int getTLSHelloLength(int cipherCount) { + return 49 + (2 * cipherCount); + } + + static byte[] packInt24(int n) { + final byte[] bs = new byte[3]; + bs[0] = (byte) (n >> 16); + bs[1] = (byte) (n >> 8); + bs[2] = (byte) n; + return bs; + } + + static private int getTimeSeconds() { + return (int) (System.currentTimeMillis() / 1000); + } + + static private byte[] getRandomBytes() { + final byte[] bs = new byte[28]; + random.nextBytes(bs); + return bs; + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSServerCipherPreferenceProbe.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSServerCipherPreferenceProbe.java new file mode 100644 index 00000000..40a9c2e1 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSServerCipherPreferenceProbe.java @@ -0,0 +1,87 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; + +import com.subgraph.vega.internal.sslprobe.SSLServerScanResult.Flag; + + +public class TLSServerCipherPreferenceProbe extends ProbeBase { + private final static Logger logger = Logger.getLogger(TLSServerCipherPreferenceProbe.class.getName()); + + TLSServerCipherPreferenceProbe(SSLServerScanResult scanResult) { + super(scanResult); + } + + @Override + public Void runProbe() { + final List ciphers = scanResult.getServerTLSCiphers(); + if(ciphers.size() < 2) { + return null; + } + + if(isServerPreference(ciphers)) { + scanResult.setFlag(Flag.SERVER_PREFERENCE); + final List orderedCiphers = orderCiphersByServerPreference(ciphers); + if(orderedCiphers != null) { + scanResult.setServerTLSCiphersServerPreferenceOrder(orderedCiphers); + } + } + return null; + } + + private boolean isServerPreference(List ciphers) { + return serverDemonstratePreference(ciphers.get(0), ciphers.get(1)) || + serverDemonstratePreference(ciphers.get(1), ciphers.get(0)); + } + + private boolean serverDemonstratePreference(TLSCipherSpec c1, TLSCipherSpec c2) { + closeConnection(); + try { + final TLSProtocol tls = new TLSProtocol(getInputStream(), getOutputStream()); + tls.sendTLSClientHello(Arrays.asList(c1, c2)); + final ByteBuffer msg = tls.getNextHandshakeMessage(); + final int c = tls.extractCipherFromServerHello(msg); + return c == c2.getNumber(); + } catch (IOException e) { + logger.warning("I/O error sending server order preference probe: "+ e); + } catch (TLSAlertException e) { + logger.info("TLS alert received sending server order preference probe: "+ e); + } + return false; + } + + private List orderCiphersByServerPreference(List ciphers) { + final List preferenceList = new ArrayList(); + final List workingList = new ArrayList(ciphers); + while(!workingList.isEmpty()) { + TLSCipherSpec chosen = chooseCipher(workingList); + if(chosen == null) { + return null; + } else { + preferenceList.add(chosen); + workingList.remove(chosen); + } + } + return preferenceList; + } + + private TLSCipherSpec chooseCipher(List ciphers) { + closeConnection(); + try { + final TLSProtocol tls = new TLSProtocol(getInputStream(), getOutputStream()); + tls.sendTLSClientHello(ciphers); + final int cipherConst = tls.extractCipherFromServerHello(tls.getNextHandshakeMessage()); + return CipherSuites.lookupTLSCipher(cipherConst); + } catch (IOException e) { + logger.info("I/O error sending server cipher ordering probe: "+ e); + } catch (TLSAlertException e) { + logger.info("TLS alert received sending server cipher ordering probe: "+ e); + } + return null; + } +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSVersionProbe.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSVersionProbe.java new file mode 100644 index 00000000..c4c9c1e8 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/internal/sslprobe/TLSVersionProbe.java @@ -0,0 +1,76 @@ +package com.subgraph.vega.internal.sslprobe; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; + +import com.subgraph.vega.internal.sslprobe.SSLServerScanResult.Flag; + +public class TLSVersionProbe extends ProbeBase { + private final static Logger logger = Logger.getLogger(TLSVersionProbe.class.getName()); + + private final static byte[] VER_SSLv3 = {0x03, 0x00}; + private final static byte[] VER_TLS1 = {0x03, 0x01}; + private final static byte[] VER_TLS1_1 = {0x03, 0x02}; + private final static byte[] VER_TLS1_2 = {0x03, 0x03}; + + private final static List ALL_VERSIONS = + Arrays.asList(VER_SSLv3, VER_TLS1, VER_TLS1_1, VER_TLS1_2); + + static List getVersionProbes(SSLServerScanResult scanResult) { + final List probes = new ArrayList(); + for(byte[] v: ALL_VERSIONS) { + probes.add(new TLSVersionProbe(scanResult, v)); + } + return probes; + } + + private final byte[] version; + + TLSVersionProbe(SSLServerScanResult scanResult, byte[] version) { + super(scanResult); + this.version = version; + } + + protected Void runProbe() throws IOException { + final TLSProtocol tls = new TLSProtocol(getInputStream(), getOutputStream()); + tls.sendTLSClientHello(scanResult.getServerTLSCiphers(), version); + final byte[] responseBytes = new byte[3]; + if(!readAll(responseBytes)) { + logger.warning("Failed to read response in TLSVersionProbe"); + } else if(responseBytes[0] != TLSProtocol.TLS_RECORD_HANDSHAKE) { + logger.warning("Unexpected record type received in response in TLSVersionProbe. type = "+ responseBytes[0]); + } else { + final boolean matches = responseBytes[1] == version[0] && responseBytes[2] == version[1]; + if (matches == true) { + processProbeResult(matches); + } + } + return null; + } + + private void processProbeResult(boolean supported) { + if (version != null) { + switch (version[1]) { + case 0x00: + scanResult.setFlag(Flag.SSLV3); + break; + case 0x01: + scanResult.setFlag(Flag.TLS1); + break; + case 0x02: + scanResult.setFlag(Flag.TLS11); + break; + case 0x03: + scanResult.setFlag(Flag.TLS12); + break; + default: + break; + } + } + } +} + + diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/Activator.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/Activator.java new file mode 100644 index 00000000..47049463 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/Activator.java @@ -0,0 +1,30 @@ +package com.subgraph.vega.sslprobe; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/SSLProbe.java b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/SSLProbe.java new file mode 100644 index 00000000..5946d6c7 --- /dev/null +++ b/platform/com.subgraph.vega.sslprobe/src/com/subgraph/vega/sslprobe/SSLProbe.java @@ -0,0 +1,277 @@ +package com.subgraph.vega.sslprobe; + + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.subgraph.vega.api.model.alerts.IScanAlert; +import com.subgraph.vega.api.model.alerts.IScanInstance; +import com.subgraph.vega.internal.sslprobe.CertificateAnalyzer; +import com.subgraph.vega.internal.sslprobe.SSLScanTaskManager; +import com.subgraph.vega.internal.sslprobe.SSLServerScanResult; +import com.subgraph.vega.internal.sslprobe.SSLv2CipherSpec; +import com.subgraph.vega.internal.sslprobe.TLSCipherSpec; +import com.subgraph.vega.internal.sslprobe.SSLServerScanResult.Flag; + +public class SSLProbe implements Runnable { + + private final int NTHREADS = 10; + private final ExecutorService executor = Executors.newFixedThreadPool(NTHREADS); + private SSLServerScanResult result; + + private final String host; + private final int port; + private final IScanInstance scanInstance; + private final String hostString; + + private final Logger logger = Logger.getLogger("scanner"); + + + public SSLProbe(IScanInstance instance, String hostname, int serverPort, String httpHostString) { + host = hostname; + port = serverPort; + scanInstance = instance; + hostString = httpHostString; + } + + public void run() { + + SSLScanTaskManager taskmanager = new SSLScanTaskManager(executor); + + try { + result = taskmanager.scanServer(host, port); + summarizeResults(result); + taskmanager.shutdown(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + private void summarizeResults(SSLServerScanResult res) { + + String output = "SSL Server Configuration Probe\n"; + + output += "Target: "+res.getTargetHost() + ":" + res.getTargetPort() + "\n\n"; + + if(res.getTLSProbeFailure()) { + output += "Scan Failed ("+ res.getErrorMessage() + ")\n"; + // return; + } + + output += "SSL/TLS Version Enumeration\n"; + output += "---------------------------------------------------------\n"; + + boolean val = res.isSet(Flag.SSLV2); + if (val) { + + /* Alert here */ + + IScanAlert alert = scanInstance.createAlert("ssl-v2-support", host+"-sslv2"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + output += " [ BAD ] SSL v2 Support: "+val + "\n"; + + } else { + output += " [ GOOD ] SSL v2 Support: "+ val + "\n"; + } + val = res.isSet(Flag.SSLV3); + if (val) { + output += " [ BAD ] SSL v3 Support: "+ val + "\n"; + IScanAlert alert = scanInstance.createAlert("ssl-v3-support",host + "-sslv3"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } else { + output += " [ GOOD ] SSL v3 Support: "+ val + "\n"; + } + output += " [ INFO ] TLS 1.0 Support: "+res.isSet(Flag.TLS1) + "\n"; + output += " [ INFO ] TLS 1.1 Support: "+res.isSet(Flag.TLS11) + "\n"; + output += " [ INFO ] TLS 1.2 Support: "+res.isSet(Flag.TLS12) + "\n"; + + output += "\nTLS Configuration Summary\n"; + output += "--------------------------------------------------------\n"; + + if (res.isSet(Flag.TLS_COMPRESSION)) { + output += " [ BAD ] TLS compression supported (CRIME attack).\n"; + IScanAlert alert = scanInstance.createAlert("ssl-compression",host + "-compression"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } else { + output += " [ GOOD ] TLS compression not supported.\n"; + } + if (res.isSet(Flag.ANON_DH)) { + output += " [ INFO ] Supported cipher spec found with Anon-DH key exchange.\n"; + IScanAlert alert = scanInstance.createAlert("ssl-anonymous-dh",host + "-anonymous-dh"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } + + if (res.isSet(Flag.RC4_SUPPORTED)) { + output += " [ INFO ] Supported ciphers using RC4 found (common).\n"; + } + + /* Certificate analyzer results */ + + if (res.isSet(Flag.SMALL_RSA_KEY)) { + output += " [ BAD ] Small RSA modulus (<= 1024 bit) found in a server certificate.\n"; + IScanAlert alert = scanInstance.createAlert("ssl-small-key",host + "-small-key"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } + if (res.isSet(Flag.SELF_SIGNED_CERTIFICATE)) { + output += " [ INFO ] Self-signed certificate found.\n"; + IScanAlert alert = scanInstance.createAlert("ssl-self-signed",host + "-self-signed"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } + + if (res.isSet(Flag.MD5_SIGNED_CERTIFICATE)) { + output += " [ BAD ] Certificate signed using MD5. \n"; + IScanAlert alert = scanInstance.createAlert("ssl-md5-cert", host + "-md5-cert"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } + + if (res.isSet(Flag.SHA1_SIGNED_CERTIFICATE)) { + output += " [ BAD ] Certificate signed using SHA1. \n"; + IScanAlert alert = scanInstance.createAlert("ssl-sha1-cert", host + "-sha1-cert"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } + + /* End certificate analyzer results */ + + if (res.isSet(Flag.SERVER_PREFERENCE)) { + output += "\n\n [ GOOD ] Server cipher spec preference detected. Server preference order: \n"; + int i = 1; + for (TLSCipherSpec c : res.getServerTLSCiphersServerPreferenceOrder()) { + output += " ["+i+"] "+c.getName() + "\n"; + if (c.getStrength() == TLSCipherSpec.keyStrength.EXPORT) { + output += " [ BAD ] Cipher spec is export grade.\n"; + } else if (c.getStrength() == TLSCipherSpec.keyStrength.LOW) { + output += " [ BAD ] Cipher spec is low security.\n"; + } else if (c.getStrength() == TLSCipherSpec.keyStrength.NONE) { + output += " [ BAD ] Cipher spec does not include encryption.\n"; + } + if (c.isAnonDH() == true) { + output += " [ BAD ] Cipher spec supports Anonymous DH.\n"; + } + if (c.isPFS() == true) { + output += " [ GOOD ] Cipher spec offers PFS.\n"; + } + if (c.isRC4() == true) { + output += " [ BAD ] Cipher spec uses RC4.\n"; + } + + i++; + } + if (res.getServerTLSCiphersServerPreferenceOrder().get(0).isPFS() == false) { + output += " [ BAD ] Server most preferred cipher does not offer PFS: "+res.getServerTLSCiphersServerPreferenceOrder().get(0).getName() + "\n"; + IScanAlert alert = scanInstance.createAlert("ssl-pfs-not-preferred",host + "-pfs-not-preferred"); + alert.setDiscretionaryHostname(hostString); + alert.setResource(hostString); + scanInstance.addAlert(alert); + } else if (res.getServerTLSCiphersServerPreferenceOrder().get(0).isPFS() == true) { + output += " [ GOOD ] Server most preferred cipher offers PFS: "+res.getServerTLSCiphersServerPreferenceOrder().get(0).getName() + "\n"; + } + if (res.getServerTLSCiphersServerPreferenceOrder().get(0).isRC4() == true) { + output += " [ BAD ] Server most preferred cipher uses RC4: "+res.getServerTLSCiphersServerPreferenceOrder().get(0).getName() + "\n"; + IScanAlert alert = scanInstance.createAlert("ssl-rc4-preference",host + "-rc4-preference"); + alert.setResource(hostString); + alert.setDiscretionaryHostname(hostString); + scanInstance.addAlert(alert); + } + + } else + { + output += "\n [ BAD ] Client cipher spec preference detected. Supported cipher specs:\n"; + if (res.getServerTLSCiphers().isEmpty() == false) { + + IScanAlert clientPreferenceAlert = scanInstance.createAlert("ssl-client-preference",host + "-client-preference"); + clientPreferenceAlert.setDiscretionaryHostname(hostString); + clientPreferenceAlert.setResource(hostString); + scanInstance.addAlert(clientPreferenceAlert); + + if (res.isSet(Flag.PFS_SUPPORTED)) { + output += " [ GOOD ] Ciphers offering PFS supported.\n"; + } else { + output += " [ BAD ] No ciphers offering PFS supported.\n"; + IScanAlert noPFSAlert = scanInstance.createAlert("ssl-no-pfs", host + "-no-pfs"); + noPFSAlert.setDiscretionaryHostname(hostString); + noPFSAlert.setResource(hostString); + scanInstance.addAlert(noPFSAlert); + } + for (TLSCipherSpec c : res.getServerTLSCiphers()) { + output += " [*] "+c.getName() + "\n"; + if (c.getStrength() == TLSCipherSpec.keyStrength.EXPORT) { + output += " [ BAD ] Cipher spec is export grade.\n"; + } else if (c.getStrength() == TLSCipherSpec.keyStrength.LOW) { + output += " [ BAD ] Cipher spec is low security.\n"; + } else if (c.getStrength() == TLSCipherSpec.keyStrength.NONE) { + output += " [ BAD ] Cipher spec does not include encryption.\n"; + } + if (c.isAnonDH() == true) { + output += " [ BAD ] Cipher spec supports Anonymous DH.\n"; + } + if (c.isPFS() == true) { + output += " [ GOOD ] Cipher spec offers PFS.\n"; + } + if (c.isRC4() == true) { + output += " [ BAD ] Cipher spec uses RC4.\n"; + } + } + } + + } if (res.isSet(Flag.SSLV2)) { + output += "\nSSLv2 Ciphers Supported:\n"; + for (SSLv2CipherSpec c : res.getServerSSLv2Ciphers()) { + output += " [*] "+c.getName() + "\n"; + if (c.getStrength() == SSLv2CipherSpec.keyStrength.EXPORT) { + output += " [ BAD ] Cipher spec is export grade.\n"; + } else if (c.getStrength() == SSLv2CipherSpec.keyStrength.LOW) { + output += " [ BAD ] Cipher spec is low security.\n"; + } else if (c.getStrength() == SSLv2CipherSpec.keyStrength.NONE) { + output += " [ BAD ] Cipher spec does not include encryption.\n"; + } + if (c.isRC4() == true) { + output += " [ BAD ] Cipher spec uses RC4.\n"; + } + + } + } + + output += "\nCertificate Analysis\n"; + output += "--------------------------------------------------------\n"; + + for (CertificateAnalyzer ca : res.getServerCertificates()) { + output += " [*] Certificate: "+ca.getCertificate().getSerialNumber() + "\n"; + if (ca.isRSA()) { + if (ca.getRSAModulusBitLength() <= 1024) { + output += " [ BAD ] RSA modulus <= 1024 found.\n"; + } + else { + output += " [ GOOD ] RSA modulus size: " +ca.getRSAModulusBitLength() + " bits.\n"; + } + } + if (ca.selfSigned()) { + output += " [ INFO ] Self-signed certificate found.\n"; + } else { + output += " [ INFO ] Not self signed.\n"; + } + } + output += "\nSSL Probe completed.\n"; + logger.log(Level.INFO, output); + } +} + + \ No newline at end of file