1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
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:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
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.
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;
50 private SecurityProtocolType securityProtocol;
53 private byte[] sessionId;
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 CipherSuite cipher;
66 private CipherSuiteCollection supportedCiphers;
68 // Last handshake message received
69 private HandshakeType lastHandshakeMsg;
71 // Handshake negotiation state
72 private HandshakeState handshakeState;
75 private bool isActual;
76 private bool connectionEnd;
77 private bool protocolNegotiated;
80 private long writeSequenceNumber;
81 private long readSequenceNumber;
84 private byte[] clientRandom;
85 private byte[] serverRandom;
86 private byte[] randomCS;
87 private byte[] randomSC;
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;
99 private TlsStream handshakeMessages;
101 // Secure Random generator
102 private RandomNumberGenerator random;
105 private RecordProtocol recordProtocol;
111 public bool ProtocolNegotiated
113 get { return this.protocolNegotiated; }
114 set { this.protocolNegotiated = value; }
117 public SecurityProtocolType SecurityProtocol
121 if ((this.securityProtocol & SecurityProtocolType.Tls) == SecurityProtocolType.Tls ||
122 (this.securityProtocol & SecurityProtocolType.Default) == SecurityProtocolType.Default)
124 return SecurityProtocolType.Tls;
128 if ((this.securityProtocol & SecurityProtocolType.Ssl3) == SecurityProtocolType.Ssl3)
130 return SecurityProtocolType.Ssl3;
134 throw new NotSupportedException("Unsupported security protocol type");
137 set { this.securityProtocol = value; }
140 public SecurityProtocolType SecurityProtocolFlags
142 get { return this.securityProtocol; }
145 public short Protocol
149 switch (this.SecurityProtocol)
151 case SecurityProtocolType.Tls:
152 case SecurityProtocolType.Default:
153 return Context.TLS1_PROTOCOL_CODE;
155 case SecurityProtocolType.Ssl3:
156 return Context.SSL3_PROTOCOL_CODE;
158 case SecurityProtocolType.Ssl2:
160 throw new NotSupportedException("Unsupported security protocol type");
165 public byte[] SessionId
167 get { return this.sessionId; }
168 set { this.sessionId = value; }
171 public SecurityCompressionType CompressionMethod
173 get { return this.compressionMethod; }
174 set { this.compressionMethod = value; }
177 public TlsServerSettings ServerSettings
179 get { return this.serverSettings; }
182 public TlsClientSettings ClientSettings
184 get { return this.clientSettings; }
189 get { return this.isActual; }
190 set { this.isActual = value; }
193 public HandshakeType LastHandshakeMsg
195 get { return this.lastHandshakeMsg; }
196 set { this.lastHandshakeMsg = value; }
199 public HandshakeState HandshakeState
201 get { return this.handshakeState; }
202 set { this.handshakeState = value; }
205 public bool ConnectionEnd
207 get { return this.connectionEnd; }
208 set { this.connectionEnd = value; }
211 public CipherSuite Cipher
213 get { return this.cipher; }
217 this.cipher.Context = this;
221 public CipherSuiteCollection SupportedCiphers
223 get { return supportedCiphers; }
224 set { supportedCiphers = value; }
227 public TlsStream HandshakeMessages
229 get { return this.handshakeMessages; }
232 public long WriteSequenceNumber
234 get { return this.writeSequenceNumber; }
235 set { this.writeSequenceNumber = value; }
238 public long ReadSequenceNumber
240 get { return this.readSequenceNumber; }
241 set { this.readSequenceNumber = value; }
244 public byte[] ClientRandom
246 get { return this.clientRandom; }
247 set { this.clientRandom = value; }
250 public byte[] ServerRandom
252 get { return this.serverRandom; }
253 set { this.serverRandom = value; }
256 public byte[] RandomCS
258 get { return this.randomCS; }
259 set { this.randomCS = value; }
262 public byte[] RandomSC
264 get { return this.randomSC; }
265 set { this.randomSC = value; }
268 public byte[] MasterSecret
270 get { return this.masterSecret; }
271 set { this.masterSecret = value; }
274 public byte[] ClientWriteMAC
276 get { return this.clientWriteMAC; }
277 set { this.clientWriteMAC = value; }
280 public byte[] ServerWriteMAC
282 get { return this.serverWriteMAC; }
283 set { this.serverWriteMAC = value; }
286 public byte[] ClientWriteKey
288 get { return this.clientWriteKey; }
289 set { this.clientWriteKey = value; }
292 public byte[] ServerWriteKey
294 get { return this.serverWriteKey; }
295 set { this.serverWriteKey = value; }
298 public byte[] ClientWriteIV
300 get { return this.clientWriteIV; }
301 set { this.clientWriteIV = value; }
304 public byte[] ServerWriteIV
306 get { return this.serverWriteIV; }
307 set { this.serverWriteIV = value; }
310 public RecordProtocol RecordProtocol
312 get { return this.recordProtocol; }
313 set { this.recordProtocol = value; }
320 public Context(SecurityProtocolType securityProtocolType)
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();
336 public int GetUnixTime()
338 DateTime now = DateTime.UtcNow;
340 return (int)(now.Ticks - UNIX_BASE_TICKS / TimeSpan.TicksPerSecond);
343 public byte[] GetSecureRandomBytes(int count)
345 byte[] secureBytes = new byte[count];
347 this.random.GetNonZeroBytes(secureBytes);
352 public virtual void Clear()
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;
364 public virtual void ClearKeyInfo()
366 // Clear Master Secret
367 this.masterSecret = null;
369 // Clear client and server random
370 this.clientRandom = null;
371 this.serverRandom = null;
372 this.randomCS = null;
373 this.randomSC = null;
376 this.clientWriteKey = null;
377 this.clientWriteIV = null;
380 this.serverWriteKey = null;
381 this.serverWriteIV = null;
383 // Reset handshake messages
384 this.handshakeMessages.Reset();
386 // Clear MAC keys if protocol is different than Ssl3
387 if (this.securityProtocol != SecurityProtocolType.Ssl3)
389 this.clientWriteMAC = null;
390 this.serverWriteMAC = null;
394 public SecurityProtocolType DecodeProtocolCode(short code)
398 case Context.TLS1_PROTOCOL_CODE:
399 return SecurityProtocolType.Tls;
401 case Context.SSL3_PROTOCOL_CODE:
402 return SecurityProtocolType.Ssl3;
405 throw new NotSupportedException("Unsupported security protocol type");
409 public void ChangeProtocol(short protocol)
411 SecurityProtocolType protocolType = this.DecodeProtocolCode(protocol);
413 if ((protocolType & this.SecurityProtocolFlags) == protocolType ||
414 (this.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
416 this.SecurityProtocol = protocolType;
417 this.SupportedCiphers.Clear();
418 this.SupportedCiphers = null;
419 this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(protocolType);
423 throw new TlsException(AlertDescription.ProtocolVersion, "Incorrect protocol version received from server");