Esempio n. 1
0
 internal static bool Equals(
     SupportedCipherSuites scs1, SupportedCipherSuites scs2)
 {
     if (scs1 == scs2)
     {
         return(true);
     }
     if (scs1 == null || scs2 == null)
     {
         return(false);
     }
     return(scs1.Equals(scs2));
 }
Esempio n. 2
0
 internal bool Equals(SupportedCipherSuites scs)
 {
     if (scs == null)
     {
         return(false);
     }
     if (prefClient != scs.prefClient ||
         prefServer != scs.prefServer)
     {
         return(false);
     }
     return(M.Equals(suites, scs.suites));
 }
Esempio n. 3
0
 public bool Equals(SupportedCipherSuites scs)
 {
     if (scs == null)
     {
         return(false);
     }
     if (prefClient != scs.prefClient ||
         prefServer != scs.prefServer)
     {
         return(false);
     }
     if (kxReuseDH != scs.kxReuseDH ||
         kxReuseECDH != scs.kxReuseECDH)
     {
         return(false);
     }
     return(M.Equals(suites, scs.suites));
 }
Esempio n. 4
0
    /*
     * Encode the report as JSON.
     */
    internal void Print(JSON js)
    {
        js.OpenInit(false);
        js.AddPair("connectionName", connName);
        js.AddPair("connectionPort", connPort);
        js.AddPair("SNI", sni);
        if (ssl2Suites != null && ssl2Suites.Length > 0)
        {
            js.OpenPairObject("SSLv2");
            js.OpenPairArray("suites");
            foreach (int s in ssl2Suites)
            {
                js.OpenElementObject();
                js.AddPair("id", s);
                js.AddPair("name", CipherSuite.ToNameV2(s));
                js.Close();
            }
            js.Close();
            js.Close();
        }

        foreach (int v in suites.Keys)
        {
            js.OpenPairObject(M.VersionString(v));
            SupportedCipherSuites scs = suites[v];
            string sel;
            if (scs.PrefClient)
            {
                sel = "client";
            }
            else if (scs.PrefServer)
            {
                sel = "server";
            }
            else
            {
                sel = "complex";
            }
            js.AddPair("suiteSelection", sel);
            js.OpenPairArray("suites");
            foreach (int s in scs.Suites)
            {
                js.OpenElementObject();
                js.AddPair("id", s);
                js.AddPair("name", CipherSuite.ToName(s));
                CipherSuite cs;
                if (CipherSuite.ALL.TryGetValue(s, out cs))
                {
                    js.AddPair("strength", cs.Strength);
                    js.AddPair("forwardSecrecy",
                               cs.HasForwardSecrecy);
                    js.AddPair("anonymous",
                               cs.IsAnonymous);
                    js.AddPair("serverKeyType",
                               cs.ServerKeyType);
                }
                js.Close();
            }
            js.Close();
            js.Close();
        }

        if (ssl2Chain != null)
        {
            js.OpenPairObject("ssl2Cert");
            PrintCert(js, ssl2Chain, 0);
            js.Close();
        }

        js.OpenPairArray("ssl3Chains");
        foreach (X509Chain xchain in chains.Values)
        {
            js.OpenElementObject();
            int n = xchain.Elements.Length;
            js.AddPair("length", n);
            js.AddPair("decoded", xchain.Decodable);
            if (xchain.Decodable)
            {
                js.AddPair("namesMatch", xchain.NamesMatch);
                js.AddPair("includesRoot", xchain.IncludesRoot);
                js.OpenPairArray("signHashes");
                foreach (string name in xchain.SignHashes)
                {
                    js.AddElement(name);
                }
                js.Close();
            }
            js.OpenPairArray("certificates");
            for (int i = 0; i < n; i++)
            {
                js.OpenElementObject();
                PrintCert(js, xchain, i);
                js.Close();
            }
            js.Close();
            js.Close();
        }
        js.Close();

        js.AddPair("deflateCompress", DeflateCompress);
        if (serverTimeOffset == Int64.MinValue)
        {
            js.AddPair("serverTime", "none");
        }
        else if (serverTimeOffset == Int64.MaxValue)
        {
            js.AddPair("serverTime", "random");
        }
        else
        {
            DateTime dt = DateTime.UtcNow;
            dt = dt.AddMilliseconds((double)serverTimeOffset);
            js.AddPair("serverTime", string.Format(
                           "{0:yyyy-MM-dd HH:mm:ss} UTC", dt));
            js.AddPair("serverTimeOffsetMillis",
                       serverTimeOffset);
        }
        js.AddPair("secureRenegotiation", doesRenego);
        js.AddPair("rfc7366EtM", doesEtM);
        js.AddPair("ssl2HelloFormat", helloV2);
        if (minDHSize > 0)
        {
            js.AddPair("minDHSize", minDHSize);
            js.AddPair("kxReuseDH", kxReuseDH);
        }
        if (minECSize > 0)
        {
            js.AddPair("minECSize", minECSize);
        }
        if (minECSizeExt > 0)
        {
            js.AddPair("minECSizeExt", minECSizeExt);
        }
        if (minECSize > 0 || minECSizeExt > 0)
        {
            js.AddPair("kxReuseECDH", kxReuseECDH);
        }

        if ((namedCurves != null && namedCurves.Length > 0) ||
            curveExplicitPrime > 0 || curveExplicitChar2 > 0)
        {
            js.OpenPairArray("namedCurves");
            foreach (SSLCurve nc in namedCurves)
            {
                js.OpenElementObject();
                js.AddPair("name", nc.Name);
                js.AddPair("size", nc.Size);
                js.AddPair("spontaneous", IsSpontaneous(nc));
                js.Close();
            }
            if (curveExplicitPrime > 0)
            {
                js.OpenElementObject();
                js.AddPair("name", "explicitPrime");
                js.AddPair("size", curveExplicitPrime);
                js.Close();
            }
            if (curveExplicitChar2 > 0)
            {
                js.OpenElementObject();
                js.AddPair("name", "explicitChar2");
                js.AddPair("size", curveExplicitChar2);
                js.Close();
            }
            js.Close();
        }

        if (warnings == null)
        {
            Analyse();
        }
        js.OpenPairArray("warnings");
        foreach (string k in warnings.Keys)
        {
            js.OpenElementObject();
            js.AddPair("id", k);
            js.AddPair("text", warnings[k]);
            js.Close();
        }
        js.Close();
        js.Close();
    }
Esempio n. 5
0
    /*
     * Print the report on the provided writer (text version for
     * humans).
     */
    internal void Print(TextWriter w)
    {
        w.WriteLine("Connection: {0}:{1}", connName, connPort);
        if (sni == null)
        {
            w.WriteLine("No SNI sent");
        }
        else
        {
            w.WriteLine("SNI: {0}", sni);
        }
        if (ssl2Suites != null && ssl2Suites.Length > 0)
        {
            w.WriteLine("  {0}", M.VersionString(M.SSLv20));
            foreach (int s in ssl2Suites)
            {
                w.WriteLine("     {0}",
                            CipherSuite.ToNameV2(s));
            }
        }
        SupportedCipherSuites last = null;

        foreach (int v in suites.Keys)
        {
            w.Write("  {0}:", M.VersionString(v));
            SupportedCipherSuites scs = suites[v];
            if (scs.Equals(last))
            {
                w.WriteLine(" idem");
                continue;
            }
            last = scs;
            w.WriteLine();
            w.Write("     server selection: ");
            if (scs.PrefClient)
            {
                w.WriteLine("uses client preferences");
            }
            else if (scs.PrefServer)
            {
                w.WriteLine("enforce server preferences");
            }
            else
            {
                w.WriteLine("complex");
            }
            foreach (int s in scs.Suites)
            {
                CipherSuite cs;
                string      strength;
                string      fsf;
                string      anon;
                string      kt;
                if (CipherSuite.ALL.TryGetValue(s, out cs))
                {
                    strength = cs.Strength.ToString();
                    fsf      = cs.HasForwardSecrecy ? "f" : "-";
                    anon     = cs.IsAnonymous ? "A" : "-";
                    kt       = cs.ServerKeyType;
                }
                else
                {
                    strength = "?";
                    fsf      = "?";
                    anon     = "?";
                    kt       = "?";
                }
                w.WriteLine("     {0}{1}{2} (key: {3,4})  {4}",
                            strength, fsf, anon, kt,
                            CipherSuite.ToName(s));
            }
        }
        w.WriteLine("=========================================");
        if (ssl2Chain != null)
        {
            w.WriteLine("+++++ SSLv2 certificate");
            PrintCert(w, ssl2Chain, 0);
        }
        w.WriteLine("+++++ SSLv3/TLS: {0} certificate chain(s)",
                    chains.Count);
        foreach (X509Chain xchain in chains.Values)
        {
            int n = xchain.Elements.Length;
            w.WriteLine("+++ chain: length={0}", n);
            if (xchain.Decodable)
            {
                w.WriteLine("names match:        {0}",
                            xchain.NamesMatch ? "yes" : "no");
                w.WriteLine("includes root:      {0}",
                            xchain.IncludesRoot ? "yes" : "no");
                w.Write("signature hash(es):");
                foreach (string name in xchain.SignHashes)
                {
                    w.Write(" {0}", name);
                }
                w.WriteLine();
            }
            else if (n == 0)
            {
                w.WriteLine("CHAIN IS EMPTY");
            }
            else
            {
                w.WriteLine("CHAIN PROCESSING ERROR");
            }
            for (int i = 0; i < n; i++)
            {
                w.WriteLine("+ certificate order: {0}", i);
                PrintCert(w, xchain, i);
            }
        }
        w.WriteLine("=========================================");
        w.WriteLine("Server compression support: {0}",
                    DeflateCompress ? "yes" : "no");
        if (serverTimeOffset == Int64.MinValue)
        {
            w.WriteLine("Server does not send its system time.");
        }
        else if (serverTimeOffset == Int64.MaxValue)
        {
            w.WriteLine("Server sends a random system time.");
        }
        else
        {
            DateTime dt = DateTime.UtcNow;
            dt = dt.AddMilliseconds((double)serverTimeOffset);
            w.WriteLine("Server time: {0:yyyy-MM-dd HH:mm:ss} UTC"
                        + " (offset: {1} ms)", dt, serverTimeOffset);
        }
        w.WriteLine("Secure renegotiation support: {0}",
                    doesRenego ? "yes" : "no");
        w.WriteLine("Encrypt-then-MAC support (RFC 7366): {0}",
                    doesEtM ? "yes" : "no");
        w.WriteLine("SSLv2 ClientHello format (for SSLv3+): {0}",
                    helloV2 ? "yes" : "no");
        if (minDHSize > 0)
        {
            w.WriteLine("Minimum DH size: {0}", minDHSize);
            w.WriteLine("DH parameter reuse: {0}",
                        kxReuseDH ? "yes" : " no");
        }
        if (minECSize > 0)
        {
            w.WriteLine("Minimum EC size (no extension):   {0}",
                        minECSize);
        }
        if (minECSizeExt > 0)
        {
            w.WriteLine("Minimum EC size (with extension): {0}",
                        minECSizeExt);
            if (minECSize == 0)
            {
                w.WriteLine("Server does not use EC without"
                            + " the client extension");
            }
        }
        if (minECSize > 0 || minECSizeExt > 0)
        {
            w.WriteLine("ECDH parameter reuse: {0}",
                        kxReuseECDH ? "yes" : " no");
        }
        if (namedCurves != null && namedCurves.Length > 0)
        {
            w.WriteLine("Supported curves (size and name)"
                        + " ('*' = selected by server):");
            foreach (SSLCurve nc in namedCurves)
            {
                w.WriteLine("  {0} {1,3}  {2}",
                            IsSpontaneous(nc) ? "*" : " ",
                            nc.Size, nc.Name);
            }
            if (curveExplicitPrime > 0)
            {
                w.WriteLine("  explicit prime, size = {0}",
                            curveExplicitPrime);
            }
            if (curveExplicitChar2 > 0)
            {
                w.WriteLine("  explicit char2, size = {0}",
                            curveExplicitChar2);
            }
        }

        w.WriteLine("=========================================");
        if (warnings == null)
        {
            Analyse();
        }
        if (warnings.Count == 0)
        {
            w.WriteLine("No warning.");
        }
        else
        {
            foreach (string k in warnings.Keys)
            {
                w.WriteLine("WARN[{0}]: {1}", k, warnings[k]);
            }
        }
    }
Esempio n. 6
0
    /*
     * Analyse data and compute the list of relevant warnings.
     */
    internal void Analyse()
    {
        warnings = new SortedDictionary <string, string>(
            StringComparer.Ordinal);
        if (ssl2Suites != null)
        {
            if (ssl2Suites.Length > 0)
            {
                warnings["PV002"] = "Server supports SSL 2.0.";
            }
            else
            {
                warnings["PV005"] = "Server claims to support"
                                    + " SSL 2.0, but with no cipher suite";
            }
        }
        if (suites.ContainsKey(M.SSLv30))
        {
            warnings["PV003"] = "Server supports SSL 3.0.";
        }
        if (unknownSKE)
        {
            warnings["SK001"] = "Some Server Key Exchange messages"
                                + " could not be processed.";
        }
        if (minDHSize > 0 && minDHSize < 2048)
        {
            warnings["SK002"] = "Server uses DH parameters smaller"
                                + " than 2048 bits.";
        }
        if (minECSize > 0 && minECSize < 192)
        {
            warnings["SK003"] = "Server chooses ECDH parameters"
                                + " smaller than 192 bits.";
        }
        if (minECSizeExt > 0 && minECSizeExt < 192)
        {
            warnings["SK004"] = "Server supports ECDH parameters"
                                + " smaller than 192 bits (if requested).";
        }
        if (NeedsShortHello)
        {
            warnings["PV001"] = "Server needs short ClientHello.";
        }
        if (NoExtensions)
        {
            warnings["PV004"] =
                "Server does not tolerate extensions.";
        }
        if (DeflateCompress)
        {
            warnings["CP001"] = "Server supports compression.";
        }

        bool hasCS0  = false;
        bool hasCS1  = false;
        bool hasCS2  = false;
        bool hasCSX  = false;
        bool hasRC4  = false;
        bool hasNoFS = false;

        foreach (int pv in suites.Keys)
        {
            SupportedCipherSuites scs = suites[pv];
            foreach (int s in scs.Suites)
            {
                CipherSuite cs;
                if (CipherSuite.ALL.TryGetValue(s, out cs))
                {
                    switch (cs.Strength)
                    {
                    case 0: hasCS0 = true; break;

                    case 1: hasCS1 = true; break;

                    case 2: hasCS2 = true; break;
                    }
                    if (cs.IsRC4)
                    {
                        hasRC4 = true;
                    }
                    if (!cs.HasForwardSecrecy)
                    {
                        hasNoFS = true;
                    }
                }
                else
                {
                    hasCSX = true;
                }
            }
        }
        if (hasCS0)
        {
            warnings["CS001"] =
                "Server supports unencrypted cipher suites.";
        }
        if (hasCS1)
        {
            warnings["CS002"] = "Server supports very weak"
                                + " cipher suites (40 bits).";
        }
        if (hasCS2)
        {
            warnings["CS003"] = "Server supports weak"
                                + " cipher suites (56 bits).";
        }
        if (hasCSX)
        {
            warnings["CS004"] = "Server supports unrecognized"
                                + " cipher suites (unknown strength).";
        }
        if (hasRC4)
        {
            warnings["CS005"] = "Server supports RC4.";
        }
        if (hasNoFS)
        {
            warnings["CS006"] = "Server supports cipher suites"
                                + " with no forward secrecy.";
        }
        if (!doesRenego)
        {
            warnings["RN001"] = "Server does not support"
                                + " secure renegotiation.";
        }
        bool hasBadSignHash = false;

        foreach (X509Chain xchain in chains.Values)
        {
            string[] shs = xchain.SignHashes;
            if (shs == null)
            {
                continue;
            }
            foreach (string sh in shs)
            {
                switch (sh)
                {
                case "MD2":
                case "MD5":
                case "SHA-1":
                case "UNKNOWN":
                    hasBadSignHash = true;
                    break;
                }
            }
        }
        if (hasBadSignHash)
        {
            warnings["XC001"] = "Server certificate was signed with"
                                + " a weak/deprecated/unknown hash function.";
        }
    }
Esempio n. 7
0
 /*
  * Set the cipher suites supported for a specific protocol version
  * (SSLv3+).
  */
 internal void SetCipherSuites(int version, SupportedCipherSuites scs)
 {
     suites[version] = scs;
 }
Esempio n. 8
0
    /*
     * Get all supported cipher suites with the current configuration.
     * If there is none, then null is returned (which means that the
     * protocol version is not supported).
     */
    SupportedCipherSuites GetSupportedCipherSuites()
    {
        int num = tb.ComputeMaxCipherSuites(maxRecordLen);

        if (num < 1)
        {
            num = 1;
        }
        if (verbose)
        {
            Console.WriteLine("[suites: version={0}"
                              + " ({1} suites per hello)]",
                              M.VersionString(tb.MaxVersion), num);
        }

        /*
         * We accumulate hashes of server key exchange parameters
         * in this map, for DHE/DH_anon and ECDHE/ECDH_anon. This
         * is used to detect duplicates, i.e. parameter reuse. The
         * dictionary maps the hash value to an integer whose
         * upper 16 bits are the cipher suite last associated with
         * these parameters, and the lower 16 bits are the number
         * of times these parameters occurred.
         */
        IDictionary <string, uint> kxHashes =
            new SortedDictionary <string, uint>(
                StringComparer.Ordinal);

        /*
         * 1. Gather all cipher suites supported by the server.
         */
        IDictionary <int, int> suppd = new SortedDictionary <int, int>();

        for (int i = 0; i < csl.Count; i += num)
        {
            int   k  = Math.Min(num, csl.Count - i);
            int[] tt = new int[k];
            for (int j = 0; j < k; j++)
            {
                tt[j] = csl[i + j];
            }
            foreach (int s in
                     GetSupportedCipherSuites(tt, kxHashes))
            {
                AddToSet(suppd, s);
            }
        }
        int[] supp = SetToArray(suppd);
        if (supp.Length == 0)
        {
            if (verbose)
            {
                Console.WriteLine();
            }
            return(null);
        }
        SupportedCipherSuites scs = new SupportedCipherSuites(supp);

        /*
         * 2. Work out server preferences. We can do that only
         * if we can send all supported suites in a single
         * ClientHello.
         *
         * Algorithm: we first try suites in numerical order. Then
         * we try suites in the reverse order of what the server
         * selected. If the second list is equal to the first one,
         * then the server enforces its own preferences. If the
         * second list is the reverse of the first one, then the
         * server follows client preferences. In all other cases,
         * the server selection algorithm is deemed "complex".
         */
        if (supp.Length <= num)
        {
            int[] supp1 = GetSupportedCipherSuites(
                supp, kxHashes);
            int[] suppRev = new int[supp1.Length];
            for (int i = 0; i < supp1.Length; i++)
            {
                suppRev[i] = supp[supp1.Length - 1 - i];
            }
            int[] supp2 = GetSupportedCipherSuites(
                suppRev, kxHashes);

            if (M.Equals(supp2, suppRev))
            {
                scs.PrefClient = true;
            }
            else if (M.Equals(supp1, supp2))
            {
                scs.PrefServer = true;
                scs.Suites     = supp1;
            }
        }

        /*
         * See if there was some parameter reuse.
         */
        foreach (uint v in kxHashes.Values)
        {
            if ((v & 0xFFFF) == 1)
            {
                continue;
            }
            int         w = (int)(v >> 16);
            CipherSuite cs;
            if (!CipherSuite.ALL.TryGetValue(w, out cs))
            {
                continue;
            }
            if (cs.IsDHE)
            {
                scs.KXReuseDH = true;
            }
            else if (cs.IsECDHE)
            {
                scs.KXReuseECDH = true;
            }
        }

        if (verbose)
        {
            Console.WriteLine();
        }
        return(scs);
    }
Esempio n. 9
0
    /*
     * Run the tests and return the report.
     */
    internal Report Run()
    {
        string sni = explicitSNI;

        if (sni == null)
        {
            sni = serverName;
        }
        else if (sni == "-")
        {
            sni = null;
        }

        /*
         * Accumulate time offsets between client and server.
         */
        timeOffsets = new List <long>();

        /*
         * To keep track of DHE/ECDHE parameters.
         */
        minDHSize          = 0;
        minECSize          = 0;
        minECSizeExt       = 0;
        namedCurves        = new SortedDictionary <int, SSLCurve>();
        curveExplicitPrime = 0;
        curveExplicitChar2 = 0;
        unknownSKE         = false;
        doesRenego         = false;
        doesEtM            = false;

        /*
         * Overall process:
         *
         *  1. First, try SSL 2.0. This is a single connection.
         *  After this test, everything else uses SSL 3.0+.
         *
         *  2. Try to confirm that we are talking to an actual
         *  SSL/TLS server and obtain its tolerance to variants:
         *  maximum client version, presence of extensions,
         *  large ClientHello messages.
         *
         *  3. For each supported protocol version, find
         *  accepted cipher suites, then work out server's
         *  behaviour for suite selection (client order, server
         *  order, other).
         *
         *  4. Print report for cipher suites.
         *
         *  5. Print other information (compression support,
         *  certificate information, DHE/ECDHE details...).
         */
        rp          = new Report();
        rp.ConnName = serverName;
        rp.ConnPort = serverPort;
        rp.SNI      = sni;

        /*
         * SSL 2.0 attempt.
         */
        if (minVersion <= M.SSLv20)
        {
            if (verbose)
            {
                Console.WriteLine("[trying version=SSLv2]");
            }
            SSL2 v2 = DoConnectV2();
            if (v2 != null)
            {
                if (verbose)
                {
                    Console.WriteLine("[SSLv2 supported,"
                                      + " {0} cipher suite(s)]",
                                      v2.CipherSuites.Length);
                }
            }
        }

        /*
         * Make the list of cipher suites we are interested in.
         */
        csl = new List <int>();
        if (allSuites)
        {
            for (int i = 1; i <= 0xFFFF; i++)
            {
                if (i == M.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ||
                    i == M.TLS_FALLBACK_SCSV)
                {
                    continue;
                }
                csl.Add(i);
            }
        }
        else
        {
            foreach (int s in CipherSuite.ALL.Keys)
            {
                if (s != 0)
                {
                    csl.Add(s);
                }
            }
        }

        /*
         * Create a test builder and populate it with the
         * configured information.
         */
        tb             = new SSLTestBuilder();
        tb.ServerName  = sni;
        tb.MaxVersion  = maxVersion;
        withExts       = true;
        gotSSLAnswer   = false;
        serverCompress = false;
        sslAlert       = -1;
        maxRecordLen   = 8192;
        if (addECExt)
        {
            List <int> rx = new List <int>();
            foreach (int x in SSLCurve.ALL.Keys)
            {
                rx.Add(x);
            }
            tb.SupportedCurves = rx.ToArray();
        }

        /*
         * Each try entails using a protocol version, a
         * maximum record length, and optional extensions.
         * We then try all chunks of cipher suites (in our
         * list of cipher suites to try) until we get a
         * successfull handshake.
         *
         * On error, we try reducing maximum record length.
         * If that still fails, we lower the maximum version.
         * If even SSL 3.0 fails with a small record, then
         * we try again the whole process without extensions.
         */
        for (;;)
        {
            maxRecordLen = 8192;
            if (TryConnect() || gotReadTimeout)
            {
                break;
            }
            maxRecordLen = 1024;
            if (TryConnect() || gotReadTimeout)
            {
                break;
            }
            maxRecordLen = 256;
            if (TryConnect() || gotReadTimeout)
            {
                break;
            }
            int v = tb.MaxVersion;
            if (v > M.SSLv30)
            {
                tb.MaxVersion = v - 1;
                continue;
            }
            if (withExts)
            {
                withExts = false;
                tb.DisableExtensions();
                tb.MaxVersion = maxVersion;
                continue;
            }

            /*
             * No success.
             */
            if (gotSSLAnswer && sslAlert >= 0)
            {
                throw new SSLAlertException(sslAlert);
            }
            else
            {
                string msg = "Could not initiate a handshake"
                             + " (not SSL/TLS?)";
                if (gotReadTimeout)
                {
                    msg += " [read timeout]";
                }
                throw new Exception(msg);
            }
        }
        if (maxRecordLen < 8192)
        {
            rp.NeedsShortHello = true;
        }
        if (!withExts)
        {
            rp.NoExtensions = true;
        }

        maxVersion = tb.MaxVersion;
        int startVersion = minVersion;

        if (startVersion < M.SSLv30)
        {
            startVersion = M.SSLv30;
        }

        /*
         * Now extract supported cipher suites for each protocol
         * version. We also try to get the highest version for
         * which EC-based cipher suites are supported, and
         * extract all supported EC-based cipher suites for
         * that version.
         *
         * For each such protocol version, we also try connecting
         * with a ClientHello in V2 format; we do so while ensuring
         * that the total hello length is no more than 127 bytes,
         * for maximum interoperability. Note that the V2 format
         * has no room for any extension.
         */
        int maxECVersion = -1;

        int[] suppEC = null;
        for (int v = startVersion; v <= maxVersion; v++)
        {
            tb.MaxVersion = v;
            SupportedCipherSuites scs = GetSupportedCipherSuites();
            if (scs == null)
            {
                continue;
            }
            rp.SetCipherSuites(v, scs);
            int[] ecs = scs.GetKnownECSuites();
            if (ecs.Length > 0)
            {
                maxECVersion = v;
                suppEC       = ecs;
            }
            if (scs.KXReuseDH)
            {
                rp.KXReuseDH = true;
            }
            if (scs.KXReuseECDH)
            {
                rp.KXReuseECDH = true;
            }

            /*
             * Check V2 format for ClientHello.
             */
            int savedRV = tb.RecordVersion;
            tb.RecordVersion = M.SSLv20;
            if (DoConnect() != null)
            {
                rp.SupportsV2Hello = true;
            }
            tb.RecordVersion = savedRV;
        }

        /*
         * At that point, if the server used an EC-based cipher
         * suite, and we did not present a Supported Elliptic
         * Curves extension, then the server selected the
         * curve(s) all by itself. If we always presented that
         * extension, then we want to try talking to the server
         * without it, to see if it accepts doing EC at all
         * without the extension, and, if yes, what curve it may
         * use in that case.
         */
        int[]      spontaneousEC;
        SSLCurve[] spontaneousNamedCurves;
        if (addECExt && withExts && maxECVersion >= 0)
        {
            if (verbose)
            {
                Console.WriteLine("[spontaneous EC support,"
                                  + " version={0}, {1} suite(s)]",
                                  M.VersionString(maxECVersion),
                                  suppEC.Length);
            }
            IDictionary <int, SSLCurve> oldNamedCurves = namedCurves;
            namedCurves            = new SortedDictionary <int, SSLCurve>();
            tb.MaxVersion          = maxECVersion;
            tb.SupportedCurves     = null;
            spontaneousEC          = GetSupportedCipherSuites(suppEC, null);
            spontaneousNamedCurves = M.ToValueArray(namedCurves);
            foreach (int s in namedCurves.Keys)
            {
                oldNamedCurves[s] = namedCurves[s];
            }
            namedCurves = oldNamedCurves;
            if (verbose)
            {
                Console.WriteLine();
            }
        }
        else
        {
            spontaneousEC          = suppEC;
            spontaneousNamedCurves = M.ToValueArray(namedCurves);
        }

        /*
         * We now try to enumerate all supported EC curves.
         */
        if (withExts && maxECVersion >= 0)
        {
            tb.MaxVersion   = maxECVersion;
            tb.CipherSuites = suppEC;

            if (verbose)
            {
                Console.WriteLine("[elliptic curve enumeration,"
                                  + " version={0}, {1} suite(s)]",
                                  M.VersionString(maxECVersion),
                                  suppEC.Length);
            }

            /*
             * Try named curves.
             */
            IDictionary <int, int> rec =
                new SortedDictionary <int, int>();
            foreach (int id in SSLCurve.ALL.Keys)
            {
                AddToSet(rec, id);
            }
            while (rec.Count > 0)
            {
                tb.SupportedCurves = SetToArray(rec);
                SSLTestResult tr = DoConnect();
                if (tr == null)
                {
                    break;
                }
                SSLCurve sc = tr.Curve;
                if (sc == null)
                {
                    break;
                }
                if (!rec.ContainsKey(sc.Id))
                {
                    break;
                }
                rec.Remove(sc.Id);
            }

            /*
             * Try explicit curves, prime and char2.
             */
            tb.SupportedCurves = new int[] {
                SSLCurve.EXPLICIT_PRIME
            };
            DoConnect();
            tb.SupportedCurves = new int[] {
                SSLCurve.EXPLICIT_CHAR2
            };
            DoConnect();

            if (verbose)
            {
                Console.WriteLine();
            }
        }

        rp.DeflateCompress             = serverCompress;
        rp.ServerTimeOffset            = GetServerTimeOffset();
        rp.SupportsSecureRenegotiation = doesRenego;
        rp.SupportsEncryptThenMAC      = doesEtM;
        rp.MinDHSize              = minDHSize;
        rp.MinECSize              = minECSize;
        rp.MinECSizeExt           = minECSizeExt;
        rp.NamedCurves            = M.ToValueArray(namedCurves);
        rp.SpontaneousEC          = spontaneousEC;
        rp.SpontaneousNamedCurves = spontaneousNamedCurves;
        rp.CurveExplicitPrime     = curveExplicitPrime;
        rp.CurveExplicitChar2     = curveExplicitChar2;
        rp.UnknownSKE             = unknownSKE;
        return(rp);
    }
Esempio n. 10
0
    /*
     * Get all supported cipher suites with the current configuration.
     * If there is none, then null is returned (which means that the
     * protocol version is not supported).
     */
    SupportedCipherSuites GetSupportedCipherSuites()
    {
        int num = tb.ComputeMaxCipherSuites(maxRecordLen);

        if (num < 1)
        {
            num = 1;
        }
        if (verbose)
        {
            Console.WriteLine("[suites: version={0}"
                              + " ({1} suites per hello)]",
                              M.VersionString(tb.MaxVersion), num);
        }

        /*
         * 1. Gather all cipher suites supported by the server.
         */
        IDictionary <int, int> suppd = new SortedDictionary <int, int>();

        for (int i = 0; i < csl.Count; i += num)
        {
            int   k  = Math.Min(num, csl.Count - i);
            int[] tt = new int[k];
            for (int j = 0; j < k; j++)
            {
                tt[j] = csl[i + j];
            }
            foreach (int s in GetSupportedCipherSuites(tt))
            {
                AddToSet(suppd, s);
            }
        }
        int[] supp = SetToArray(suppd);
        if (supp.Length == 0)
        {
            if (verbose)
            {
                Console.WriteLine();
            }
            return(null);
        }
        SupportedCipherSuites scs = new SupportedCipherSuites(supp);

        /*
         * 2. Work out server preferences. We can do that only
         * if we can send all supported suites in a single
         * ClientHello.
         *
         * Algorithm: we first try suites in numerical order. Then
         * we try suites in the reverse order of what the server
         * selected. If the second list is equal to the first one,
         * then the server enforces its own preferences. If the
         * second list is the reverse of the first one, then the
         * server follows client preferences. In all other cases,
         * the server selection algorithm is deemed "complex".
         */
        if (supp.Length <= num)
        {
            int[] supp1   = GetSupportedCipherSuites(supp);
            int[] suppRev = new int[supp1.Length];
            for (int i = 0; i < supp1.Length; i++)
            {
                suppRev[i] = supp[supp1.Length - 1 - i];
            }
            int[] supp2 = GetSupportedCipherSuites(suppRev);

            if (M.Equals(supp2, suppRev))
            {
                scs.PrefClient = true;
            }
            else if (M.Equals(supp1, supp2))
            {
                scs.PrefServer = true;
                scs.Suites     = supp1;
            }
        }
        if (verbose)
        {
            Console.WriteLine();
        }
        return(scs);
    }
Esempio n. 11
0
    public static void UpdateReportAggregator(ReportAggregator aggregator, Report report)
    {
        String serverUnderTest = $"{report.ConnName}:{report.ConnPort}";

        if (report.SSLv2Chain != null)
        {
            aggregator.AddSsl2Cert(serverUnderTest, report.SSLv2Chain);
            X509Cert xc = report.SSLv2Chain.ElementsRev[0];
            if (xc != null && xc.ValidTo.CompareTo(DateTime.Now) < 0)
            {
                aggregator.AddOverduedCertificate(serverUnderTest, xc.ValidTo);
            }
        }

        if (report.ssl2Suites != null && report.ssl2Suites.Length > 0)
        {
            aggregator.AddSuportedSslVersion(M.VersionString(M.SSLv20));
            foreach (int s in report.ssl2Suites)
            {
                aggregator.AddSupportedCipherSuite(CipherSuite.ToNameV2(s));
            }
        }

        aggregator.AddSsl3Certs(serverUnderTest, report.chains.Values);
        InspectCerts(aggregator, report, serverUnderTest);

        foreach (int v in report.suites.Keys)
        {
            aggregator.AddSuportedSslVersion(M.VersionString(v));
            SupportedCipherSuites scs = report.suites[v];
            if (scs.PrefClient)
            {
                aggregator.AddCipherSuiteSelectionMode("uses client preferences");
            }
            else if (scs.PrefServer)
            {
                aggregator.AddCipherSuiteSelectionMode("enforce server preferences");
            }
            else
            {
                aggregator.AddCipherSuiteSelectionMode("complex");
            }
            foreach (int s in scs.Suites)
            {
                CipherSuite cs;
                string      strength;
                string      fsf;
                string      anon;
                string      kt;
                if (CipherSuite.ALL.TryGetValue(s, out cs))
                {
                    strength = cs.Strength.ToString();
                    fsf      = cs.HasForwardSecrecy ? "f" : "-";
                    anon     = cs.IsAnonymous ? "A" : "-";
                    kt       = cs.ServerKeyType;
                }
                else
                {
                    strength = "?";
                    fsf      = "?";
                    anon     = "?";
                    kt       = "?";
                }
                aggregator.AddSupportedCipherSuite($"{strength}{fsf}{anon} (key: {kt,4})  {CipherSuite.ToName(s)}");
            }
        }

        foreach (var warning in report.Warnings)
        {
            aggregator.AddWarning(warning.Value);
        }
    }
Esempio n. 12
0
    /*
     * Print the report on the provided writer (text version for
     * humans).
     */
    internal void Print(TextWriter w)
    {
        w.WriteLine("Connection: {0}:{1}", connName, connPort);
        if (sni == null)
        {
            w.WriteLine("No SNI sent");
        }
        else
        {
            w.WriteLine("SNI: {0}", sni);
        }
        if (ssl2Suites != null && ssl2Suites.Length > 0)
        {
            w.WriteLine("  {0}", M.VersionString(M.SSLv20));
            foreach (int s in ssl2Suites)
            {
                w.WriteLine("     {0}",
                            CipherSuite.ToNameV2(s));
            }
        }
        SupportedCipherSuites last = null;

        foreach (int v in suites.Keys)
        {
            w.Write("  {0}:", M.VersionString(v));
            SupportedCipherSuites scs = suites[v];
            if (scs.Equals(last))
            {
                w.WriteLine(" idem");
                continue;
            }
            last = scs;
            w.WriteLine();
            w.Write("     server selection: ");
            if (scs.PrefClient)
            {
                w.WriteLine("uses client preferences");
            }
            else if (scs.PrefServer)
            {
                w.WriteLine("enforce server preferences");
            }
            else
            {
                w.WriteLine("complex");
            }
            foreach (int s in scs.Suites)
            {
                CipherSuite cs;
                string      strength;
                string      fsf;
                string      anon;
                string      kt;
                if (CipherSuite.ALL.TryGetValue(s, out cs))
                {
                    strength = cs.Strength.ToString();
                    fsf      = cs.HasForwardSecrecy ? "f" : "-";
                    anon     = cs.IsAnonymous ? "A" : "-";
                    kt       = cs.ServerKeyType;
                }
                else
                {
                    strength = "?";
                    fsf      = "?";
                    anon     = "?";
                    kt       = "?";
                }
                w.WriteLine("     {0}{1}{2} (key: {3,4})  {4}",
                            strength, fsf, anon, kt,
                            CipherSuite.ToName(s));
            }
        }
        w.WriteLine("=========================================");
        if (ssl2Chain != null)
        {
            w.WriteLine("+++++ SSLv2 certificate");
            PrintCert(w, ssl2Chain, 0, withPEM);
        }
        w.WriteLine("+++++ SSLv3/TLS: {0} certificate chain(s)",
                    chains.Count);
        foreach (X509Chain xchain in chains.Values)
        {
            PrintChain(w, xchain, withPEM);
        }
        w.WriteLine("=========================================");
        w.WriteLine("Server compression support: {0}",
                    DeflateCompress ? "yes" : "no");
        if (serverTimeOffset == Int64.MinValue)
        {
            w.WriteLine("Server does not send its system time.");
        }
        else if (serverTimeOffset == Int64.MaxValue)
        {
            w.WriteLine("Server sends a random system time.");
        }
        else
        {
            DateTime dt = DateTime.UtcNow;
            dt = dt.AddMilliseconds((double)serverTimeOffset);
            w.WriteLine("Server time: {0:yyyy-MM-dd HH:mm:ss} UTC"
                        + " (offset: {1} ms)", dt, serverTimeOffset);
        }
        w.WriteLine("Secure renegotiation support: {0}",
                    doesRenego ? "yes" : "no");
        if (minDHSize > 0)
        {
            w.WriteLine("Minimum DH size: {0}", minDHSize);
        }
        if (minECSize > 0)
        {
            w.WriteLine("Minimum EC size (no extension):   {0}",
                        minECSize);
        }
        if (minECSizeExt > 0)
        {
            w.WriteLine("Minimum EC size (with extension): {0}",
                        minECSizeExt);
        }
        if (namedCurves != null && namedCurves.Length > 0)
        {
            w.WriteLine("Supported curves (size and name)"
                        + " ('*' = selected by server):");
            foreach (SSLCurve nc in namedCurves)
            {
                w.WriteLine("  {0} {1,3}  {2}",
                            IsSpontaneous(nc) ? "*" : " ",
                            nc.Size, nc.Name);
            }
            if (curveExplicitPrime > 0)
            {
                w.WriteLine("  explicit prime, size = {0}",
                            curveExplicitPrime);
            }
            if (curveExplicitChar2 > 0)
            {
                w.WriteLine("  explicit char2, size = {0}",
                            curveExplicitChar2);
            }
        }

        w.WriteLine("=========================================");
        if (warnings == null)
        {
            Analyse();
        }
        if (warnings.Count == 0)
        {
            w.WriteLine("No warning.");
        }
        else
        {
            foreach (string k in warnings.Keys)
            {
                w.WriteLine("WARN[{0}]: {1}", k, warnings[k]);
            }
        }
    }