Merge pull request #2869 from BrzVlad/feature-mod-union-opt
[mono.git] / mcs / class / System / System.Net.Security / SslStream.cs
index aa075912da212aec92a40908fa65b88aa1c087ce..59e741722b67b820861fb63af0005b004087397c 100644 (file)
 //
-// System.Net.Security.SslStream.cs
+// SslStream.cs
 //
-// Authors:
-//     Tim Coleman (tim@timcoleman.com)
-//     Atsushi Enomoto (atsushi@ximian.com)
-//     Marek Safar (marek.safar@gmail.com)
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
 //
-// Copyright (C) Tim Coleman, 2004
-// (c) 2004,2007 Novell, Inc. (http://www.novell.com)
-// Copyright 2011 Xamarin Inc.
+// Copyright (c) 2015 Xamarin, Inc.
 //
-
+// 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:
 //
-// 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.
+// 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.
+
+#if !MONO_FEATURE_NEW_TLS
 #if SECURITY_DEP
 
-#if MONOTOUCH || MONODROID
-using Mono.Security.Protocol.Tls;
-
-using CipherAlgorithmType = System.Security.Authentication.CipherAlgorithmType;
-using HashAlgorithmType = System.Security.Authentication.HashAlgorithmType;
-using ExchangeAlgorithmType = System.Security.Authentication.ExchangeAlgorithmType;
-
-using MonoCipherAlgorithmType = Mono.Security.Protocol.Tls.CipherAlgorithmType;
-using MonoHashAlgorithmType = Mono.Security.Protocol.Tls.HashAlgorithmType;
-using MonoExchangeAlgorithmType = Mono.Security.Protocol.Tls.ExchangeAlgorithmType;
-using MonoSecurityProtocolType = Mono.Security.Protocol.Tls.SecurityProtocolType;
-#else
-extern alias PrebuiltSystem;
+#if MONO_SECURITY_ALIAS
 extern alias MonoSecurity;
+#endif
 
-using X509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
+#if MONO_SECURITY_ALIAS
+using MonoSecurity::Mono.Security.Interface;
+#else
+using Mono.Security.Interface;
+#endif
 
 using CipherAlgorithmType = System.Security.Authentication.CipherAlgorithmType;
 using HashAlgorithmType = System.Security.Authentication.HashAlgorithmType;
 using ExchangeAlgorithmType = System.Security.Authentication.ExchangeAlgorithmType;
 
-using MonoCipherAlgorithmType = MonoSecurity::Mono.Security.Protocol.Tls.CipherAlgorithmType;
-using MonoHashAlgorithmType = MonoSecurity::Mono.Security.Protocol.Tls.HashAlgorithmType;
-using MonoExchangeAlgorithmType = MonoSecurity::Mono.Security.Protocol.Tls.ExchangeAlgorithmType;
-using MonoSecurityProtocolType = MonoSecurity::Mono.Security.Protocol.Tls.SecurityProtocolType;
-
-using MonoSecurity::Mono.Security.Protocol.Tls;
-#endif
-
 using System;
 using System.IO;
 using System.Net;
+using System.Net.Security;
 using System.Security.Authentication;
 using System.Security.Cryptography.X509Certificates;
+using System.Security.Permissions;
 using System.Security.Principal;
 using System.Security.Cryptography;
 
 using System.Threading.Tasks;
 
-namespace System.Net.Security 
+using MNS = Mono.Net.Security;
+
+namespace System.Net.Security
 {
-       [MonoTODO ("Non-X509Certificate2 certificate is not supported")]
-       public class SslStream : AuthenticatedStream
+       /*
+        * These two are defined by the referencesource; add them heere to make
+        * it easy to switch between the two implementations.
+        */
+
+       internal delegate bool RemoteCertValidationCallback (
+               string host,
+               X509Certificate certificate,
+               X509Chain chain,
+               SslPolicyErrors sslPolicyErrors);
+
+       internal delegate X509Certificate LocalCertSelectionCallback (
+               string targetHost,
+               X509CertificateCollection localCertificates,
+               X509Certificate remoteCertificate,
+               string[] acceptableIssuers);
+
+       public class SslStream : AuthenticatedStream, MNS.IMonoSslStream
        {
-               #region Fields
+               MonoTlsProvider provider;
+               IMonoSslStream impl;
 
-               SslStreamBase ssl_stream;
-               RemoteCertificateValidationCallback validation_callback;
-               LocalCertificateSelectionCallback selection_callback;
+               internal IMonoSslStream Impl {
+                       get {
+                               CheckDisposed ();
+                               return impl;
+                       }
+               }
 
-               #endregion // Fields
+               internal MonoTlsProvider Provider {
+                       get {
+                               CheckDisposed ();
+                               return provider;
+                       }
+               }
 
-               #region Constructors
+               static MonoTlsProvider GetProvider ()
+               {
+                       return MonoTlsProviderFactory.GetDefaultProvider ();
+               }
 
                public SslStream (Stream innerStream)
                        : this (innerStream, false)
@@ -96,537 +106,303 @@ namespace System.Net.Security
                public SslStream (Stream innerStream, bool leaveInnerStreamOpen)
                        : base (innerStream, leaveInnerStreamOpen)
                {
+                       provider = GetProvider ();
+                       impl = provider.CreateSslStream (innerStream, leaveInnerStreamOpen);
                }
 
-               [MonoTODO ("userCertificateValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
                public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback)
                        : this (innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, null)
                {
                }
 
-               [MonoTODO ("userCertificateValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
                public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback)
                        : base (innerStream, leaveInnerStreamOpen)
                {
-                       // they are nullable.
-                       validation_callback = userCertificateValidationCallback;
-                       selection_callback = userCertificateSelectionCallback;
-               }
-               #endregion // Constructors
-
-               #region Properties
-
-               public override bool CanRead {
-                       get { return InnerStream.CanRead; }
-               }
-
-               public override bool CanSeek {
-                       get { return InnerStream.CanSeek; }
+                       provider = GetProvider ();
+                       var settings = MonoTlsSettings.CopyDefaultSettings ();
+                       settings.RemoteCertificateValidationCallback = MNS.Private.CallbackHelpers.PublicToMono (userCertificateValidationCallback);
+                       settings.ClientCertificateSelectionCallback = MNS.Private.CallbackHelpers.PublicToMono (userCertificateSelectionCallback);
+                       impl = provider.CreateSslStream (innerStream, leaveInnerStreamOpen, settings);
                }
 
-               public override bool CanTimeout {
-                       get { return InnerStream.CanTimeout; }
+               internal SslStream (Stream innerStream, bool leaveInnerStreamOpen, IMonoSslStream impl)
+                       : base (innerStream, leaveInnerStreamOpen)
+               {
+                       this.impl = impl;
                }
 
-               public override bool CanWrite {
-                       get { return InnerStream.CanWrite; }
+               public virtual void AuthenticateAsClient (string targetHost)
+               {
+                       Impl.AuthenticateAsClient (targetHost);
                }
 
-               public override long Length {
-                       get { return InnerStream.Length; }
+               public virtual void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       Impl.AuthenticateAsClient (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation);
                }
 
-               public override long Position {
-                       get { return InnerStream.Position; }
-                       set {
-                               throw new NotSupportedException ("This stream does not support seek operations");
-                       }
+               // [HostProtection (ExternalThreading=true)]
+               public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
+               {
+                       return Impl.BeginAuthenticateAsClient (targetHost, asyncCallback, asyncState);
                }
 
-               // AuthenticatedStream overrides
-
-               public override bool IsAuthenticated { 
-                       get { return ssl_stream != null; }
+               // [HostProtection (ExternalThreading=true)]
+               public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
+               {
+                       return Impl.BeginAuthenticateAsClient (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, asyncCallback, asyncState);
                }
 
-               public override bool IsEncrypted { 
-                       get { return IsAuthenticated; }
+               public virtual void EndAuthenticateAsClient (IAsyncResult asyncResult)
+               {
+                       Impl.EndAuthenticateAsClient (asyncResult);
                }
 
-               public override bool IsMutuallyAuthenticated { 
-                       get { return IsAuthenticated && (IsServer ? RemoteCertificate != null : LocalCertificate != null); }
+               public virtual void AuthenticateAsServer (X509Certificate serverCertificate)
+               {
+                       Impl.AuthenticateAsServer (serverCertificate);
                }
 
-               public override bool IsServer { 
-                       get { return ssl_stream is SslServerStream; }
+               public virtual void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       Impl.AuthenticateAsServer (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation);
                }
 
-               public override bool IsSigned { 
-                       get { return IsAuthenticated; }
+               // [HostProtection (ExternalThreading=true)]
+               public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
+               {
+                       return Impl.BeginAuthenticateAsServer (serverCertificate, asyncCallback, asyncState);
                }
 
-               public override int ReadTimeout {
-                       get { return InnerStream.ReadTimeout; }
-                       set { InnerStream.ReadTimeout = value; }
+               public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
+               {
+                       return Impl.BeginAuthenticateAsServer (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, asyncCallback, asyncState);
                }
 
-               public override int WriteTimeout {
-                       get { return InnerStream.WriteTimeout; }
-                       set { InnerStream.WriteTimeout = value; }
+               public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
+               {
+                       Impl.EndAuthenticateAsServer (asyncResult);
                }
 
-               // SslStream
-
-               public virtual bool CheckCertRevocationStatus {
+               public TransportContext TransportContext {
                        get {
-                               if (!IsAuthenticated)
-                                       return false;
-
-                               return ssl_stream.CheckCertRevocationStatus;
+                               throw new NotSupportedException();
                        }
                }
 
-               public virtual CipherAlgorithmType CipherAlgorithm  {
-                       get {
-                               CheckConnectionAuthenticated ();
-
-                               switch (ssl_stream.CipherAlgorithm) {
-                               case MonoCipherAlgorithmType.Des:
-                                       return CipherAlgorithmType.Des;
-                               case MonoCipherAlgorithmType.None:
-                                       return CipherAlgorithmType.None;
-                               case MonoCipherAlgorithmType.Rc2:
-                                       return CipherAlgorithmType.Rc2;
-                               case MonoCipherAlgorithmType.Rc4:
-                                       return CipherAlgorithmType.Rc4;
-                               case MonoCipherAlgorithmType.SkipJack:
-                                       break;
-                               case MonoCipherAlgorithmType.TripleDes:
-                                       return CipherAlgorithmType.TripleDes;
-                               case MonoCipherAlgorithmType.Rijndael:
-                                       switch (ssl_stream.CipherStrength) {
-                                       case 128:
-                                               return CipherAlgorithmType.Aes128;
-                                       case 192:
-                                               return CipherAlgorithmType.Aes192;
-                                       case 256:
-                                               return CipherAlgorithmType.Aes256;
-                                       }
-                                       break;
-                               }
+               // [HostProtection (ExternalThreading=true)]
+               public virtual Task AuthenticateAsClientAsync (string targetHost)
+               {
+                       return Impl.AuthenticateAsClientAsync (targetHost);
+               }
 
-                               throw new InvalidOperationException ("Not supported cipher algorithm is in use. It is likely a bug in SslStream.");
-                       }
+               public virtual Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       return Impl.AuthenticateAsClientAsync (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation);
                }
 
-               public virtual int CipherStrength  {
-                       get {
-                               CheckConnectionAuthenticated ();
+               public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
+               {
+                       return Impl.AuthenticateAsServerAsync (serverCertificate);
+               }
 
-                               return ssl_stream.CipherStrength;
-                       }
+               public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       return Impl.AuthenticateAsServerAsync (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation);
                }
 
-               public virtual HashAlgorithmType HashAlgorithm  {
-                       get {
-                               CheckConnectionAuthenticated ();
-
-                               switch (ssl_stream.HashAlgorithm) {
-                               case MonoHashAlgorithmType.Md5:
-                                       return HashAlgorithmType.Md5;
-                               case MonoHashAlgorithmType.None:
-                                       return HashAlgorithmType.None;
-                               case MonoHashAlgorithmType.Sha1:
-                                       return HashAlgorithmType.Sha1;
-                               }
+               public override bool IsAuthenticated {
+                       get { return Impl.IsAuthenticated; }
+               }
 
-                               throw new InvalidOperationException ("Not supported hash algorithm is in use. It is likely a bug in SslStream.");
-                       }
+               public override bool IsMutuallyAuthenticated {
+                       get { return Impl.IsMutuallyAuthenticated; }
                }
 
-               public virtual int HashStrength  {
-                       get {
-                               CheckConnectionAuthenticated ();
+               public override bool IsEncrypted {
+                       get { return Impl.IsEncrypted; }
+               }
 
-                               return ssl_stream.HashStrength;
-                       }
+               public override bool IsSigned {
+                       get { return Impl.IsSigned; }
                }
 
-               public virtual ExchangeAlgorithmType KeyExchangeAlgorithm { 
-                       get {
-                               CheckConnectionAuthenticated ();
-
-                               switch (ssl_stream.KeyExchangeAlgorithm) {
-                               case MonoExchangeAlgorithmType.DiffieHellman:
-                                       return ExchangeAlgorithmType.DiffieHellman;
-                               case MonoExchangeAlgorithmType.Fortezza:
-                                       break;
-                               case MonoExchangeAlgorithmType.None:
-                                       return ExchangeAlgorithmType.None;
-                               case MonoExchangeAlgorithmType.RsaKeyX:
-                                       return ExchangeAlgorithmType.RsaKeyX;
-                               case MonoExchangeAlgorithmType.RsaSign:
-                                       return ExchangeAlgorithmType.RsaSign;
-                               }
+               public override bool IsServer {
+                       get { return Impl.IsServer; }
+               }
 
-                               throw new InvalidOperationException ("Not supported exchange algorithm is in use. It is likely a bug in SslStream.");
-                       }
+               public virtual SslProtocols SslProtocol {
+                       get { return (SslProtocols)Impl.SslProtocol; }
                }
 
-               public virtual int KeyExchangeStrength { 
-                       get {
-                               CheckConnectionAuthenticated ();
+               public virtual bool CheckCertRevocationStatus {
+                       get { return Impl.CheckCertRevocationStatus; }
+               }
 
-                               return ssl_stream.KeyExchangeStrength;
-                       }
+               X509Certificate MNS.IMonoSslStream.InternalLocalCertificate {
+                       get { return Impl.InternalLocalCertificate; }
                }
 
                public virtual X509Certificate LocalCertificate {
-                       get {
-                               CheckConnectionAuthenticated ();
-
-                               return IsServer ? ssl_stream.ServerCertificate : ((SslClientStream) ssl_stream).SelectedClientCertificate;
-                       }
+                       get { return Impl.LocalCertificate; }
                }
 
                public virtual X509Certificate RemoteCertificate {
-                       get {
-                               CheckConnectionAuthenticated ();
-                               return !IsServer ? ssl_stream.ServerCertificate : ((SslServerStream) ssl_stream).ClientCertificate;
-                       }
+                       get { return Impl.RemoteCertificate; }
                }
 
-               public virtual SslProtocols SslProtocol {
-                       get {
-                               CheckConnectionAuthenticated ();
-
-                               switch (ssl_stream.SecurityProtocol) {
-                               case MonoSecurityProtocolType.Default:
-                                       return SslProtocols.Default;
-                               case MonoSecurityProtocolType.Ssl2:
-                                       return SslProtocols.Ssl2;
-                               case MonoSecurityProtocolType.Ssl3:
-                                       return SslProtocols.Ssl3;
-                               case MonoSecurityProtocolType.Tls:
-                                       return SslProtocols.Tls;
-                               }
-
-                               throw new InvalidOperationException ("Not supported SSL/TLS protocol is in use. It is likely a bug in SslStream.");
-                       }
+               public virtual CipherAlgorithmType CipherAlgorithm {
+                       get { return (CipherAlgorithmType)Impl.CipherAlgorithm; }
                }
 
-               #endregion // Properties
-
-               #region Methods
-/*
-               AsymmetricAlgorithm GetPrivateKey (X509Certificate cert, string targetHost)
-               {
-                       // FIXME: what can I do for non-X509Certificate2 ?
-                       X509Certificate2 cert2 = cert as X509Certificate2;
-                       return cert2 != null ? cert2.PrivateKey : null;
-               }
-*/
-               X509Certificate OnCertificateSelection (X509CertificateCollection clientCerts, X509Certificate serverCert, string targetHost, X509CertificateCollection serverRequestedCerts)
-               {
-                       string [] acceptableIssuers = new string [serverRequestedCerts != null ? serverRequestedCerts.Count : 0];
-                       for (int i = 0; i < acceptableIssuers.Length; i++)
-                               acceptableIssuers [i] = serverRequestedCerts [i].GetIssuerName ();
-                       return selection_callback (this, targetHost, clientCerts, serverCert, acceptableIssuers);
+               public virtual int CipherStrength {
+                       get { return Impl.CipherStrength; }
                }
 
-               public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
-               {
-                       return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false, asyncCallback, asyncState);
+               public virtual HashAlgorithmType HashAlgorithm {
+                       get { return (HashAlgorithmType)Impl.HashAlgorithm; }
                }
 
-               public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
-               {
-                       if (IsAuthenticated)
-                               throw new InvalidOperationException ("This SslStream is already authenticated");
-
-                       SslClientStream s = new SslClientStream (InnerStream, targetHost, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols), clientCertificates);
-                       s.CheckCertRevocationStatus = checkCertificateRevocation;
-
-                       // Due to the Mono.Security internal, it cannot reuse
-                       // the delegated argument, as Mono.Security creates 
-                       // another instance of X509Certificate which lacks 
-                       // private key but is filled the private key via this
-                       // delegate.
-                       s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string host) {
-                               string hash = cert.GetCertHashString ();
-                               // ... so, we cannot use the delegate argument.
-                               foreach (X509Certificate cc in clientCertificates) {
-                                       if (cc.GetCertHashString () != hash)
-                                               continue;
-                                       X509Certificate2 cert2 = cc as X509Certificate2;
-                                       cert2 = cert2 ?? new X509Certificate2 (cc);
-                                       return cert2.PrivateKey;
-                               }
-                               return null;
-                       };
-
-#if MONOTOUCH || MONODROID
-                       // Even if validation_callback is null this allows us to verify requests where the user
-                       // does not provide a verification callback but attempts to authenticate with the website
-                       // as a client (see https://bugzilla.xamarin.com/show_bug.cgi?id=18962 for an example)
-                       var helper = new ServicePointManager.ChainValidationHelper (this, targetHost);
-                       helper.ServerCertificateValidationCallback = validation_callback;
-                       s.ServerCertValidation2 += new CertificateValidationCallback2 (helper.ValidateChain);
-#else
-                       if (validation_callback != null) {
-                               s.ServerCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
-                                       X509Chain chain = new X509Chain ();
-                                       X509Certificate2 x2 = (cert as X509Certificate2);
-                                       if (x2 == null)
-                                               x2 = new X509Certificate2 (cert);
-
-                                       if (!ServicePointManager.CheckCertificateRevocationList)
-                                               chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
-
-                                       // SSL specific checks (done by Mono.Security.dll SSL/TLS implementation) 
-                                       SslPolicyErrors errors = SslPolicyErrors.None;
-                                       foreach (int i in certErrors) {
-                                               switch (i) {
-                                               case -2146762490: // CERT_E_PURPOSE
-                                                       errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
-                                                       break;
-                                               case -2146762481: // CERT_E_CN_NO_MATCH
-                                                       errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
-                                                       break;
-                                               default:
-                                                       errors |= SslPolicyErrors.RemoteCertificateChainErrors;
-                                                       break;
-                                               }
-                                       }
-
-                                       chain.Build (x2);
-
-                                       // non-SSL specific X509 checks (i.e. RFC3280 related checks)
-                                       foreach (X509ChainStatus status in chain.ChainStatus) {
-                                               if (status.Status == X509ChainStatusFlags.NoError)
-                                                       continue;
-                                               if ((status.Status & X509ChainStatusFlags.PartialChain) != 0)
-                                                       errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
-                                               else
-                                                       errors |= SslPolicyErrors.RemoteCertificateChainErrors;
-                                       }
-
-                                       return validation_callback (this, cert, chain, errors);
-                               };
-                       }
-#endif
-                       if (selection_callback != null)
-                               s.ClientCertSelectionDelegate = OnCertificateSelection;
-
-                       ssl_stream = s;
-
-                       return BeginWrite (new byte [0], 0, 0, asyncCallback, asyncState);
+               public virtual int HashStrength {
+                       get { return Impl.HashStrength; }
                }
 
-               public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
-               {
-                       CheckConnectionAuthenticated ();
-
-                       return ssl_stream.BeginRead (buffer, offset, count, asyncCallback, asyncState);
+               public virtual ExchangeAlgorithmType KeyExchangeAlgorithm {
+                       get { return (ExchangeAlgorithmType)Impl.KeyExchangeAlgorithm; }
                }
 
-               public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
-               {
-                       return BeginAuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false, asyncCallback, asyncState);
+               public virtual int KeyExchangeStrength {
+                       get { return Impl.KeyExchangeStrength; }
                }
 
-               public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
-               {
-                       if (IsAuthenticated)
-                               throw new InvalidOperationException ("This SslStream is already authenticated");
-
-                       SslServerStream s = new SslServerStream (InnerStream, serverCertificate, clientCertificateRequired, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols));
-                       s.CheckCertRevocationStatus = checkCertificateRevocation;
-                       // Due to the Mono.Security internal, it cannot reuse
-                       // the delegated argument, as Mono.Security creates 
-                       // another instance of X509Certificate which lacks 
-                       // private key but is filled the private key via this
-                       // delegate.
-                       s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string targetHost) {
-                               // ... so, we cannot use the delegate argument.
-                               X509Certificate2 cert2 = serverCertificate as X509Certificate2 ?? new X509Certificate2 (serverCertificate);
-                               return cert2 != null ? cert2.PrivateKey : null;
-                       };
-
-                       if (validation_callback != null)
-                               s.ClientCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
-                                       X509Chain chain = null;
-                                       if (cert is X509Certificate2) {
-                                               chain = new X509Chain ();
-                                               chain.Build ((X509Certificate2) cert);
-                                       }
-                                       // FIXME: SslPolicyErrors is incomplete
-                                       SslPolicyErrors errors = certErrors.Length > 0 ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None;
-                                       return validation_callback (this, cert, chain, errors);
-                               };
-
-                       ssl_stream = s;
-
-                       return BeginWrite (new byte[0], 0, 0, asyncCallback, asyncState);
-               }
-
-               MonoSecurityProtocolType GetMonoSslProtocol (SslProtocols ms)
-               {
-                       switch (ms) {
-                       case SslProtocols.Ssl2:
-                               return MonoSecurityProtocolType.Ssl2;
-                       case SslProtocols.Ssl3:
-                               return MonoSecurityProtocolType.Ssl3;
-                       case SslProtocols.Tls:
-                               return MonoSecurityProtocolType.Tls;
-                       default:
-                               return MonoSecurityProtocolType.Default;
-                       }
+               public override bool CanSeek {
+                       get { return false; }
                }
 
-               public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
-               {
-                       CheckConnectionAuthenticated ();
+               public override bool CanRead {
+                       get { return Impl.CanRead; }
+               }
 
-                       return ssl_stream.BeginWrite (buffer, offset, count, asyncCallback, asyncState);
+               public override bool CanTimeout {
+                       get { return Impl.CanTimeout; }
                }
 
-               public virtual void AuthenticateAsClient (string targetHost)
-               {
-                       AuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false);
+               public override bool CanWrite {
+                       get { return Impl.CanWrite; }
                }
 
-               public virtual void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
-               {
-                       EndAuthenticateAsClient (BeginAuthenticateAsClient (
-                               targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, null, null));
+               public override int ReadTimeout {
+                       get { return Impl.ReadTimeout; }
+                       set { Impl.ReadTimeout = value; }
                }
 
-               public virtual void AuthenticateAsServer (X509Certificate serverCertificate)
-               {
-                       AuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false);
+               public override int WriteTimeout {
+                       get { return Impl.WriteTimeout; }
+                       set { Impl.WriteTimeout = value; }
                }
 
-               public virtual void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
-               {
-                       EndAuthenticateAsServer (BeginAuthenticateAsServer (
-                               serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, null, null));
+               public override long Length {
+                       get { return Impl.Length; }
                }
 
-               protected override void Dispose (bool disposing)
-               {
-                       if (disposing) {
-                               if (ssl_stream != null)
-                                       ssl_stream.Dispose ();
-                               ssl_stream = null;
+               public override long Position {
+                       get { return Impl.Position; }
+                       set {
+                               throw new NotSupportedException (SR.GetString (SR.net_noseek));
                        }
-                       base.Dispose (disposing);
                }
 
-               public virtual void EndAuthenticateAsClient (IAsyncResult asyncResult)
+               public override void SetLength (long value)
                {
-                       CheckConnectionAuthenticated ();
-
-                       if (CanRead)
-                               ssl_stream.EndRead (asyncResult);
-                       else
-                               ssl_stream.EndWrite (asyncResult);
+                       Impl.SetLength (value);
                }
 
-               public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
+               public override long Seek (long offset, SeekOrigin origin)
                {
-                       CheckConnectionAuthenticated ();
-
-                       if (CanRead)
-                               ssl_stream.EndRead (asyncResult);
-                       else
-                               ssl_stream.EndWrite (asyncResult);
+                       throw new NotSupportedException (SR.GetString (SR.net_noseek));
                }
 
-               public override int EndRead (IAsyncResult asyncResult)
+               public override void Flush ()
                {
-                       CheckConnectionAuthenticated ();
-
-                       return ssl_stream.EndRead (asyncResult);
+                       Impl.Flush ();
                }
 
-               public override void EndWrite (IAsyncResult asyncResult)
+               void CheckDisposed ()
                {
-                       CheckConnectionAuthenticated ();
-
-                       ssl_stream.EndWrite (asyncResult);
+                       if (impl == null)
+                               throw new ObjectDisposedException ("SslStream");
                }
 
-               public override void Flush ()
+               protected override void Dispose (bool disposing)
                {
-                       CheckConnectionAuthenticated ();
-
-                       InnerStream.Flush ();
+                       try {
+                               if (impl != null && disposing) {
+                                       impl.Dispose ();
+                                       impl = null;
+                               }
+                       } finally {
+                               base.Dispose (disposing);
+                       }
                }
 
                public override int Read (byte[] buffer, int offset, int count)
                {
-                       return EndRead (BeginRead (buffer, offset, count, null, null));
+                       return Impl.Read (buffer, offset, count);
                }
 
-               public override long Seek (long offset, SeekOrigin origin)
-               {
-                       throw new NotSupportedException ("This stream does not support seek operations");
-               }
-
-               public override void SetLength (long value)
+               public void Write (byte[] buffer)
                {
-                       InnerStream.SetLength (value);
+                       Impl.Write (buffer);
                }
 
                public override void Write (byte[] buffer, int offset, int count)
                {
-                       EndWrite (BeginWrite (buffer, offset, count, null, null));
+                       Impl.Write (buffer, offset, count);
                }
 
-               public void Write (byte[] buffer)
+               // [HostProtection (ExternalThreading=true)]
+               public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
                {
-                       Write (buffer, 0, buffer.Length);
+                       return Impl.BeginRead (buffer, offset, count, asyncCallback, asyncState);
                }
 
-               void CheckConnectionAuthenticated ()
+               public override int EndRead (IAsyncResult asyncResult)
                {
-                       if (!IsAuthenticated)
-                               throw new InvalidOperationException ("This operation is invalid until it is successfully authenticated");
+                       return Impl.EndRead (asyncResult);
                }
 
-               public virtual Task AuthenticateAsClientAsync (string targetHost)
+               // [HostProtection (ExternalThreading=true)]
+               public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
                {
-                       return Task.Factory.FromAsync (BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null);
+                       return Impl.BeginWrite (buffer, offset, count, asyncCallback, asyncState);
                }
 
-               public virtual Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               public override void EndWrite (IAsyncResult asyncResult)
                {
-                       var t = Tuple.Create (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, this);
+                       Impl.EndWrite (asyncResult);
+               }
 
-                       return Task.Factory.FromAsync ((callback, state) => {
-                               var d = (Tuple<string, X509CertificateCollection, SslProtocols, bool, SslStream>) state;
-                               return d.Item5.BeginAuthenticateAsClient (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
-                       }, EndAuthenticateAsClient, t);
+               AuthenticatedStream MNS.IMonoSslStream.AuthenticatedStream {
+                       get { return this; }
                }
 
-               public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
-               {
-                       return Task.Factory.FromAsync (BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null);
+               MonoTlsProvider MNS.IMonoSslStream.Provider {
+                       get { return provider; }
                }
 
-               public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               MonoTlsConnectionInfo MNS.IMonoSslStream.GetConnectionInfo ()
                {
-                       var t = Tuple.Create (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, this);
-
-                       return Task.Factory.FromAsync ((callback, state) => {
-                               var d = (Tuple<X509Certificate, bool, SslProtocols, bool, SslStream>) state;
-                               return d.Item5.BeginAuthenticateAsServer (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
-                       }, EndAuthenticateAsServer, t);
+                       return Impl.GetConnectionInfo ();
                }
-
-               #endregion // Methods
        }
 }
+#else // !SECURITY_DEP
+namespace System.Net.Security
+{
+       public class SslStream
+       {
+       }
+}
+#endif
 
 #endif