[Mono-dev] SslStream implementation

Sebastien Pouliot sebastien.pouliot at gmail.com
Thu Aug 23 07:48:46 EDT 2007


Hello Atsushi,

On Thu, 2007-08-23 at 16:04 +0900, Atsushi Eno wrote:
> Hello,
> 
> I have created a System.Net.Security.SslStream implementation, which
> is based on Mono.Security.Protocol.Tls.

Nice work :)

> It requires some Makefile changes (due to cyclic dependency foo).

This is kind of strange as System.dll (v2) already depends on
Mono.Security.dll

> I have also created a few port of Mono.Security sample tools (which
> are found in Mono.Security/Test/tools) to verify SslStream behavior.
> 
> There are some issues (grep MonoTODO and FIXME) e.g. it requires
> X509Certificate2 due to certificate population in Mono.Security
> (I doubt that it could be solved without changing Mono.Security
> internals).

a few things inline

> If it looks good I'll check it in svn (probably port of those
> "tools" as well).
> 
> Atsushi Eno
> plain text document attachment (sslstream.patch)
> Index: Makefile
> ===================================================================
> --- Makefile	(revision 84522)
> +++ Makefile	(working copy)
> @@ -40,6 +40,8 @@
>  SECURITY_DEP_FILE := $(wildcard ../lib/$(PROFILE)/$(SECURITY_DEP))
>  CONFIGURATION_DEP := System.Configuration.dll
>  CONFIGURATION_DEP_FILE := $(wildcard ../lib/$(PROFILE)/$(CONFIGURATION_DEP))
> +PREBUILT_DEP := System.dll
> +PREBUILT_DEP_FILE := $(wildcard ../lib/$(PROFILE)/$(PREBUILT_DEP))
>  CYCLIC_DEPS += $(SECURITY_DEP) $(CONFIGURATION_DEP)
>  CYCLIC_DEP_FILES += $(SECURITY_DEP_FILE) $(CONFIGURATION_DEP_FILE)
>  LIB_MCS_FLAGS = -nowarn:618 -d:CONFIGURATION_2_0 -unsafe $(RESOURCE_FILES:%=-resource:%)
> @@ -95,10 +97,14 @@
>  endif
>  
>  ifdef CONFIGURATION_DEP_FILE
> -LIB_MCS_FLAGS += -define:CONFIGURATION_DEP -r:$(CONFIGURATION_DEP) -r:PrebuiltSystem=$(topdir)/class/lib/$(PROFILE)/System.dll
> +LIB_MCS_FLAGS += -define:CONFIGURATION_DEP -r:$(CONFIGURATION_DEP)
>  $(the_lib): $(CONFIGURATION_DEP_FILE)
>  endif
>  
> +ifdef PREBUILT_DEP_FILE
> +LIB_MCS_FLAGS += -r:PrebuiltSystem=$(topdir)/class/lib/$(PROFILE)/System.dll
> +endif
> +
>  $(test_lib): $(test_lib).config $(TEST_RESOURCES)
>  
>  $(test_lib).config: Test/test-config-file
> Index: System.Net.Security/SslStream.cs
> ===================================================================
> --- System.Net.Security/SslStream.cs	(revision 84522)
> +++ System.Net.Security/SslStream.cs	(working copy)
> @@ -3,9 +3,10 @@
>  //
>  // Authors:
>  //	Tim Coleman (tim at timcoleman.com)
> +//	Atsushi Enomoto (atsushi at ximian.com)
>  //
>  // Copyright (C) Tim Coleman, 2004
> -// (c) 2004 Novell, Inc. (http://www.novell.com)
> +// (c) 2004,2007 Novell, Inc. (http://www.novell.com)
>  //
>  
>  //
> @@ -29,7 +30,8 @@
>  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>  //
>  
> -#if NET_2_0 
> +#if NET_2_0 && SECURITY_DEP
> +extern alias PrebuiltSystem;
>  
>  using System;
>  using System.IO;
> @@ -37,44 +39,61 @@
>  using System.Security.Authentication;
>  using System.Security.Cryptography.X509Certificates;
>  using System.Security.Principal;
> +using System.Security.Cryptography;
> +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;
> +
> +using X509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
> +
>  namespace System.Net.Security 
>  {
> +	[MonoLimitation ("Non-X509Certificate2 certificate is not supported")]

The original X509Certificate is busted, design-wise, wrt to the private
key.

>  	public class SslStream : AuthenticatedStream
>  	{
>  		#region Fields
>  
> -		int readTimeout;
> -		int writeTimeout;
> +		int read_timeout;
> +		int write_timeout;
> +		SslStreamBase ssl_stream;
> +		RemoteCertificateValidationCallback validation_callback;
> +		LocalCertificateSelectionCallback selection_callback;
>  
>  		#endregion // Fields
>  
>  		#region Constructors
>  
> -		[MonoTODO]
>  		public SslStream (Stream innerStream)
> -			: base (innerStream, false)
> +			: this (innerStream, false)
>  		{
>  		}
>  
> -		[MonoTODO]
>  		public SslStream (Stream innerStream, bool leaveStreamOpen)
>  			: base (innerStream, leaveStreamOpen)
>  		{
>  		}
> -#if SECURITY_DEP
> -		[MonoTODO]
> +
> +		[MonoTODO ("certValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
>  		public SslStream (Stream innerStream, bool leaveStreamOpen, RemoteCertificateValidationCallback certValidationCallback)
> -			: base (innerStream, leaveStreamOpen)
> +			: this (innerStream, leaveStreamOpen, certValidationCallback, null)
>  		{
>  		}
>  
> -		[MonoTODO]
> +		[MonoTODO ("certValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
>  		public SslStream (Stream innerStream, bool leaveStreamOpen, RemoteCertificateValidationCallback certValidationCallback, LocalCertificateSelectionCallback certSelectionCallback)
>  			: base (innerStream, leaveStreamOpen)
>  		{
> +			// they are nullable.
> +			validation_callback = certValidationCallback;
> +			selection_callback = certSelectionCallback;
>  		}
> -#endif
>  		#endregion // Constructors
>  
>  		#region Properties
> @@ -87,231 +106,420 @@
>  			get { return InnerStream.CanSeek; }
>  		}
>  
> -		[MonoTODO]
>  		public override bool CanTimeout {
> -			get { throw new NotImplementedException (); }
> +			get { return InnerStream.CanTimeout; }
>  		}
>  
>  		public override bool CanWrite {
>  			get { return InnerStream.CanWrite; }
>  		}
>  
> -		[MonoTODO]
> -		public virtual bool CheckCertRevocationStatus {
> -			get { throw new NotImplementedException (); }
> +		public override long Length {
> +			get { return InnerStream.Length; }
>  		}
>  
> -		[MonoTODO]
> -		public virtual CipherAlgorithmType CipherAlgorithm  {
> -			get { throw new NotImplementedException (); }
> +		public override long Position {
> +			get { return InnerStream.Position; }
> +			set {
> +				throw new NotSupportedException ("This stream does not support seek operations");
> +			}
>  		}
>  
> -		[MonoTODO]
> -		public virtual int CipherStrength  {
> -			get { throw new NotImplementedException (); }
> -		}
> +		// AuthenticatedStream overrides
>  
> -		[MonoTODO]
> -		public virtual HashAlgorithmType HashAlgorithm  {
> -			get { throw new NotImplementedException (); }
> -		}
> -
> -		[MonoTODO]
> -		public virtual int HashStrength  {
> -			get { throw new NotImplementedException (); }
> -		}
> -
> -		[MonoTODO]
>  		public override bool IsAuthenticated { 
> -			get { throw new NotImplementedException (); }
> +			get { return ssl_stream != null; }
>  		}
>  
> -		[MonoTODO]
>  		public override bool IsEncrypted { 
> -			get { throw new NotImplementedException (); }
> +			get { return IsAuthenticated; }
>  		}
>  
> -		[MonoTODO]
>  		public override bool IsMutuallyAuthenticated { 
> -			get { throw new NotImplementedException (); }
> +			get { return IsAuthenticated && (IsServer ? RemoteCertificate != null : LocalCertificate != null); }
>  		}
>  
> -		[MonoTODO]
>  		public override bool IsServer { 
> -			get { throw new NotImplementedException (); }
> +			get { return ssl_stream is SslServerStream; }
>  		}
>  
> -		[MonoTODO]
>  		public override bool IsSigned { 
> -			get { throw new NotImplementedException (); }
> +			get { return IsAuthenticated; }
>  		}
>  
> -		[MonoTODO]
> -		public virtual ExchangeAlgorithmType KeyExchangeAlgorithm { 
> -			get { throw new NotImplementedException (); }
> +		[MonoTODO ("The property exists but not supported")]

Since it's an override over Stream.ReadTimeout can't the original (base)
do the job ?

> +		public override int ReadTimeout {
> +			get { return read_timeout; }
> +			set { read_timeout = value; }
>  		}
>  
> -		[MonoTODO]
> -		public virtual int KeyExchangeStrength { 
> -			get { throw new NotImplementedException (); }
> +		[MonoTODO ("The property exists but not supported")]

same

> +		public override int WriteTimeout {
> +			get { return write_timeout; }
> +			set { write_timeout = value; }
>  		}
>  
> -		public override long Length {
> -			get { return InnerStream.Length; }
> +		// SslStream
> +
> +		public virtual bool CheckCertRevocationStatus {
> +			get {
> +				if (!IsAuthenticated)
> +					return false;
> +
> +				return ssl_stream.CheckCertRevocationStatus;
> +			}
>  		}
>  
> -		[MonoTODO]
> -		public virtual X509Certificate LocalCertificate {
> -			get { throw new NotImplementedException (); }
> +		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;
> +				}
> +
> +				throw new InvalidOperationException ("Not supported cipher algorithm is in use. It is likely a bug in SslStream.");
> +			}
>  		}
>  
> -		public override long Position {
> -			get { return InnerStream.Position; }
> -			set { InnerStream.Position = value; }
> +		public virtual int CipherStrength  {
> +			get {
> +				CheckConnectionAuthenticated ();
> +
> +				return ssl_stream.CipherStrength;
> +			}
>  		}
>  
> -		public override int ReadTimeout {
> -			get { return readTimeout; }
> -			set { readTimeout = value; }
> +		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;
> +				}
> +
> +				throw new InvalidOperationException ("Not supported hash algorithm is in use. It is likely a bug in SslStream.");
> +			}
>  		}
>  
> -		[MonoTODO]
> +		public virtual int HashStrength  {
> +			get {
> +				CheckConnectionAuthenticated ();
> +
> +				return ssl_stream.HashStrength;
> +			}
> +		}
> +
> +		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;
> +				}
> +
> +				throw new InvalidOperationException ("Not supported exchange algorithm is in use. It is likely a bug in SslStream.");
> +			}
> +		}
> +
> +		public virtual int KeyExchangeStrength { 
> +			get {
> +				CheckConnectionAuthenticated ();
> +
> +				return ssl_stream.KeyExchangeStrength;
> +			}
> +		}
> +
> +		public virtual X509Certificate LocalCertificate {
> +			get {
> +				CheckConnectionAuthenticated ();
> +
> +				return IsServer ? ssl_stream.ServerCertificate : ((SslClientStream) ssl_stream).SelectedClientCertificate;
> +			}
> +		}
> +
>  		public virtual X509Certificate RemoteCertificate {
> -			get { throw new NotImplementedException (); }
> +			get {
> +				CheckConnectionAuthenticated ();
> +
> +				return !IsServer ? ssl_stream.ServerCertificate : ((SslServerStream) ssl_stream).ClientCertificate;
> +			}
>  		}
>  
> -		[MonoTODO]
>  		public virtual SslProtocols SslProtocol {
> -			get { throw new NotImplementedException (); }
> -		}
> +			get {
> +				CheckConnectionAuthenticated ();
>  
> -		public override int WriteTimeout {
> -			get { return writeTimeout; }
> -			set { writeTimeout = value; }
> +				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.");
> +			}
>  		}
>  
>  		#endregion // Properties
>  
>  		#region Methods
>  
> -		[MonoTODO]
> +		AsymmetricAlgorithm GetPrivateKey (X509Certificate cert, string targetHost)
> +		{
> +			// FIXME: what can I do for non-X509Certificate2 ?
nothing, MS can't do much either. It will find a private key *if* the
X509Certificate exists in the CryptoAPI key store (associated to the
certificate store) but the X509Store class (2.0) deals with
X509Certificate2 so...
> +			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 IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
>  		{
> -			throw new NotImplementedException ();
> +			return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false, asyncCallback, asyncState);
>  		}
>  
> -		[MonoTODO]
>  		public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols sslProtocolType, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
>  		{
> -			throw new NotImplementedException ();
> +			if (IsAuthenticated)
> +				throw new InvalidOperationException ("This SslStream is already authenticated");
> +
> +			SslClientStream s = new SslClientStream (InnerStream,  targetHost, !LeaveInnerStreamOpen, GetMonoSslProtocol (sslProtocolType), 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.
this could be changed, in the 2.0 profile, as the Mono.Security version
of X509Certificate is private-key aware.
> 
> +			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 (validation_callback != null)

The X509Chain inside System.dll is more RFC3280 compliant than the
(older) one provided in Mono.Security.dll and should be used.

> +				s.ServerCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
> +					// FIXME: X509Chain is not provided
> +					// FIXME: SslPolicyErrors is incomplete
> +					SslPolicyErrors errors = certErrors.Length > 0 ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None;
> +					return validation_callback (this, cert, null, errors);
> +				};
> +			if (selection_callback != null)
> +				s.ClientCertSelectionDelegate = OnCertificateSelection;
> +
> +			ssl_stream = s;
> +
> +			return BeginWrite (new byte [0], 0, 0, asyncCallback, asyncState);
>  		}
>  
> -		[MonoTODO]
>  		public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
>  		{
> -			throw new NotImplementedException ();
> +			CheckConnectionAuthenticated ();
> +
> +			return ssl_stream.BeginRead (buffer, offset, count, asyncCallback, asyncState);
>  		}
>  
> -		[MonoTODO]
>  		public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback callback, object asyncState)
>  		{
> -			throw new NotImplementedException ();
> +			return BeginAuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false, callback, asyncState);
>  		}
>  
> -		[MonoTODO]
>  		public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols sslProtocolType, bool checkCertificateRevocation, AsyncCallback callback, object asyncState)
>  		{
> -			throw new NotImplementedException ();
> +			if (IsAuthenticated)
> +				throw new InvalidOperationException ("This SslStream is already authenticated");
> +
> +			SslServerStream s = new SslServerStream (InnerStream, serverCertificate, clientCertificateRequired, !LeaveInnerStreamOpen, GetMonoSslProtocol (sslProtocolType));
> +			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.
same
> +			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) {
> +					// FIXME: X509Chain is not provided
> +					// FIXME: SslPolicyErrors is incomplete
> +					SslPolicyErrors errors = certErrors.Length > 0 ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None;
> +					return validation_callback (this, cert, null, errors);
> +				};
> +
> +			ssl_stream = s;
> +
> +			return BeginRead (new byte [0], 0, 0, callback, asyncState);
>  		}
>  
> -		[MonoTODO]
> +		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 IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
>  		{
> -			throw new NotImplementedException ();
> +			CheckConnectionAuthenticated ();
> +
> +			return ssl_stream.BeginWrite (buffer, offset, count, asyncCallback, asyncState);
>  		}
>  
> -		[MonoTODO]
>  		public virtual void AuthenticateAsClient (string targetHost)
>  		{
> -			throw new NotImplementedException ();
> +			AuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false);
>  		}
>  
> -		[MonoTODO]
>  		public virtual void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols sslProtocolType, bool checkCertificateRevocation)
>  		{
> -			throw new NotImplementedException ();
> +			EndAuthenticateAsClient (BeginAuthenticateAsClient (
> +				targetHost, clientCertificates, sslProtocolType, checkCertificateRevocation, null, null));
>  		}
>  
> -		[MonoTODO]
>  		public virtual void AuthenticateAsServer (X509Certificate serverCertificate)
>  		{
> -			throw new NotImplementedException ();
> +			AuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false);
>  		}
>  
> -		[MonoTODO]
>  		public virtual void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols sslProtocolType, bool checkCertificateRevocation)
>  		{
> -			throw new NotImplementedException ();
> +			EndAuthenticateAsServer (BeginAuthenticateAsServer (
> +				serverCertificate, clientCertificateRequired, sslProtocolType, checkCertificateRevocation, null, null));
>  		}
>  
> -		[MonoTODO]
>  		protected override void Dispose (bool disposing)
>  		{
> +			if (disposing) {
> +				if (ssl_stream != null)
> +					ssl_stream.Dispose ();
> +				ssl_stream = null;
> +			}
>  			base.Dispose (disposing);
>  		}
>  
> -		[MonoTODO]
>  		public virtual void EndAuthenticateAsClient (IAsyncResult asyncResult)
>  		{
> -			throw new NotImplementedException ();
> +			CheckConnectionAuthenticated ();
> +
> +			if (CanRead)
> +				ssl_stream.EndRead (asyncResult);
> +			else
> +				ssl_stream.EndWrite (asyncResult);
>  		}
>  
> -		[MonoTODO]
> -		public override int EndRead (IAsyncResult asyncResult)
> +		public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
>  		{
> -			throw new NotImplementedException ();
> +			CheckConnectionAuthenticated ();
> +
> +			if (CanRead)
> +				ssl_stream.EndRead (asyncResult);
> +			else
> +				ssl_stream.EndWrite (asyncResult);
>  		}
>  
> -		[MonoTODO]
> -		public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
> +		public override int EndRead (IAsyncResult asyncResult)
>  		{
> -			throw new NotImplementedException ();
> +			CheckConnectionAuthenticated ();
> +
> +			return ssl_stream.EndRead (asyncResult);
>  		}
>  
> -		[MonoTODO]
>  		public override void EndWrite (IAsyncResult asyncResult)
>  		{
> -			throw new NotImplementedException ();
> +			CheckConnectionAuthenticated ();
> +
> +			ssl_stream.EndWrite (asyncResult);
>  		}
>  
> -		[MonoTODO]
>  		public override void Flush ()
>  		{
> +			CheckConnectionAuthenticated ();
> +
>  			InnerStream.Flush ();
>  		}
>  
> -		[MonoTODO]
>  		public override int Read (byte[] buffer, int offset, int count)
>  		{
> -			throw new NotImplementedException ();
> +			return EndRead (BeginRead (buffer, offset, count, null, null));
>  		}
>  
> -		[MonoTODO]
>  		public override long Seek (long offset, SeekOrigin origin)
>  		{
> -			throw new NotImplementedException ();
> +			throw new NotSupportedException ("This stream does not support seek operations");
>  		}
>  
> -		[MonoTODO]
>  		public override void SetLength (long value)
>  		{
> -			throw new NotImplementedException ();
> +			InnerStream.SetLength (value);
>  		}
>  
> -		[MonoTODO]
>  		public override void Write (byte[] buffer, int offset, int count)
>  		{
> -			throw new NotImplementedException ();
> +			EndWrite (BeginWrite (buffer, offset, count, null, null));
>  		}
>  
>  		public void Write (byte[] buffer)
> @@ -319,6 +527,12 @@
>  			Write (buffer, 0, buffer.Length);
>  		}
>  
> +		void CheckConnectionAuthenticated ()
> +		{
> +			if (!IsAuthenticated)
> +				throw new InvalidOperationException ("This operation is invalid until it is successfully authenticated");
> +		}
> +
>  		#endregion // Methods
>  	}
>  }
> Index: System.Net.Security/LocalCertificateSelectionCallback.cs
> ===================================================================
> --- System.Net.Security/LocalCertificateSelectionCallback.cs	(revision 84522)
> +++ System.Net.Security/LocalCertificateSelectionCallback.cs	(working copy)
> @@ -29,10 +29,13 @@
>  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>  //
>  
> -#if NET_2_0 
> +#if NET_2_0 && SECURITY_DEP
> +extern alias PrebuiltSystem;
>  
>  using System.Security.Cryptography.X509Certificates;
>  
> +using X509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
> +
>  namespace System.Net.Security 
>  {
>  	public delegate X509Certificate LocalCertificateSelectionCallback (
> _______________________________________________
> Mono-devel-list mailing list
> Mono-devel-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list




More information about the Mono-devel-list mailing list