2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / TlsCipherSuite.cs
1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
3
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 // 
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 // 
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24
25 using System;
26 using System.IO;
27 using System.Text;
28 using System.Security.Cryptography;
29 using System.Security.Cryptography.X509Certificates;
30
31 using Mono.Security;
32 using Mono.Security.Cryptography;
33
34 namespace Mono.Security.Protocol.Tls
35 {
36         internal class TlsCipherSuite : CipherSuite
37         {
38                 #region Constructors
39                 
40                 public TlsCipherSuite(
41                         short code, string name, CipherAlgorithmType cipherAlgorithmType, 
42                         HashAlgorithmType hashAlgorithmType, ExchangeAlgorithmType exchangeAlgorithmType,
43                         bool exportable, bool blockMode, byte keyMaterialSize, 
44                         byte expandedKeyMaterialSize, short effectiveKeyBytes, 
45                         byte ivSize, byte blockSize) 
46                         :base(code, name, cipherAlgorithmType, hashAlgorithmType, 
47                         exchangeAlgorithmType, exportable, blockMode, keyMaterialSize, 
48                         expandedKeyMaterialSize, effectiveKeyBytes, ivSize, blockSize)
49                 {
50                 }
51
52                 #endregion
53
54                 #region MAC Generation Methods
55
56                 public override byte[] ComputeServerRecordMAC(ContentType contentType, byte[] fragment)
57                 {
58                         TlsStream       data    = new TlsStream();
59                         byte[]          result  = null;
60
61                         if (this.Context is ClientContext)
62                         {
63                                 data.Write(this.Context.ReadSequenceNumber);
64                         }
65                         else
66                         {
67                                 data.Write(this.Context.WriteSequenceNumber);
68                         }
69
70                         data.Write((byte)contentType);
71                         data.Write(this.Context.Protocol);
72                         data.Write((short)fragment.Length);
73                         data.Write(fragment);
74
75                         result = this.ServerHMAC.ComputeHash(data.ToArray());
76
77                         data.Reset();
78
79                         return result;
80                 }
81
82                 public override byte[] ComputeClientRecordMAC(ContentType contentType, byte[] fragment)
83                 {
84                         TlsStream       data    = new TlsStream();
85                         byte[]          result  = null;
86
87                         if (this.Context is ClientContext)
88                         {
89                                 data.Write(this.Context.WriteSequenceNumber);
90                         }
91                         else
92                         {
93                                 data.Write(this.Context.ReadSequenceNumber);
94                         }
95
96                         data.Write((byte)contentType);
97                         data.Write(this.Context.Protocol);
98                         data.Write((short)fragment.Length);
99                         data.Write(fragment);
100
101                         result = this.ClientHMAC.ComputeHash(data.ToArray());
102
103                         data.Reset();
104
105                         return result;
106                 }
107
108                 #endregion
109
110                 #region Key Generation Methods
111
112                 public override void ComputeMasterSecret(byte[] preMasterSecret)
113                 {
114                         // Create master secret
115                         this.Context.MasterSecret = new byte[preMasterSecret.Length];
116                         this.Context.MasterSecret = this.PRF(
117                                 preMasterSecret, "master secret", this.Context.RandomCS, 48);
118
119                         DebugHelper.WriteLine(">>>> MasterSecret", this.Context.MasterSecret);
120                 }
121
122                 public override void ComputeKeys()
123                 {
124                         // Create keyblock
125                         TlsStream keyBlock = new TlsStream(
126                                 this.PRF(
127                                 this.Context.MasterSecret, 
128                                 "key expansion",
129                                 this.Context.RandomSC,
130                                 this.KeyBlockSize));
131
132                         this.Context.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize);
133                         this.Context.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize);
134                         this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize);
135                         this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize);
136
137                         if (!this.IsExportable)
138                         {
139                                 if (this.IvSize != 0)
140                                 {
141                                         this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize);
142                                         this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize);
143                                 }
144                                 else
145                                 {
146                                         this.Context.ClientWriteIV = CipherSuite.EmptyArray;
147                                         this.Context.ServerWriteIV = CipherSuite.EmptyArray;
148                                 }
149                         }
150                         else
151                         {
152                                 // Generate final write keys
153                                 byte[] finalClientWriteKey      = PRF(this.Context.ClientWriteKey, "client write key", this.Context.RandomCS, this.ExpandedKeyMaterialSize);
154                                 byte[] finalServerWriteKey      = PRF(this.Context.ServerWriteKey, "server write key", this.Context.RandomCS, this.ExpandedKeyMaterialSize);
155                                 
156                                 this.Context.ClientWriteKey     = finalClientWriteKey;
157                                 this.Context.ServerWriteKey     = finalServerWriteKey;
158
159                                 if (this.IvSize > 0) 
160                                 {
161                                         // Generate IV block
162                                         byte[] ivBlock = PRF(CipherSuite.EmptyArray, "IV block", this.Context.RandomCS, this.IvSize*2);
163
164                                         // Generate IV keys
165                                         this.Context.ClientWriteIV = new byte[this.IvSize];                             
166                                         Buffer.BlockCopy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length);
167
168                                         this.Context.ServerWriteIV = new byte[this.IvSize];
169                                         Buffer.BlockCopy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.Length);
170                                 }
171                                 else 
172                                 {
173                                         this.Context.ClientWriteIV = CipherSuite.EmptyArray;
174                                         this.Context.ServerWriteIV = CipherSuite.EmptyArray;
175                                 }
176                         }
177
178                         DebugHelper.WriteLine(">>>> KeyBlock", keyBlock.ToArray());
179                         DebugHelper.WriteLine(">>>> ClientWriteKey", this.Context.ClientWriteKey);
180                         DebugHelper.WriteLine(">>>> ClientWriteIV", this.Context.ClientWriteIV);
181                         DebugHelper.WriteLine(">>>> ClientWriteMAC", this.Context.ClientWriteMAC);
182                         DebugHelper.WriteLine(">>>> ServerWriteKey", this.Context.ServerWriteKey);
183                         DebugHelper.WriteLine(">>>> ServerWriteIV", this.Context.ServerWriteIV);
184                         DebugHelper.WriteLine(">>>> ServerWriteMAC", this.Context.ServerWriteMAC);
185
186                         // Clear no more needed data
187                         keyBlock.Reset();
188                 }
189
190                 #endregion
191         }
192 }