2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / Context.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.Text;
27 using System.Collections;
28 using System.Security.Cryptography;
29 using System.Security.Cryptography.X509Certificates;
30
31 using Mono.Security.Cryptography;
32 using Mono.Security.Protocol.Tls.Handshake;
33
34 namespace Mono.Security.Protocol.Tls
35 {
36         internal abstract class Context
37         {
38                 #region Internal Constants
39
40                 internal const short MAX_FRAGMENT_SIZE  = 16384; // 2^14
41                 internal const short TLS1_PROTOCOL_CODE = (0x03 << 8) | 0x01;
42                 internal const short SSL3_PROTOCOL_CODE = (0x03 << 8) | 0x00;
43                 internal const long  UNIX_BASE_TICKS    = 621355968000000000;
44
45                 #endregion
46
47                 #region Fields
48                 
49                 // Protocol version
50                 private SecurityProtocolType securityProtocol;
51                 
52                 // Sesison ID
53                 private byte[] sessionId;
54
55                 // Compression method
56                 private SecurityCompressionType compressionMethod;
57
58                 // Information sent and request by the server in the Handshake protocol
59                 private TlsServerSettings serverSettings;
60
61                 // Client configuration
62                 private TlsClientSettings clientSettings;
63
64                 // Cipher suite information
65                 private CipherSuite                             cipher;
66                 private CipherSuiteCollection   supportedCiphers;
67
68                 // Last handshake message received
69                 private HandshakeType lastHandshakeMsg;
70
71                 // Handshake negotiation state
72                 private HandshakeState handshakeState;
73
74                 // Misc
75                 private bool    isActual;
76                 private bool    connectionEnd;
77                 private bool    protocolNegotiated;
78                 
79                 // Sequence numbers
80                 private long    writeSequenceNumber;
81                 private long    readSequenceNumber;
82
83                 // Random data
84                 private byte[]  clientRandom;
85                 private byte[]  serverRandom;
86                 private byte[]  randomCS;
87                 private byte[]  randomSC;
88
89                 // Key information
90                 private byte[]  masterSecret;
91                 private byte[]  clientWriteMAC;
92                 private byte[]  serverWriteMAC;
93                 private byte[]  clientWriteKey;
94                 private byte[]  serverWriteKey;
95                 private byte[]  clientWriteIV;
96                 private byte[]  serverWriteIV;
97                 
98                 // Handshake hashes
99                 private TlsStream handshakeMessages;
100                 
101                 // Secure Random generator              
102                 private RandomNumberGenerator random;
103
104                 // Record protocol
105                 private RecordProtocol recordProtocol;
106
107                 #endregion
108
109                 #region Properties
110
111                 public bool     ProtocolNegotiated
112                 {
113                         get { return this.protocolNegotiated; }
114                         set { this.protocolNegotiated = value; }
115                 }
116
117                 public SecurityProtocolType SecurityProtocol
118                 {
119                         get 
120                         {
121                                 if ((this.securityProtocol & SecurityProtocolType.Tls) == SecurityProtocolType.Tls ||   
122                                         (this.securityProtocol & SecurityProtocolType.Default) == SecurityProtocolType.Default)
123                                 {
124                                         return SecurityProtocolType.Tls;
125                                 }
126                                 else
127                                 {
128                                         if ((this.securityProtocol & SecurityProtocolType.Ssl3) == SecurityProtocolType.Ssl3)
129                                         {
130                                                 return SecurityProtocolType.Ssl3;
131                                         }
132                                 }
133
134                                 throw new NotSupportedException("Unsupported security protocol type");
135                         }
136
137                         set { this.securityProtocol = value; }
138                 }
139
140                 public SecurityProtocolType SecurityProtocolFlags
141                 {
142                         get { return this.securityProtocol; }
143                 }
144
145                 public short Protocol
146                 {
147                         get 
148                         { 
149                                 switch (this.SecurityProtocol)
150                                 {
151                                         case SecurityProtocolType.Tls:
152                                         case SecurityProtocolType.Default:
153                                                 return Context.TLS1_PROTOCOL_CODE;
154
155                                         case SecurityProtocolType.Ssl3:
156                                                 return Context.SSL3_PROTOCOL_CODE;
157
158                                         case SecurityProtocolType.Ssl2:
159                                         default:
160                                                 throw new NotSupportedException("Unsupported security protocol type");
161                                 }
162                         }
163                 }
164
165                 public byte[] SessionId
166                 {
167                         get { return this.sessionId; }
168                         set { this.sessionId = value; }
169                 }
170
171                 public SecurityCompressionType CompressionMethod
172                 {
173                         get { return this.compressionMethod; }
174                         set { this.compressionMethod = value; }
175                 }
176
177                 public TlsServerSettings ServerSettings
178                 {
179                         get { return this.serverSettings; }
180                 }
181
182                 public TlsClientSettings ClientSettings
183                 {
184                         get { return this.clientSettings; }
185                 }
186
187                 public bool     IsActual
188                 {
189                         get { return this.isActual; }
190                         set { this.isActual = value; }
191                 }
192
193                 public HandshakeType LastHandshakeMsg
194                 {
195                         get { return this.lastHandshakeMsg; }
196                         set { this.lastHandshakeMsg = value; }
197                 }
198
199                 public  HandshakeState HandshakeState
200                 {
201                         get { return this.handshakeState; }
202                         set { this.handshakeState = value; }
203                 }
204
205                 public bool ConnectionEnd
206                 {
207                         get { return this.connectionEnd; }
208                         set { this.connectionEnd = value; }
209                 }
210
211                 public CipherSuite Cipher
212                 {
213                         get { return this.cipher; }
214                         set 
215                         { 
216                                 this.cipher                     = value; 
217                                 this.cipher.Context = this;
218                         }
219                 }
220
221                 public CipherSuiteCollection SupportedCiphers
222                 {
223                         get { return supportedCiphers; }
224                         set { supportedCiphers = value; }
225                 }
226
227                 public TlsStream HandshakeMessages
228                 {
229                         get { return this.handshakeMessages; }
230                 }
231
232                 public long WriteSequenceNumber
233                 {
234                         get { return this.writeSequenceNumber; }
235                         set { this.writeSequenceNumber = value; }
236                 }
237
238                 public long ReadSequenceNumber
239                 {
240                         get { return this.readSequenceNumber; }
241                         set { this.readSequenceNumber = value; }
242                 }
243
244                 public byte[] ClientRandom
245                 {
246                         get { return this.clientRandom; }
247                         set { this.clientRandom = value; }
248                 }
249
250                 public byte[] ServerRandom
251                 {
252                         get { return this.serverRandom; }
253                         set { this.serverRandom = value; }
254                 }
255
256                 public byte[] RandomCS
257                 {
258                         get { return this.randomCS; }
259                         set { this.randomCS = value; }
260                 }
261
262                 public byte[] RandomSC
263                 {
264                         get { return this.randomSC; }
265                         set { this.randomSC = value; }
266                 }
267
268                 public byte[] MasterSecret
269                 {
270                         get { return this.masterSecret; }
271                         set { this.masterSecret = value; }
272                 }
273
274                 public byte[] ClientWriteMAC
275                 {
276                         get { return this.clientWriteMAC; }
277                         set { this.clientWriteMAC = value; }
278                 }
279
280                 public byte[] ServerWriteMAC
281                 {
282                         get { return this.serverWriteMAC; }
283                         set { this.serverWriteMAC = value; }
284                 }
285
286                 public byte[] ClientWriteKey
287                 {
288                         get { return this.clientWriteKey; }
289                         set { this.clientWriteKey = value; }
290                 }
291
292                 public byte[] ServerWriteKey
293                 {
294                         get { return this.serverWriteKey; }
295                         set { this.serverWriteKey = value; }
296                 }
297
298                 public byte[] ClientWriteIV
299                 {
300                         get { return this.clientWriteIV; }
301                         set { this.clientWriteIV = value; }
302                 }
303
304                 public byte[] ServerWriteIV
305                 {
306                         get { return this.serverWriteIV; }
307                         set { this.serverWriteIV = value; }
308                 }
309
310                 public RecordProtocol RecordProtocol
311                 {
312                         get { return this.recordProtocol; }
313                         set { this.recordProtocol = value; }
314                 }
315
316                 #endregion
317
318                 #region Constructors
319
320                 public Context(SecurityProtocolType securityProtocolType)
321                 {
322                         this.SecurityProtocol   = securityProtocolType;
323                         this.compressionMethod  = SecurityCompressionType.None;
324                         this.serverSettings             = new TlsServerSettings();
325                         this.clientSettings             = new TlsClientSettings();
326                         this.handshakeMessages  = new TlsStream();
327                         this.sessionId                  = null;
328                         this.handshakeState             = HandshakeState.None;
329                         this.random                             = RandomNumberGenerator.Create();
330                 }
331
332                 #endregion
333
334                 #region Methods
335                 
336                 public int GetUnixTime()
337                 {
338                         DateTime now = DateTime.UtcNow;
339                                                                                                                                                      
340                         return (int)(now.Ticks - UNIX_BASE_TICKS / TimeSpan.TicksPerSecond);
341                 }
342
343                 public byte[] GetSecureRandomBytes(int count)
344                 {
345                         byte[] secureBytes = new byte[count];
346
347                         this.random.GetNonZeroBytes(secureBytes);
348                         
349                         return secureBytes;
350                 }
351
352                 public virtual void Clear()
353                 {
354                         this.compressionMethod  = SecurityCompressionType.None;
355                         this.serverSettings             = new TlsServerSettings();
356                         this.clientSettings             = new TlsClientSettings();
357                         this.handshakeMessages  = new TlsStream();
358                         this.sessionId                  = null;
359                         this.handshakeState             = HandshakeState.None;
360
361                         this.ClearKeyInfo();
362                 }
363
364                 public virtual void ClearKeyInfo()
365                 {
366                         // Clear Master Secret
367                         this.masterSecret       = null;
368
369                         // Clear client and server random
370                         this.clientRandom       = null;
371                         this.serverRandom       = null;
372                         this.randomCS           = null;
373                         this.randomSC           = null;
374
375                         // Clear client keys
376                         this.clientWriteKey     = null;
377                         this.clientWriteIV      = null;
378                         
379                         // Clear server keys
380                         this.serverWriteKey     = null;
381                         this.serverWriteIV      = null;
382
383                         // Reset handshake messages
384                         this.handshakeMessages.Reset();
385
386                         // Clear MAC keys if protocol is different than Ssl3
387                         if (this.securityProtocol != SecurityProtocolType.Ssl3)
388                         {
389                                 this.clientWriteMAC = null;
390                                 this.serverWriteMAC = null;
391                         }
392                 }
393
394                 public SecurityProtocolType DecodeProtocolCode(short code)
395                 {
396                         switch (code)
397                         {
398                                 case Context.TLS1_PROTOCOL_CODE:
399                                         return SecurityProtocolType.Tls;
400
401                                 case Context.SSL3_PROTOCOL_CODE:
402                                         return SecurityProtocolType.Ssl3;
403
404                                 default:
405                                         throw new NotSupportedException("Unsupported security protocol type");
406                         }
407                 }
408
409                 public void ChangeProtocol(short protocol)
410                 {
411                         SecurityProtocolType protocolType = this.DecodeProtocolCode(protocol);
412
413                         if ((protocolType & this.SecurityProtocolFlags) == protocolType ||
414                                 (this.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
415                         {
416                                 this.SecurityProtocol = protocolType;
417                                 this.SupportedCiphers.Clear();
418                                 this.SupportedCiphers = null;
419                                 this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(protocolType);
420                         }
421                         else
422                         {
423                                 throw new TlsException(AlertDescription.ProtocolVersion, "Incorrect protocol version received from server");
424                         }
425                 }
426
427                 #endregion
428         }
429 }