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 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)); }
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)); }