Merge branch 'master' of github.com:mono/mono
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / Context.cs
index f452db3bc47336d92fb42836754860013934f875..792a9970a1774369fcd68897cbe3a3a17fb05aa0 100644 (file)
@@ -1,4 +1,6 @@
-
+// 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
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-/* Transport Security Layer (TLS)
- * Copyright (c) 2003-2004 Carlos Guzman Alvarez
- * 
- * 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;
@@ -83,8 +62,11 @@ namespace Mono.Security.Protocol.Tls
                private TlsClientSettings clientSettings;
 
                // Cipher suite information
-               private CipherSuite                             cipher;
-               private CipherSuiteCollection   supportedCiphers;
+               private SecurityParameters current;
+               private SecurityParameters negotiating;
+               private SecurityParameters read;
+               private SecurityParameters write;
+               private CipherSuiteCollection supportedCiphers;
 
                // Last handshake message received
                private HandshakeType lastHandshakeMsg;
@@ -93,13 +75,14 @@ namespace Mono.Security.Protocol.Tls
                private HandshakeState handshakeState;
 
                // Misc
-               private bool    isActual;
-               private bool    connectionEnd;
+               private bool    abbreviatedHandshake;
+               private bool    receivedConnectionEnd;
+               private bool    sentConnectionEnd;
                private bool    protocolNegotiated;
                
                // Sequence numbers
-               private long    writeSequenceNumber;
-               private long    readSequenceNumber;
+               private ulong   writeSequenceNumber;
+               private ulong   readSequenceNumber;
 
                // Random data
                private byte[]  clientRandom;
@@ -109,8 +92,6 @@ namespace Mono.Security.Protocol.Tls
 
                // Key information
                private byte[]  masterSecret;
-               private byte[]  clientWriteMAC;
-               private byte[]  serverWriteMAC;
                private byte[]  clientWriteKey;
                private byte[]  serverWriteKey;
                private byte[]  clientWriteIV;
@@ -129,6 +110,12 @@ namespace Mono.Security.Protocol.Tls
 
                #region Properties
 
+               public bool AbbreviatedHandshake
+               {
+                       get { return abbreviatedHandshake; }
+                       set { abbreviatedHandshake = value; }
+               }
+
                public bool     ProtocolNegotiated
                {
                        get { return this.protocolNegotiated; }
@@ -205,12 +192,6 @@ namespace Mono.Security.Protocol.Tls
                        get { return this.clientSettings; }
                }
 
-               public bool     IsActual
-               {
-                       get { return this.isActual; }
-                       set { this.isActual = value; }
-               }
-
                public HandshakeType LastHandshakeMsg
                {
                        get { return this.lastHandshakeMsg; }
@@ -223,20 +204,16 @@ namespace Mono.Security.Protocol.Tls
                        set { this.handshakeState = value; }
                }
 
-               public bool ConnectionEnd
+               public bool ReceivedConnectionEnd
                {
-                       get { return this.connectionEnd; }
-                       set { this.connectionEnd = value; }
+                       get { return this.receivedConnectionEnd; }
+                       set { this.receivedConnectionEnd = value; }
                }
 
-               public CipherSuite Cipher
+               public bool SentConnectionEnd
                {
-                       get { return this.cipher; }
-                       set 
-                       { 
-                               this.cipher                     = value; 
-                               this.cipher.Context = this;
-                       }
+                       get { return this.sentConnectionEnd; }
+                       set { this.sentConnectionEnd = value; }
                }
 
                public CipherSuiteCollection SupportedCiphers
@@ -250,13 +227,13 @@ namespace Mono.Security.Protocol.Tls
                        get { return this.handshakeMessages; }
                }
 
-               public long WriteSequenceNumber
+               public ulong WriteSequenceNumber
                {
                        get { return this.writeSequenceNumber; }
                        set { this.writeSequenceNumber = value; }
                }
 
-               public long ReadSequenceNumber
+               public ulong ReadSequenceNumber
                {
                        get { return this.readSequenceNumber; }
                        set { this.readSequenceNumber = value; }
@@ -292,18 +269,6 @@ namespace Mono.Security.Protocol.Tls
                        set { this.masterSecret = value; }
                }
 
-               public byte[] ClientWriteMAC
-               {
-                       get { return this.clientWriteMAC; }
-                       set { this.clientWriteMAC = value; }
-               }
-
-               public byte[] ServerWriteMAC
-               {
-                       get { return this.serverWriteMAC; }
-                       set { this.serverWriteMAC = value; }
-               }
-
                public byte[] ClientWriteKey
                {
                        get { return this.clientWriteKey; }
@@ -358,7 +323,7 @@ namespace Mono.Security.Protocol.Tls
                {
                        DateTime now = DateTime.UtcNow;
                                                                                                                                                     
-                       return (int)(now.Ticks - UNIX_BASE_TICKS / TimeSpan.TicksPerSecond);
+                       return (int)((now.Ticks - UNIX_BASE_TICKS) / TimeSpan.TicksPerSecond);
                }
 
                public byte[] GetSecureRandomBytes(int count)
@@ -385,30 +350,58 @@ namespace Mono.Security.Protocol.Tls
                public virtual void ClearKeyInfo()
                {
                        // Clear Master Secret
-                       this.masterSecret       = null;
+                       if (masterSecret != null) {
+                               Array.Clear (masterSecret, 0, masterSecret.Length);
+                               masterSecret = null;
+                       }
 
                        // Clear client and server random
-                       this.clientRandom       = null;
-                       this.serverRandom       = null;
-                       this.randomCS           = null;
-                       this.randomSC           = null;
+                       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
-                       this.clientWriteKey     = null;
-                       this.clientWriteIV      = null;
+                       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
-                       this.serverWriteKey     = null;
-                       this.serverWriteIV      = null;
+                       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;
+//                             this.clientWriteMAC = null;
+//                             this.serverWriteMAC = null;
                        }
                }
 
@@ -427,6 +420,96 @@ namespace Mono.Security.Protocol.Tls
                        }
                }
 
+               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.Clear();
+                               this.SupportedCiphers = null;
+                               this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(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
        }
 }