protected SslHandshakeStatus ProcessClientHello(HandshakeMessage message) { if (m_State != HandshakeType.Nothing && m_State != HandshakeType.Finished) { throw new SslException(AlertDescription.UnexpectedMessage, "ClientHello message must be the first message or must be preceded by a Finished message."); } m_IsNegotiating = true; UpdateHashes(message, HashUpdate.All); // input message // process ClientHello ProtocolVersion pv = new ProtocolVersion(message.fragment[0], message.fragment[1]); m_MaxClientVersion = pv; if (CompatibilityLayer.SupportsProtocol(m_Options.Protocol, pv) && pv.GetVersionInt() != GetVersion().GetVersionInt()) { throw new SslException(AlertDescription.IllegalParameter, "Unknown protocol version of the client."); } try { // extract the time from the client [== 1 uint] m_ClientTime = new byte[4]; Array.Copy(message.fragment, 2, m_ClientTime, 0, 4); // extract the random bytes [== 28 bytes] m_ClientRandom = new byte[28]; Array.Copy(message.fragment, 6, m_ClientRandom, 0, 28); // extact the session ID [== 0..32 bytes] int length = message.fragment[34]; if (length > 32) { throw new SslException(AlertDescription.IllegalParameter, "The length of the SessionID cannot be more than 32 bytes."); } m_SessionID = new byte[length]; Array.Copy(message.fragment, 35, m_SessionID, 0, length); // extract the available cipher suites length += 35; int ciphers_size = message.fragment[length] * 256 + message.fragment[length + 1]; if (ciphers_size < 2 || ciphers_size % 2 != 0) { throw new SslException(AlertDescription.IllegalParameter, "The number of ciphers is invalid -or- the cipher length is not even."); } byte[] ciphers = new byte[ciphers_size]; Array.Copy(message.fragment, length + 2, ciphers, 0, ciphers_size); m_EncryptionScheme = CipherSuites.GetCipherSuiteAlgorithm(ciphers, m_Options.AllowedAlgorithms); // extract the available compression algorithms length += ciphers_size + 2; int compressors_size = message.fragment[length]; if (compressors_size == 0) { throw new SslException(AlertDescription.IllegalParameter, "No compressor specified."); } byte[] compressors = new byte[compressors_size]; Array.Copy(message.fragment, length + 1, compressors, 0, compressors_size); m_CompressionMethod = CompressionAlgorithm.GetCompressionAlgorithm(compressors, m_Options.AllowedAlgorithms); } catch (Exception e) { throw new SslException(e, AlertDescription.InternalError, "The message is invalid."); } // create reply return(GetClientHelloResult()); }
// Thanks to Brandon for notifying us about a bug in this method public override SslHandshakeStatus ProcessSsl2Hello(byte[] hello) { if (m_State != HandshakeType.Nothing) { throw new SslException(AlertDescription.UnexpectedMessage, "SSL2 ClientHello message must be the first message."); } m_IsNegotiating = true; m_State = HandshakeType.ClientHello; UpdateHashes(hello, HashUpdate.All); // input message // process ClientHello ProtocolVersion pv = new ProtocolVersion(hello[1], hello[2]); m_MaxClientVersion = pv; if (CompatibilityLayer.SupportsProtocol(m_Options.Protocol, pv) && pv.GetVersionInt() != GetVersion().GetVersionInt()) { throw new SslException(AlertDescription.IllegalParameter, "Unknown protocol version of the client."); } int csl = hello[3] * 256 + hello[4]; // cipher spec length int sidl = hello[5] * 256 + hello[6]; // session id length int cl = hello[7] * 256 + hello[8]; // challenge length // process ciphers byte[] ciphers = new byte[(csl / 3) * 2]; int offset = 10; for (int i = 0; i < ciphers.Length; i += 2) { Array.Copy(hello, offset, ciphers, i, 2); offset += 3; } m_EncryptionScheme = CipherSuites.GetCipherSuiteAlgorithm(ciphers, m_Options.AllowedAlgorithms); // process session id m_SessionID = new byte[sidl]; Array.Copy(hello, 9 + csl, m_SessionID, 0, sidl); // process random data [challenge] m_ClientTime = new byte[4]; m_ClientRandom = new byte[28]; if (cl <= 28) { Array.Copy(hello, 9 + csl + sidl, m_ClientRandom, m_ClientRandom.Length - cl, cl); } else { Array.Copy(hello, 9 + csl + sidl + (cl - 28), m_ClientRandom, 0, 28); Array.Copy(hello, 9 + csl + sidl, m_ClientTime, 4 - (cl - 28), cl - 28); } m_CompressionMethod = SslAlgorithms.NULL_COMPRESSION; return(GetClientHelloResult()); }