/* * do_client() */ private void do_client(int build_mode, string[] args) { if (build_mode < axtls.SSL_BUILD_ENABLE_CLIENT) { print_client_options(build_mode, args[1]); } int i = 1, res; int port = 4433; bool quiet = false; string password = null; int reconnect = 0; string private_key_file = null; string hostname = "127.0.0.1"; /* organise the cert/ca_cert lists */ int cert_index = 0; int ca_cert_index = 0; int cert_size = SSLUtil.MaxCerts(); int ca_cert_size = SSLUtil.MaxCACerts(); string[] cert = new string[cert_size]; string[] ca_cert = new string[ca_cert_size]; uint options = axtls.SSL_SERVER_VERIFY_LATER | axtls.SSL_DISPLAY_CERTS; byte[] session_id = null; while (i < args.Length) { if (args[i] == "-connect") { string host_port; if (i >= args.Length - 1) { print_client_options(build_mode, args[i]); } host_port = args[++i]; int index_colon; if ((index_colon = host_port.IndexOf(':')) < 0) { print_client_options(build_mode, args[i]); } hostname = new string(host_port.ToCharArray(), 0, index_colon); port = Int32.Parse(new String(host_port.ToCharArray(), index_colon + 1, host_port.Length - index_colon - 1)); } else if (args[i] == "-cert") { if (i >= args.Length - 1 || cert_index >= cert_size) { print_client_options(build_mode, args[i]); } cert[cert_index++] = args[++i]; } else if (args[i] == "-key") { if (i >= args.Length - 1) { print_client_options(build_mode, args[i]); } private_key_file = args[++i]; options |= axtls.SSL_NO_DEFAULT_KEY; } else if (args[i] == "-CAfile") { if (i >= args.Length - 1 || ca_cert_index >= ca_cert_size) { print_client_options(build_mode, args[i]); } ca_cert[ca_cert_index++] = args[++i]; } else if (args[i] == "-verify") { options &= ~(uint)axtls.SSL_SERVER_VERIFY_LATER; } else if (args[i] == "-reconnect") { reconnect = 4; } else if (args[i] == "-quiet") { quiet = true; options &= ~(uint)axtls.SSL_DISPLAY_CERTS; } else if (args[i] == "-pass") { if (i >= args.Length - 1) { print_client_options(build_mode, args[i]); } password = args[++i]; } else if (build_mode == axtls.SSL_BUILD_FULL_MODE) { if (args[i] == "-debug") { options |= axtls.SSL_DISPLAY_BYTES; } else if (args[i] == "-state") { options |= axtls.SSL_DISPLAY_STATES; } else if (args[i] == "-show-rsa") { options |= axtls.SSL_DISPLAY_RSA; } else { print_client_options(build_mode, args[i]); } } else /* don't know what this is */ { print_client_options(build_mode, args[i]); } i++; } // IPHostEntry hostInfo = Dns.Resolve(hostname); IPHostEntry hostInfo = Dns.GetHostEntry(hostname); IPAddress[] addresses = hostInfo.AddressList; IPEndPoint ep = new IPEndPoint(addresses[0], port); Socket client_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client_sock.Connect(ep); if (!client_sock.Connected) { Console.WriteLine("could not connect"); Environment.Exit(1); } if (!quiet) { Console.WriteLine("CONNECTED"); } /********************************************************************** * This is where the interesting stuff happens. Up until now we've * just been setting up sockets etc. Now we do the SSL handshake. **********************************************************************/ SSLClient ssl_ctx = new SSLClient(options, axtls.SSL_DEFAULT_CLNT_SESS); if (ssl_ctx == null) { Console.Error.WriteLine("Error: Client context is invalid"); Environment.Exit(1); } if (private_key_file != null) { int obj_type = axtls.SSL_OBJ_RSA_KEY; if (private_key_file.EndsWith(".p8")) { obj_type = axtls.SSL_OBJ_PKCS8; } else if (private_key_file.EndsWith(".p12")) { obj_type = axtls.SSL_OBJ_PKCS12; } if (ssl_ctx.ObjLoad(obj_type, private_key_file, password) != axtls.SSL_OK) { Console.Error.WriteLine("Private key '" + private_key_file + "' is undefined."); Environment.Exit(1); } } for (i = 0; i < cert_index; i++) { if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, cert[i], null) != axtls.SSL_OK) { Console.WriteLine("Certificate '" + cert[i] + "' is undefined."); Environment.Exit(1); } } for (i = 0; i < ca_cert_index; i++) { if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, ca_cert[i], null) != axtls.SSL_OK) { Console.WriteLine("Certificate '" + cert[i] + "' is undefined."); Environment.Exit(1); } } SSL ssl = new SSL(new IntPtr(0)); /* keep compiler happy */ /* Try session resumption? */ if (reconnect > 0) { while (reconnect-- > 0) { ssl = ssl_ctx.Connect(client_sock, session_id); if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK) { if (!quiet) { SSLUtil.DisplayError(res); } ssl.Dispose(); Environment.Exit(1); } display_session_id(ssl); session_id = ssl.GetSessionId(); if (reconnect > 0) { ssl.Dispose(); client_sock.Close(); /* and reconnect */ client_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client_sock.Connect(ep); } } } else { ssl = ssl_ctx.Connect(client_sock, null); } /* check the return status */ if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK) { if (!quiet) { SSLUtil.DisplayError(res); } Environment.Exit(1); } if (!quiet) { string common_name = ssl.GetCertificateDN(axtls.SSL_X509_CERT_COMMON_NAME); if (common_name != null) { Console.WriteLine("Common Name:\t\t\t" + common_name); } display_session_id(ssl); display_cipher(ssl); } for (;;) { string user_input = Console.ReadLine(); if (user_input == null) { break; } byte[] buf = new byte[user_input.Length + 2]; buf[buf.Length - 2] = (byte)'\n'; /* add the carriage return */ buf[buf.Length - 1] = 0; /* null terminate */ for (i = 0; i < buf.Length - 2; i++) { buf[i] = (byte)user_input[i]; } if ((res = ssl_ctx.Write(ssl, buf, buf.Length)) < axtls.SSL_OK) { if (!quiet) { SSLUtil.DisplayError(res); } break; } } ssl_ctx.Dispose(); }
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(); }