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" } }; }
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"); } }
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(); }
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++; } } }