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 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)); }
public void ChangeRemoteState(CompressionAlgorithm decompressor, ICryptoTransform decryptor, KeyedHashAlgorithm remoteHasher) { m_RemoteCompressor = decompressor; m_BulkDecryption = decryptor; m_RemoteHasher = remoteHasher; m_InputSequenceNumber = 0; }
public void ChangeLocalState(CompressionAlgorithm compressor, ICryptoTransform encryptor, KeyedHashAlgorithm localHasher) { m_LocalCompressor = compressor; m_BulkEncryption = encryptor; m_LocalHasher = localHasher; m_OutputSequenceNumber = 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 //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)); }
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 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 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); }
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)); }