You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			520 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			520 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| // Transport Security Layer (TLS)
 | |
| // Copyright (c) 2003-2004 Carlos Guzman Alvarez
 | |
| // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
 | |
| //
 | |
| // Permission is hereby granted, free of charge, to any person obtaining
 | |
| // a copy of this software and associated documentation files (the
 | |
| // "Software"), to deal in the Software without restriction, including
 | |
| // without limitation the rights to use, copy, modify, merge, publish,
 | |
| // distribute, sublicense, and/or sell copies of the Software, and to
 | |
| // permit persons to whom the Software is furnished to do so, subject to
 | |
| // the following conditions:
 | |
| // 
 | |
| // The above copyright notice and this permission notice shall be
 | |
| // included in all copies or substantial portions of the Software.
 | |
| // 
 | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
| // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
| // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | |
| // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | |
| // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | |
| // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | |
| //
 | |
| 
 | |
| using System;
 | |
| using System.Text;
 | |
| using System.Collections;
 | |
| using System.Security.Cryptography;
 | |
| using System.Security.Cryptography.X509Certificates;
 | |
| 
 | |
| using Mono.Security.Cryptography;
 | |
| using Mono.Security.Protocol.Tls.Handshake;
 | |
| 
 | |
| namespace Mono.Security.Protocol.Tls
 | |
| {
 | |
| 	internal abstract class Context
 | |
| 	{
 | |
| 		#region Internal Constants
 | |
| 
 | |
| 		internal const short MAX_FRAGMENT_SIZE	= 16384; // 2^14
 | |
| 		internal const short TLS1_PROTOCOL_CODE = (0x03 << 8) | 0x01;
 | |
| 		internal const short SSL3_PROTOCOL_CODE = (0x03 << 8) | 0x00;
 | |
| 		internal const long  UNIX_BASE_TICKS	= 621355968000000000;
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Fields
 | |
| 		
 | |
| 		// Protocol version
 | |
| 		private SecurityProtocolType securityProtocol;
 | |
| 		
 | |
| 		// Sesison ID
 | |
| 		private byte[] sessionId;
 | |
| 
 | |
| 		// Compression method
 | |
| 		private SecurityCompressionType compressionMethod;
 | |
| 
 | |
| 		// Information sent and request by the server in the Handshake protocol
 | |
| 		private TlsServerSettings serverSettings;
 | |
| 
 | |
| 		// Client configuration
 | |
| 		private TlsClientSettings clientSettings;
 | |
| 
 | |
| 		// Cipher suite information
 | |
| 		private SecurityParameters current;
 | |
| 		private SecurityParameters negotiating;
 | |
| 		private SecurityParameters read;
 | |
| 		private SecurityParameters write;
 | |
| 		private CipherSuiteCollection supportedCiphers;
 | |
| 
 | |
| 		// Last handshake message received
 | |
| 		private HandshakeType lastHandshakeMsg;
 | |
| 
 | |
| 		// Handshake negotiation state
 | |
| 		private	HandshakeState handshakeState;
 | |
| 
 | |
| 		// Misc
 | |
| 		private bool	abbreviatedHandshake;
 | |
| 		private bool	receivedConnectionEnd;
 | |
| 		private bool	sentConnectionEnd;
 | |
| 		private bool	protocolNegotiated;
 | |
| 		
 | |
| 		// Sequence numbers
 | |
| 		private ulong	writeSequenceNumber;
 | |
| 		private ulong	readSequenceNumber;
 | |
| 
 | |
| 		// Random data
 | |
| 		private byte[]	clientRandom;
 | |
| 		private byte[]	serverRandom;
 | |
| 		private byte[]	randomCS;
 | |
| 		private byte[]	randomSC;
 | |
| 
 | |
| 		// Key information
 | |
| 		private byte[]	masterSecret;
 | |
| 		private byte[]	clientWriteKey;
 | |
| 		private byte[]	serverWriteKey;
 | |
| 		private byte[]	clientWriteIV;
 | |
| 		private byte[]	serverWriteIV;
 | |
| 		
 | |
| 		// Handshake hashes
 | |
| 		private TlsStream handshakeMessages;
 | |
| 		
 | |
| 		// Secure Random generator		
 | |
| 		private RandomNumberGenerator random;
 | |
| 
 | |
| 		// Record protocol
 | |
| 		private RecordProtocol recordProtocol;
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Properties
 | |
| 
 | |
| 		public bool AbbreviatedHandshake
 | |
| 		{
 | |
| 			get { return abbreviatedHandshake; }
 | |
| 			set { abbreviatedHandshake = value; }
 | |
| 		}
 | |
| 
 | |
| 		public bool	ProtocolNegotiated
 | |
| 		{
 | |
| 			get { return this.protocolNegotiated; }
 | |
| 			set { this.protocolNegotiated = value; }
 | |
| 		}
 | |
| 
 | |
| 		public bool ChangeCipherSpecDone { get; set; }
 | |
| 
 | |
| 		public SecurityProtocolType SecurityProtocol
 | |
| 		{
 | |
| 			get 
 | |
| 			{
 | |
| 				if ((this.securityProtocol & SecurityProtocolType.Tls) == SecurityProtocolType.Tls ||	
 | |
| 					(this.securityProtocol & SecurityProtocolType.Default) == SecurityProtocolType.Default)
 | |
| 				{
 | |
| 					return SecurityProtocolType.Tls;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					if ((this.securityProtocol & SecurityProtocolType.Ssl3) == SecurityProtocolType.Ssl3)
 | |
| 					{
 | |
| 						return SecurityProtocolType.Ssl3;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				throw new NotSupportedException("Unsupported security protocol type");
 | |
| 			}
 | |
| 
 | |
| 			set { this.securityProtocol = value; }
 | |
| 		}
 | |
| 
 | |
| 		public SecurityProtocolType SecurityProtocolFlags
 | |
| 		{
 | |
| 			get { return this.securityProtocol; }
 | |
| 		}
 | |
| 
 | |
| 		public short Protocol
 | |
| 		{
 | |
| 			get 
 | |
| 			{ 
 | |
| 				switch (this.SecurityProtocol)
 | |
| 				{
 | |
| 					case SecurityProtocolType.Tls:
 | |
| 					case SecurityProtocolType.Default:
 | |
| 						return Context.TLS1_PROTOCOL_CODE;
 | |
| 
 | |
| 					case SecurityProtocolType.Ssl3:
 | |
| 						return Context.SSL3_PROTOCOL_CODE;
 | |
| 
 | |
| 					case SecurityProtocolType.Ssl2:
 | |
| 					default:
 | |
| 						throw new NotSupportedException("Unsupported security protocol type");
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public byte[] SessionId
 | |
| 		{
 | |
| 			get { return this.sessionId; }
 | |
| 			set { this.sessionId = value; }
 | |
| 		}
 | |
| 
 | |
| 		public SecurityCompressionType CompressionMethod
 | |
| 		{
 | |
| 			get { return this.compressionMethod; }
 | |
| 			set { this.compressionMethod = value; }
 | |
| 		}
 | |
| 
 | |
| 		public TlsServerSettings ServerSettings
 | |
| 		{
 | |
| 			get { return this.serverSettings; }
 | |
| 		}
 | |
| 
 | |
| 		public TlsClientSettings ClientSettings
 | |
| 		{
 | |
| 			get { return this.clientSettings; }
 | |
| 		}
 | |
| 
 | |
| 		public HandshakeType LastHandshakeMsg
 | |
| 		{
 | |
| 			get { return this.lastHandshakeMsg; }
 | |
| 			set { this.lastHandshakeMsg = value; }
 | |
| 		}
 | |
| 
 | |
| 		public	HandshakeState HandshakeState
 | |
| 		{
 | |
| 			get { return this.handshakeState; }
 | |
| 			set { this.handshakeState = value; }
 | |
| 		}
 | |
| 
 | |
| 		public bool ReceivedConnectionEnd
 | |
| 		{
 | |
| 			get { return this.receivedConnectionEnd; }
 | |
| 			set { this.receivedConnectionEnd = value; }
 | |
| 		}
 | |
| 
 | |
| 		public bool SentConnectionEnd
 | |
| 		{
 | |
| 			get { return this.sentConnectionEnd; }
 | |
| 			set { this.sentConnectionEnd = value; }
 | |
| 		}
 | |
| 
 | |
| 		public CipherSuiteCollection SupportedCiphers
 | |
| 		{
 | |
| 			get { return supportedCiphers; }
 | |
| 			set { supportedCiphers = value; }
 | |
| 		}
 | |
| 
 | |
| 		public TlsStream HandshakeMessages
 | |
| 		{
 | |
| 			get { return this.handshakeMessages; }
 | |
| 		}
 | |
| 
 | |
| 		public ulong WriteSequenceNumber
 | |
| 		{
 | |
| 			get { return this.writeSequenceNumber; }
 | |
| 			set { this.writeSequenceNumber = value; }
 | |
| 		}
 | |
| 
 | |
| 		public ulong ReadSequenceNumber
 | |
| 		{
 | |
| 			get { return this.readSequenceNumber; }
 | |
| 			set { this.readSequenceNumber = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] ClientRandom
 | |
| 		{
 | |
| 			get { return this.clientRandom; }
 | |
| 			set { this.clientRandom = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] ServerRandom
 | |
| 		{
 | |
| 			get { return this.serverRandom; }
 | |
| 			set { this.serverRandom = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] RandomCS
 | |
| 		{
 | |
| 			get { return this.randomCS; }
 | |
| 			set { this.randomCS = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] RandomSC
 | |
| 		{
 | |
| 			get { return this.randomSC; }
 | |
| 			set { this.randomSC = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] MasterSecret
 | |
| 		{
 | |
| 			get { return this.masterSecret; }
 | |
| 			set { this.masterSecret = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] ClientWriteKey
 | |
| 		{
 | |
| 			get { return this.clientWriteKey; }
 | |
| 			set { this.clientWriteKey = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] ServerWriteKey
 | |
| 		{
 | |
| 			get { return this.serverWriteKey; }
 | |
| 			set { this.serverWriteKey = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] ClientWriteIV
 | |
| 		{
 | |
| 			get { return this.clientWriteIV; }
 | |
| 			set { this.clientWriteIV = value; }
 | |
| 		}
 | |
| 
 | |
| 		public byte[] ServerWriteIV
 | |
| 		{
 | |
| 			get { return this.serverWriteIV; }
 | |
| 			set { this.serverWriteIV = value; }
 | |
| 		}
 | |
| 
 | |
| 		public RecordProtocol RecordProtocol
 | |
| 		{
 | |
| 			get { return this.recordProtocol; }
 | |
| 			set { this.recordProtocol = value; }
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Constructors
 | |
| 
 | |
| 		public Context(SecurityProtocolType securityProtocolType)
 | |
| 		{
 | |
| 			this.SecurityProtocol	= securityProtocolType;
 | |
| 			this.compressionMethod	= SecurityCompressionType.None;
 | |
| 			this.serverSettings		= new TlsServerSettings();
 | |
| 			this.clientSettings		= new TlsClientSettings();
 | |
| 			this.handshakeMessages	= new TlsStream();
 | |
| 			this.sessionId			= null;
 | |
| 			this.handshakeState		= HandshakeState.None;
 | |
| 			this.random				= RandomNumberGenerator.Create();
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Methods
 | |
| 		
 | |
| 		public int GetUnixTime()
 | |
| 		{
 | |
| 			DateTime now = DateTime.UtcNow;
 | |
| 																		     
 | |
| 			return (int)((now.Ticks - UNIX_BASE_TICKS) / TimeSpan.TicksPerSecond);
 | |
| 		}
 | |
| 
 | |
| 		public byte[] GetSecureRandomBytes(int count)
 | |
| 		{
 | |
| 			byte[] secureBytes = new byte[count];
 | |
| 
 | |
| 			this.random.GetNonZeroBytes(secureBytes);
 | |
| 			
 | |
| 			return secureBytes;
 | |
| 		}
 | |
| 
 | |
| 		public virtual void Clear()
 | |
| 		{
 | |
| 			this.compressionMethod	= SecurityCompressionType.None;
 | |
| 			this.serverSettings		= new TlsServerSettings();
 | |
| 			this.clientSettings		= new TlsClientSettings();
 | |
| 			this.handshakeMessages	= new TlsStream();
 | |
| 			this.sessionId			= null;
 | |
| 			this.handshakeState		= HandshakeState.None;
 | |
| 
 | |
| 			this.ClearKeyInfo();
 | |
| 		}
 | |
| 
 | |
| 		public virtual void ClearKeyInfo()
 | |
| 		{
 | |
| 			// Clear Master Secret
 | |
| 			if (masterSecret != null) {
 | |
| 				Array.Clear (masterSecret, 0, masterSecret.Length);
 | |
| 				masterSecret = null;
 | |
| 			}
 | |
| 
 | |
| 			// Clear client and server random
 | |
| 			if (clientRandom != null) {
 | |
| 				Array.Clear (clientRandom, 0, clientRandom.Length);
 | |
| 				clientRandom = null;
 | |
| 			}
 | |
| 			if (serverRandom != null) {
 | |
| 				Array.Clear (serverRandom, 0, serverRandom.Length);
 | |
| 				serverRandom = null;
 | |
| 			}
 | |
| 			if (randomCS != null) {
 | |
| 				Array.Clear (randomCS, 0, randomCS.Length);
 | |
| 				randomCS = null;
 | |
| 			}
 | |
| 			if (randomSC != null) {
 | |
| 				Array.Clear (randomSC, 0, randomSC.Length);
 | |
| 				randomSC = null;
 | |
| 			}
 | |
| 
 | |
| 			// Clear client keys
 | |
| 			if (clientWriteKey != null) {
 | |
| 				Array.Clear (clientWriteKey, 0, clientWriteKey.Length);
 | |
| 				clientWriteKey = null;
 | |
| 			}
 | |
| 			if (clientWriteIV != null) {
 | |
| 				Array.Clear (clientWriteIV, 0, clientWriteIV.Length);
 | |
| 				clientWriteIV = null;
 | |
| 			}
 | |
| 			
 | |
| 			// Clear server keys
 | |
| 			if (serverWriteKey != null) {
 | |
| 				Array.Clear (serverWriteKey, 0, serverWriteKey.Length);
 | |
| 				serverWriteKey = null;
 | |
| 			}
 | |
| 			if (serverWriteIV != null) {
 | |
| 				Array.Clear (serverWriteIV, 0, serverWriteIV.Length);
 | |
| 				serverWriteIV = null;
 | |
| 			}
 | |
| 
 | |
| 			// Reset handshake messages
 | |
| 			this.handshakeMessages.Reset();
 | |
| 
 | |
| 			// Clear MAC keys if protocol is different than Ssl3
 | |
| 			// SSLv3 needs them inside Mono.Security.Protocol.Tls.SslCipherSuite.Compute[Client|Server]RecordMAC
 | |
| 			if (this.securityProtocol != SecurityProtocolType.Ssl3)
 | |
| 			{
 | |
| //				this.clientWriteMAC = null;
 | |
| //				this.serverWriteMAC = null;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public SecurityProtocolType DecodeProtocolCode (short code, bool allowFallback = false)
 | |
| 		{
 | |
| 			switch (code)
 | |
| 			{
 | |
| 				case Context.TLS1_PROTOCOL_CODE:
 | |
| 					return SecurityProtocolType.Tls;
 | |
| 
 | |
| 				case Context.SSL3_PROTOCOL_CODE:
 | |
| 					return SecurityProtocolType.Ssl3;
 | |
| 
 | |
| 				default:
 | |
| 					// if allowed we'll continue using TLS (1.0) even if the other side is capable of using a newer
 | |
| 					// version of the TLS protocol
 | |
| 					if (allowFallback && (code > (short) Context.TLS1_PROTOCOL_CODE))
 | |
| 						return SecurityProtocolType.Tls;
 | |
| 					throw new NotSupportedException("Unsupported security protocol type");
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public void ChangeProtocol(short protocol)
 | |
| 		{
 | |
| 			SecurityProtocolType protocolType = this.DecodeProtocolCode(protocol);
 | |
| 
 | |
| 			if ((protocolType & this.SecurityProtocolFlags) == protocolType ||
 | |
| 				(this.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
 | |
| 			{
 | |
| 				this.SecurityProtocol = protocolType;
 | |
| 				this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers ((this is ServerContext), protocolType);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				throw new TlsException(AlertDescription.ProtocolVersion, "Incorrect protocol version received from server");
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public SecurityParameters Current
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				if (current == null)
 | |
| 					current = new SecurityParameters ();
 | |
| 				if (current.Cipher != null)
 | |
| 					current.Cipher.Context = this;
 | |
| 				return current;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public SecurityParameters Negotiating
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				if (negotiating == null)
 | |
| 					negotiating = new SecurityParameters ();
 | |
| 				if (negotiating.Cipher != null)
 | |
| 					negotiating.Cipher.Context = this;
 | |
| 				return negotiating;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public SecurityParameters Read
 | |
| 		{
 | |
| 			get { return read; }
 | |
| 		}
 | |
| 
 | |
| 		public SecurityParameters Write
 | |
| 		{
 | |
| 			get { return write; }
 | |
| 		}
 | |
| 
 | |
| 		public void StartSwitchingSecurityParameters (bool client)
 | |
| 		{
 | |
| 			if (client) {
 | |
| 				// everything we write from now on is encrypted
 | |
| 				write = negotiating;
 | |
| 				// but we still read with the older cipher until we 
 | |
| 				// receive the ChangeCipherSpec message
 | |
| 				read = current;
 | |
| 			} else {
 | |
| 				// everything we read from now on is encrypted
 | |
| 				read = negotiating;
 | |
| 				// but we still write with the older cipher until we 
 | |
| 				// receive the ChangeCipherSpec message
 | |
| 				write = current;
 | |
| 			}
 | |
| 			current = negotiating;
 | |
| 		}
 | |
| 
 | |
| 		public void EndSwitchingSecurityParameters (bool client)
 | |
| 		{
 | |
| 			SecurityParameters temp;
 | |
| 			if (client) {
 | |
| 				temp = read;
 | |
| 				// we now read with the new, negotiated, security parameters
 | |
| 				read = current;
 | |
| 			} else {
 | |
| 				temp = write;
 | |
| 				// we now write with the new, negotiated, security parameters
 | |
| 				write = current;
 | |
| 			}
 | |
| 			// so we clear the old one (last reference)
 | |
| 			if (temp != null)
 | |
| 				temp.Clear ();
 | |
| 			negotiating = temp;
 | |
| 			// and are now ready for a future renegotiation
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 	}
 | |
| }
 |