Merge the 'martin-ssl-integration' branch.
authorMartin Baulig <martin.baulig@xamarin.com>
Thu, 5 Feb 2015 03:58:39 +0000 (04:58 +0100)
committerMarek Safar <marek.safar@gmail.com>
Mon, 2 May 2016 22:07:48 +0000 (00:07 +0200)
All changes are conditional to MONO_FEATURE_NEW_TLS.

In addition to that, all changes to their code are also conditional to 'MONO'; this
mostly applies to SecureChannel, which needed several changes to replace their native
SSPI implementation with Mono's new managed version.

* Net/SecureProtocols/SslStream.cs: Make partial and comment out 'SslStream.TransportContext'.

* Net/SecureProtocols/SslState.cs: Make partial and add new internal constructor; pass the
  'SSPIConfiguration' argument down to SecureChannel's .ctor.

* Net/SecureProtocols/_SslStream.cs: Make partial.

* Net/SecureProtocols/_SecureChannel.cs: Add Mono-specific SSPI APIs.

* Net/_SslSessionCache.cs: Make conditional.

mcs/class/referencesource/System/net/System/Net/SecureProtocols/SslStream.cs
mcs/class/referencesource/System/net/System/Net/SecureProtocols/_SslState.cs
mcs/class/referencesource/System/net/System/Net/SecureProtocols/_SslStream.cs
mcs/class/referencesource/System/net/System/Net/_SecureChannel.cs
mcs/class/referencesource/System/net/System/Net/_SslSessionsCache.cs

index 8b1efa799ee6aec95c7f851021515fd583162837..6f8f5cfaed52a91131e74b635c5b7354d1bc8c0c 100644 (file)
@@ -15,6 +15,7 @@ Author:
 Revision History:
 
 --*/
+#if MONO_FEATURE_NEW_TLS && SECURITY_DEP
 namespace System.Net.Security {
 using System;
 using System.IO;
@@ -60,7 +61,7 @@ using System.Net.Configuration;
     //
     //
     //
-    public class SslStream: AuthenticatedStream
+    public partial class SslStream: AuthenticatedStream
     {
         private SslState _SslState;
         private RemoteCertificateValidationCallback _userCertificateValidationCallback;
@@ -221,7 +222,11 @@ using System.Net.Configuration;
         {
             get
             {
+                #if MONO_NOT_SUPPORTED
                 return new SslStreamContext(this);
+                #else
+                throw new NotSupportedException();
+                #endif
             }
         }
 
@@ -488,6 +493,7 @@ using System.Net.Configuration;
    }
 
 }
+#endif
 
 
 
index 257492c8262257140f4d8fe551b9cdc7d4fa3586..6e3b791aff8f5479dabbd3bc4bc972cb0eaf6026 100644 (file)
@@ -19,7 +19,7 @@ Revision History:
     15-Sept-2003    Implemented concurent rehanshake
 
 --*/
-
+#if MONO_FEATURE_NEW_TLS && SECURITY_DEP
 namespace System.Net.Security {
     using System;
     using System.IO;
@@ -34,7 +34,7 @@ namespace System.Net.Security {
     using System.ComponentModel;
     using System.Diagnostics;
 
-    internal class SslState {
+    internal partial class SslState {
 
         static int UniqueNameInteger = 123;
         static AsyncProtocolCallback _PartialFrameCallback  = new AsyncProtocolCallback(PartialFrameCallback);
@@ -120,6 +120,17 @@ namespace System.Net.Security {
             _CertSelectionDelegate  = certSelectionCallback;
             _EncryptionPolicy = encryptionPolicy;
         }
+
+#if MONO
+        private readonly SSPIConfiguration _Configuration;
+
+        internal SslState(Stream innerStream, RemoteCertValidationCallback certValidationCallback, LocalCertSelectionCallback  certSelectionCallback, EncryptionPolicy encryptionPolicy, SSPIConfiguration config)
+            : this(innerStream, certValidationCallback, certSelectionCallback, encryptionPolicy)
+        {
+            _Configuration = config;
+        }
+#endif
+
         //
         //
         //
@@ -175,8 +186,13 @@ namespace System.Net.Security {
 
             _Exception = null;
             try {
+#if MONO
+                _Context = new SecureChannel(targetHost, isServer, (SchProtocols)((int)enabledSslProtocols), serverCertificate, clientCertificates, remoteCertRequired,
+                    checkCertName, checkCertRevocationStatus, _EncryptionPolicy, _CertSelectionDelegate, _CertValidationDelegate, _Configuration);
+#else
                 _Context = new SecureChannel(targetHost, isServer, (SchProtocols)((int)enabledSslProtocols), serverCertificate, clientCertificates, remoteCertRequired,
                                                                checkCertName, checkCertRevocationStatus, _EncryptionPolicy, _CertSelectionDelegate);
+#endif
             }
             catch (Win32Exception e) {
                 throw new AuthenticationException(SR.GetString(SR.net_auth_SSPI), e);
@@ -1728,3 +1744,4 @@ namespace System.Net.Security {
 #endif
     }
 }
+#endif
index 6bb6bd71e040b0d3d34ad760e4d17d38415a2787..4ac07c5d5c0d207e83bfde9a863416e523004721 100644 (file)
@@ -16,7 +16,7 @@ Revision History:
     22-Aug-2003 New design that has obsoleted SslClientStream and SslServerStream class
 
 --*/
-
+#if MONO_FEATURE_NEW_TLS && SECURITY_DEP
 namespace System.Net.Security {
     using System;
     using System.IO;
@@ -30,7 +30,7 @@ namespace System.Net.Security {
     //
     // This is a wrapping stream that does data encryption/decryption based on a successfully authenticated SSPI context.
     //
-    internal class _SslStream
+    internal partial class _SslStream
     {
         private static AsyncCallback _WriteCallback         = new AsyncCallback(WriteCallback);
         private static AsyncCallback _MulitpleWriteCallback = new AsyncCallback(MulitpleWriteCallback);
@@ -1058,3 +1058,4 @@ namespace System.Net.Security {
         //
     }
 }
+#endif
index ee0bdf395d42bcb46e93997d9de061c920276f3c..b4e7e7f643c306dfe8d016f8d6628b066328209e 100644 (file)
@@ -3,6 +3,7 @@
 //     Copyright (c) Microsoft Corporation.  All rights reserved.
 // </copyright>
 //------------------------------------------------------------------------------
+#if MONO_FEATURE_NEW_TLS && SECURITY_DEP
 
 namespace System.Net.Security {
     using System.Diagnostics;
@@ -27,7 +28,7 @@ namespace System.Net.Security {
     //  for the SSL Stream to utilize.
     //
 
-    internal class SecureChannel {
+    internal partial class SecureChannel {
         //also used as a lock object
         internal const string SecurityPackage = "Microsoft Unified Security Protocol Provider";
         private  static readonly object s_SyncObject = new object();
@@ -82,13 +83,47 @@ namespace System.Net.Security {
 
         private bool                m_RefreshCredentialNeeded;
 
+        private SSPIInterface       m_SecModule;
 
+
+#if MONO
+        internal SecureChannel(string hostname, bool serverMode, SchProtocols protocolFlags, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName,
+            bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate, RemoteCertValidationCallback remoteValidationCallback, SSPIConfiguration config)
+        {
+            GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)));
+            if (Logging.On) Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy);
+            m_SecModule = GlobalSSPI.Create(hostname, serverMode, protocolFlags, serverCertificate, clientCertificates, remoteCertRequired, checkCertName, checkCertRevocationStatus, encryptionPolicy, certSelectionDelegate, remoteValidationCallback, config);
+
+            m_Destination = hostname;
+
+            GlobalLog.Assert(hostname != null, "SecureChannel#{0}::.ctor()|hostname == null", ValidationHelper.HashString(this));
+            m_HostName = hostname;
+            m_ServerMode = serverMode;
+
+            if (serverMode)
+                m_ProtocolFlags = (protocolFlags & SchProtocols.ServerMask);
+            else
+                m_ProtocolFlags = (protocolFlags & SchProtocols.ClientMask);
+
+            m_ServerCertificate = serverCertificate;
+            m_ClientCertificates = clientCertificates;
+            m_RemoteCertRequired = remoteCertRequired;
+            m_SecurityContext = null;
+            m_CheckCertRevocation = checkCertRevocationStatus;
+            m_CheckCertName = checkCertName;
+            m_CertSelectionDelegate = certSelectionDelegate;
+            m_RefreshCredentialNeeded = true;
+            m_EncryptionPolicy = encryptionPolicy;
+            GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::.ctor");
+        }
+#else
         internal SecureChannel(string hostname, bool serverMode, SchProtocols protocolFlags, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName, 
                                                   bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate)
         {
             GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)));
             if (Logging.On) Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy);
-            SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true);
+            m_SecModule = GlobalSSPI.SSPISecureChannel;
+            SSPIWrapper.GetVerifyPackageInfo(m_SecModule, SecurityPackage, true);
 
             m_Destination = hostname;
 
@@ -112,6 +147,7 @@ namespace System.Net.Security {
             m_EncryptionPolicy = encryptionPolicy;
             GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::.ctor");
         }
+#endif
 
         //
         // SecureChannel properties
@@ -140,7 +176,7 @@ namespace System.Net.Security {
             }
         }
 
-
+#if MONO_NOT_SUPPORTED
         unsafe static class UnmanagedCertificateContext
         {
 
@@ -177,12 +213,17 @@ namespace System.Net.Security {
                 return result;
             }
         }
+#endif
+
         //
         //This code extracts a remote certificate upon request.
         //SECURITY: The scenario is allowed in semitrust
         //
         internal X509Certificate2 GetRemoteCertificate(out X509Certificate2Collection remoteCertificateStore)
         {
+#if MONO
+            return SSPIWrapper.GetRemoteCertificate(m_SecurityContext, out remoteCertificateStore);
+#else
             remoteCertificateStore = null;
 
             if (m_SecurityContext == null)
@@ -192,7 +233,7 @@ namespace System.Net.Security {
             X509Certificate2 result = null;
             SafeFreeCertContext remoteContext = null;
             try {
-                remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.RemoteCertificate) as SafeFreeCertContext;
+                remoteContext = SSPIWrapper.QueryContextAttributes(m_SecModule, m_SecurityContext, ContextAttribute.RemoteCertificate) as SafeFreeCertContext;
                 if (remoteContext != null && !remoteContext.IsInvalid) {
                     result = new X509Certificate2(remoteContext.DangerousGetHandle());
                 }
@@ -208,6 +249,7 @@ namespace System.Net.Security {
             GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::RemoteCertificate{get;}", (result == null? "null" :result.Subject));
             
             return result;
+#endif
         }
 
         internal ChannelBinding GetChannelBinding(ChannelBindingKind kind)
@@ -217,7 +259,7 @@ namespace System.Net.Security {
             ChannelBinding result = null;
             if (m_SecurityContext != null)
             {
-                result = SSPIWrapper.QueryContextChannelBinding(GlobalSSPI.SSPISecureChannel, m_SecurityContext, (ContextAttribute)kind);
+                result = SSPIWrapper.QueryContextChannelBinding(m_SecModule, m_SecurityContext, (ContextAttribute)kind);
             }
 
             GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::GetChannelBindingToken", ValidationHelper.HashString(result));
@@ -393,7 +435,9 @@ namespace System.Net.Security {
                             // For v 1.1 compat We want to ensure the store is opened under the **process** acount.
                             //
                             try {
+#if !DISABLE_CAS_USE
                                 using (WindowsIdentity.Impersonate(IntPtr.Zero))
+#endif
                                 {
                                     store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
                                     GlobalLog.Print("SecureChannel::EnsureStoreOpened() storeLocation:" + storeLocation + " returned store:" + store.GetHashCode().ToString("x"));
@@ -456,7 +500,8 @@ namespace System.Net.Security {
 
             if (IsValidContext)
             {
-                IssuerListInfoEx issuerList = (IssuerListInfoEx)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.IssuerListInfoEx);
+#if MONO_NOT_IMPLEMENTED
+                IssuerListInfoEx issuerList = (IssuerListInfoEx)SSPIWrapper.QueryContextAttributes(m_SecModule, m_SecurityContext, ContextAttribute.IssuerListInfoEx);
                 try
                 {
                     if (issuerList.cIssuers>0) {
@@ -488,6 +533,7 @@ namespace System.Net.Security {
                         issuerList.aIssuers.Close();
                     }
                 }
+#endif
             }
             return issuers;
         }
@@ -852,12 +898,14 @@ namespace System.Net.Security {
                 //
                 // For v 1.1 compat We want to ensure the credential are accessed under >>process<< acount.
                 //
+#if !DISABLE_CAS_USE
                 using (WindowsIdentity.Impersonate(IntPtr.Zero))
+#endif
                 {
-                    return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
+                    return SSPIWrapper.AcquireCredentialsHandle(m_SecModule, SecurityPackage, credUsage, secureCredential);
                 }
             } catch {
-                return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
+                return SSPIWrapper.AcquireCredentialsHandle(m_SecModule, SecurityPackage, credUsage, secureCredential);
             }
         }
 
@@ -949,7 +997,7 @@ namespace System.Net.Security {
                     if (m_ServerMode)
                     {
                         errorCode = SSPIWrapper.AcceptSecurityContext(
-                                        GlobalSSPI.SSPISecureChannel,
+                                        m_SecModule,
                                         ref m_CredentialsHandle,
                                         ref m_SecurityContext,
                                         ServerRequiredFlags | (m_RemoteCertRequired? ContextFlags.MutualAuth: ContextFlags.Zero),
@@ -965,7 +1013,7 @@ namespace System.Net.Security {
                         if(incomingSecurity == null)
                         {
                             errorCode = SSPIWrapper.InitializeSecurityContext(
-                                            GlobalSSPI.SSPISecureChannel,
+                                            m_SecModule,
                                             ref m_CredentialsHandle,
                                             ref m_SecurityContext,
                                             m_Destination,
@@ -976,23 +1024,25 @@ namespace System.Net.Security {
                                             ref m_Attributes
                                             );
 
+#if !MONO
                             // This only needs to happen the first time per context.
                             if ((errorCode == (int)SecurityStatus.OK || errorCode == (int)SecurityStatus.ContinueNeeded) 
                                 && ComNetOS.IsWin8orLater && Microsoft.Win32.UnsafeNativeMethods.IsPackagedProcess.Value)
                             {
                                 // Windows Store app. Specify a window handle in case SChannel needs to pop-up prompts, like 
                                 // when it asks for permission to use a client certificate.
-                                int setError = SSPIWrapper.SetContextAttributes(GlobalSSPI.SSPISecureChannel,
+                                int setError = SSPIWrapper.SetContextAttributes(m_SecModule,
                                                 m_SecurityContext, 
                                                 ContextAttribute.UiInfo,
                                                 UnsafeNclNativeMethods.AppXHelper.PrimaryWindowHandle.Value);
                                 Debug.Assert(setError == 0, "SetContextAttributes error: " + setError);
                             }
+#endif
                         }
                         else
                         {
                             errorCode = SSPIWrapper.InitializeSecurityContext(
-                                            GlobalSSPI.SSPISecureChannel,
+                                            m_SecModule,
                                             m_CredentialsHandle,
                                             ref m_SecurityContext,
                                             m_Destination,
@@ -1050,7 +1100,10 @@ namespace System.Net.Security {
         --*/
         internal void ProcessHandshakeSuccess() {
             GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::ProcessHandshakeSuccess");
-            StreamSizes streamSizes = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.StreamSizes) as StreamSizes;
+#if MONO
+            m_HeaderSize = m_TrailerSize = 0;
+#else
+            StreamSizes streamSizes = SSPIWrapper.QueryContextAttributes(m_SecModule, m_SecurityContext, ContextAttribute.StreamSizes) as StreamSizes;
             if (streamSizes != null) {
                 try
                 {
@@ -1066,7 +1119,8 @@ namespace System.Net.Security {
                     throw;
                 }
             }
-            m_ConnectionInfo = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.ConnectionInfo) as SslConnectionInfo;
+            m_ConnectionInfo = SSPIWrapper.QueryContextAttributes(m_SecModule, m_SecurityContext, ContextAttribute.ConnectionInfo) as SslConnectionInfo;
+#endif
             GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::ProcessHandshakeSuccess");
         }
 
@@ -1090,6 +1144,13 @@ namespace System.Net.Security {
             GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() +" buffersize: " + buffer.Length.ToString() );
             GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt() buffer:[" + Encoding.ASCII.GetString(buffer, 0, Math.Min(buffer.Length,128)) + "]");
 
+#if MONO
+            var incoming = new SecurityBuffer (buffer, offset, size, BufferType.Data);
+            var errorCode = (SecurityStatus)SSPIWrapper.EncryptMessage(m_SecModule, m_SecurityContext, incoming, 0);
+            output = incoming.token;
+            resultSize = incoming.size;
+            return errorCode;
+#else
             byte[] e_writeBuffer;
             try
             {
@@ -1132,7 +1193,7 @@ namespace System.Net.Security {
             securityBuffer[2] = new SecurityBuffer(e_writeBuffer, m_HeaderSize + size, m_TrailerSize, BufferType.Trailer);
             securityBuffer[3] = new SecurityBuffer(null, BufferType.Empty);
 
-            int errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPISecureChannel, m_SecurityContext, securityBuffer, 0);
+            int errorCode = SSPIWrapper.EncryptMessage(m_SecModule, m_SecurityContext, securityBuffer, 0);
 
             if (errorCode != 0) {
                 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt ERROR", errorCode.ToString("x"));
@@ -1146,6 +1207,7 @@ namespace System.Net.Security {
                 return SecurityStatus.OK;
 
             }
+#endif
         }
 
         internal SecurityStatus Decrypt(byte[] payload, ref int offset, ref int count) {
@@ -1162,6 +1224,20 @@ namespace System.Net.Security {
                 throw new ArgumentOutOfRangeException("count");
             }
 
+#if MONO
+            var buffer = new SecurityBuffer (payload, offset, count, BufferType.Data);
+            var errorCode = (SecurityStatus)SSPIWrapper.DecryptMessage(m_SecModule, m_SecurityContext, buffer, 0);
+            count = buffer.size;
+            if (buffer.type == BufferType.Empty) {
+                offset = count = 0;
+            } else if (payload != buffer.token) {
+                Buffer.BlockCopy(buffer.token, buffer.offset, payload, 0, buffer.size);
+                Array.Clear(buffer.token, 0, buffer.token.Length);
+                offset = 0;
+            } else {
+                offset = buffer.offset;
+            }
+#else
             // decryption using SCHANNEL requires four buffers
             SecurityBuffer[] decspc = new SecurityBuffer[4];
             decspc[0] = new SecurityBuffer(payload, offset, count, BufferType.Data);
@@ -1169,7 +1245,7 @@ namespace System.Net.Security {
             decspc[2] = new SecurityBuffer(null, BufferType.Empty);
             decspc[3] = new SecurityBuffer(null, BufferType.Empty);
 
-            SecurityStatus errorCode = (SecurityStatus)SSPIWrapper.DecryptMessage(GlobalSSPI.SSPISecureChannel, m_SecurityContext, decspc, 0);
+            SecurityStatus errorCode = (SecurityStatus)SSPIWrapper.DecryptMessage(m_SecModule, m_SecurityContext, decspc, 0);
 
             count = 0;
             for (int i = 0; i < decspc.Length; i++) {
@@ -1182,6 +1258,7 @@ namespace System.Net.Security {
                     break;
                 }
             }
+#endif
           
             return errorCode;
         }
@@ -1206,6 +1283,14 @@ namespace System.Net.Security {
             SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;
             // we don't catch exceptions in this method, so it's safe for "accepted" be initialized with true
             bool success = false;
+
+#if MONO
+            if (IsServer)
+                // FIXME
+                success = true;
+            else
+                success = SSPIWrapper.CheckRemoteCertificate(m_SecurityContext);
+#else
             X509Chain chain = null;
             X509Certificate2 remoteCertificateEx = null;
 
@@ -1309,6 +1394,7 @@ namespace System.Net.Security {
                     remoteCertificateEx.Reset();
             }
             GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::VerifyRemoteCertificate", success.ToString());
+#endif
             return success;
         }
 
@@ -1842,4 +1928,5 @@ namespace System.Net.Security {
     }
 
 }
+#endif
 
index f18ef20944d238d818aaee4600173761240e50a3..913e6106f2ceb0f4d3546dd0fc58764be25e53c1 100644 (file)
@@ -17,6 +17,7 @@ Revision History:
 
 
 --*/
+#if MONO_FEATURE_NEW_TLS && SECURITY_DEP
 namespace System.Net.Security {
 
 using System.Net;
@@ -231,3 +232,4 @@ using System.Collections;
         }
     }
 }
+#endif