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 ([EMAIL PROTECTED]) > +// Atsushi Enomoto ([EMAIL PROTECTED]) > // > // 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@lists.ximian.com > http://lists.ximian.com/mailman/listinfo/mono-devel-list _______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list