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