Example #1
0
		protected override SslHandshakeStatus ProcessMessage(HandshakeMessage message) { // throws SslExceptions
			SslHandshakeStatus ret = new SslHandshakeStatus();
			switch(message.type) {
				case HandshakeType.ServerHello:
					ret = ProcessServerHello(message);
					break;
				case HandshakeType.Certificate: // optional
					ret = ProcessCertificate(message, true);
					break;
				case HandshakeType.ServerKeyExchange: // optional
					ret = ProcessServerKeyExchange(message);
					break;
				case HandshakeType.CertificateRequest: // optional
					ret = ProcessCertificateRequest(message);
					break;
				case HandshakeType.ServerHelloDone:
					ret = ProcessServerHelloDone(message);
					break;
				case HandshakeType.Finished:
					ret = ProcessFinished(message);
					break;
				case HandshakeType.HelloRequest:
					ret = ProcessHelloRequest(message);
					break;
				default:
					throw new SslException(AlertDescription.UnexpectedMessage, "The received message was not expected from a server.");
			}
			return ret;
		}
		protected override byte[] GetFinishedMessage() {
			HandshakeMessage hm = new HandshakeMessage(HandshakeType.Finished, new byte[36]);
			Ssl3HandshakeMac md5 = new Ssl3HandshakeMac(HashType.MD5, m_LocalMD5Hash, m_MasterSecret);
			Ssl3HandshakeMac sha1 = new Ssl3HandshakeMac(HashType.SHA1, m_LocalSHA1Hash, m_MasterSecret);
			md5.TransformFinalBlock(new byte[]{0x53, 0x52, 0x56, 0x52}, 0, 4);
			sha1.TransformFinalBlock(new byte[]{0x53, 0x52, 0x56, 0x52}, 0, 4);
			Array.Copy(md5.Hash, 0, hm.fragment, 0, 16);
			Array.Copy(sha1.Hash, 0, hm.fragment, 16, 20);
			md5.Clear();
			sha1.Clear();
			return hm.ToBytes();
		}
		protected override byte[] GetFinishedMessage() {
			HandshakeMessage hm = new HandshakeMessage(HandshakeType.Finished, null);
			byte[] hash = new byte[36];
			m_LocalMD5Hash.TransformFinalBlock(new byte[0], 0, 0);
			m_LocalSHA1Hash.TransformFinalBlock(new byte[0], 0, 0);
			Array.Copy(m_LocalMD5Hash.Hash, 0, hash, 0, 16);
			Array.Copy(m_LocalSHA1Hash.Hash, 0, hash, 16, 20);
			PseudoRandomDeriveBytes prf = new PseudoRandomDeriveBytes(m_MasterSecret, "client finished", hash);
			hm.fragment = prf.GetBytes(12);
			prf.Dispose();
			return hm.ToBytes();
		}
		protected override byte[] GetFinishedMessage() {
			byte[] temp, hash = new byte[36];
			m_LocalMD5Hash.TransformFinalBlock(new byte[0], 0, 0);
			m_LocalSHA1Hash.TransformFinalBlock(new byte[0], 0, 0);
			Array.Copy(m_LocalMD5Hash.Hash, 0, hash, 0, 16);
			Array.Copy(m_LocalSHA1Hash.Hash, 0, hash, 16, 20);
			PseudoRandomDeriveBytes prf = new PseudoRandomDeriveBytes(m_MasterSecret, "server finished", hash);
			HandshakeMessage hm = new HandshakeMessage(HandshakeType.Finished, prf.GetBytes(12));
			temp = hm.ToBytes();
			prf.Dispose();
			return temp;
		}
Example #5
0
		protected override SslHandshakeStatus ProcessMessage(HandshakeMessage message) { // throws SslExceptions
			SslHandshakeStatus ret;
			switch(message.type) {
				case HandshakeType.ClientHello:
					ret = ProcessClientHello(message);
					break;
				case HandshakeType.Certificate: // optional
					ret = ProcessCertificate(message, false);
					break;
				case HandshakeType.ClientKeyExchange:
					ret = ProcessClientKeyExchange(message);
					break;
				case HandshakeType.CertificateVerify: // optional
					ret = ProcessCertificateVerify(message);
					break;
				case HandshakeType.Finished:
					ret = ProcessFinished(message);
					break;
				default:
					throw new SslException(AlertDescription.UnexpectedMessage, "The received message was not expected from a client.");
			}
			return ret;
		}
Example #6
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));
        }
Example #7
0
		protected SslHandshakeStatus GetClientHelloResult() {
			MemoryStream retMessage = new MemoryStream();
			SslHandshakeStatus ret = new SslHandshakeStatus();
			HandshakeMessage temp;
			byte[] bytes;
			// ServerHello message
			temp = new HandshakeMessage(HandshakeType.ServerHello, new byte[38]);
			m_ServerTime = GetUnixTime();
			m_ServerRandom = new byte[28];
			m_RNG.GetBytes(m_ServerRandom);
			temp.fragment[0] = GetVersion().major;
			temp.fragment[1] = GetVersion().minor;
			Array.Copy(m_ServerTime, 0, temp.fragment, 2, 4);
			Array.Copy(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
			Array.Copy(CipherSuites.GetCipherAlgorithmBytes(m_EncryptionScheme), 0, temp.fragment, 35, 2);
			temp.fragment[37] = CompressionAlgorithm.GetAlgorithmByte(m_CompressionMethod);
			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);
					Array.Copy(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;
		}
Example #8
0
        protected SslHandshakeStatus ProcessCertificateRequest(HandshakeMessage message)
        {
            if (m_State == HandshakeType.ServerKeyExchange)
            {
                CipherDefinition cd = CipherSuites.GetCipherDefinition(m_EncryptionScheme);
                if (this.m_RemoteCertificate.GetPublicKeyLength() <= 512 || !cd.Exportable)
                {
                    throw new SslException(AlertDescription.HandshakeFailure, "Invalid message.");
                }
            }
            else if (m_State != HandshakeType.Certificate)
            {
                throw new SslException(AlertDescription.UnexpectedMessage, "CertificateRequest message must be preceded by a Certificate or ServerKeyExchange message.");
            }
            UpdateHashes(message, HashUpdate.All);             // input message
            // get supported certificate types
            bool supportsRsaCerts = false;

            byte[] certTypes = new byte[message.fragment[0]];             // currently we're not doing anything with the supported certificate types
            Array.Copy(message.fragment, 1, certTypes, 0, certTypes.Length);
            for (int i = 0; i < certTypes.Length; i++)
            {
                if (certTypes[i] == 1)                   // rsa_sign
                {
                    supportsRsaCerts = true;
                    break;
                }
            }
            // get list of distinguished names
            if (m_Options.RequestHandler != null && supportsRsaCerts)               // make sure the client passed a delegate
            {
                Queue q = new Queue();
                DistinguishedNameList r = new DistinguishedNameList();
                int    size, offset = message.fragment[0] + 3;
                byte[] buffer;
                while (offset < message.fragment.Length)
                {
                    size   = message.fragment[offset] * 256 + message.fragment[offset + 1];
                    buffer = new byte[size];
                    Array.Copy(message.fragment, offset + 2, buffer, 0, size);
                    q.Enqueue(buffer);
                    offset += size + 2;
                }
                // decode RDN structures
                while (q.Count > 0)
                {
                    r.Add(ProcessName((byte[])q.Dequeue()));
                }
                RequestEventArgs e = new RequestEventArgs();
                try {
                    m_Options.RequestHandler(Parent, r, e);
                    if (e.Certificate != null)
                    {
                        m_Options.Certificate = e.Certificate;
                    }
                } catch (Exception de) {
                    throw new SslException(de, AlertDescription.InternalError, "The code in the CertRequestEventHandler delegate threw an error.");
                }
            }
            if (!supportsRsaCerts)
            {
                m_Options.Certificate = null;                 // do not send client certificate
            }
            m_MutualAuthentication = true;
            return(new SslHandshakeStatus(SslStatus.MessageIncomplete, null));
        }
Example #9
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();
		}
 protected SslHandshakeStatus ProcessHelloRequest(HandshakeMessage message)
 {
     if (IsNegotiating())
         return new SslHandshakeStatus(SslStatus.OK, null); // ignore hello request
     return new SslHandshakeStatus(SslStatus.ContinueNeeded, GetClientHello());
 }
        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);
        }
 protected void UpdateHashes(HandshakeMessage message, HashUpdate update)
 {
     byte[] header = new byte[4];
     header[0] = (byte)message.type;
     header[1] = (byte)(message.fragment.Length / 65536);
     header[2] = (byte)((message.fragment.Length % 65536) / 256);
     header[3] = (byte)(message.fragment.Length % 256);
     UpdateHashes(header, update);
     UpdateHashes(message.fragment, update);
 }
 protected SslHandshakeStatus ProcessCertificateRequest(HandshakeMessage message)
 {
     if (m_State == HandshakeType.ServerKeyExchange) {
         CipherDefinition cd = CipherSuites.GetCipherDefinition(m_EncryptionScheme);
         if (this.m_RemoteCertificate.GetPublicKeyLength() <= 512 || !cd.Exportable)
             throw new SslException(AlertDescription.HandshakeFailure, "Invalid message.");
     } else if (m_State != HandshakeType.Certificate) {
         throw new SslException(AlertDescription.UnexpectedMessage, "CertificateRequest message must be preceded by a Certificate or ServerKeyExchange message.");
     }
     UpdateHashes(message, HashUpdate.All); // input message
     // get supported certificate types
     bool supportsRsaCerts = false;
     byte[] certTypes = new byte[message.fragment[0]]; // currently we're not doing anything with the supported certificate types
     Buffer.BlockCopy(message.fragment, 1, certTypes, 0, certTypes.Length);
     for(int i = 0; i < certTypes.Length; i++) {
         if (certTypes[i] == 1) { // rsa_sign
             supportsRsaCerts = true;
             break;
         }
     }
     // get list of distinguished names
     if (m_Options.RequestHandler != null && supportsRsaCerts) { // make sure the client passed a delegate
         Queue q = new Queue();
         DistinguishedNameList r = new DistinguishedNameList();
         int size, offset = message.fragment[0] + 3;
         byte[] buffer;
         while(offset < message.fragment.Length) {
             size = message.fragment[offset] * 256 + message.fragment[offset + 1];
             buffer = new byte[size];
             Buffer.BlockCopy(message.fragment, offset + 2, buffer, 0, size);
             q.Enqueue(buffer);
             offset += size + 2;
         }
         // decode RDN structures
         while(q.Count > 0) {
             r.Add(ProcessName((byte[])q.Dequeue()));
         }
         RequestEventArgs e = new RequestEventArgs();
         try {
             m_Options.RequestHandler(Parent, r, e);
             if (e.Certificate != null)
                 m_Options.Certificate = e.Certificate;
         } catch (Exception de) {
             throw new SslException(de, AlertDescription.InternalError, "The code in the CertRequestEventHandler delegate threw an error.");
         }
     }
     if (!supportsRsaCerts)
         m_Options.Certificate = null; // do not send client certificate
     m_MutualAuthentication = true;
     return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
 }
 protected SslHandshakeStatus ProcessCertificate(HandshakeMessage message, bool client)
 {
     if (client) {
         if (m_State != HandshakeType.ServerHello)
             throw new SslException(AlertDescription.UnexpectedMessage, "Certificate message must be preceded by a ServerHello message.");
     } else { // server
         if (m_State != HandshakeType.ClientHello)
             throw new SslException(AlertDescription.UnexpectedMessage, "Certificate message must be preceded by a ClientHello message.");
     }
     UpdateHashes(message, HashUpdate.All); // input message
     Certificate[] certs = null;
     try {
         certs = ParseCertificateList(message.fragment);
         if (certs.Length == 0) {
             if (!m_MutualAuthentication)
                 return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
         }
     } catch (SslException t) {
         throw t;
     } catch (Exception f) {
         throw new SslException(f, AlertDescription.InternalError, "The Certificate message is invalid.");
     }
     CertificateChain chain = null;
     m_RemoteCertificate = null;
     if (certs.Length != 0) {
         m_RemoteCertificate = certs[0];
         if (m_RemoteCertificate.GetPublicKeyLength() < 512) {
             throw new SslException(AlertDescription.HandshakeFailure, "The pulic key should be at least 512 bits.");
         }
         CertificateStore cs = new CertificateStore(certs);
         for(int i = 0; i < certs.Length; i++) {
             certs[i].Store = cs;
         }
         chain = new CertificateChain(m_RemoteCertificate, cs);
     }
     VerifyChain(chain, client);
     return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
 }
Example #15
0
        protected SslHandshakeStatus GetClientHelloResult()
        {
            MemoryStream       retMessage = new MemoryStream();
            SslHandshakeStatus ret        = new SslHandshakeStatus();
            HandshakeMessage   temp;

            byte[] bytes;
            // ServerHello message
            temp           = new HandshakeMessage(HandshakeType.ServerHello, new byte[38]);
            m_ServerTime   = GetUnixTime();
            m_ServerRandom = new byte[28];
            m_RNG.GetBytes(m_ServerRandom);
            temp.fragment[0] = GetVersion().major;
            temp.fragment[1] = GetVersion().minor;
            Array.Copy(m_ServerTime, 0, temp.fragment, 2, 4);
            Array.Copy(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
            Array.Copy(CipherSuites.GetCipherAlgorithmBytes(m_EncryptionScheme), 0, temp.fragment, 35, 2);
            temp.fragment[37] = CompressionAlgorithm.GetAlgorithmByte(m_CompressionMethod);
            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);
                    Array.Copy(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);
        }
Example #16
0
		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);
		}
        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);
        }
Example #18
0
		protected SslHandshakeStatus ProcessServerHello(HandshakeMessage message) {
			if (m_State != HandshakeType.ClientHello && m_State != HandshakeType.HelloRequest)
				throw new SslException(AlertDescription.UnexpectedMessage, "ServerHello message must be preceded by a ClientHello message.");
			UpdateHashes(message, HashUpdate.All); // input message
			if (message.fragment.Length < 2 || message.fragment[0] != GetVersion().major || message.fragment[1] != GetVersion().minor)
				throw new SslException(AlertDescription.IllegalParameter, "Unknown protocol version of the client.");
			try {
				// extract the time from the client [== 1 uint]
				m_ServerTime = new byte[4];
				Array.Copy(message.fragment, 2, m_ServerTime, 0, 4);
				// extract the random bytes [== 28 bytes]
				m_ServerRandom = new byte[28];
				Array.Copy(message.fragment, 6, m_ServerRandom, 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 selected cipher suite
				m_EncryptionScheme = CipherSuites.GetCipherAlgorithmType(message.fragment, 35 + length);
				// extract the selected compression method
				m_CompressionMethod = CompressionAlgorithm.GetCompressionAlgorithmType(message.fragment, 37 + length);
			} catch (Exception e) {
				throw new SslException(e, AlertDescription.InternalError, "The message is invalid.");
			}
			return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
		}
 protected abstract SslHandshakeStatus ProcessMessage(HandshakeMessage message);
Example #20
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);
		}
        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);
        }
Example #22
0
		protected SslHandshakeStatus ProcessCertificateVerify(HandshakeMessage message) {
			if (m_State != HandshakeType.ClientKeyExchange)
				throw new SslException(AlertDescription.UnexpectedMessage, "CertificateVerify message must be preceded by a ClientKeyExchange message.");
			UpdateHashes(message, HashUpdate.LocalRemote);
			byte[] signature;
			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 CertificateVerify message.");
				signature = new byte[message.fragment.Length - 2];
				Array.Copy(message.fragment, 2, signature, 0, signature.Length);
			} else {
				signature = message.fragment;
			}
			m_CertSignHash.MasterKey = this.m_MasterSecret;
			m_CertSignHash.TransformFinalBlock(signature, 0, 0); // finalize hash
			if (!m_CertSignHash.VerifySignature(m_RemoteCertificate, signature))
				throw new SslException(AlertDescription.CertificateUnknown, "The signature in the CertificateVerify message is invalid.");
			return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
		}
        protected SslHandshakeStatus ProcessFinished(HandshakeMessage message)
        {
            if (m_State != HandshakeType.ChangeCipherSpec)
                throw new SslException(AlertDescription.UnexpectedMessage, "Finished message must be preceded by a ChangeCipherSpec message.");
            // check hash received from client
            this.VerifyFinishedMessage(message.fragment);
            m_IsNegotiating = false;

            if (this.OnHandshakeFinished != null)
                this.OnHandshakeFinished(this, null);

            ClearHandshakeStructures();
            return new SslHandshakeStatus(SslStatus.OK, null);
        }
Example #24
0
		protected SslHandshakeStatus ProcessFinished(HandshakeMessage message) {
			if (m_State != HandshakeType.ChangeCipherSpec)
				throw new SslException(AlertDescription.UnexpectedMessage, "Finished message must be preceded by a ChangeCipherSpec message.");
			byte[] temp;
			// check hash received from client
			VerifyFinishedMessage(message.fragment);
			// send ChangeCipherSpec
			UpdateHashes(message, HashUpdate.Local);
			MemoryStream ms = new MemoryStream();
			temp = m_RecordLayer.EncryptBytes(new byte[]{1}, 0, 1, ContentType.ChangeCipherSpec);
			ms.Write(temp, 0, temp.Length);
			m_RecordLayer.ChangeLocalState(null, m_CipherSuite.Encryptor, m_CipherSuite.LocalHasher);
			// send Finished message
			temp = GetFinishedMessage();
			temp = m_RecordLayer.EncryptBytes(temp, 0, temp.Length, ContentType.Handshake);
			ms.Write(temp, 0, temp.Length);
			m_State = HandshakeType.Nothing;
			// 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
			byte[] ret = ms.ToArray();
			ms.Close();
			m_IsNegotiating = false;
			ClearHandshakeStructures();
			return new SslHandshakeStatus(SslStatus.OK, ret);
		}
        protected SslHandshakeStatus ProcessServerHello(HandshakeMessage message)
        {
            if (m_State != HandshakeType.ClientHello && m_State != HandshakeType.HelloRequest)
                throw new SslException(AlertDescription.UnexpectedMessage, "ServerHello message must be preceded by a ClientHello message.");

            UpdateHashes(message, HashUpdate.All); // input message

            //Violation with tls spec. If remote side uses higher protocol version than your, then we must answer with your highest version
            //if (message.fragment.Length < 2 || message.fragment[0] != GetVersion().major || message.fragment[1] != GetVersion().minor)
                //throw new SslException(AlertDescription.IllegalParameter, "Unknown protocol version of the client.");

            int currentProcessedLen = 2;
            try {
                // extract the time from the client [== 1 uint]
                m_ServerTime = new byte[4];
                Buffer.BlockCopy(message.fragment, currentProcessedLen, m_ServerTime, 0, 4);
                currentProcessedLen += 4;

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

                // extact the session ID [== 0..32 bytes]
                int length = message.fragment[currentProcessedLen++];
                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, currentProcessedLen, m_SessionID, 0, length);
                currentProcessedLen += length;

                // extract the selected cipher suite
                m_EncryptionScheme = CipherSuites.GetCipherAlgorithmType(message.fragment, currentProcessedLen);
                currentProcessedLen += 2;

                // extract the selected compression method
                m_CompressionMethod = CompressionAlgorithm.GetCompressionAlgorithmType(message.fragment, currentProcessedLen++);
            }
            catch (Exception e)
            {
                throw new SslException(e, AlertDescription.InternalError, "The message is invalid.");
            }

            if (message.fragment.Length == currentProcessedLen)
                return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);

            this.ProcessExtensions(message.fragment, ref currentProcessedLen, ConnectionEnd.Client);

            return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
        }
Example #26
0
		protected override byte[] GetRenegotiateBytes() {
			if (IsNegotiating())
				return null;
			HandshakeMessage hm = new HandshakeMessage(HandshakeType.HelloRequest, new byte[0]);
			return m_RecordLayer.EncryptBytes(hm.ToBytes(), 0, 4, ContentType.Handshake);
		}
 protected SslHandshakeStatus ProcessServerKeyExchange(HandshakeMessage message)
 {
     if (m_State != HandshakeType.Certificate)
         throw new SslException(AlertDescription.UnexpectedMessage, "ServerKeyExchange message must be preceded by a Certificate message.");
     CipherDefinition cd = CipherSuites.GetCipherDefinition(m_EncryptionScheme);
     if (!cd.Exportable)
         throw new SslException(AlertDescription.HandshakeFailure, "The ServerKeyExchange message should not be sent for non-exportable ciphers.");
     if (m_RemoteCertificate.GetPublicKeyLength() <= 512)
         throw new SslException(AlertDescription.HandshakeFailure, "The ServerKeyExchange message should not be sent because the server certificate public key is of exportable length.");
     UpdateHashes(message, HashUpdate.All); // input message
     // extract modulus and exponent
     RSAParameters pars = new RSAParameters();
     int size = message.fragment[0] * 256 + message.fragment[1];
     pars.Modulus = new byte[size];
     Buffer.BlockCopy(message.fragment, 2, pars.Modulus, 0, size);
     int offset = size + 2;
     size = message.fragment[offset] * 256 + message.fragment[offset + 1];
     pars.Exponent = new byte[size];
     Buffer.BlockCopy(message.fragment, offset + 2, pars.Exponent, 0, size);
     offset += size + 2;
     pars.Modulus = RemoveLeadingZeros(pars.Modulus);
     pars.Exponent = RemoveLeadingZeros(pars.Exponent);
     m_KeyCipher = new RSACryptoServiceProvider();
     m_KeyCipher.ImportParameters(pars);
     // compute verification hashes
     MD5SHA1CryptoServiceProvider ms = new MD5SHA1CryptoServiceProvider();
     ms.TransformBlock(m_ClientTime, 0, m_ClientTime.Length, m_ClientTime, 0);
     ms.TransformBlock(m_ClientRandom, 0, m_ClientRandom.Length, m_ClientRandom, 0);
     ms.TransformBlock(m_ServerTime, 0, m_ServerTime.Length, m_ServerTime, 0);
     ms.TransformBlock(m_ServerRandom, 0, m_ServerRandom.Length, m_ServerRandom, 0);
     ms.TransformFinalBlock(message.fragment, 0, offset);
     // verify the signature
     size = message.fragment[offset] * 256 + message.fragment[offset + 1];
     byte[] signature = new byte[size]; // holds the signature returned by the server
     Buffer.BlockCopy(message.fragment, offset + 2, signature, 0, size);
     if (!ms.VerifySignature(m_RemoteCertificate, signature))
         throw new SslException(AlertDescription.HandshakeFailure, "The data was not signed by the server certificate.");
     ms.Clear();
     return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
 }
Example #28
0
 protected abstract SslHandshakeStatus ProcessMessage(HandshakeMessage message);