public async ValueTask <GetFiberRwSSLResult <T> > GetFiberRwSSL <T>(X509Certificate certificate_client, string targethost = "localhost", Func <Stream, Stream, GetFiberRwResult> init = null) where T : class
        {
            if (await RStream.WaitStreamInit())
            {
                var mergestream = new MergeStream(RStream as Stream, WStream as Stream);

                var sslstream = new SslStream(mergestream, false, (sender, certificate, chain, errors) => true,
                                              (sender, host, certificates, certificate, issuers) => certificate_client);

                try
                {
                    await sslstream.AuthenticateAsClientAsync(targethost);
                }
                catch (Exception er)
                {
                    return(new GetFiberRwSSLResult <T> {
                        IsError = true, FiberRw = null, ErrMsg = er.Message
                    });
                }

                var fiber = new FiberRw <T>(this, RStream, WStream, MemoryPool, Encoding, ObjFormat, IsLittleEndian, sslstream, sslstream, init: init);
                fibersslT = fiber;
                taskCompletionSource?.TrySetResult(fiber);
                return(new GetFiberRwSSLResult <T> {
                    IsError = false, FiberRw = fiber, ErrMsg = null
                });
            }
            else
            {
                return new GetFiberRwSSLResult <T> {
                           IsError = true, FiberRw = null, ErrMsg = "not install"
                }
            };
        }
Esempio n. 2
0
 public async ValueTask <(IFiberRw, string)> GetFiberRwSSL(X509Certificate certificate, Func <Stream, Stream, GetFiberRwResult> init = null)
 {
     if (await RStream.WaitStreamInit())
     {
         var mergestream = new MergeStream(RStream as Stream, WStream as Stream);
         var sslstream   = new SslStream(mergestream, false);
         try
         {
             await sslstream.AuthenticateAsServerAsync(certificate);
         }
         catch (Exception er)
         {
             return(null, er.Message);
         }
         var fiber = new FiberRw <object>(this, RStream, WStream, MemoryPool, Encoding, ObjFormat, IsLittleEndian, sslstream, sslstream, init: init);
         fibersslobj = fiber;
         return(fiber, null);
     }
     else
     {
         return(null, "not install");
     }
 }
Esempio n. 3
0
    void Run(string[] args)
    {
        bool          verbose = true;
        bool          trace   = false;
        string        host    = null;
        string        sni     = null;
        List <string> csNames = null;
        List <string> hsNames = null;
        int           vmin    = 0;
        int           vmax    = 0;

        for (int i = 0; i < args.Length; i++)
        {
            string a = args[i];
            if (!a.StartsWith("-"))
            {
                if (host != null)
                {
                    throw new Exception(
                              "duplicate host name");
                }
                host = a;
                continue;
            }
            a = a.Substring(1).ToLowerInvariant();
            switch (a)
            {
            case "v":
                verbose = true;
                break;

            case "q":
                verbose = false;
                break;

            case "trace":
                trace = true;
                break;

            case "sni":
                if (sni != null)
                {
                    throw new Exception(
                              "duplicate SNI");
                }
                if (++i >= args.Length)
                {
                    throw new Exception(
                              "no SNI provided");
                }
                sni = args[i];
                break;

            case "nosni":
                if (sni != null)
                {
                    throw new Exception(
                              "duplicate SNI");
                }
                sni = "";
                break;

            case "cs":
                if (++i >= args.Length)
                {
                    throw new Exception(
                              "no cipher names provided");
                }
                if (csNames == null)
                {
                    csNames = new List <string>();
                }
                AddNames(csNames, args[i]);
                break;

            case "hs":
                if (++i >= args.Length)
                {
                    throw new Exception(
                              "no hash-and-sign provided");
                }
                if (hsNames == null)
                {
                    hsNames = new List <string>();
                }
                AddNames(hsNames, args[i]);
                break;

            case "vmin":
                if (vmin != 0)
                {
                    throw new Exception(
                              "duplicate minimum version");
                }
                if (++i >= args.Length)
                {
                    throw new Exception(
                              "no minimum version provided");
                }
                vmin = SSL.GetVersionByName(args[i]);
                break;

            case "vmax":
                if (vmax != 0)
                {
                    throw new Exception(
                              "duplicate maximum version");
                }
                if (++i >= args.Length)
                {
                    throw new Exception(
                              "no maximum version provided");
                }
                vmax = SSL.GetVersionByName(args[i]);
                break;

            default:
                throw new Exception(string.Format(
                                        "Unknown option: '-{0}'", a));
            }
        }

        if (host == null)
        {
            throw new Exception("no host name provided");
        }
        int j = host.LastIndexOf(':');
        int port;

        if (j < 0)
        {
            port = 443;
        }
        else
        {
            if (!Int32.TryParse(host.Substring(j + 1), out port) ||
                port <= 0 || port > 65535)
            {
                throw new Exception("invalid port number");
            }
            host = host.Substring(0, j);
        }
        if (sni == null)
        {
            sni = host;
        }
        int[] css = null;
        if (csNames != null)
        {
            css = new int[csNames.Count];
            for (int i = 0; i < css.Length; i++)
            {
                css[i] = SSL.GetSuiteByName(csNames[i]);
            }
        }
        int[] hss = null;
        if (hsNames != null)
        {
            hss = new int[hsNames.Count];
            for (int i = 0; i < hss.Length; i++)
            {
                hss[i] = SSL.GetHashAndSignByName(hsNames[i]);
            }
        }
        if (vmin != 0 && vmax != 0 && vmin > vmax)
        {
            throw new Exception("invalid version range");
        }

        /*
         * Connect to the designated server.
         */
        TcpClient tc   = new TcpClient(host, port);
        Socket    sock = tc.Client;
        Stream    ns   = tc.GetStream();

        if (trace)
        {
            MergeStream ms = new MergeStream(ns, ns);
            ms.Debug = Console.Out;
            ns       = ms;
        }
        SSLClient ssl = new SSLClient(ns);

        if (sni != "")
        {
            ssl.ServerName = sni;
        }
        if (css != null)
        {
            ssl.SupportedCipherSuites = css;
        }
        if (hss != null)
        {
            ssl.SupportedHashAndSign = hss;
        }
        if (vmin != 0)
        {
            ssl.VersionMin = vmin;
        }
        if (vmax != 0)
        {
            ssl.VersionMax = vmax;
        }

        /*
         * This is a debug tool; we accept the server certificate
         * without validation.
         */
        ssl.ServerCertValidator = SSLClient.InsecureCertValidator;

        /*
         * Force a Flush. There is no application data to flush
         * at this point, but as a side-effect it forces the
         * handshake to complete.
         */
        ssl.Flush();

        if (verbose)
        {
            Console.WriteLine("Handshake completed:");
            Console.WriteLine("  Version      = {0}",
                              SSL.VersionName(ssl.Version));
            Console.WriteLine("  Cipher suite = {0}",
                              SSL.CipherSuiteName(ssl.CipherSuite));
        }

        /*
         * Now relay data back and forth between the connection
         * and the console. Since the underlying SSL stream does
         * not support simultaneous reads and writes, we use
         * the following approximation:
         *
         *  - We poll on the socket for incoming data. When there
         *    is some activity, we assume that some application
         *    data (or closure) follows, and we read it. It is
         *    then immediately written out (synchronously) on
         *    standard output.
         *
         *  - When waiting for read activity on the socket, we
         *    regularly (every 200 ms) check for data to read on
         *    standard input. If there is, we read it, and send
         *    it synchronously on the SSL stream.
         *
         *  - The data reading from console is performed by
         *    another thread.
         *
         * Since SSL records are read one by one, we know that,
         * by using a buffer larger than 16 kB, a single Read()
         * call cannot leave any buffered application data.
         */
        ssl.CloseSub = false;
        Thread t = new Thread(new ThreadStart(CRThread));

        t.IsBackground = true;
        t.Start();
        byte[] buf    = new byte[16384];
        Stream stdout = Console.OpenStandardOutput();

        for (;;)
        {
            if (sock.Poll(200000, SelectMode.SelectRead))
            {
                int rlen = ssl.Read(buf, 0, buf.Length);
                if (rlen < 0)
                {
                    Console.WriteLine(
                        "Connection closed.\n");
                    break;
                }
                stdout.Write(buf, 0, rlen);
            }
            else
            {
                while (CRHasData())
                {
                    int rlen = CRRead(buf, 0, buf.Length);
                    if (rlen < 0)
                    {
                        ssl.Close();
                        break;
                    }
                    if (rlen > 0)
                    {
                        ssl.Write(buf, 0, rlen);
                    }
                }
            }
        }
        sock.Close();
    }
Esempio n. 4
0
    void RunTest(bool cmdClient, object obj)
    {
        string name = JSON.GetString(obj, "name")
                      + (cmdClient ? "_client" : "_server");

        Console.Write("\r({0}/{1})",
                      totalSuccess + totalFailures + 1, totalTests);
        // Console.Write("{0}:", name);

        /*
         * Expected command exit code:
         *
         *   0 if the command is supposed to exit gracefully
         *   1 if the command should detect and report an error
         */
        int expectedExitCode;

        JSON.TryGetInt32(obj, "expectedExitCode", out expectedExitCode);

        /*
         * Expected failure: if defined, then we expect our
         * library to throw an exception, and the message should
         * contain that specific string.
         */
        string expectedFailure;

        JSON.TryGetString(obj, "expectedFailure", out expectedFailure);

        /*
         * Assemble the sub-process command line:
         *
         *  - Always one of "-client" or "-server"
         *  - For a server command, a certificate and key are
         *    always provided (defaults to RSA); for a client,
         *    only if explicitly asked for.
         */
        StringBuilder sb = new StringBuilder();

        if (cmdClient)
        {
            sb.Append("-client");
        }
        else
        {
            sb.Append("-server");
        }
        if (commandVerbose)
        {
            sb.Append(" -v");
        }
        string certType = GetCertType(obj, cmdClient);

        switch (certType)
        {
        case "RSA":
            sb.AppendFormat(" -cert \"{0}\" -key \"{1}\"",
                            chainRSAFile, skeyRSAFile);
            break;

        case "EC":
            sb.AppendFormat(" -cert \"{0}\" -key \"{1}\"",
                            chainECFile, skeyECFile);
            break;

        case "none":
            break;

        default:
            throw new Exception("Unknown certType: " + certType);
        }
        string extra;

        if (JSON.TryGetString(obj, "extraArgs", out extra))
        {
            sb.Append(' ');
            sb.Append(extra);
        }

        /*
         * Run the sub-process.
         */
        ProcessStartInfo si = new ProcessStartInfo();

        si.FileName               = commandFile;
        si.Arguments              = string.Format(commandArgs, sb.ToString());
        si.UseShellExecute        = false;
        si.ErrorDialog            = false;
        si.CreateNoWindow         = true;
        si.RedirectStandardInput  = true;
        si.RedirectStandardOutput = true;

        using (Process pp = new Process()) {
            pp.StartInfo = si;
            pp.Start();
            Exception delayed = null;
            try {
                /*
                 * TODO: add a time-out on the streams
                 * so that the test never stalls
                 * indefinitely if the two SSL engines
                 * lose synchronisation.
                 */
                MergeStream ms = new MergeStream(
                    pp.StandardOutput.BaseStream,
                    pp.StandardInput.BaseStream);
                if (trace)
                {
                    ms.Debug = Console.Out;
                }
                RunTestInner(cmdClient, obj, ms);
            } catch (Exception ex) {
                delayed = ex;
            }

            /*
             * Once the test has run, we must make sure that
             * the sub-processed is finished. It _should_ end
             * properly by itself for all successful test cases,
             * so if we have to kill it, then it's a bug.
             */
            bool killed = false;
            if (!pp.WaitForExit(2000))
            {
                try {
                    pp.Kill();
                } catch {
                    // ignored
                }
                pp.WaitForExit();
                killed = true;
            }
            int exc = pp.ExitCode;

            /*
             * If we had to kill the command, then that is
             * always a bug. Otherwise, we compare what we
             * got with the expected outcomes.
             */
            List <string> msg = new List <string>();
            if (killed)
            {
                msg.Add("COMMAND KILLED");
            }
            if (exc != expectedExitCode)
            {
                msg.Add("Wrong exit code: "
                        + exc + " (expected: "
                        + expectedExitCode + ")");
            }
            if (delayed == null)
            {
                if (expectedFailure != null)
                {
                    msg.Add("An exception was expected");
                }
            }
            else
            {
                if (expectedFailure == null)
                {
                    msg.Add(delayed.ToString());
                }
                else
                {
                    string s = delayed.Message;
                    if (s == null)
                    {
                        s = "";
                    }
                    if (s.IndexOf(expectedFailure) < 0)
                    {
                        msg.Add(delayed.ToString());
                    }
                }
            }
            if (msg.Count == 0)
            {
                totalSuccess++;
            }
            else
            {
                Console.WriteLine("{0}: FAIL:", name);
                foreach (string s in msg)
                {
                    Console.WriteLine(s);
                }
                totalFailures++;
            }
        }
    }