protected SslHandshakeStatus ProcessClientKeyExchange(HandshakeMessage message)
 {
     if (!(this.m_MutualAuthentication ? m_State == HandshakeType.Certificate : m_State == HandshakeType.ClientHello))
     {
         throw new SslException(AlertDescription.UnexpectedMessage, "ClientKeyExchange message must be preceded by a ClientHello or Certificate message.");
     }
     byte[] preMasterSecret;
     UpdateHashes(message, HashUpdate.All);             // input message
     try {
         if (message.fragment.Length % 8 == 2)          // check whether the length is prepended or not
         {
             if (message.fragment[0] * 256 + message.fragment[1] != message.fragment.Length - 2)
             {
                 throw new SslException(AlertDescription.DecodeError, "Invalid ClientKeyExchange message.");
             }
             preMasterSecret = new byte[message.fragment.Length - 2];
             Array.Copy(message.fragment, 2, preMasterSecret, 0, preMasterSecret.Length);
             message.fragment = preMasterSecret;
         }
         RSAKeyTransform df = new RSAKeyTransform(m_KeyCipher);
         preMasterSecret = df.DecryptKeyExchange(message.fragment);
         if (preMasterSecret.Length != 48)
         {
             throw new SslException(AlertDescription.IllegalParameter, "Invalid message.");
         }
         if (((int)m_Options.Flags & (int)SecurityFlags.IgnoreMaxProtocol) == 0)
         {
             if (preMasterSecret[0] != m_MaxClientVersion.major || preMasterSecret[1] != m_MaxClientVersion.minor)
             {
                 throw new SslException(AlertDescription.IllegalParameter, "Version rollback detected.");
             }
         }
         else
         {
             if (preMasterSecret[0] != 3 || (preMasterSecret[1] != 0 && preMasterSecret[1] != 1))
             {
                 throw new SslException(AlertDescription.IllegalParameter, "Invalid protocol version detected.");
             }
         }
         m_KeyCipher.Clear();
         m_KeyCipher = null;
     } catch {
         // this is to avoid RSA PKCS#1 padding attacks
         // and the Klima-Pokorny-Rosa attack on RSA in SSL/TLS
         preMasterSecret = new byte[48];
         m_RNG.GetBytes(preMasterSecret);
     }
     GenerateCiphers(preMasterSecret);
     return(new SslHandshakeStatus(SslStatus.MessageIncomplete, null));
 }
예제 #2
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];
                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);
        }
예제 #3
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];
                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));
        }
예제 #4
0
		protected SslHandshakeStatus ProcessClientKeyExchange(HandshakeMessage message) {
			if (!(this.m_MutualAuthentication ? m_State == HandshakeType.Certificate : m_State == HandshakeType.ClientHello))
				throw new SslException(AlertDescription.UnexpectedMessage, "ClientKeyExchange message must be preceded by a ClientHello or Certificate message.");
			byte[] preMasterSecret;
			UpdateHashes(message, HashUpdate.All); // input message
			try {
				if (message.fragment.Length % 8 == 2) { // check whether the length is prepended or not
					if (message.fragment[0] * 256 + message.fragment[1] != message.fragment.Length - 2)
						throw new SslException(AlertDescription.DecodeError, "Invalid ClientKeyExchange message.");
					preMasterSecret = new byte[message.fragment.Length - 2];
					Array.Copy(message.fragment, 2, preMasterSecret, 0, preMasterSecret.Length);
					message.fragment = preMasterSecret;
				}
				RSAKeyTransform df = new RSAKeyTransform(m_KeyCipher);
				preMasterSecret = df.DecryptKeyExchange(message.fragment);
				if (preMasterSecret.Length != 48)
					throw new SslException(AlertDescription.IllegalParameter, "Invalid message.");
				if (((int)m_Options.Flags & (int)SecurityFlags.IgnoreMaxProtocol) == 0) {
					if (preMasterSecret[0] != m_MaxClientVersion.major || preMasterSecret[1] != m_MaxClientVersion.minor)
						throw new SslException(AlertDescription.IllegalParameter, "Version rollback detected.");
				} else {
					if (preMasterSecret[0] != 3 || (preMasterSecret[1] != 0 && preMasterSecret[1] != 1))
						throw new SslException(AlertDescription.IllegalParameter, "Invalid protocol version detected.");
				}
				m_KeyCipher.Clear();
				m_KeyCipher = null;
			} catch {
				// this is to avoid RSA PKCS#1 padding attacks
				// and the Klima-Pokorny-Rosa attack on RSA in SSL/TLS
				preMasterSecret = new byte[48];
				m_RNG.GetBytes(preMasterSecret);
			}
			GenerateCiphers(preMasterSecret);
			return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
		}