-/* Transport Security Layer (TLS)
- * Copyright (c) 2003 Carlos Guzmán Álvarez
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
+// Transport Security Layer (TLS)
+// Copyright (c) 2003-2004 Carlos Guzman Alvarez
+// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
using System;
using System.IO;
-using System.Text;
using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-
-using Mono.Security;
-using Mono.Security.Cryptography;
namespace Mono.Security.Protocol.Tls
{
- internal class TlsCipherSuite : TlsAbstractCipherSuite
+ internal class TlsCipherSuite : CipherSuite
{
- #region CONSTRUCTORS
+ private const int MacHeaderLength = 13;
+ private byte[] header;
+
+ #region Constructors
- public TlsCipherSuite(short code, string name, string algName,
- string hashName, bool exportable, bool blockMode,
- byte keyMaterialSize, byte expandedKeyMaterialSize,
- short effectiveKeyBytes, byte ivSize, byte blockSize)
- : base (code, name, algName, hashName, exportable, blockMode,
- keyMaterialSize, expandedKeyMaterialSize, effectiveKeyBytes,
- ivSize, blockSize)
+ public TlsCipherSuite(
+ short code, string name, CipherAlgorithmType cipherAlgorithmType,
+ HashAlgorithmType hashAlgorithmType, ExchangeAlgorithmType exchangeAlgorithmType,
+ bool exportable, bool blockMode, byte keyMaterialSize,
+ byte expandedKeyMaterialSize, short effectiveKeyBytes,
+ byte ivSize, byte blockSize)
+ :base(code, name, cipherAlgorithmType, hashAlgorithmType,
+ exchangeAlgorithmType, exportable, blockMode, keyMaterialSize,
+ expandedKeyMaterialSize, effectiveKeyBytes, ivSize, blockSize)
{
}
#endregion
- #region METHODS
+ #region MAC Generation Methods
- public override byte[] EncryptRecord(byte[] fragment, byte[] mac)
+ public override byte[] ComputeServerRecordMAC(ContentType contentType, byte[] fragment)
{
- // Encryption ( fragment + mac [+ padding + padding_length] )
- MemoryStream ms = new MemoryStream();
- CryptoStream cs = new CryptoStream(ms, encryptionCipher, CryptoStreamMode.Write);
-
- cs.Write(fragment, 0, fragment.Length);
- cs.Write(mac, 0, mac.Length);
- if (cipherMode == CipherMode.CBC)
- {
- // Calculate padding_length
- int fragmentLength = fragment.Length + mac.Length + 1;
- int paddingLength = (((fragmentLength/blockSize)*blockSize) + blockSize) - fragmentLength;
-
- // Write padding length byte
- cs.WriteByte((byte)paddingLength);
- }
- //cs.FlushFinalBlock();
- cs.Close();
-
- return ms.ToArray();
+ if (header == null)
+ header = new byte [MacHeaderLength];
+
+ ulong seqnum = (Context is ClientContext) ? Context.ReadSequenceNumber : Context.WriteSequenceNumber;
+ Write (header, 0, seqnum);
+ header [8] = (byte) contentType;
+ Write (header, 9, this.Context.Protocol);
+ Write (header, 11, (short)fragment.Length);
+
+ HashAlgorithm mac = this.ServerHMAC;
+ mac.TransformBlock (header, 0, header.Length, header, 0);
+ mac.TransformBlock (fragment, 0, fragment.Length, fragment, 0);
+ // hack, else the method will allocate a new buffer of the same length (negative half the optimization)
+ mac.TransformFinalBlock (CipherSuite.EmptyArray, 0, 0);
+ return mac.Hash;
}
- public override void DecryptRecord(byte[] fragment, ref byte[] dcrFragment, ref byte[] dcrMAC)
+ public override byte[] ComputeClientRecordMAC(ContentType contentType, byte[] fragment)
{
- int fragmentSize = 0;
- int paddingLength = 0;
-
- // Decrypt message fragment ( fragment + mac [+ padding + padding_length] )
- byte[] buffer = new byte[fragment.Length];
- decryptionCipher.TransformBlock(fragment, 0, fragment.Length, buffer, 0);
-
- // Calculate fragment size
- if (cipherMode == CipherMode.CBC)
- {
- // Calculate padding_length
- paddingLength = buffer[buffer.Length - 1];
- for (int i = (buffer.Length - 1); i > (buffer.Length - (paddingLength + 1)); i--)
- {
- if (buffer[i] != paddingLength)
- {
- paddingLength = 0;
- break;
- }
- }
-
- fragmentSize = (buffer.Length - (paddingLength + 1)) - HashSize;
- }
- else
- {
- fragmentSize = buffer.Length - HashSize;
- }
-
- dcrFragment = new byte[fragmentSize];
- dcrMAC = new byte[HashSize];
-
- Buffer.BlockCopy(buffer, 0, dcrFragment, 0, dcrFragment.Length);
- Buffer.BlockCopy(buffer, dcrFragment.Length, dcrMAC, 0, dcrMAC.Length);
+ if (header == null)
+ header = new byte [MacHeaderLength];
+
+ ulong seqnum = (Context is ClientContext) ? Context.WriteSequenceNumber : Context.ReadSequenceNumber;
+ Write (header, 0, seqnum);
+ header [8] = (byte) contentType;
+ Write (header, 9, this.Context.Protocol);
+ Write (header, 11, (short)fragment.Length);
+
+ HashAlgorithm mac = this.ClientHMAC;
+ mac.TransformBlock (header, 0, header.Length, header, 0);
+ mac.TransformBlock (fragment, 0, fragment.Length, fragment, 0);
+ // hack, else the method will allocate a new buffer of the same length (negative half the optimization)
+ mac.TransformFinalBlock (CipherSuite.EmptyArray, 0, 0);
+ return mac.Hash;
}
#endregion
- #region KEY_GENERATION_METODS
+ #region Key Generation Methods
- public override void CreateMasterSecret(byte[] preMasterSecret)
+ public override void ComputeMasterSecret(byte[] preMasterSecret)
{
- TlsStream seed = new TlsStream();
-
- // Seed
- seed.Write(context.ClientRandom);
- seed.Write(context.ServerRandom);
-
// Create master secret
- context.MasterSecret = new byte[preMasterSecret.Length];
- context.MasterSecret = PRF(preMasterSecret, "master secret", seed.ToArray(), 48);
+ this.Context.MasterSecret = new byte[preMasterSecret.Length];
+ this.Context.MasterSecret = this.PRF(
+ preMasterSecret, "master secret", this.Context.RandomCS, 48);
- seed.Reset();
+ DebugHelper.WriteLine(">>>> MasterSecret", this.Context.MasterSecret);
}
- public override void CreateKeys()
+ public override void ComputeKeys()
{
- TlsStream seed = new TlsStream();
-
- // Seed
- seed.Write(context.ServerRandom);
- seed.Write(context.ClientRandom);
-
// Create keyblock
TlsStream keyBlock = new TlsStream(
- PRF(this.Context.MasterSecret,
+ this.PRF(
+ this.Context.MasterSecret,
"key expansion",
- seed.ToArray(),
+ this.Context.RandomSC,
this.KeyBlockSize));
- this.Context.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize);
- this.Context.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize);
+ 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);
}
else
{
- this.Context.ClientWriteIV = new byte[0];
- this.Context.ServerWriteIV = new byte[0];
+ this.Context.ClientWriteIV = CipherSuite.EmptyArray;
+ this.Context.ServerWriteIV = CipherSuite.EmptyArray;
}
}
else
{
- // Seed
- seed.Reset();
- seed.Write(this.Context.ClientRandom);
- seed.Write(this.Context.ServerRandom);
-
// Generate final write keys
- byte[] finalClientWriteKey = PRF(this.Context.ClientWriteKey, "client write key", seed.ToArray(), this.KeyMaterialSize);
- byte[] finalServerWriteKey = PRF(this.Context.ServerWriteKey, "server write key", seed.ToArray(), this.KeyMaterialSize);
+ 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;
- // Generate IV block
- byte[] ivBlock = PRF(new byte[]{}, "IV block", seed.ToArray(), this.IvSize*2);
+ 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);
- // Generate IV keys
- this.Context.ClientWriteIV = new byte[this.IvSize];
- System.Array.Copy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length);
- this.Context.ServerWriteIV = new byte[this.IvSize];
- System.Array.Copy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.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
- seed.Reset();
keyBlock.Reset();
}
#endregion
}
-}
\ No newline at end of file
+}