protected override byte[] GetClientHello()
        {
            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;
            m_State         = HandshakeType.ClientHello;
            byte[]           ciphers = CipherSuites.GetCipherAlgorithmBytes(m_Options.AllowedAlgorithms);
            byte[]           compr   = CompressionAlgorithm.GetCompressionAlgorithmBytes(m_Options.AllowedAlgorithms);
            HandshakeMessage temp    = new HandshakeMessage(HandshakeType.ClientHello, new byte[38 + ciphers.Length + compr.Length]);

            m_ClientTime   = GetUnixTime();
            m_ClientRandom = new byte[28];
            m_RNG.GetBytes(m_ClientRandom);
            ProtocolVersion pv = CompatibilityLayer.GetMaxProtocol(m_Options.Protocol);

            temp.fragment[0] = pv.major;
            temp.fragment[1] = pv.minor;
            Array.Copy(m_ClientTime, 0, temp.fragment, 2, 4);
            Array.Copy(m_ClientRandom, 0, temp.fragment, 6, 28);
            temp.fragment[34] = 0;             // do not resume a session, and do not let the other side cache it
            temp.fragment[35] = (byte)(ciphers.Length / 256);
            temp.fragment[36] = (byte)(ciphers.Length % 256);
            Array.Copy(ciphers, 0, temp.fragment, 37, ciphers.Length);
            temp.fragment[37 + ciphers.Length] = (byte)compr.Length;
            Array.Copy(compr, 0, temp.fragment, 38 + ciphers.Length, compr.Length);
            byte[] ret = temp.ToBytes();
            UpdateHashes(ret, HashUpdate.All);             // client hello message
            return(m_RecordLayer.EncryptBytes(ret, 0, ret.Length, ContentType.Handshake));
        }
示例#2
0
 public SocketController(SecureSocket parent, Socket socket, SecurityOptions options)
 {
     m_Parent          = parent;
     m_Socket          = socket;
     m_IsDisposed      = false;
     m_ActiveSend      = null;
     m_ActiveReceive   = null;
     m_DecryptedBuffer = new XBuffer();
     m_ToSendList      = new ArrayList(2);
     m_SentList        = new ArrayList(2);
     m_ReceiveBuffer   = new byte[m_ReceiveBufferLength];
     m_Compatibility   = new CompatibilityLayer(this, options);
     //			m_RecordLayer = new RecordLayer(this, options);
     try {
         m_Socket.BeginReceive(m_ReceiveBuffer, 0, m_ReceiveBufferLength, SocketFlags.None, new AsyncCallback(this.OnReceive), null);
     } catch (Exception e) {
         CloseConnection(e);
     }
     if (options.Entity == ConnectionEnd.Client)
     {
         //				byte[] hello = m_RecordLayer.GetControlBytes(ControlType.ClientHello);
         byte[] hello = m_Compatibility.GetClientHello();
         BeginSend(hello, 0, hello.Length, null, DataType.ProtocolData);
     }
 }
        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());
        }
        protected override byte[] GetClientHello()
        {
            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;
            m_State         = HandshakeType.ClientHello;
            byte[] ciphers = CipherSuites.GetCipherAlgorithmBytes(m_Options.AllowedAlgorithms);
            byte[] compr   = CompressionAlgorithm.GetCompressionAlgorithmBytes(m_Options.AllowedAlgorithms);

            MemoryStream clientHello = new MemoryStream();

            m_ClientTime   = GetUnixTime();
            m_ClientRandom = new byte[28];
            m_RNG.GetBytes(m_ClientRandom);

            ProtocolVersion pv = CompatibilityLayer.GetMaxProtocol(m_Options.Protocol);

            clientHello.WriteByte(pv.major);
            clientHello.WriteByte(pv.minor);
            clientHello.Write(m_ClientTime, 0, m_ClientTime.Length);
            clientHello.Write(m_ClientRandom, 0, m_ClientRandom.Length);
            clientHello.WriteByte(0);
            clientHello.WriteByte((byte)(ciphers.Length / 256));
            clientHello.WriteByte((byte)(ciphers.Length % 256));
            clientHello.Write(ciphers, 0, ciphers.Length);
            clientHello.WriteByte((byte)compr.Length);
            clientHello.Write(compr, 0, compr.Length);

            if (this.clientHelloExts != null)
            {
                this.clientHelloExts.WriteExtensions(clientHello, ConnectionEnd.Client);
            }

            HandshakeMessage hm = new HandshakeMessage(HandshakeType.ClientHello, clientHello.ToArray());

            byte[] ret = hm.ToBytes();
            UpdateHashes(ret, HashUpdate.All);             // client hello message
            return(m_RecordLayer.EncryptBytes(ret, 0, ret.Length, ContentType.Handshake));
        }
示例#6
0
		public SocketController(SecureSocket parent, Socket socket, SecurityOptions options) {
			m_Parent = parent;
			m_Socket = socket;
			m_IsDisposed = false;
			m_ActiveSend = null;
			m_ActiveReceive = null;
			m_DecryptedBuffer = new XBuffer();
			m_ToSendList = new ArrayList(2);
			m_SentList = new ArrayList(2);
			m_ReceiveBuffer = new byte[m_ReceiveBufferLength];
			m_Compatibility = new CompatibilityLayer(this, options);
			//			m_RecordLayer = new RecordLayer(this, options);
			try {
				m_Socket.BeginReceive(m_ReceiveBuffer, 0, m_ReceiveBufferLength, SocketFlags.None, new AsyncCallback(this.OnReceive), null);
			} catch (Exception e) {
				CloseConnection(e);
			}
			if (options.Entity == ConnectionEnd.Client) {
				//				byte[] hello = m_RecordLayer.GetControlBytes(ControlType.ClientHello);
				byte[] hello = m_Compatibility.GetClientHello();
				BeginSend(hello, 0, hello.Length, null, DataType.ProtocolData);
			}
		}
        protected SslHandshakeStatus ProcessServerHelloDone(HandshakeMessage message)
        {
            if (m_State != HandshakeType.Certificate && m_State != HandshakeType.ServerKeyExchange && m_State != HandshakeType.CertificateRequest)
            {
                throw new SslException(AlertDescription.UnexpectedMessage, "ServerHello message must be preceded by a ClientHello message.");
            }
            if (message.fragment.Length != 0)
            {
                throw new SslException(AlertDescription.IllegalParameter, "The ServerHelloDone message is invalid.");
            }
            UpdateHashes(message, HashUpdate.All);             // input message
            MemoryStream     ms = new MemoryStream();
            HandshakeMessage hm = new HandshakeMessage(HandshakeType.ClientKeyExchange, null);

            byte[] buffer;
            // send Certificate [optional]
            if (m_MutualAuthentication)
            {
                hm.type     = HandshakeType.Certificate;
                hm.fragment = GetCertificateBytes(m_Options.Certificate);
                buffer      = m_RecordLayer.EncryptBytes(hm.ToBytes(), 0, hm.fragment.Length + 4, ContentType.Handshake);
                ms.Write(buffer, 0, buffer.Length);
                UpdateHashes(hm, HashUpdate.All);                 // output message
            }
            // send ClientKeyExchange
            if (m_KeyCipher == null)
            {
                m_KeyCipher = (RSACryptoServiceProvider)m_RemoteCertificate.PublicKey;
            }
            RSAKeyTransform kf = new RSAKeyTransform(m_KeyCipher);

            byte[] preMasterSecret = new byte[48];
            m_RNG.GetBytes(preMasterSecret);
            ProtocolVersion pv = CompatibilityLayer.GetMaxProtocol(m_Options.Protocol);

            preMasterSecret[0] = pv.major;
            preMasterSecret[1] = pv.minor;
            buffer             = kf.CreateKeyExchange(preMasterSecret); // public-key-encrypt the preMasterSecret
            hm.type            = HandshakeType.ClientKeyExchange;
            if (GetProtocol() == SecureProtocol.Ssl3)                   // SSL
            {
                hm.fragment = buffer;
            }
            else                 // TLS
            {
                hm.fragment = new byte[buffer.Length + 2];
                Buffer.BlockCopy(buffer, 0, hm.fragment, 2, buffer.Length);
                hm.fragment[0] = (byte)(buffer.Length / 256);                 // prepend the length of the preMasterSecret
                hm.fragment[1] = (byte)(buffer.Length % 256);
            }
            GenerateCiphers(preMasterSecret);             // generate the local ciphers
            buffer = m_RecordLayer.EncryptBytes(hm.ToBytes(), 0, hm.fragment.Length + 4, ContentType.Handshake);
            ms.Write(buffer, 0, buffer.Length);
            UpdateHashes(hm, HashUpdate.All);             // output message
            m_KeyCipher.Clear();
            m_KeyCipher = null;
            // send CertificateVerify [optional]
            if (m_MutualAuthentication && m_Options.Certificate != null)
            {
                m_CertSignHash.MasterKey = this.m_MasterSecret;
                m_CertSignHash.TransformFinalBlock(buffer, 0, 0);                 // finalize hash
                buffer         = m_CertSignHash.CreateSignature(m_Options.Certificate);
                hm.type        = HandshakeType.CertificateVerify;
                hm.fragment    = new byte[buffer.Length + 2];
                hm.fragment[0] = (byte)(buffer.Length / 256);
                hm.fragment[1] = (byte)(buffer.Length % 256);
                Buffer.BlockCopy(buffer, 0, hm.fragment, 2, buffer.Length);
                buffer = m_RecordLayer.EncryptBytes(hm.ToBytes(), 0, hm.fragment.Length + 4, ContentType.Handshake);
                ms.Write(buffer, 0, buffer.Length);
                UpdateHashes(hm, HashUpdate.LocalRemote);                 // output message
            }
            // send ChangeCipherSpec
            buffer = m_RecordLayer.EncryptBytes(new byte[] { 1 }, 0, 1, ContentType.ChangeCipherSpec);
            ms.Write(buffer, 0, buffer.Length);
            m_RecordLayer.ChangeLocalState(null, m_CipherSuite.Encryptor, m_CipherSuite.LocalHasher);

            //ExtAnswers

            if (this.serverHelloExts != null)
            {
                foreach (var extension in this.serverHelloExts)
                {
                    var responseMessage = extension.GetExtensionResponseMessage();
                    if (responseMessage != null)
                    {
                        buffer = m_RecordLayer.EncryptBytes(responseMessage.ToBytes(), 0, responseMessage.fragment.Length + 4, ContentType.Handshake);
                        ms.Write(buffer, 0, buffer.Length);
                        UpdateHashes(responseMessage, HashUpdate.LocalRemote); // output message
                    }
                }
            }

            // send Finished
            buffer = GetFinishedMessage();
            UpdateHashes(buffer, HashUpdate.Remote);             // output message
            buffer = m_RecordLayer.EncryptBytes(buffer, 0, buffer.Length, ContentType.Handshake);
            ms.Write(buffer, 0, buffer.Length);
            // send empty record [http://www.openssl.org/~bodo/tls-cbc.txt]
            if (this.m_CipherSuite.Encryptor.OutputBlockSize != 1)               // is bulk cipher?
            {
                if (((int)m_Options.Flags & (int)SecurityFlags.DontSendEmptyRecord) == 0)
                {
                    byte[] empty = m_RecordLayer.EncryptBytes(new byte[0], 0, 0, ContentType.ApplicationData);
                    ms.Write(empty, 0, empty.Length);
                }
            }
            // finalize
            buffer = ms.ToArray();
            ms.Close();
            return(new SslHandshakeStatus(SslStatus.ContinueNeeded, buffer));
        }
示例#8
0
 protected void OnReceive(IAsyncResult ar)
 {
     lock (this) {	// synchronize
         try {
             int size = m_Socket.EndReceive(ar);
             if (size == 0) {
                 CloseConnection(null); // connection has been shut down
             } else {
                 SslRecordStatus status;
                 if (m_RecordLayer == null) {
                     CompatibilityResult ret = m_Compatibility.ProcessHello(m_ReceiveBuffer, 0, size);
                     m_RecordLayer = ret.RecordLayer;
                     status = ret.Status;
                     if (m_RecordLayer != null)
                         m_Compatibility = null;
                 } else {
                     status = m_RecordLayer.ProcessBytes(m_ReceiveBuffer, 0, size);
                 }
                 if (status.Buffer != null) {
                     if (status.Status == SslStatus.Close) { // shut down the connection after the send
                         m_IsShuttingDown = true;
                     }
                     BeginSend(status.Buffer, 0, status.Buffer.Length, null, DataType.ProtocolData);
                 } else if (status.Status == SslStatus.Close) { // Record Layer instructs us to shut down
                     m_Socket.Shutdown(SocketShutdown.Both);
                     CloseConnection(null);
                 } else if (status.Status == SslStatus.OK) {
                     ResumeSending();
                 }
                 if (status.Decrypted != null)
                     ProcessDecryptedBytes(status.Decrypted);
                 if (!m_IsDisposed && !m_IsShuttingDown)
                     m_Socket.BeginReceive(m_ReceiveBuffer, 0, m_ReceiveBufferLength, SocketFlags.None, new AsyncCallback(this.OnReceive), null);
             }
         } catch (Exception e) {
             CloseConnection(e);
         }
     }
 }
示例#9
0
        public SocketController(SecureSocket parent, Socket socket, SecurityOptions options)
        {
            this.m_Parent = parent;
            this.m_Socket = socket;
            this.m_IsDisposed = false;
            this.m_ActiveSend = null;
            this.m_ActiveReceive = null;
            this.m_DecryptedBuffer = new XBuffer();
            this.m_ToSendList = new ArrayList(2);
            this.m_SentList = new ArrayList(2);
            this.m_ReceiveBuffer = new byte[m_ReceiveBufferLength];
            this.m_End = options.Entity;

            this.OnConnectionClose += parent.ConnectionCloseHandler;

            this.m_Compatibility = new CompatibilityLayer(this, options);
        }