1 /* Transport Security Layer (TLS)
2 * Copyright (c) 2003-2004 Carlos Guzman Alvarez
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
28 using System.Security.Cryptography;
29 using System.Security.Cryptography.X509Certificates;
32 using Mono.Security.Cryptography;
34 namespace Mono.Security.Protocol.Tls
36 internal class SslCipherSuite : CipherSuite
47 public SslCipherSuite(
48 short code, string name, CipherAlgorithmType cipherAlgorithmType,
49 HashAlgorithmType hashAlgorithmType, ExchangeAlgorithmType exchangeAlgorithmType,
50 bool exportable, bool blockMode, byte keyMaterialSize,
51 byte expandedKeyMaterialSize, short effectiveKeyBytes,
52 byte ivSize, byte blockSize) :
53 base(code, name, cipherAlgorithmType, hashAlgorithmType,
54 exchangeAlgorithmType, exportable, blockMode, keyMaterialSize,
55 expandedKeyMaterialSize, effectiveKeyBytes, ivSize, blockSize)
58 int padLength = (hashAlgorithmType == HashAlgorithmType.Md5) ? 48 : 40;
61 this.pad1 = new byte[padLength];
62 this.pad2 = new byte[padLength];
64 /* Pad the key for inner and outer digest */
65 for (int i = 0; i < padLength; ++i)
74 #region MAC Generation Methods
76 public override byte[] ComputeServerRecordMAC(ContentType contentType, byte[] fragment)
78 HashAlgorithm hash = HashAlgorithm.Create(this.HashAlgorithmName);
79 TlsStream block = new TlsStream();
81 block.Write(this.Context.ServerWriteMAC);
82 block.Write(this.pad1);
83 if (this.Context is ClientContext)
85 block.Write(this.Context.ReadSequenceNumber);
89 block.Write(this.Context.WriteSequenceNumber);
91 block.Write((byte)contentType);
92 block.Write((short)fragment.Length);
93 block.Write(fragment);
95 hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
97 byte[] blockHash = hash.Hash;
101 block.Write(this.Context.ServerWriteMAC);
102 block.Write(this.pad2);
103 block.Write(blockHash);
105 hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
112 public override byte[] ComputeClientRecordMAC(ContentType contentType, byte[] fragment)
114 HashAlgorithm hash = HashAlgorithm.Create(this.HashAlgorithmName);
115 TlsStream block = new TlsStream();
117 block.Write(this.Context.ClientWriteMAC);
118 block.Write(this.pad1);
119 if (this.Context is ClientContext)
121 block.Write(this.Context.ReadSequenceNumber);
125 block.Write(this.Context.WriteSequenceNumber);
127 block.Write((byte)contentType);
128 block.Write((short)fragment.Length);
129 block.Write(fragment);
131 hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
133 byte[] blockHash = hash.Hash;
137 block.Write(this.Context.ClientWriteMAC);
138 block.Write(this.pad2);
139 block.Write(blockHash);
141 hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
150 #region Key Generation Methods
152 public override void ComputeMasterSecret(byte[] preMasterSecret)
154 TlsStream masterSecret = new TlsStream();
156 masterSecret.Write(this.prf(preMasterSecret, "A", this.Context.RandomCS));
157 masterSecret.Write(this.prf(preMasterSecret, "BB", this.Context.RandomCS));
158 masterSecret.Write(this.prf(preMasterSecret, "CCC", this.Context.RandomCS));
160 this.Context.MasterSecret = masterSecret.ToArray();
163 public override void ComputeKeys()
166 TlsStream tmp = new TlsStream();
168 char labelChar = 'A';
170 while (tmp.Length < this.KeyBlockSize)
172 string label = String.Empty;
174 for (int i = 0; i < count; i++)
176 label += labelChar.ToString();
179 byte[] block = this.prf(this.Context.MasterSecret, label.ToString(), this.Context.RandomSC);
181 int size = (tmp.Length + block.Length) > this.KeyBlockSize ? (this.KeyBlockSize - (int)tmp.Length) : block.Length;
183 tmp.Write(block, 0, size);
190 TlsStream keyBlock = new TlsStream(tmp.ToArray());
192 this.Context.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize);
193 this.Context.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize);
194 this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize);
195 this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize);
197 if (!this.IsExportable)
199 if (this.IvSize != 0)
201 this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize);
202 this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize);
206 this.Context.ClientWriteIV = CipherSuite.EmptyArray;
207 this.Context.ServerWriteIV = CipherSuite.EmptyArray;
212 HashAlgorithm md5 = MD5.Create();
214 // Generate final write keys
215 byte[] finalClientWriteKey = new byte[md5.HashSize];
216 md5.TransformBlock(this.Context.ClientWriteKey, 0, this.Context.ClientWriteKey.Length, finalClientWriteKey, 0);
217 finalClientWriteKey = md5.TransformFinalBlock(this.Context.RandomCS, 0, this.Context.RandomCS.Length);
219 byte[] finalServerWriteKey = new byte[md5.HashSize];
220 md5.TransformBlock(this.Context.ServerWriteKey, 0, this.Context.ServerWriteKey.Length, finalServerWriteKey, 0);
221 finalClientWriteKey = md5.TransformFinalBlock(this.Context.RandomSC, 0, this.Context.RandomSC.Length);
223 this.Context.ClientWriteKey = finalClientWriteKey;
224 this.Context.ServerWriteKey = finalServerWriteKey;
227 this.Context.ClientWriteIV = md5.TransformFinalBlock(this.Context.RandomCS, 0, this.Context.RandomCS.Length);
228 this.Context.ServerWriteIV = md5.TransformFinalBlock(this.Context.RandomSC, 0, this.Context.RandomSC.Length);
231 // Clear no more needed data
238 #region Private Methods
240 private byte[] prf(byte[] secret, string label, byte[] random)
242 HashAlgorithm md5 = MD5.Create();
243 HashAlgorithm sha = SHA1.Create();
246 TlsStream block = new TlsStream();
247 block.Write(Encoding.ASCII.GetBytes(label));
251 byte[] shaHash = sha.ComputeHash(block.ToArray(), 0, (int)block.Length);
257 block.Write(shaHash);
259 byte[] result = md5.ComputeHash(block.ToArray(), 0, (int)block.Length);