/* * Begin a new handshake, and return the server data. If the * server refused to complete the handshake with an explicit * alert, then an SSLAlertException is thrown; for all other * error conditions, an other kind of exception is thrown. */ internal SSLTestResult RunTest(SSLRecord rec) { /* * Send ClientHello. */ byte[] ch = MakeClientHello(cipherSuites); rec.SetOutType(M.HANDSHAKE); rec.SetOutVersion(recordVersion); rec.Write(ch); rec.Flush(); /* * Read handshake messages from server, up to the * ServerHelloDone. */ SSLTestResult tr = new SSLTestResult(); tr.Parse(rec); tr.CipherSuiteInClientList = false; foreach (int s in cipherSuites) { if (s == tr.SelectedCipherSuite) { tr.CipherSuiteInClientList = true; } } return(tr); }
/* * Try a connection with the current test settings. Connection * errors get through as exceptions. Other errors result in a * null returned value. If the handshake failed after the * ServerHello, then a non-null object is returned. */ SSLTestResult DoConnect() { Stream ns = null; try { ns = OpenConnection(); if (verbose) { Console.Write("."); } if (!gotSSLAnswer && readTimeout > 0) { RTStream rns = new RTStream(ns); rns.RTimeout = readTimeout; ns = rns; } try { bool hasECExt = tb.SupportedCurves != null && tb.SupportedCurves.Length > 0; SSLRecord rec = new SSLRecord(ns); SSLTestResult tr = tb.RunTest(rec); gotSSLAnswer = true; if (tr != null) { if (tr.DeflateCompress) { serverCompress = true; } AddServerChain(tr.CertificateChain); AddServerTime(tr.TimeMillis); AddServerDHSize(tr.DHSize); AddServerECSize(tr.ECSize, hasECExt); AddServerNamedCurve(tr.Curve); if (tr.CurveExplicitPrime) { curveExplicitPrime = tr.ECSize; } else if (tr.CurveExplicitChar2) { curveExplicitChar2 = tr.ECSize; } if (tr.UnknownSKE) { unknownSKE = true; } if (tr.RenegotiationInfo != null) { doesRenego = true; } if (tr.DoesEtM) { doesEtM = true; } } return(tr); } catch (SSLAlertException ae) { gotSSLAnswer = true; sslAlert = ae.Alert; return(null); } catch (ReadTimeoutException) { gotReadTimeout = true; return(null); } catch (Exception) { return(null); } } finally { try { if (ns != null) { ns.Close(); } } catch (Exception) { // ignored } } }
/* * Parse messages from the server: from ServerHello to * ServerHelloDone. */ internal void Parse(SSLRecord rec) { rec.SetExpectedType(M.HANDSHAKE); /* * First parse a ServerHello. */ HMParser sh = new HMParser(rec); if (sh.MessageType != M.SERVER_HELLO) { throw new Exception("Not a ServerHello"); } version = sh.Read2(); byte[] serverRandom = sh.ReadBlobFixed(32); timeMillis = 1000 * (long)M.Dec32be(serverRandom, 0); sessionID = sh.ReadBlobVar(1); if (sessionID.Length > 32) { throw new Exception("Oversized session ID"); } selectedCipherSuite = sh.Read2(); int cm = sh.Read1(); if (cm == 0) { deflateCompress = false; } else if (cm == 1) { deflateCompress = true; } else { throw new Exception( "Unknown compression method: " + cm); } if (!sh.EndOfStruct) { sh.OpenVar(2); Dictionary <int, bool> d = new Dictionary <int, bool>(); while (!sh.EndOfStruct) { int extType = sh.Read2(); if (d.ContainsKey(extType)) { throw new Exception( "Duplicate extension: " + extType); } d[extType] = true; sh.OpenVar(2); switch (extType) { case M.EXT_SERVER_NAME: ParseEmptyServerName(sh); break; case M.EXT_RENEGOTIATION_INFO: ParseRenegInfo(sh); break; case M.EXT_SUPPORTED_CURVES: ParseSupportedCurves(sh); break; case M.EXT_SUPPORTED_EC_POINTS: ParseSupportedECPoints(sh); break; default: throw new Exception( "Unknown extension: " + extType); } sh.Close(); } sh.Close(); } sh.Close(); /* * Read other messages, up to the ServerHelloDone. */ try { bool seenSHD = false; while (!seenSHD) { HMParser hm = new HMParser(rec); switch (hm.MessageType) { case M.CERTIFICATE: ParseCertificate(hm); break; case M.SERVER_KEY_EXCHANGE: ParseServerKeyExchange(hm); break; case M.CERTIFICATE_REQUEST: ParseCertificateRequest(hm); break; case M.SERVER_HELLO_DONE: hm.Close(); seenSHD = true; break; default: hm.Close(true); break; } } } catch { failedAfterHello = true; } recordVersion = rec.GetInVersion(); }