Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
0
        protected SslHandshakeStatus GetClientHelloResult(Alert alert)
        {
            SslHandshakeStatus ret = new SslHandshakeStatus();

            if (alert != null)
            {
                ret.Status = SslStatus.Close;
                ret.Message = m_RecordLayer.EncryptBytes(new byte[] { (byte) alert.Level, (byte) alert.Description }, 0, 2, ContentType.Alert);
                return ret;
            }

            MemoryStream retMessage = new MemoryStream();
            HandshakeMessage temp;
            byte[] bytes;

            Int16 extensionsSize = sizeof(Int16);
            if (this.clientHelloExts != null)
            {
                extensionsSize += this.clientHelloExts.ExtensionsByteLength;
            }
            // ServerHello message
            temp = new HandshakeMessage(HandshakeType.ServerHello, new byte[38 + extensionsSize]);
            m_ServerTime = GetUnixTime();
            m_ServerRandom = new byte[28];
            m_RNG.GetBytes(m_ServerRandom);
            temp.fragment[0] = GetVersion().major;
            temp.fragment[1] = GetVersion().minor;
            Buffer.BlockCopy(m_ServerTime, 0, temp.fragment, 2, 4);
            Buffer.BlockCopy(m_ServerRandom, 0, temp.fragment, 6, 28);
            temp.fragment[34] = 0; // do not resume a session, and do not let the other side cache it
            Buffer.BlockCopy(CipherSuites.GetCipherAlgorithmBytes(m_EncryptionScheme), 0, temp.fragment, 35, 2);
            temp.fragment[37] = CompressionAlgorithm.GetAlgorithmByte(m_CompressionMethod);

            MemoryStream extsStream = new MemoryStream();
            this.clientHelloExts.WriteExtensions(extsStream, ConnectionEnd.Server);
            byte[] extsBytes = extsStream.ToArray();
            Buffer.BlockCopy(extsBytes, 0, temp.fragment, 38, extsBytes.Length);
            bytes = temp.ToBytes();
            retMessage.Write(bytes, 0, bytes.Length);

            // Certificate message
            byte[] certs = GetCertificateList(m_Options.Certificate);
            temp.type = HandshakeType.Certificate;
            temp.fragment = certs;
            bytes = temp.ToBytes();

            retMessage.Write(bytes, 0, bytes.Length);
            // ServerKeyExchange message [optional] => only with RSA_EXPORT and public key > 512 bits
            if (m_Options.Certificate.GetPublicKeyLength() > 512 && CipherSuites.GetCipherDefinition(m_EncryptionScheme).Exportable) {
                MemoryStream kes = new MemoryStream();
                MD5SHA1CryptoServiceProvider mscsp = new MD5SHA1CryptoServiceProvider();
                // hash the client and server random values
                mscsp.TransformBlock(m_ClientTime, 0, 4, m_ClientTime, 0);
                mscsp.TransformBlock(m_ClientRandom, 0, 28, m_ClientRandom, 0);
                mscsp.TransformBlock(m_ServerTime, 0, 4, m_ServerTime, 0);
                mscsp.TransformBlock(m_ServerRandom, 0, 28, m_ServerRandom, 0);
                // create a new 512 bit RSA key
                m_KeyCipher = new RSACryptoServiceProvider(512);
                RSAParameters p = m_KeyCipher.ExportParameters(false);
                // write the key parameters to the output stream
                bytes = new byte[]{(byte)(p.Modulus.Length / 256), (byte)(p.Modulus.Length % 256)};
                kes.Write(bytes, 0, 2);
                kes.Write(p.Modulus, 0, p.Modulus.Length);
                mscsp.TransformBlock(bytes, 0, 2, bytes, 0);
                mscsp.TransformBlock(p.Modulus, 0, p.Modulus.Length, p.Modulus, 0);
                bytes = new byte[]{(byte)(p.Exponent.Length / 256), (byte)(p.Exponent.Length % 256)};
                kes.Write(bytes, 0, 2);
                kes.Write(p.Exponent, 0, p.Exponent.Length);
                mscsp.TransformBlock(bytes, 0, 2, bytes, 0);
                mscsp.TransformFinalBlock(p.Exponent, 0, p.Exponent.Length);
                // create signature
                bytes = mscsp.CreateSignature(m_Options.Certificate);
                kes.Write(new byte[]{(byte)(bytes.Length / 256), (byte)(bytes.Length % 256)}, 0, 2);
                kes.Write(bytes, 0, bytes.Length);
                // write to output
                temp.type = HandshakeType.ServerKeyExchange;
                temp.fragment = kes.ToArray();
                bytes = temp.ToBytes();
                retMessage.Write(bytes, 0, bytes.Length);
                kes.Close();
            } else {
                m_KeyCipher = (RSACryptoServiceProvider)m_Options.Certificate.PrivateKey;
            }
            // CertificateRequest message [optional]
            if (m_MutualAuthentication) {
                bytes = GetDistinguishedNames();
                if (bytes.Length != 0) { // make sure at least one certificate is returned
                    temp.type = HandshakeType.CertificateRequest;
                    temp.fragment = new byte[bytes.Length + 4];
                    temp.fragment[0] = 1; // one certificate type supported
                    temp.fragment[1] = 1; // cert type RSA
                    temp.fragment[2] = (byte)(bytes.Length / 256);
                    temp.fragment[3] = (byte)(bytes.Length % 256);
                    Buffer.BlockCopy(bytes, 0, temp.fragment, 4, bytes.Length);
                    bytes = temp.ToBytes();
                    retMessage.Write(bytes, 0, bytes.Length);
                }
            }
            // ServerHelloDone message
            temp.type = HandshakeType.ServerHelloDone;
            temp.fragment = new byte[0];
            bytes = temp.ToBytes();

            retMessage.Write(bytes, 0, bytes.Length);
            // final adjustments
            ret.Status = SslStatus.ContinueNeeded;
            ret.Message = retMessage.ToArray();
            retMessage.Close();
            UpdateHashes(ret.Message, HashUpdate.All); // output message
            ret.Message = m_RecordLayer.EncryptBytes(ret.Message, 0, ret.Message.Length, ContentType.Handshake);
            return ret;
        }