Advertisement
opexxx

TestSSLServer.cs

Nov 18th, 2014
285
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 48.29 KB | None | 0 0
  1. /*
  2.  * Command-line tool to test a SSL/TLS server for some vulnerabilities.
  3.  * =====================================================================
  4.  *
  5.  * This application connects to the provided SSL/TLS server (by name and
  6.  * port) and extracts the following information:
  7.  * - supported versions (SSL 2.0, SSL 3.0, TLS 1.0 to 1.2)
  8.  * - support of Deflate compression
  9.  * - list of supported cipher suites (for each protocol version)
  10.  * - BEAST/CRIME vulnerabilities.
  11.  *
  12.  * BEAST and CRIME are client-side attack, but the server can protect the
  13.  * client by refusing to use the feature combinations which can be
  14.  * attacked. For CRIME, the weakness is Deflate compression. For BEAST,
  15.  * the attack conditions are more complex: it works with CBC ciphers with
  16.  * SSL 3.0 and TLS 1.0. Hence, a server fails to protect the client against
  17.  * BEAST if it does not enforce usage of RC4 over CBC ciphers under these
  18.  * protocol versions, if given the choice.
  19.  *
  20.  * (The BEAST test considers only the cipher suites with strong
  21.  * encryption; if the server supports none, then there are bigger
  22.  * problems. We also assume that all clients support RC4-128; thus, the
  23.  * server protects the client if it selects RC4-128 even if some strong
  24.  * CBC-based ciphers are announced as supported by the client with a
  25.  * higher preference level.)
  26.  *
  27.  * ----------------------------------------------------------------------
  28.  * Copyright (c) 2012  Thomas Pornin <pornin@bolet.org>
  29.  *
  30.  * Permission is hereby granted, free of charge, to any person obtaining
  31.  * a copy of this software and associated documentation files (the
  32.  * "Software"), to deal in the Software without restriction, including
  33.  * without limitation the rights to use, copy, modify, merge, publish,
  34.  * distribute, sublicense, and/or sell copies of the Software, and to
  35.  * permit persons to whom the Software is furnished to do so, subject to
  36.  * the following conditions:
  37.  *
  38.  * The above copyright notice and this permission notice shall be
  39.  * included in all copies or substantial portions of the Software.
  40.  *
  41.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  42.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  43.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  44.  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  45.  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  46.  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  47.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  48.  * SOFTWARE.
  49.  * ----------------------------------------------------------------------
  50.  */
  51.  
  52. using System;
  53. using System.Collections.Generic;
  54. using System.IO;
  55. using System.Net.Sockets;
  56. using System.Security.Cryptography;
  57. using System.Security.Cryptography.X509Certificates;
  58. using System.Text;
  59.  
  60. namespace TestSSLServer {
  61.  
  62. class TestSSLServer {
  63.  
  64.     static void Usage()
  65.     {
  66.         Console.WriteLine("usage: TestSSLServer servername [ port ]");
  67.         Environment.Exit(1);
  68.     }
  69.  
  70.     static void Main(string[] args)
  71.     {
  72.         try {
  73.             Main0(args);
  74.         } catch (Exception e) {
  75.             Console.WriteLine(e.ToString());
  76.             Environment.Exit(1);
  77.         }
  78.     }
  79.  
  80.     static void Main0(string[] args)
  81.     {
  82.         InitCipherSuites();
  83.         if (args.Length == 0 || args.Length > 2) {
  84.             Usage();
  85.         }
  86.         string name = args[0];
  87.         int port = 443;
  88.         if (args.Length == 2) {
  89.             try {
  90.                 port = Int32.Parse(args[1]);
  91.             } catch (Exception) {
  92.                 Usage();
  93.             }
  94.             if (port <= 0 || port > 65535) {
  95.                 Usage();
  96.             }
  97.         }
  98.  
  99.         IDictionary<int, int> sv = new SortedDictionary<int, int>();
  100.         bool compress = false;
  101.         for (int v = 0x0300; v <= 0x0303; v ++) {
  102.             ServerHello sh = Connect(name, port,
  103.                 v, CIPHER_SUITES.Keys);
  104.             if (sh == null) {
  105.                 continue;
  106.             }
  107.             AddToSet(sv, sh.protoVersion);
  108.             if (sh.compression == 1) {
  109.                 compress = true;
  110.             }
  111.         }
  112.  
  113.         ServerHelloSSLv2 sh2 = ConnectV2(name, port);
  114.         if (sh2 != null) {
  115.             AddToSet(sv, 0x0200);
  116.         }
  117.  
  118.         if (sv.Count == 0) {
  119.             Console.WriteLine("No SSL/TLS server at " + name
  120.                 + ":" + port);
  121.             Environment.Exit(1);
  122.         }
  123.         Console.WriteLine("Supported versions:");
  124.         foreach (int v in sv.Keys) {
  125.             Console.Write(" ");
  126.             Console.Write(VersionString(v));
  127.         }
  128.         Console.WriteLine();
  129.         Console.WriteLine("Deflate compression: "
  130.             + (compress ? "YES" : "no"));
  131.  
  132.         Console.WriteLine("Supported cipher suites"
  133.             + " (ORDER IS NOT SIGNIFICANT):");
  134.         IDictionary<int, int> lastSuppCS = null;
  135.         IDictionary<int, IDictionary<int, int>> suppCS =
  136.             new SortedDictionary<int, IDictionary<int, int>>();
  137.         IDictionary<string, int> certID =
  138.             new SortedDictionary<string, int>();
  139.  
  140.         if (sh2 != null) {
  141.             Console.WriteLine("  " + VersionString(0x0200));
  142.             IDictionary<int, int> vc2 =
  143.                 new SortedDictionary<int, int>();
  144.             foreach (int c in sh2.cipherSuites) {
  145.                 AddToSet(vc2, c);
  146.             }
  147.             foreach (int c in vc2.Keys) {
  148.                 Console.WriteLine("     "
  149.                     + CipherSuiteString(c));
  150.             }
  151.             suppCS.Add(0x0200, vc2);
  152.             if (sh2.serverCertName != null) {
  153.                 AddToSet(certID, sh2.serverCertHash
  154.                     + ": " + sh2.serverCertName);
  155.             }
  156.         }
  157.  
  158.         foreach (int v in sv.Keys) {
  159.             if (v == 0x0200) {
  160.                 continue;
  161.             }
  162.             IDictionary<int, int> vsc =
  163.                 SupportedSuites(name, port, v, certID);
  164.             suppCS.Add(v, vsc);
  165.             if (!SameSetInt(lastSuppCS, vsc)) {
  166.                 Console.WriteLine("  " + VersionString(v));
  167.                 foreach (int c in vsc.Keys) {
  168.                     Console.WriteLine("     "
  169.                         + CipherSuiteString(c));
  170.                 }
  171.                 lastSuppCS = vsc;
  172.             } else {
  173.                 Console.WriteLine("  (" + VersionString(v)
  174.                     + ": idem)");
  175.             }
  176.         }
  177.         Console.WriteLine("----------------------");
  178.         if (certID.Count == 0) {
  179.             Console.WriteLine("No server certificate !");
  180.         } else {
  181.             Console.WriteLine("Server certificate(s):");
  182.             foreach (string cc in certID.Keys) {
  183.                 Console.WriteLine("  " + cc);
  184.             }
  185.         }
  186.         Console.WriteLine("----------------------");
  187.         int agMaxStrength = STRONG;
  188.         int agMinStrength = STRONG;
  189.         bool vulnBEAST = false;
  190.         foreach (int v in sv.Keys) {
  191.             IDictionary<int, int> vsc = suppCS[v];
  192.             agMaxStrength = Math.Min(
  193.                 MaxStrength(vsc), agMaxStrength);
  194.             agMinStrength = Math.Min(
  195.                 MinStrength(vsc), agMinStrength);
  196.             if (!vulnBEAST) {
  197.                 vulnBEAST = TestBEAST(name, port, v, vsc);
  198.             }
  199.         }
  200.         Console.WriteLine("Minimal encryption strength:     "
  201.             + StrengthString(agMinStrength));
  202.         Console.WriteLine("Achievable encryption strength:  "
  203.             + StrengthString(agMaxStrength));
  204.         Console.WriteLine("BEAST status: "
  205.             + (vulnBEAST ? "vulnerable" : "protected"));
  206.         Console.WriteLine("CRIME status: "
  207.             + (compress ? "vulnerable" : "protected"));
  208.     }
  209.  
  210.     static void AddToSet<T>(IDictionary<T, int> s, T val)
  211.     {
  212.         if (!s.ContainsKey(val)) {
  213.             s.Add(val, 0);
  214.         }
  215.     }
  216.  
  217.     static bool IsInSet<T>(IDictionary<T, int> s, T val)
  218.     {
  219.         return s.ContainsKey(val);
  220.     }
  221.  
  222.     static bool SameSetInt(
  223.         IDictionary<int, int> s1, IDictionary<int, int> s2)
  224.     {
  225.         if (s1 == s2) {
  226.             return true;
  227.         }
  228.         if (s1 == null || s2 == null) {
  229.             return false;
  230.         }
  231.         if (s1.Count != s2.Count) {
  232.             return false;
  233.         }
  234.         foreach (int k in s1.Keys) {
  235.             if (!s2.ContainsKey(k)) {
  236.                 return false;
  237.             }
  238.         }
  239.         return true;
  240.     }
  241.  
  242.     /*
  243.      * Get cipher suites supported by the server. This is done by
  244.      * repeatedly contacting the server, each time removing from our
  245.      * list of supported suites the suite which the server just
  246.      * selected. We keep on until the server can no longer respond
  247.      * to us with a ServerHello.
  248.      */
  249.     static IDictionary<int, int> SupportedSuites(
  250.         string name, int port, int version,
  251.         IDictionary<string, int> serverCertID)
  252.     {
  253.         IDictionary<int, int> cs = new SortedDictionary<int, int>();
  254.         foreach (int k in CIPHER_SUITES.Keys) {
  255.             AddToSet(cs, k);
  256.         }
  257.         IDictionary<int, int> rs = new SortedDictionary<int, int>();
  258.         for (;;) {
  259.             ServerHello sh = Connect(name, port, version, cs.Keys);
  260.             if (sh == null) {
  261.                 break;
  262.             }
  263.             if (!IsInSet(cs, sh.cipherSuite)) {
  264.                 Console.WriteLine("[ERR: server wants to use"
  265.                     + " cipher suite 0x{0:X4} which client"
  266.                     + " did not announce]", sh.cipherSuite);
  267.                 break;
  268.             }
  269.             cs.Remove(sh.cipherSuite);
  270.             AddToSet(rs, sh.cipherSuite);
  271.             if (sh.serverCertName != null) {
  272.                 AddToSet(serverCertID, sh.serverCertHash
  273.                     + ": " + sh.serverCertName);
  274.             }
  275.         }
  276.         return rs;
  277.     }
  278.  
  279.     static int MinStrength(IDictionary<int, int> supp)
  280.     {
  281.         int m = STRONG;
  282.         foreach (int suite in supp.Keys) {
  283.             CipherSuite cs = CIPHER_SUITES[suite];
  284.             if (cs == null) {
  285.                 continue;
  286.             }
  287.             if (cs.strength < m) {
  288.                 m = cs.strength;
  289.             }
  290.         }
  291.         return m;
  292.     }
  293.  
  294.     static int MaxStrength(IDictionary<int, int> supp)
  295.     {
  296.         int m = CLEAR;
  297.         foreach (int suite in supp.Keys) {
  298.             CipherSuite cs = CIPHER_SUITES[suite];
  299.             if (cs == null) {
  300.                 continue;
  301.             }
  302.             if (cs.strength > m) {
  303.                 m = cs.strength;
  304.             }
  305.         }
  306.         return m;
  307.     }
  308.  
  309.     static bool TestBEAST(string name, int port,
  310.         int version, IDictionary<int, int> supp)
  311.     {
  312.         /*
  313.          * TLS 1.1+ is not vulnerable to BEAST.
  314.          * We do not test SSLv2 either.
  315.          */
  316.         if (version < 0x0300 || version > 0x0301) {
  317.             return false;
  318.         }
  319.  
  320.         /*
  321.          * BEAST attack works if the server allows the client to
  322.          * use a CBC cipher. Existing clients also supports RC4,
  323.          * so we consider that a server protects the clients if
  324.          * it chooses RC4 over CBC streams when given the choice.
  325.          * We only consider strong cipher suites here.
  326.          */
  327.         IList<int> strongCBC = new List<int>();
  328.         IList<int> strongStream = new List<int>();
  329.         foreach (int suite in supp.Keys) {
  330.             CipherSuite cs = CIPHER_SUITES[suite];
  331.             if (cs == null) {
  332.                 continue;
  333.             }
  334.             if (cs.strength < STRONG) {
  335.                 continue;
  336.             }
  337.             if (cs.isCBC) {
  338.                 strongCBC.Add(suite);
  339.             } else {
  340.                 strongStream.Add(suite);
  341.             }
  342.         }
  343.         if (strongCBC.Count == 0) {
  344.             return false;
  345.         }
  346.         if (strongStream.Count == 0) {
  347.             return true;
  348.         }
  349.         IList<int> ns = new List<int>();
  350.         foreach (int suite in strongCBC) {
  351.             ns.Add(suite);
  352.         }
  353.         foreach (int suite in strongStream) {
  354.             ns.Add(suite);
  355.         }
  356.         ServerHello sh = Connect(name, port, version, ns);
  357.         return CIPHER_SUITES[sh.cipherSuite].isCBC;
  358.     }
  359.  
  360.     static string VersionString(int version)
  361.     {
  362.         if (version == 0x0200) {
  363.             return "SSLv2";
  364.         } else if (version == 0x0300) {
  365.             return "SSLv3";
  366.         } else if (((uint)version >> 8) == 0x03) {
  367.             return "TLSv1." + ((version & 0xFF) - 1);
  368.         } else {
  369.             return String.Format(
  370.                 "UNKNOWN_VERSION:0x{0:X4}", version);
  371.         }
  372.     }
  373.  
  374.     /*
  375.      * Connect to the server, send a ClientHello, and decode the
  376.      * response (ServerHello). On error, null is returned.
  377.      */
  378.     static ServerHello Connect(string name, int port,
  379.         int version, ICollection<int> cipherSuites)
  380.     {
  381.         NetworkStream ns = null;
  382.         try {
  383.             try {
  384.                 TcpClient tc = new TcpClient(name, port);
  385.                 ns = tc.GetStream();
  386.             } catch (Exception e) {
  387.                 Console.WriteLine("could not connect to "
  388.                     + name + ":" + port);
  389.                 Console.WriteLine(e.ToString());
  390.                 return null;
  391.             }
  392.             byte[] ch = MakeClientHello(version, cipherSuites);
  393.             SSLRecord rec = new SSLRecord(ns);
  394.             rec.SetOutType(M.HANDSHAKE);
  395.             rec.SetOutVersion(version);
  396.             rec.Write(ch);
  397.             rec.Flush();
  398.             return new ServerHello(rec);
  399.         } catch (Exception) {
  400.             // ignored
  401.         } finally {
  402.             try {
  403.                 if (ns != null) {
  404.                     ns.Close();
  405.                 }
  406.             } catch (Exception) {
  407.                 // ignored
  408.             }
  409.         }
  410.         return null;
  411.     }
  412.  
  413.     /*
  414.      * Connect to the server, send a SSLv2 CLIENT-HELLO, and decode
  415.      * the response (SERVER-HELLO). On error, null is returned.
  416.      */
  417.     static ServerHelloSSLv2 ConnectV2(string name, int port)
  418.     {
  419.         NetworkStream ns = null;
  420.         try {
  421.             try {
  422.                 TcpClient tc = new TcpClient(name, port);
  423.                 ns = tc.GetStream();
  424.             } catch (Exception e) {
  425.                 Console.WriteLine("could not connect to "
  426.                     + name + ":" + port);
  427.                 Console.WriteLine(e.ToString());
  428.                 return null;
  429.             }
  430.             ns.Write(M.SSL2_CLIENT_HELLO,
  431.                 0, M.SSL2_CLIENT_HELLO.Length);
  432.             return new ServerHelloSSLv2(ns);
  433.         } catch (Exception) {
  434.             // ignored
  435.         } finally {
  436.             try {
  437.                 if (ns != null) {
  438.                     ns.Close();
  439.                 }
  440.             } catch (Exception) {
  441.                 // ignored
  442.             }
  443.         }
  444.         return null;
  445.     }
  446.  
  447.     static readonly RandomNumberGenerator RNG =
  448.         new RNGCryptoServiceProvider();
  449.  
  450.     /*
  451.      * Build a ClientHello message, with the specified maximum
  452.      * supported version, and list of cipher suites.
  453.      */
  454.     static byte[] MakeClientHello(int version,
  455.         ICollection<int> cipherSuites)
  456.     {
  457.         MemoryStream b = new MemoryStream();
  458.  
  459.         /*
  460.          * Message header:
  461.          *   message type: one byte (1 = "ClientHello")
  462.          *   message length: three bytes (this will be adjusted
  463.          *   at the end of this method).
  464.          */
  465.         b.WriteByte(1);
  466.         b.WriteByte(0);
  467.         b.WriteByte(0);
  468.         b.WriteByte(0);
  469.  
  470.         /*
  471.          * The maximum version that we intend to support.
  472.          */
  473.         b.WriteByte((byte)(version >> 8));
  474.         b.WriteByte((byte)version);
  475.  
  476.         /*
  477.          * The client random has length 32 bytes, but begins with
  478.          * the client's notion of the current time, over 32 bits
  479.          * (seconds since 1970/01/01 00:00:00 UTC, not counting
  480.          * leap seconds).
  481.          */
  482.         byte[] rand = new byte[32];
  483.         RNG.GetBytes(rand);
  484.         M.Enc32be((int)(M.CurrentTimeMillis() / 1000), rand, 0);
  485.         b.Write(rand, 0, rand.Length);
  486.  
  487.         /*
  488.          * We send an empty session ID.
  489.          */
  490.         b.WriteByte(0);
  491.  
  492.         /*
  493.          * The list of cipher suites (list of 16-bit values; the
  494.          * list length in bytes is written first).
  495.          */
  496.         int num = cipherSuites.Count;
  497.         byte[] cs = new byte[2 + num * 2];
  498.         M.Enc16be(num * 2, cs, 0);
  499.         int j = 2;
  500.         foreach (int s in cipherSuites) {
  501.             M.Enc16be(s, cs, j);
  502.             j += 2;
  503.         }
  504.         b.Write(cs, 0, cs.Length);
  505.  
  506.         /*
  507.          * Compression methods: we claim to support Deflate (1)
  508.          * and the standard no-compression (0), with Deflate
  509.          * being preferred.
  510.          */
  511.         b.WriteByte(2);
  512.         b.WriteByte(1);
  513.         b.WriteByte(0);
  514.  
  515.         /*
  516.          * If we had extensions to add, they would go here.
  517.          */
  518.  
  519.         /*
  520.          * We now get the message as a blob. The message length
  521.          * must be adjusted in the header.
  522.          */
  523.         byte[] msg = b.ToArray();
  524.         M.Enc24be(msg.Length - 4, msg, 1);
  525.         return msg;
  526.     }
  527.  
  528.     static readonly IDictionary<int, CipherSuite> CIPHER_SUITES =
  529.         new SortedDictionary<int, CipherSuite>();
  530.  
  531.     const int CLEAR  = 0; // no encryption
  532.     const int WEAK   = 1; // weak encryption: 40-bit key
  533.     const int MEDIUM = 2; // medium encryption: 56-bit key
  534.     const int STRONG = 3; // strong encryption
  535.  
  536.     static string StrengthString(int strength)
  537.     {
  538.         switch (strength) {
  539.         case CLEAR:  return "no encryption";
  540.         case WEAK:   return "weak encryption (40-bit)";
  541.         case MEDIUM: return "medium encryption (56-bit)";
  542.         case STRONG: return "strong encryption (96-bit or more)";
  543.         default:
  544.             throw new Exception("strange strength: " + strength);
  545.         }
  546.     }
  547.  
  548.     static string CipherSuiteString(int suite)
  549.     {
  550.         CipherSuite cs = CIPHER_SUITES[suite];
  551.         if (cs == null) {
  552.             return String.Format("UNKNOWN_SUITE:0x{0:X4}", suite);
  553.         } else {
  554.             return cs.name;
  555.         }
  556.     }
  557.  
  558.     static string CipherSuiteStringV2(int suite)
  559.     {
  560.         CipherSuite cs = CIPHER_SUITES[suite];
  561.         if (cs == null) {
  562.             return String.Format(
  563.                 "UNKNOWN_SUITE:{0:X2},{0:X2},{0:X2}",
  564.                 suite >> 16, (suite >> 8) & 0xFF, suite & 0xFF);
  565.         } else {
  566.             return cs.name;
  567.         }
  568.     }
  569.  
  570.     static void MakeCS(int suite, String name,
  571.         bool isCBC, int strength)
  572.     {
  573.         CipherSuite cs = new CipherSuite();
  574.         cs.suite = suite;
  575.         cs.name = name;
  576.         cs.isCBC = isCBC;
  577.         cs.strength = strength;
  578.         CIPHER_SUITES.Add(suite, cs);
  579.  
  580.         /*
  581.          * Consistency test: the strength and CBC status can normally
  582.          * be inferred from the name itself.
  583.          */
  584.         bool inferredCBC = name.Contains("_CBC_");
  585.         int inferredStrength;
  586.         if (name.Contains("_NULL_")) {
  587.             inferredStrength = CLEAR;
  588.         } else if (name.Contains("DES40") || name.Contains("_40_")
  589.             || name.Contains("EXPORT40"))
  590.         {
  591.             inferredStrength = WEAK;
  592.         } else if ((name.Contains("_DES_") || name.Contains("DES_64"))
  593.             && !name.Contains("DES_192"))
  594.         {
  595.             inferredStrength = MEDIUM;
  596.         } else {
  597.             inferredStrength = STRONG;
  598.         }
  599.         if (inferredStrength != strength || inferredCBC != isCBC) {
  600.             throw new Exception("wrong classification: " + name);
  601.         }
  602.     }
  603.  
  604.     static void N(int suite, string name)
  605.     {
  606.         MakeCS(suite, name, false, CLEAR);
  607.     }
  608.  
  609.     static void S4(int suite, string name)
  610.     {
  611.         MakeCS(suite, name, false, WEAK);
  612.     }
  613.  
  614.     static void S8(int suite, string name)
  615.     {
  616.         MakeCS(suite, name, false, STRONG);
  617.     }
  618.  
  619.     static void B4(int suite, string name)
  620.     {
  621.         MakeCS(suite, name, true, WEAK);
  622.     }
  623.  
  624.     static void B5(int suite, string name)
  625.     {
  626.         MakeCS(suite, name, true, MEDIUM);
  627.     }
  628.  
  629.     static void B8(int suite, string name)
  630.     {
  631.         MakeCS(suite, name, true, STRONG);
  632.     }
  633.  
  634.     static void InitCipherSuites()
  635.     {
  636.         /*
  637.          * SSLv2 cipher suites.
  638.          */
  639.         S8(0x010080, "RC4_128_WITH_MD5"               );
  640.         S4(0x020080, "RC4_128_EXPORT40_WITH_MD5"      );
  641.         B8(0x030080, "RC2_128_CBC_WITH_MD5"           );
  642.         B4(0x040080, "RC2_128_CBC_EXPORT40_WITH_MD5"  );
  643.         B8(0x050080, "IDEA_128_CBC_WITH_MD5"          );
  644.         B5(0x060040, "DES_64_CBC_WITH_MD5"            );
  645.         B8(0x0700C0, "DES_192_EDE3_CBC_WITH_MD5"      );
  646.  
  647.         /*
  648.          * Original suites (SSLv3, TLS 1.0).
  649.          */
  650.         N(0x0000, "NULL_WITH_NULL_NULL"                );
  651.         N(0x0001, "RSA_WITH_NULL_MD5"                  );
  652.         N(0x0002, "RSA_WITH_NULL_SHA"                  );
  653.         S4(0x0003, "RSA_EXPORT_WITH_RC4_40_MD5"        );
  654.         S8(0x0004, "RSA_WITH_RC4_128_MD5"              );
  655.         S8(0x0005, "RSA_WITH_RC4_128_SHA"              );
  656.         B4(0x0006, "RSA_EXPORT_WITH_RC2_CBC_40_MD5"    );
  657.         B8(0x0007, "RSA_WITH_IDEA_CBC_SHA"             );
  658.         B4(0x0008, "RSA_EXPORT_WITH_DES40_CBC_SHA"     );
  659.         B5(0x0009, "RSA_WITH_DES_CBC_SHA"              );
  660.         B8(0x000A, "RSA_WITH_3DES_EDE_CBC_SHA"         );
  661.         B4(0x000B, "DH_DSS_EXPORT_WITH_DES40_CBC_SHA"  );
  662.         B5(0x000C, "DH_DSS_WITH_DES_CBC_SHA"           );
  663.         B8(0x000D, "DH_DSS_WITH_3DES_EDE_CBC_SHA"      );
  664.         B4(0x000E, "DH_RSA_EXPORT_WITH_DES40_CBC_SHA"  );
  665.         B5(0x000F, "DH_RSA_WITH_DES_CBC_SHA"           );
  666.         B8(0x0010, "DH_RSA_WITH_3DES_EDE_CBC_SHA"      );
  667.         B4(0x0011, "DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" );
  668.         B5(0x0012, "DHE_DSS_WITH_DES_CBC_SHA"          );
  669.         B8(0x0013, "DHE_DSS_WITH_3DES_EDE_CBC_SHA"     );
  670.         B4(0x0014, "DHE_RSA_EXPORT_WITH_DES40_CBC_SHA" );
  671.         B5(0x0015, "DHE_RSA_WITH_DES_CBC_SHA"          );
  672.         B8(0x0016, "DHE_RSA_WITH_3DES_EDE_CBC_SHA"     );
  673.         S4(0x0017, "DH_anon_EXPORT_WITH_RC4_40_MD5"    );
  674.         S8(0x0018, "DH_anon_WITH_RC4_128_MD5"          );
  675.         B4(0x0019, "DH_anon_EXPORT_WITH_DES40_CBC_SHA" );
  676.         B5(0x001A, "DH_anon_WITH_DES_CBC_SHA"          );
  677.         B8(0x001B, "DH_anon_WITH_3DES_EDE_CBC_SHA"     );
  678.  
  679.         /*
  680.          * FORTEZZA suites (SSLv3 only; see RFC 6101).
  681.          */
  682.         N(0x001C, "FORTEZZA_KEA_WITH_NULL_SHA"          );
  683.         B8(0x001D, "FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA" );
  684.  
  685.         /* This one is deactivated since it conflicts with
  686.            one of the Kerberos cipher suites.
  687.         S8(0x001E, "FORTEZZA_KEA_WITH_RC4_128_SHA"      );
  688.         */
  689.  
  690.         /*
  691.          * Kerberos cipher suites (RFC 2712).
  692.          */
  693.         B5(0x001E, "KRB5_WITH_DES_CBC_SHA"             );
  694.         B8(0x001F, "KRB5_WITH_3DES_EDE_CBC_SHA"        );
  695.         S8(0x0020, "KRB5_WITH_RC4_128_SHA"             );
  696.         B8(0x0021, "KRB5_WITH_IDEA_CBC_SHA"            );
  697.         B5(0x0022, "KRB5_WITH_DES_CBC_MD5"             );
  698.         B8(0x0023, "KRB5_WITH_3DES_EDE_CBC_MD5"        );
  699.         S8(0x0024, "KRB5_WITH_RC4_128_MD5"             );
  700.         B8(0x0025, "KRB5_WITH_IDEA_CBC_MD5"            );
  701.         B4(0x0026, "KRB5_EXPORT_WITH_DES_CBC_40_SHA"   );
  702.         B4(0x0027, "KRB5_EXPORT_WITH_RC2_CBC_40_SHA"   );
  703.         S4(0x0028, "KRB5_EXPORT_WITH_RC4_40_SHA"       );
  704.         B4(0x0029, "KRB5_EXPORT_WITH_DES_CBC_40_MD5"   );
  705.         B4(0x002A, "KRB5_EXPORT_WITH_RC2_CBC_40_MD5"   );
  706.         S4(0x002B, "KRB5_EXPORT_WITH_RC4_40_MD5"       );
  707.  
  708.         /*
  709.          * Pre-shared key, no encryption cipher suites (RFC 4785).
  710.          */
  711.         N(0x002C, "PSK_WITH_NULL_SHA"                  );
  712.         N(0x002D, "DHE_PSK_WITH_NULL_SHA"              );
  713.         N(0x002E, "RSA_PSK_WITH_NULL_SHA"              );
  714.  
  715.         /*
  716.          * AES-based suites (TLS 1.1).
  717.          */
  718.         B8(0x002F, "RSA_WITH_AES_128_CBC_SHA"          );
  719.         B8(0x0030, "DH_DSS_WITH_AES_128_CBC_SHA"       );
  720.         B8(0x0031, "DH_RSA_WITH_AES_128_CBC_SHA"       );
  721.         B8(0x0032, "DHE_DSS_WITH_AES_128_CBC_SHA"      );
  722.         B8(0x0033, "DHE_RSA_WITH_AES_128_CBC_SHA"      );
  723.         B8(0x0034, "DH_anon_WITH_AES_128_CBC_SHA"      );
  724.         B8(0x0035, "RSA_WITH_AES_256_CBC_SHA"          );
  725.         B8(0x0036, "DH_DSS_WITH_AES_256_CBC_SHA"       );
  726.         B8(0x0037, "DH_RSA_WITH_AES_256_CBC_SHA"       );
  727.         B8(0x0038, "DHE_DSS_WITH_AES_256_CBC_SHA"      );
  728.         B8(0x0039, "DHE_RSA_WITH_AES_256_CBC_SHA"      );
  729.         B8(0x003A, "DH_anon_WITH_AES_256_CBC_SHA"      );
  730.  
  731.         /*
  732.          * Suites with SHA-256 (TLS 1.2).
  733.          */
  734.         N(0x003B, "RSA_WITH_NULL_SHA256"               );
  735.         B8(0x003C, "RSA_WITH_AES_128_CBC_SHA256"       );
  736.         B8(0x003D, "RSA_WITH_AES_256_CBC_SHA256"       );
  737.         B8(0x003E, "DH_DSS_WITH_AES_128_CBC_SHA256"    );
  738.         B8(0x003F, "DH_RSA_WITH_AES_128_CBC_SHA256"    );
  739.         B8(0x0040, "DHE_DSS_WITH_AES_128_CBC_SHA256"   );
  740.         B8(0x0067, "DHE_RSA_WITH_AES_128_CBC_SHA256"   );
  741.         B8(0x0068, "DH_DSS_WITH_AES_256_CBC_SHA256"    );
  742.         B8(0x0069, "DH_RSA_WITH_AES_256_CBC_SHA256"    );
  743.         B8(0x006A, "DHE_DSS_WITH_AES_256_CBC_SHA256"   );
  744.         B8(0x006B, "DHE_RSA_WITH_AES_256_CBC_SHA256"   );
  745.         B8(0x006C, "DH_anon_WITH_AES_128_CBC_SHA256"   );
  746.         B8(0x006D, "DH_anon_WITH_AES_256_CBC_SHA256"   );
  747.  
  748.         /*
  749.          * Camellia cipher suites (RFC 5932).
  750.          */
  751.         B8(0x0041, "RSA_WITH_CAMELLIA_128_CBC_SHA"     );
  752.         B8(0x0042, "DH_DSS_WITH_CAMELLIA_128_CBC_SHA"  );
  753.         B8(0x0043, "DH_RSA_WITH_CAMELLIA_128_CBC_SHA"  );
  754.         B8(0x0044, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA" );
  755.         B8(0x0045, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA" );
  756.         B8(0x0046, "DH_anon_WITH_CAMELLIA_128_CBC_SHA" );
  757.         B8(0x0084, "RSA_WITH_CAMELLIA_256_CBC_SHA"     );
  758.         B8(0x0085, "DH_DSS_WITH_CAMELLIA_256_CBC_SHA"  );
  759.         B8(0x0086, "DH_RSA_WITH_CAMELLIA_256_CBC_SHA"  );
  760.         B8(0x0087, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA" );
  761.         B8(0x0088, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA" );
  762.         B8(0x0089, "DH_anon_WITH_CAMELLIA_256_CBC_SHA" );
  763.  
  764.         /*
  765.          * Unsorted (yet), from the IANA TLS registry:
  766.          * http://www.iana.org/assignments/tls-parameters/
  767.          */
  768.         S8(0x008A, "TLS_PSK_WITH_RC4_128_SHA"                        );
  769.         B8(0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"                   );
  770.         B8(0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA"                    );
  771.         B8(0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA"                    );
  772.         S8(0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA"                    );
  773.         B8(0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"               );
  774.         B8(0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"                );
  775.         B8(0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"                );
  776.         S8(0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"                    );
  777.         B8(0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"               );
  778.         B8(0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"                );
  779.         B8(0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"                );
  780.         B8(0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"                       );
  781.         B8(0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"                    );
  782.         B8(0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"                    );
  783.         B8(0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"                   );
  784.         B8(0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"                   );
  785.         B8(0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA"                   );
  786.         S8(0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256"                 );
  787.         S8(0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384"                 );
  788.         S8(0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"             );
  789.         S8(0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"             );
  790.         S8(0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"              );
  791.         S8(0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"              );
  792.         S8(0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"             );
  793.         S8(0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"             );
  794.         S8(0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"              );
  795.         S8(0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"              );
  796.         S8(0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"             );
  797.         S8(0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"             );
  798.         S8(0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256"                 );
  799.         S8(0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384"                 );
  800.         S8(0x00AA, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"             );
  801.         S8(0x00AB, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"             );
  802.         S8(0x00AC, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"             );
  803.         S8(0x00AD, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"             );
  804.         B8(0x00AE, "TLS_PSK_WITH_AES_128_CBC_SHA256"                 );
  805.         B8(0x00AF, "TLS_PSK_WITH_AES_256_CBC_SHA384"                 );
  806.         N(0x00B0, "TLS_PSK_WITH_NULL_SHA256"                         );
  807.         N(0x00B1, "TLS_PSK_WITH_NULL_SHA384"                         );
  808.         B8(0x00B2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"             );
  809.         B8(0x00B3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"             );
  810.         N(0x00B4, "TLS_DHE_PSK_WITH_NULL_SHA256"                     );
  811.         N(0x00B5, "TLS_DHE_PSK_WITH_NULL_SHA384"                     );
  812.         B8(0x00B6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"             );
  813.         B8(0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"             );
  814.         N(0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256"                     );
  815.         N(0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384"                     );
  816.         B8(0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"            );
  817.         B8(0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"         );
  818.         B8(0x00BC, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"         );
  819.         B8(0x00BD, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"        );
  820.         B8(0x00BE, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"        );
  821.         B8(0x00BF, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"        );
  822.         B8(0x00C0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"            );
  823.         B8(0x00C1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"         );
  824.         B8(0x00C2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"         );
  825.         B8(0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"        );
  826.         B8(0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"        );
  827.         B8(0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"        );
  828.         /* This one is a fake cipher suite which marks a
  829.            renegotiation.
  830.         N(0x00FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"                );
  831.         */
  832.         N(0xC001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"                     );
  833.         S8(0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"                 );
  834.         B8(0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"            );
  835.         B8(0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"             );
  836.         B8(0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"             );
  837.         N(0xC006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"                    );
  838.         S8(0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"                );
  839.         B8(0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"           );
  840.         B8(0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"            );
  841.         B8(0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"            );
  842.         N(0xC00B, "TLS_ECDH_RSA_WITH_NULL_SHA"                       );
  843.         S8(0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA"                   );
  844.         B8(0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"              );
  845.         B8(0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"               );
  846.         B8(0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"               );
  847.         N(0xC010, "TLS_ECDHE_RSA_WITH_NULL_SHA"                      );
  848.         S8(0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"                  );
  849.         B8(0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"             );
  850.         B8(0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"              );
  851.         B8(0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"              );
  852.         N(0xC015, "TLS_ECDH_anon_WITH_NULL_SHA"                     );
  853.         S8(0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA"                  );
  854.         B8(0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"             );
  855.         B8(0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"              );
  856.         B8(0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"              );
  857.         B8(0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"               );
  858.         B8(0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"           );
  859.         B8(0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"           );
  860.         B8(0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"                );
  861.         B8(0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"            );
  862.         B8(0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"            );
  863.         B8(0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"                );
  864.         B8(0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"            );
  865.         B8(0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"            );
  866.         B8(0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"         );
  867.         B8(0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"         );
  868.         B8(0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"          );
  869.         B8(0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"          );
  870.         B8(0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"           );
  871.         B8(0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"           );
  872.         B8(0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"            );
  873.         B8(0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"            );
  874.         S8(0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"         );
  875.         S8(0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"         );
  876.         S8(0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"          );
  877.         S8(0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"          );
  878.         S8(0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"           );
  879.         S8(0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"           );
  880.         S8(0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"            );
  881.         S8(0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"            );
  882.         S8(0xC033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"                  );
  883.         B8(0xC034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"             );
  884.         B8(0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"              );
  885.         B8(0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"              );
  886.         B8(0xC037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"           );
  887.         B8(0xC038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"           );
  888.         N(0xC039, "TLS_ECDHE_PSK_WITH_NULL_SHA"                      );
  889.         N(0xC03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256"                   );
  890.         N(0xC03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384"                   );
  891.         B8(0xC03C, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"                );
  892.         B8(0xC03D, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"                );
  893.         B8(0xC03E, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"             );
  894.         B8(0xC03F, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"             );
  895.         B8(0xC040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"             );
  896.         B8(0xC041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"             );
  897.         B8(0xC042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"            );
  898.         B8(0xC043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"            );
  899.         B8(0xC044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"            );
  900.         B8(0xC045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"            );
  901.         B8(0xC046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"            );
  902.         B8(0xC047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"            );
  903.         B8(0xC048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"        );
  904.         B8(0xC049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"        );
  905.         B8(0xC04A, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"         );
  906.         B8(0xC04B, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"         );
  907.         B8(0xC04C, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"          );
  908.         B8(0xC04D, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"          );
  909.         B8(0xC04E, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"           );
  910.         B8(0xC04F, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"           );
  911.         S8(0xC050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"                );
  912.         S8(0xC051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"                );
  913.         S8(0xC052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"            );
  914.         S8(0xC053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"            );
  915.         S8(0xC054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"             );
  916.         S8(0xC055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"             );
  917.         S8(0xC056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"            );
  918.         S8(0xC057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"            );
  919.         S8(0xC058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"             );
  920.         S8(0xC059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"             );
  921.         S8(0xC05A, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"            );
  922.         S8(0xC05B, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"            );
  923.         S8(0xC05C, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"        );
  924.         S8(0xC05D, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"        );
  925.         S8(0xC05E, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"         );
  926.         S8(0xC05F, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"         );
  927.         S8(0xC060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"          );
  928.         S8(0xC061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"          );
  929.         S8(0xC062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"           );
  930.         S8(0xC063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"           );
  931.         B8(0xC064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"                );
  932.         B8(0xC065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"                );
  933.         B8(0xC066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"            );
  934.         B8(0xC067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"            );
  935.         B8(0xC068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"            );
  936.         B8(0xC069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"            );
  937.         S8(0xC06A, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"                );
  938.         S8(0xC06B, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"                );
  939.         S8(0xC06C, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"            );
  940.         S8(0xC06D, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"            );
  941.         S8(0xC06E, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"            );
  942.         S8(0xC06F, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"            );
  943.         B8(0xC070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"          );
  944.         B8(0xC071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"          );
  945.         B8(0xC072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"    );
  946.         B8(0xC073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"    );
  947.         B8(0xC074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"     );
  948.         B8(0xC075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"     );
  949.         B8(0xC076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"      );
  950.         B8(0xC077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"      );
  951.         B8(0xC078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"       );
  952.         B8(0xC079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"       );
  953.         S8(0xC07A, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"            );
  954.         S8(0xC07B, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"            );
  955.         S8(0xC07C, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"        );
  956.         S8(0xC07D, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"        );
  957.         S8(0xC07E, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"         );
  958.         S8(0xC07F, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"         );
  959.         S8(0xC080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"        );
  960.         S8(0xC081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"        );
  961.         S8(0xC082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"         );
  962.         S8(0xC083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"         );
  963.         S8(0xC084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"        );
  964.         S8(0xC085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"        );
  965.         S8(0xC086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"    );
  966.         S8(0xC087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"    );
  967.         S8(0xC088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"     );
  968.         S8(0xC089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"     );
  969.         S8(0xC08A, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"      );
  970.         S8(0xC08B, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"      );
  971.         S8(0xC08C, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"       );
  972.         S8(0xC08D, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"       );
  973.         S8(0xC08E, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"            );
  974.         S8(0xC08F, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"            );
  975.         S8(0xC090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"        );
  976.         S8(0xC091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"        );
  977.         S8(0xC092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"        );
  978.         S8(0xC093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"        );
  979.         B8(0xC094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"            );
  980.         B8(0xC095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"            );
  981.         B8(0xC096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"        );
  982.         B8(0xC097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"        );
  983.         B8(0xC098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"        );
  984.         B8(0xC099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"        );
  985.         B8(0xC09A, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"      );
  986.         B8(0xC09B, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"      );
  987.         S8(0xC09C, "TLS_RSA_WITH_AES_128_CCM"                        );
  988.         S8(0xC09D, "TLS_RSA_WITH_AES_256_CCM"                        );
  989.         S8(0xC09E, "TLS_DHE_RSA_WITH_AES_128_CCM"                    );
  990.         S8(0xC09F, "TLS_DHE_RSA_WITH_AES_256_CCM"                    );
  991.         S8(0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8"                      );
  992.         S8(0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8"                      );
  993.         S8(0xC0A2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"                  );
  994.         S8(0xC0A3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"                  );
  995.         S8(0xC0A4, "TLS_PSK_WITH_AES_128_CCM"                        );
  996.         S8(0xC0A5, "TLS_PSK_WITH_AES_256_CCM"                        );
  997.         S8(0xC0A6, "TLS_DHE_PSK_WITH_AES_128_CCM"                    );
  998.         S8(0xC0A7, "TLS_DHE_PSK_WITH_AES_256_CCM"                    );
  999.         S8(0xC0A8, "TLS_PSK_WITH_AES_128_CCM_8"                      );
  1000.         S8(0xC0A9, "TLS_PSK_WITH_AES_256_CCM_8"                      );
  1001.         S8(0xC0AA, "TLS_PSK_DHE_WITH_AES_128_CCM_8"                  );
  1002.         S8(0xC0AB, "TLS_PSK_DHE_WITH_AES_256_CCM_8"                  );
  1003.     }
  1004. }
  1005.  
  1006. class CipherSuite {
  1007.  
  1008.     internal int suite;
  1009.     internal string name;
  1010.     internal bool isCBC;
  1011.     internal int strength;
  1012. }
  1013.  
  1014. class M {
  1015.  
  1016.     internal const int CHANGE_CIPHER_SPEC = 20;
  1017.     internal const int ALERT              = 21;
  1018.     internal const int HANDSHAKE          = 22;
  1019.     internal const int APPLICATION        = 23;
  1020.  
  1021.     internal static void Enc16be(int val, byte[] buf, int off)
  1022.     {
  1023.         buf[off] = (byte)(val >> 8);
  1024.         buf[off + 1] = (byte)val;
  1025.     }
  1026.  
  1027.     internal static void Enc24be(int val, byte[] buf, int off)
  1028.     {
  1029.         buf[off] = (byte)(val >> 16);
  1030.         buf[off + 1] = (byte)(val >> 8);
  1031.         buf[off + 2] = (byte)val;
  1032.     }
  1033.  
  1034.     internal static void Enc32be(int val, byte[] buf, int off)
  1035.     {
  1036.         buf[off] = (byte)(val >> 24);
  1037.         buf[off + 1] = (byte)(val >> 16);
  1038.         buf[off + 2] = (byte)(val >> 8);
  1039.         buf[off + 3] = (byte)val;
  1040.     }
  1041.  
  1042.     internal static int Dec16be(byte[] buf, int off)
  1043.     {
  1044.         return ((int)buf[off] << 8)
  1045.             | (int)buf[off + 1];
  1046.     }
  1047.  
  1048.     internal static int Dec24be(byte[] buf, int off)
  1049.     {
  1050.         return ((int)buf[off] << 16)
  1051.             | ((int)buf[off + 1] << 8)
  1052.             | (int)buf[off + 2];
  1053.     }
  1054.  
  1055.     internal static uint Dec32be(byte[] buf, int off)
  1056.     {
  1057.         return ((uint)buf[off] << 24)
  1058.             | ((uint)buf[off + 1] << 16)
  1059.             | ((uint)buf[off + 2] << 8)
  1060.             | (uint)buf[off + 3];
  1061.     }
  1062.  
  1063.     internal static void ReadFully(Stream s, byte[] buf)
  1064.     {
  1065.         ReadFully(s, buf, 0, buf.Length);
  1066.     }
  1067.  
  1068.     internal static void ReadFully(Stream s, byte[] buf, int off, int len)
  1069.     {
  1070.         while (len > 0) {
  1071.             int rlen = s.Read(buf, off, len);
  1072.             if (rlen <= 0) {
  1073.                 throw new EndOfStreamException();
  1074.             }
  1075.             off += rlen;
  1076.             len -= rlen;
  1077.         }
  1078.     }
  1079.  
  1080.     static readonly DateTime Jan1st1970 =
  1081.         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  1082.  
  1083.     internal static long CurrentTimeMillis()
  1084.     {
  1085.         return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
  1086.     }
  1087.  
  1088.     /*
  1089.      * Compute the SHA-1 hash of some bytes, returning the hash
  1090.      * value in hexadecimal.
  1091.      */
  1092.     internal static string DoSHA1(byte[] buf)
  1093.     {
  1094.         return DoSHA1(buf, 0, buf.Length);
  1095.     }
  1096.  
  1097.     internal static string DoSHA1(byte[] buf, int off, int len)
  1098.     {
  1099.         byte[] hv = new SHA1Managed().ComputeHash(buf, off, len);
  1100.         StringBuilder sb = new StringBuilder();
  1101.         foreach (byte b in hv) {
  1102.             sb.AppendFormat("{0:x2}", b);
  1103.         }
  1104.         return sb.ToString();
  1105.     }
  1106.  
  1107.     /*
  1108.      * A constant SSLv2 CLIENT-HELLO message. Only one connection
  1109.      * is needed for SSLv2, since the server response will contain
  1110.      * _all_ the cipher suites that the server is willing to
  1111.      * support.
  1112.      *
  1113.      * Note: when (mis)interpreted as a SSLv3+ record, this message
  1114.      * apparently encodes some data of (invalid) 0x80 type, using
  1115.      * protocol version TLS 44.1, and record length of 2 bytes.
  1116.      * Thus, the receiving part will quickly conclude that it will
  1117.      * not support that, instead of stalling for more data from the
  1118.      * client.
  1119.      */
  1120.     internal static byte[] SSL2_CLIENT_HELLO = {
  1121.         0x80, 0x2E,              // header (record length)
  1122.         0x01,                    // message type (CLIENT HELLO)
  1123.         0x00, 0x02,              // version (0x0002)
  1124.         0x00, 0x15,              // cipher specs list length
  1125.         0x00, 0x00,              // session ID length
  1126.         0x00, 0x10,              // challenge length
  1127.         0x01, 0x00, 0x80,        // SSL_CK_RC4_128_WITH_MD5
  1128.         0x02, 0x00, 0x80,        // SSL_CK_RC4_128_EXPORT40_WITH_MD5
  1129.         0x03, 0x00, 0x80,        // SSL_CK_RC2_128_CBC_WITH_MD5
  1130.         0x04, 0x00, 0x80,        // SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5
  1131.         0x05, 0x00, 0x80,        // SSL_CK_IDEA_128_CBC_WITH_MD5
  1132.         0x06, 0x00, 0x40,        // SSL_CK_DES_64_CBC_WITH_MD5
  1133.         0x07, 0x00, 0xC0,        // SSL_CK_DES_192_EDE3_CBC_WITH_MD5
  1134.         0x54, 0x54, 0x54, 0x54,  // challenge data (16 bytes)
  1135.         0x54, 0x54, 0x54, 0x54,
  1136.         0x54, 0x54, 0x54, 0x54,
  1137.         0x54, 0x54, 0x54, 0x54
  1138.     };
  1139. }
  1140.  
  1141. // CanRead, CanSeek, CanWrite, Flush, Length, Position, Seek, SetLength
  1142.  
  1143. class SSLRecord : Stream {
  1144.  
  1145.     const int MAX_RECORD_LEN = 16384;
  1146.  
  1147.     Stream sub;
  1148.     byte[] outBuf = new byte[MAX_RECORD_LEN + 5];
  1149.     int outPtr;
  1150.     int outVersion;
  1151.     int outType;
  1152.     byte[] inBuf = new byte[MAX_RECORD_LEN + 5];
  1153.     int inPtr;
  1154.     int inEnd;
  1155.     int inVersion;
  1156.     int inType;
  1157.     int inExpectedType;
  1158.  
  1159.     internal SSLRecord(Stream sub)
  1160.     {
  1161.         this.sub = sub;
  1162.         outPtr = 5;
  1163.         inPtr = 0;
  1164.         inEnd = 0;
  1165.     }
  1166.  
  1167.     public override bool CanRead { get { return true; } }
  1168.     public override bool CanSeek { get { return false; } }
  1169.     public override bool CanWrite { get { return true; } }
  1170.     public override long Length {
  1171.         get { throw new NotSupportedException(); }
  1172.     }
  1173.     public override long Position {
  1174.         get { throw new NotSupportedException(); }
  1175.         set { throw new NotSupportedException(); }
  1176.     }
  1177.  
  1178.     public override long Seek(long offset, SeekOrigin origin)
  1179.     {
  1180.         throw new NotSupportedException();
  1181.     }
  1182.  
  1183.     public override void SetLength(long value)
  1184.     {
  1185.         throw new NotSupportedException();
  1186.     }
  1187.  
  1188.     internal void SetOutType(int type)
  1189.     {
  1190.         this.outType = type;
  1191.     }
  1192.  
  1193.     internal void SetOutVersion(int version)
  1194.     {
  1195.         this.outVersion = version;
  1196.     }
  1197.  
  1198.     public override void Flush()
  1199.     {
  1200.         outBuf[0] = (byte)outType;
  1201.         M.Enc16be(outVersion, outBuf, 1);
  1202.         M.Enc16be(outPtr - 5, outBuf, 3);
  1203.         sub.Write(outBuf, 0, outPtr);
  1204.         sub.Flush();
  1205.         outPtr = 5;
  1206.     }
  1207.  
  1208.     public override void WriteByte(byte b)
  1209.     {
  1210.         outBuf[outPtr ++] = b;
  1211.         if (outPtr == outBuf.Length) {
  1212.             Flush();
  1213.         }
  1214.     }
  1215.  
  1216.     public void Write(byte[] buf)
  1217.     {
  1218.         Write(buf, 0, buf.Length);
  1219.     }
  1220.  
  1221.     public override void Write(byte[] buf, int off, int len)
  1222.     {
  1223.         while (len > 0) {
  1224.             int clen = Math.Min(outBuf.Length - outPtr, len);
  1225.             Array.Copy(buf, off, outBuf, outPtr, clen);
  1226.             outPtr += clen;
  1227.             off += clen;
  1228.             len -= clen;
  1229.             if (outPtr == outBuf.Length) {
  1230.                 Flush();
  1231.             }
  1232.         }
  1233.     }
  1234.  
  1235.     internal void SetExpectedType(int expectedType)
  1236.     {
  1237.         this.inExpectedType = expectedType;
  1238.     }
  1239.  
  1240.     internal int GetInVersion()
  1241.     {
  1242.         return inVersion;
  1243.     }
  1244.  
  1245.     void Refill()
  1246.     {
  1247.         for (;;) {
  1248.             M.ReadFully(sub, inBuf, 0, 5);
  1249.             inType = inBuf[0];
  1250.             inVersion = M.Dec16be(inBuf, 1);
  1251.             inEnd = M.Dec16be(inBuf, 3);
  1252.             M.ReadFully(sub, inBuf, 0, inEnd);
  1253.             inPtr = 0;
  1254.             if (inType != inExpectedType) {
  1255.                 if (inType == M.ALERT) {
  1256.                     /*
  1257.                      * We just ignore alert
  1258.                      * messages.
  1259.                      */
  1260.                     continue;
  1261.                 }
  1262.                 throw new IOException(
  1263.                     "unexpected record type: "
  1264.                     + inType);
  1265.             }
  1266.             return;
  1267.         }
  1268.     }
  1269.  
  1270.     public override int ReadByte()
  1271.     {
  1272.         while (inPtr == inEnd) {
  1273.             Refill();
  1274.         }
  1275.         return inBuf[inPtr ++];
  1276.     }
  1277.  
  1278.     public override int Read(byte[] buf, int off, int len)
  1279.     {
  1280.         while (inPtr == inEnd) {
  1281.             Refill();
  1282.         }
  1283.         int clen = Math.Min(inEnd - inPtr, len);
  1284.         Array.Copy(inBuf, inPtr, buf, off, clen);
  1285.         inPtr += clen;
  1286.         return clen;
  1287.     }
  1288. }
  1289.  
  1290. /*
  1291.  * This class decodes a ServerHello message from the server. The
  1292.  * fields we are interested in are stored in the
  1293.  * package-accessible fields.
  1294.  */
  1295. class ServerHello {
  1296.  
  1297.     internal int recordVersion;
  1298.     internal int protoVersion;
  1299.     internal long serverTime;
  1300.     internal int cipherSuite;
  1301.     internal int compression;
  1302.     internal string serverCertName;
  1303.     internal string serverCertHash;
  1304.  
  1305.     internal ServerHello(SSLRecord rec)
  1306.     {
  1307.         rec.SetExpectedType(M.HANDSHAKE);
  1308.  
  1309.         /*
  1310.          * First, get the handshake message header (4 bytes).
  1311.          * First byte should be 2 ("ServerHello"), then
  1312.          * comes the message size (over 3 bytes).
  1313.          */
  1314.         byte[] buf = new byte[4];
  1315.         M.ReadFully(rec, buf);
  1316.         recordVersion = rec.GetInVersion();
  1317.         if (buf[0] != 2) {
  1318.             throw new IOException("unexpected handshake"
  1319.                 + " message type: " + buf[0]);
  1320.         }
  1321.         buf = new byte[M.Dec24be(buf, 1)];
  1322.  
  1323.         /*
  1324.          * Read the complete message in RAM.
  1325.          */
  1326.         M.ReadFully(rec, buf);
  1327.         int ptr = 0;
  1328.  
  1329.         /*
  1330.          * The protocol version which we will use.
  1331.          */
  1332.         if (ptr + 2 > buf.Length) {
  1333.             throw new IOException("invalid ServerHello");
  1334.         }
  1335.         protoVersion = M.Dec16be(buf, 0);
  1336.         ptr += 2;
  1337.  
  1338.         /*
  1339.          * The server random begins with the server's notion
  1340.          * of the current time.
  1341.          */
  1342.         if (ptr + 32 > buf.Length) {
  1343.             throw new IOException("invalid ServerHello");
  1344.         }
  1345.         serverTime = 1000L * (long)M.Dec32be(buf, ptr);
  1346.         ptr += 32;
  1347.  
  1348.         /*
  1349.          * We skip the session ID.
  1350.          */
  1351.         if (ptr + 1 > buf.Length) {
  1352.             throw new IOException("invalid ServerHello");
  1353.         }
  1354.         ptr += 1 + buf[ptr];
  1355.  
  1356.         /*
  1357.          * The cipher suite and compression follow.
  1358.          */
  1359.         if (ptr + 3 > buf.Length) {
  1360.             throw new IOException("invalid ServerHello");
  1361.         }
  1362.         cipherSuite = M.Dec16be(buf, ptr);
  1363.         compression = buf[ptr + 2];
  1364.  
  1365.         /*
  1366.          * The ServerHello could include some extensions
  1367.          * here, which we ignore.
  1368.          */
  1369.  
  1370.         /*
  1371.          * We now read a few extra messages, until we
  1372.          * reach the server's Certificate message, or
  1373.          * ServerHelloDone.
  1374.          */
  1375.         for (;;) {
  1376.             buf = new byte[4];
  1377.             M.ReadFully(rec, buf);
  1378.             int mt = buf[0];
  1379.             buf = new byte[M.Dec24be(buf, 1)];
  1380.             M.ReadFully(rec, buf);
  1381.             switch (mt) {
  1382.             case 11:
  1383.                 ProcessCertificate(buf);
  1384.                 return;
  1385.             case 14:
  1386.                 // ServerHelloDone
  1387.                 return;
  1388.             }
  1389.         }
  1390.     }
  1391.  
  1392.     private void ProcessCertificate(byte[] buf)
  1393.     {
  1394.         if (buf.Length <= 6) {
  1395.             return;
  1396.         }
  1397.         int len1 = M.Dec24be(buf, 0);
  1398.         if (len1 != buf.Length - 3) {
  1399.             return;
  1400.         }
  1401.         int len2 = M.Dec24be(buf, 3);
  1402.         if (len2 > buf.Length - 6) {
  1403.             return;
  1404.         }
  1405.         byte[] ec = new byte[len2];
  1406.         Array.Copy(buf, 6, ec, 0, len2);
  1407.  
  1408.         try {
  1409.             X509Certificate2 xc = new X509Certificate2(ec);
  1410.             serverCertName = xc.SubjectName.Name;
  1411.         } catch (Exception) {
  1412.             // ignored
  1413.             return;
  1414.         }
  1415.         serverCertHash = M.DoSHA1(ec);
  1416.     }
  1417. }
  1418.  
  1419. /*
  1420.  * This class represents the response of a server which knows
  1421.  $ SSLv2. It includes the list of cipher suites and the
  1422.  * identification of the server certificate.
  1423.  */
  1424. class ServerHelloSSLv2 {
  1425.  
  1426.     internal int[] cipherSuites;
  1427.     internal string serverCertName;
  1428.     internal string serverCertHash;
  1429.  
  1430.     internal ServerHelloSSLv2(Stream ss)
  1431.     {
  1432.         // Record length
  1433.         byte[] buf = new byte[2];
  1434.         M.ReadFully(ss, buf);
  1435.         int len = M.Dec16be(buf, 0);
  1436.         if ((len & 0x8000) == 0) {
  1437.             throw new IOException("not a SSLv2 record");
  1438.         }
  1439.         len &= 0x7FFF;
  1440.         if (len < 11) {
  1441.             throw new IOException(
  1442.                 "not a SSLv2 server hello");
  1443.         }
  1444.         buf = new byte[11];
  1445.         M.ReadFully(ss, buf);
  1446.         if (buf[0] != 0x04) {
  1447.             throw new IOException(
  1448.                 "not a SSLv2 server hello");
  1449.         }
  1450.         int certLen = M.Dec16be(buf, 5);
  1451.         int csLen = M.Dec16be(buf, 7);
  1452.         int connIdLen = M.Dec16be(buf, 9);
  1453.         if (len != 11 + certLen + csLen + connIdLen) {
  1454.             throw new IOException(
  1455.                 "not a SSLv2 server hello");
  1456.         }
  1457.         if (csLen == 0 || csLen % 3 != 0) {
  1458.             throw new IOException(
  1459.                 "not a SSLv2 server hello");
  1460.         }
  1461.         byte[] cert = new byte[certLen];
  1462.         M.ReadFully(ss, cert);
  1463.         byte[] cs = new byte[csLen];
  1464.         M.ReadFully(ss, cs);
  1465.         byte[] connId = new byte[connIdLen];
  1466.         M.ReadFully(ss, connId);
  1467.         cipherSuites = new int[csLen / 3];
  1468.         for (int i = 0, j = 0; i < csLen; i += 3, j ++) {
  1469.             cipherSuites[j] = M.Dec24be(cs, i);
  1470.         }
  1471.         try {
  1472.             X509Certificate2 xc = new X509Certificate2(cert);
  1473.             serverCertName = xc.SubjectName.Name;
  1474.         } catch (Exception) {
  1475.             // ignored
  1476.             return;
  1477.         }
  1478.         serverCertHash = M.DoSHA1(cert);
  1479.     }
  1480. }
  1481.  
  1482. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement