예제 #1
0
		public RecordMessage(MessageType messageType, ContentType contentType, ProtocolVersion version, byte[] bytes) {
			this.messageType = messageType;
			this.contentType = contentType;
			this.version = version;
			if (bytes != null)
				this.fragment = bytes;
			else
				this.fragment = new byte[0];
			this.length = (ushort)this.fragment.Length;
		}
예제 #2
0
 public RecordMessage(byte[] bytes, int offset)
 {
     if (bytes == null)
         throw new ArgumentNullException();
     if (offset < 0 || offset >= bytes.Length)
         throw new ArgumentException();
     this.messageType = MessageType.Encrypted;
     this.contentType = (ContentType)bytes[offset];
     this.version = new ProtocolVersion(bytes[offset + 1], bytes[offset + 2]);
     this.length = (ushort)(bytes[offset + 3] * 256 + bytes[offset + 4]);
     this.fragment = new byte[this.length];
     Buffer.BlockCopy(bytes, offset + 5, this.fragment, 0, this.length);
 }
예제 #3
0
		private CompatibilityResult ProcessServerHello(byte[] bytes, int offset, int size) {
			byte[] temp = new byte[m_Buffer.Length + size];
			Array.Copy(m_Buffer, 0, temp, 0, m_Buffer.Length);
			Array.Copy(bytes, offset, temp, m_Buffer.Length, size);
			if (IsInvalidSsl3Hello(temp))
				throw new SslException(AlertDescription.HandshakeFailure, "The server hello message uses a protocol that was not recognized.");
			if (m_Buffer.Length + size < 11) { // not enough bytes
				m_Buffer = temp;
				return new CompatibilityResult(null, new SslRecordStatus(SslStatus.MessageIncomplete, null, null));
			}
			ProtocolVersion pv = new ProtocolVersion(temp[9], temp[10]);
			if (SupportsProtocol(m_Options.Protocol, pv)) {
				if (m_MinLayer.HandshakeLayer.GetVersion().GetVersionInt() != pv.GetVersionInt()) {
					if (pv.GetVersionInt() == 30) { // SSL 3.0
						m_MinLayer.HandshakeLayer = new Ssl3ClientHandshakeLayer(m_MinLayer.HandshakeLayer);
					} else { // TLS 1.0
						m_MinLayer.HandshakeLayer = new Tls1ClientHandshakeLayer(m_MinLayer.HandshakeLayer);
					}
				}
				return new CompatibilityResult(m_MinLayer, m_MinLayer.ProcessBytes(temp, 0, temp.Length));
			} else {
				throw new SslException(AlertDescription.HandshakeFailure, "The client and server could not agree on the protocol version to use.");
			}
		}
예제 #4
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.");
			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();
		}
예제 #5
0
		// 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();
		}
예제 #6
0
        public CompatibilityLayer(SocketController controller, SecurityOptions options)
        {
            m_Buffer = new byte[0];
            m_MinVersion = GetMinProtocol(options.Protocol);
            m_MaxVersion = GetMaxProtocol(options.Protocol);

            this.handshakeMonitor = new SslTlsHandshakeMonitor();

            HandshakeLayer layer = null;
            if (m_MinVersion.GetVersionInt() == 30)
            { // SSL 3.0
                if (options.Entity == ConnectionEnd.Client)
                {
                    layer = new Ssl3ClientHandshakeLayer(null, options);
                    m_MinLayer = new RecordLayer(controller, layer as ClientHandshakeLayer);

                    this.handshakeMonitor.Attach(controller.Parent, layer as ClientHandshakeLayer);
                }
                else
                {
                    layer = new Ssl3ServerHandshakeLayer(null, options);
                    m_MinLayer = new RecordLayer(controller, layer as ServerHandshakeLayer);

                    this.handshakeMonitor.Attach(controller.Parent, layer as ServerHandshakeLayer);
                }
            }
            else
            { // TLS 1.0
                if (options.Entity == ConnectionEnd.Client)
                {
                    layer = new Tls1ClientHandshakeLayer(null, options);
                    m_MinLayer = new RecordLayer(controller, layer as ClientHandshakeLayer);

                    this.handshakeMonitor.Attach(controller.Parent, layer as ClientHandshakeLayer);
                }
                else
                {
                    layer = new Tls1ServerHandshakeLayer(null, options);
                    m_MinLayer = new RecordLayer(controller, layer as ServerHandshakeLayer);

                    this.handshakeMonitor.Attach(controller.Parent, layer as ServerHandshakeLayer);
                }
               }

            m_MinLayer.HandshakeLayer.RecordLayer = m_MinLayer;
            m_Options = options;
        }
예제 #7
0
        private CompatibilityResult ProcessClientHello(byte[] bytes, int offset, int size)
        {
            byte[] temp = new byte[m_Buffer.Length + size];
            Buffer.BlockCopy(m_Buffer, 0, temp, 0, m_Buffer.Length);
            Buffer.BlockCopy(bytes, offset, temp, m_Buffer.Length, size);
            if (IsInvalidSsl3Hello(temp) && IsInvalidSsl2Hello(temp)) // SSL2 hello
                throw new SslException(AlertDescription.HandshakeFailure, "The client hello message uses a protocol that was not recognized.");
            if (m_Buffer.Length + bytes.Length < 11 || (IsInvalidSsl3Hello(temp) && !IsSsl2HelloComplete(temp))) { // not enough bytes
                m_Buffer = temp;
                return new CompatibilityResult(null, new SslRecordStatus(SslStatus.MessageIncomplete, null, null));
            }
            ProtocolVersion pv;
            if (!IsInvalidSsl3Hello(temp))
                pv = new ProtocolVersion(temp[9], temp[10]);
            else
                pv = ExtractSsl2Version(temp);

            if (pv.GetVersionInt() > m_MaxVersion.GetVersionInt())
                pv = m_MaxVersion;
            if (SupportsProtocol(m_Options.Protocol, pv)) {
                if (m_MinLayer.HandshakeLayer.GetVersion().GetVersionInt() != pv.GetVersionInt()) {
                    if (pv.GetVersionInt() == 30) { // SSL 3.0
                        m_MinLayer.HandshakeLayer = new Ssl3ServerHandshakeLayer(m_MinLayer.HandshakeLayer);
                    } else { // TLS 1.0
                        m_MinLayer.HandshakeLayer = new Tls1ServerHandshakeLayer(m_MinLayer.HandshakeLayer);
                    }
                }
                if (!IsInvalidSsl3Hello(temp)) {
                    return new CompatibilityResult(m_MinLayer, m_MinLayer.ProcessBytes(temp, 0, temp.Length));
                } else {
                    return new CompatibilityResult(m_MinLayer, m_MinLayer.ProcessSsl2Hello(ExtractSsl2Content(temp)));
                }
            } else {
                throw new SslException(AlertDescription.HandshakeFailure, "The client and server could not agree on the protocol version to use.");
            }
        }
예제 #8
0
 public static bool SupportsProtocol(SecureProtocol protocol, ProtocolVersion pv)
 {
     if (pv.GetVersionInt() == 30)
         return SupportsSsl3(protocol);
     else
         return SupportsTls1(protocol);
 }
예제 #9
0
 public ServerHandshakeLayer(HandshakeLayer handshakeLayer)
     : base(handshakeLayer)
 {
     m_MaxClientVersion = ((ServerHandshakeLayer)handshakeLayer).m_MaxClientVersion;
 }
예제 #10
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);
        }
예제 #11
0
 public ServerHandshakeLayer(HandshakeLayer handshakeLayer)
     : base(handshakeLayer)
 {
     m_MaxClientVersion = ((ServerHandshakeLayer)handshakeLayer).m_MaxClientVersion;
     this.serverHelloExts = m_Options.ExtensionList;
 }
예제 #12
0
        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];
                Array.Copy(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);
                Array.Copy(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);
            // 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));
        }