public override void ComputeKeys() { // Compute KeyBlock TlsStream tmp = new TlsStream(); char labelChar = 'A'; int count = 1; while (tmp.Length < this.KeyBlockSize) { string label = String.Empty; for (int i = 0; i < count; i++) { label += labelChar.ToString(); } byte[] block = this.prf(this.Context.MasterSecret, label.ToString(), this.Context.RandomSC); int size = (tmp.Length + block.Length) > this.KeyBlockSize ? (this.KeyBlockSize - (int)tmp.Length) : block.Length; tmp.Write(block, 0, size); labelChar++; count++; } // Create keyblock TlsStream keyBlock = new TlsStream(tmp.ToArray()); this.Context.Negotiating.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.Negotiating.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); if (!this.IsExportable) { if (this.IvSize != 0) { this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize); this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } else { HashAlgorithm md5 = MD5.Create(); int keySize = (md5.HashSize >> 3); //in bytes not bits byte[] temp = new byte [keySize]; // Generate final write keys md5.TransformBlock(this.Context.ClientWriteKey, 0, this.Context.ClientWriteKey.Length, temp, 0); md5.TransformFinalBlock(this.Context.RandomCS, 0, this.Context.RandomCS.Length); byte[] finalClientWriteKey = new byte[this.ExpandedKeyMaterialSize]; Buffer.BlockCopy(md5.Hash, 0, finalClientWriteKey, 0, this.ExpandedKeyMaterialSize); md5.Initialize(); md5.TransformBlock(this.Context.ServerWriteKey, 0, this.Context.ServerWriteKey.Length, temp, 0); md5.TransformFinalBlock(this.Context.RandomSC, 0, this.Context.RandomSC.Length); byte[] finalServerWriteKey = new byte[this.ExpandedKeyMaterialSize]; Buffer.BlockCopy(md5.Hash, 0, finalServerWriteKey, 0, this.ExpandedKeyMaterialSize); this.Context.ClientWriteKey = finalClientWriteKey; this.Context.ServerWriteKey = finalServerWriteKey; // Generate IV keys if (this.IvSize > 0) { md5.Initialize(); temp = md5.ComputeHash(this.Context.RandomCS, 0, this.Context.RandomCS.Length); this.Context.ClientWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(temp, 0, this.Context.ClientWriteIV, 0, this.IvSize); md5.Initialize(); temp = md5.ComputeHash(this.Context.RandomSC, 0, this.Context.RandomSC.Length); this.Context.ServerWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(temp, 0, this.Context.ServerWriteIV, 0, this.IvSize); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } DebugHelper.WriteLine(">>>> KeyBlock", keyBlock.ToArray()); DebugHelper.WriteLine(">>>> ClientWriteKey", this.Context.ClientWriteKey); DebugHelper.WriteLine(">>>> ClientWriteIV", this.Context.ClientWriteIV); DebugHelper.WriteLine(">>>> ClientWriteMAC", this.Context.Negotiating.ClientWriteMAC); DebugHelper.WriteLine(">>>> ServerWriteKey", this.Context.ServerWriteKey); DebugHelper.WriteLine(">>>> ServerWriteIV", this.Context.ServerWriteIV); DebugHelper.WriteLine(">>>> ServerWriteMAC", this.Context.Negotiating.ServerWriteMAC); ClientSessionCache.SetContextInCache(this.Context); // Clear no more needed data keyBlock.Reset(); tmp.Reset(); }
internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult) { this.protocol.EndSendRecord(asyncResult); // Read server response while (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone) { // Read next record SafeReceiveRecord(this.innerStream); // special case for abbreviated handshake where no ServerHelloDone is sent from the server if (this.context.AbbreviatedHandshake && (this.context.LastHandshakeMsg == HandshakeType.ServerHello)) { break; } } // the handshake is much easier if we can reuse a previous session settings if (this.context.AbbreviatedHandshake) { ClientSessionCache.SetContextFromCache(this.context); this.context.Negotiating.Cipher.ComputeKeys(); this.context.Negotiating.Cipher.InitializeCipher(); // Send Cipher Spec protocol this.protocol.SendChangeCipherSpec(); // Read record until server finished is received while (this.context.HandshakeState != HandshakeState.Finished) { // If all goes well this will process messages: // Change Cipher Spec // Server finished SafeReceiveRecord(this.innerStream); } // Send Finished message this.protocol.SendRecord(HandshakeType.Finished); } else { // Send client certificate if requested // even if the server ask for it it _may_ still be optional bool clientCertificate = this.context.ServerSettings.CertificateRequest; // NOTE: sadly SSL3 and TLS1 differs in how they handle this and // the current design doesn't allow a very cute way to handle // SSL3 alert warning for NoCertificate (41). if (this.context.SecurityProtocol == SecurityProtocolType.Ssl3) { clientCertificate = ((this.context.ClientSettings.Certificates != null) && (this.context.ClientSettings.Certificates.Count > 0)); // this works well with OpenSSL (but only for SSL3) } if (clientCertificate) { this.protocol.SendRecord(HandshakeType.Certificate); } // Send Client Key Exchange this.protocol.SendRecord(HandshakeType.ClientKeyExchange); // Now initialize session cipher with the generated keys this.context.Negotiating.Cipher.InitializeCipher(); // Send certificate verify if requested (optional) if (clientCertificate && (this.context.ClientSettings.ClientCertificate != null)) { this.protocol.SendRecord(HandshakeType.CertificateVerify); } // Send Cipher Spec protocol this.protocol.SendChangeCipherSpec(); // Send Finished message this.protocol.SendRecord(HandshakeType.Finished); // Read record until server finished is received while (this.context.HandshakeState != HandshakeState.Finished) { // If all goes well this will process messages: // Change Cipher Spec // Server finished SafeReceiveRecord(this.innerStream); } } // Reset Handshake messages information this.context.HandshakeMessages.Reset(); // Clear Key Info this.context.ClearKeyInfo(); }
public override void ComputeKeys() { // Create keyblock TlsStream keyBlock = new TlsStream( this.PRF( this.Context.MasterSecret, "key expansion", this.Context.RandomSC, this.KeyBlockSize)); this.Context.Negotiating.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.Negotiating.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); if (!this.IsExportable) { if (this.IvSize != 0) { this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize); this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } else { // Generate final write keys byte[] finalClientWriteKey = PRF(this.Context.ClientWriteKey, "client write key", this.Context.RandomCS, this.ExpandedKeyMaterialSize); byte[] finalServerWriteKey = PRF(this.Context.ServerWriteKey, "server write key", this.Context.RandomCS, this.ExpandedKeyMaterialSize); this.Context.ClientWriteKey = finalClientWriteKey; this.Context.ServerWriteKey = finalServerWriteKey; if (this.IvSize > 0) { // Generate IV block byte[] ivBlock = PRF(CipherSuite.EmptyArray, "IV block", this.Context.RandomCS, this.IvSize * 2); // Generate IV keys this.Context.ClientWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length); this.Context.ServerWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.Length); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } DebugHelper.WriteLine(">>>> KeyBlock", keyBlock.ToArray()); DebugHelper.WriteLine(">>>> ClientWriteKey", this.Context.ClientWriteKey); DebugHelper.WriteLine(">>>> ClientWriteIV", this.Context.ClientWriteIV); DebugHelper.WriteLine(">>>> ClientWriteMAC", this.Context.Negotiating.ClientWriteMAC); DebugHelper.WriteLine(">>>> ServerWriteKey", this.Context.ServerWriteKey); DebugHelper.WriteLine(">>>> ServerWriteIV", this.Context.ServerWriteIV); DebugHelper.WriteLine(">>>> ServerWriteMAC", this.Context.Negotiating.ServerWriteMAC); ClientSessionCache.SetContextInCache(this.Context); // Clear no more needed data keyBlock.Reset(); }