* xbuild/Microsoft.Common.targets (_RecordCleanFile): Append list of
[mcs.git] / class / System.ServiceModel / Mono.Security.Protocol.Tls / Context.cs
blob295eee5e60621f7c6310fe3ad33992cfc02bb048
1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
3 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
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.
25 using System;
26 using System.Text;
27 using System.Collections;
28 using System.Security.Cryptography;
29 using System.Security.Cryptography.X509Certificates;
31 using Mono.Security.Cryptography;
32 using Mono.Security.Protocol.Tls.Handshake;
34 namespace Mono.Security.Protocol.Tls
36 internal abstract class Context
38 #region Internal Constants
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;
45 #endregion
47 #region Fields
49 // Protocol version
50 private SecurityProtocolType securityProtocol;
52 // Sesison ID
53 private byte[] sessionId;
55 // Compression method
56 private SecurityCompressionType compressionMethod;
58 // Information sent and request by the server in the Handshake protocol
59 private TlsServerSettings serverSettings;
61 // Client configuration
62 private TlsClientSettings clientSettings;
64 // Cipher suite information
65 private SecurityParameters current;
66 private SecurityParameters negotiating;
67 private SecurityParameters read;
68 private SecurityParameters write;
69 private CipherSuiteCollection supportedCiphers;
71 // Last handshake message received
72 private HandshakeType lastHandshakeMsg;
74 // Handshake negotiation state
75 private HandshakeState handshakeState;
77 // Misc
78 private bool abbreviatedHandshake;
79 private bool connectionEnd;
80 private bool protocolNegotiated;
82 // Sequence numbers
83 private ulong writeSequenceNumber;
84 private ulong readSequenceNumber;
86 // Random data
87 private byte[] clientRandom;
88 private byte[] serverRandom;
89 private byte[] randomCS;
90 private byte[] randomSC;
92 // Key information
93 private byte[] masterSecret;
94 private byte[] clientWriteKey;
95 private byte[] serverWriteKey;
96 private byte[] clientWriteIV;
97 private byte[] serverWriteIV;
99 // Handshake hashes
100 private TlsStream handshakeMessages;
102 // Secure Random generator
103 private RandomNumberGenerator random;
105 // Record protocol
106 private RecordProtocol recordProtocol;
108 #endregion
110 #region Properties
112 public bool AbbreviatedHandshake
114 get { return abbreviatedHandshake; }
115 set { abbreviatedHandshake = value; }
118 public bool ProtocolNegotiated
120 get { return this.protocolNegotiated; }
121 set { this.protocolNegotiated = value; }
124 public SecurityProtocolType SecurityProtocol
126 get
128 if ((this.securityProtocol & SecurityProtocolType.Tls) == SecurityProtocolType.Tls ||
129 (this.securityProtocol & SecurityProtocolType.Default) == SecurityProtocolType.Default)
131 return SecurityProtocolType.Tls;
133 else
135 if ((this.securityProtocol & SecurityProtocolType.Ssl3) == SecurityProtocolType.Ssl3)
137 return SecurityProtocolType.Ssl3;
141 throw new NotSupportedException("Unsupported security protocol type");
144 set { this.securityProtocol = value; }
147 public SecurityProtocolType SecurityProtocolFlags
149 get { return this.securityProtocol; }
152 public short Protocol
154 get
156 switch (this.SecurityProtocol)
158 case SecurityProtocolType.Tls:
159 case SecurityProtocolType.Default:
160 return Context.TLS1_PROTOCOL_CODE;
162 case SecurityProtocolType.Ssl3:
163 return Context.SSL3_PROTOCOL_CODE;
165 case SecurityProtocolType.Ssl2:
166 default:
167 throw new NotSupportedException("Unsupported security protocol type");
172 public byte[] SessionId
174 get { return this.sessionId; }
175 set { this.sessionId = value; }
178 public SecurityCompressionType CompressionMethod
180 get { return this.compressionMethod; }
181 set { this.compressionMethod = value; }
184 public TlsServerSettings ServerSettings
186 get { return this.serverSettings; }
189 public TlsClientSettings ClientSettings
191 get { return this.clientSettings; }
194 public HandshakeType LastHandshakeMsg
196 get { return this.lastHandshakeMsg; }
197 set { this.lastHandshakeMsg = value; }
200 public HandshakeState HandshakeState
202 get { return this.handshakeState; }
203 set { this.handshakeState = value; }
206 public bool ConnectionEnd
208 get { return this.connectionEnd; }
209 set { this.connectionEnd = value; }
212 public CipherSuiteCollection SupportedCiphers
214 get { return supportedCiphers; }
215 set { supportedCiphers = value; }
218 public TlsStream HandshakeMessages
220 get { return this.handshakeMessages; }
223 public ulong WriteSequenceNumber
225 get { return this.writeSequenceNumber; }
226 set { this.writeSequenceNumber = value; }
229 public ulong ReadSequenceNumber
231 get { return this.readSequenceNumber; }
232 set { this.readSequenceNumber = value; }
235 public byte[] ClientRandom
237 get { return this.clientRandom; }
238 set { this.clientRandom = value; }
241 public byte[] ServerRandom
243 get { return this.serverRandom; }
244 set { this.serverRandom = value; }
247 public byte[] RandomCS
249 get { return this.randomCS; }
250 set { this.randomCS = value; }
253 public byte[] RandomSC
255 get { return this.randomSC; }
256 set { this.randomSC = value; }
259 public byte[] MasterSecret
261 get { return this.masterSecret; }
262 set { this.masterSecret = value; }
265 public byte[] ClientWriteKey
267 get { return this.clientWriteKey; }
268 set { this.clientWriteKey = value; }
271 public byte[] ServerWriteKey
273 get { return this.serverWriteKey; }
274 set { this.serverWriteKey = value; }
277 public byte[] ClientWriteIV
279 get { return this.clientWriteIV; }
280 set { this.clientWriteIV = value; }
283 public byte[] ServerWriteIV
285 get { return this.serverWriteIV; }
286 set { this.serverWriteIV = value; }
289 public RecordProtocol RecordProtocol
291 get { return this.recordProtocol; }
292 set { this.recordProtocol = value; }
295 #endregion
297 #region Constructors
299 public Context(SecurityProtocolType securityProtocolType)
301 this.SecurityProtocol = securityProtocolType;
302 this.compressionMethod = SecurityCompressionType.None;
303 this.serverSettings = new TlsServerSettings();
304 this.clientSettings = new TlsClientSettings();
305 this.handshakeMessages = new TlsStream();
306 this.sessionId = null;
307 this.handshakeState = HandshakeState.None;
308 this.random = RandomNumberGenerator.Create();
311 #endregion
313 #region Methods
315 public int GetUnixTime()
317 DateTime now = DateTime.UtcNow;
319 return (int)((now.Ticks - UNIX_BASE_TICKS) / TimeSpan.TicksPerSecond);
322 public byte[] GetSecureRandomBytes(int count)
324 byte[] secureBytes = new byte[count];
326 this.random.GetNonZeroBytes(secureBytes);
328 return secureBytes;
331 public virtual void Clear()
333 this.compressionMethod = SecurityCompressionType.None;
334 this.serverSettings = new TlsServerSettings();
335 this.clientSettings = new TlsClientSettings();
336 this.handshakeMessages = new TlsStream();
337 this.sessionId = null;
338 this.handshakeState = HandshakeState.None;
340 this.ClearKeyInfo();
343 public virtual void ClearKeyInfo()
345 // Clear Master Secret
346 if (masterSecret != null) {
347 Array.Clear (masterSecret, 0, masterSecret.Length);
348 masterSecret = null;
351 // Clear client and server random
352 if (clientRandom != null) {
353 Array.Clear (clientRandom, 0, clientRandom.Length);
354 clientRandom = null;
356 if (serverRandom != null) {
357 Array.Clear (serverRandom, 0, serverRandom.Length);
358 serverRandom = null;
360 if (randomCS != null) {
361 Array.Clear (randomCS, 0, randomCS.Length);
362 randomCS = null;
364 if (randomSC != null) {
365 Array.Clear (randomSC, 0, randomSC.Length);
366 randomSC = null;
369 // Clear client keys
370 if (clientWriteKey != null) {
371 Array.Clear (clientWriteKey, 0, clientWriteKey.Length);
372 clientWriteKey = null;
374 if (clientWriteIV != null) {
375 Array.Clear (clientWriteIV, 0, clientWriteIV.Length);
376 clientWriteIV = null;
379 // Clear server keys
380 if (serverWriteKey != null) {
381 Array.Clear (serverWriteKey, 0, serverWriteKey.Length);
382 serverWriteKey = null;
384 if (serverWriteIV != null) {
385 Array.Clear (serverWriteIV, 0, serverWriteIV.Length);
386 serverWriteIV = null;
389 // Reset handshake messages
390 this.handshakeMessages.Reset();
392 // Clear MAC keys if protocol is different than Ssl3
393 // SSLv3 needs them inside Mono.Security.Protocol.Tls.SslCipherSuite.Compute[Client|Server]RecordMAC
394 if (this.securityProtocol != SecurityProtocolType.Ssl3)
396 // this.clientWriteMAC = null;
397 // this.serverWriteMAC = null;
401 public SecurityProtocolType DecodeProtocolCode(short code)
403 switch (code)
405 case Context.TLS1_PROTOCOL_CODE:
406 return SecurityProtocolType.Tls;
408 case Context.SSL3_PROTOCOL_CODE:
409 return SecurityProtocolType.Ssl3;
411 default:
412 throw new NotSupportedException("Unsupported security protocol type");
416 public void ChangeProtocol(short protocol)
418 SecurityProtocolType protocolType = this.DecodeProtocolCode(protocol);
420 if ((protocolType & this.SecurityProtocolFlags) == protocolType ||
421 (this.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
423 this.SecurityProtocol = protocolType;
424 this.SupportedCiphers.Clear();
425 this.SupportedCiphers = null;
426 this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(protocolType);
428 else
430 throw new TlsException(AlertDescription.ProtocolVersion, "Incorrect protocol version received from server");
435 public SecurityParameters Current
439 if (current == null)
440 current = new SecurityParameters ();
441 if (current.Cipher != null)
442 current.Cipher.Context = this;
443 return current;
447 public SecurityParameters Negotiating
451 if (negotiating == null)
452 negotiating = new SecurityParameters ();
453 if (negotiating.Cipher != null)
454 negotiating.Cipher.Context = this;
455 return negotiating;
459 public SecurityParameters Read
461 get { return read; }
464 public SecurityParameters Write
466 get { return write; }
469 public void StartSwitchingSecurityParameters (bool client)
471 if (client) {
472 // everything we write from now on is encrypted
473 write = negotiating;
474 // but we still read with the older cipher until we
475 // receive the ChangeCipherSpec message
476 read = current;
477 } else {
478 // everything we read from now on is encrypted
479 read = negotiating;
480 // but we still write with the older cipher until we
481 // receive the ChangeCipherSpec message
482 write = current;
484 current = negotiating;
487 public void EndSwitchingSecurityParameters (bool client)
489 SecurityParameters temp;
490 if (client) {
491 temp = read;
492 // we now read with the new, negotiated, security parameters
493 read = current;
494 } else {
495 temp = write;
496 // we now write with the new, negotiated, security parameters
497 write = current;
499 // so we clear the old one (last reference)
500 if (temp != null)
501 temp.Clear ();
502 negotiating = temp;
503 // and are now ready for a future renegotiation
506 #endregion