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());
        }
예제 #2
0
        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.");
            }

            Alert alert = null;

            m_IsNegotiating = true;
            UpdateHashes(message, HashUpdate.All);             // input message
            // process ClientHello

            int currentLen = 0;

            ProtocolVersion pv = new ProtocolVersion(message.fragment[currentLen++], message.fragment[currentLen++]);

            m_MaxClientVersion = pv;

            //Violation with tls spec. If remote side uses higher protocol version than your, then we must answer with your highest version
            //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];
                Buffer.BlockCopy(message.fragment, currentLen, m_ClientTime, 0, 4);
                currentLen += 4;

                // extract the random bytes [== 28 bytes]
                m_ClientRandom = new byte[28];
                Buffer.BlockCopy(message.fragment, currentLen, m_ClientRandom, 0, 28);
                currentLen += 28;

                // extact the session ID [== 0..32 bytes]
                byte length = message.fragment[currentLen++];
                if (length > 32)
                {
                    throw new SslException(AlertDescription.IllegalParameter, "The length of the SessionID cannot be more than 32 bytes.");
                }

                m_SessionID = new byte[length];
                Buffer.BlockCopy(message.fragment, currentLen, m_SessionID, 0, length);
                currentLen += length;

                // extract the available cipher suites
                Int16 ciphers_size = BinaryHelper.Int16FromBytes(message.fragment[currentLen++], message.fragment[currentLen++]);//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];
                Buffer.BlockCopy(message.fragment, currentLen, ciphers, 0, ciphers_size);
                currentLen += ciphers_size;

                m_EncryptionScheme = CipherSuites.GetCipherSuiteAlgorithm(ciphers, m_Options.AllowedAlgorithms);
                // extract the available compression algorithms

                int compressors_size = message.fragment[currentLen++];
                if (compressors_size == 0)
                {
                    throw new SslException(AlertDescription.IllegalParameter, "No compressor specified.");
                }

                byte[] compressors = new byte[compressors_size];
                Buffer.BlockCopy(message.fragment, currentLen, compressors, 0, compressors_size);
                m_CompressionMethod = CompressionAlgorithm.GetCompressionAlgorithm(compressors, m_Options.AllowedAlgorithms);
                currentLen         += compressors_size;
                try
                {
                    if (message.fragment.Length > currentLen)
                    {
                        this.ProcessExtensions(message.fragment, ref currentLen, ConnectionEnd.Server);
                    }
                }
                catch (ALPNCantSelectProtocolException ex)
                {
                    alert = new Alert(ex.Description, ex.Level);
                }
            } catch (Exception e) {
                throw new SslException(e, AlertDescription.InternalError, "The message is invalid.");
            }
            // create reply
            return(GetClientHelloResult(alert));
        }