Convert blocking operations in HttpWebRequest and SslClientStream to non-blocking...
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / SslServerStream.cs
index 09b7c1f1df827341047abf4e618c0fea6c87ee38..b0d8bba6ffc99cc8b92675f31d8318bc32d43ef7 100644 (file)
@@ -34,7 +34,12 @@ using Mono.Security.Protocol.Tls.Handshake;
 
 namespace Mono.Security.Protocol.Tls
 {
-       public class SslServerStream : SslStreamBase
+#if INSIDE_SYSTEM
+       internal
+#else
+       public
+#endif
+       class SslServerStream : SslStreamBase
        {
                #region Internal Events
                
@@ -76,6 +81,7 @@ namespace Mono.Security.Protocol.Tls
 
                #endregion
 
+               public event CertificateValidationCallback2 ClientCertValidation2;
                #region Constructors
 
                public SslServerStream(
@@ -102,19 +108,41 @@ namespace Mono.Security.Protocol.Tls
                {
                }
 
+               public SslServerStream(
+                       Stream                  stream,
+                       X509Certificate serverCertificate,
+                       bool                    clientCertificateRequired,
+                       bool                    requestClientCertificate,
+                       bool                    ownsStream)
+                               : this (stream, serverCertificate, clientCertificateRequired, requestClientCertificate, ownsStream, SecurityProtocolType.Default)
+               {
+               }
+
                public SslServerStream(
                        Stream                                  stream,
                        X509Certificate                 serverCertificate,
                        bool                                    clientCertificateRequired,
                        bool                                    ownsStream,
                        SecurityProtocolType    securityProtocolType)
+                       : this (stream, serverCertificate, clientCertificateRequired, false, ownsStream, securityProtocolType)
+               {
+               }
+
+               public SslServerStream(
+                       Stream                                  stream,
+                       X509Certificate                 serverCertificate,
+                       bool                                    clientCertificateRequired,
+                       bool                                    requestClientCertificate,
+                       bool                                    ownsStream,
+                       SecurityProtocolType    securityProtocolType)
                        : base(stream, ownsStream)
                {
                        this.context = new ServerContext(
                                this,
                                securityProtocolType,
                                serverCertificate,
-                               clientCertificateRequired);
+                               clientCertificateRequired,
+                               requestClientCertificate);
 
                        this.protocol = new ServerRecordProtocol(innerStream, (ServerContext)this.context);
                }
@@ -168,7 +196,7 @@ namespace Mono.Security.Protocol.Tls
                                        Fig. 1 - Message flow for a full handshake              
                */
 
-               internal override IAsyncResult OnBeginNegotiateHandshake(AsyncCallback callback, object state)
+               internal override IAsyncResult BeginNegotiateHandshake(AsyncCallback callback, object state)
                {
                        // Reset the context if needed
                        if (this.context.HandshakeState != HandshakeState.None)
@@ -187,7 +215,7 @@ namespace Mono.Security.Protocol.Tls
 
                }
 
-               internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult)
+               internal override void EndNegotiateHandshake(IAsyncResult asyncResult)
                {
                        // Receive Client Hello message and ignore it
                        this.protocol.EndReceiveRecord(asyncResult);
@@ -206,50 +234,47 @@ namespace Mono.Security.Protocol.Tls
                        this.protocol.SendRecord(HandshakeType.Certificate);
 
                        // If the negotiated cipher is a KeyEx cipher send ServerKeyExchange
-                       if (this.context.Cipher.ExchangeAlgorithmType == ExchangeAlgorithmType.RsaKeyX)
+                       if (this.context.Negotiating.Cipher.IsExportable)
                        {
                                this.protocol.SendRecord(HandshakeType.ServerKeyExchange);
                        }
 
-                       bool certRequested = false;
-
                        // If the negotiated cipher is a KeyEx cipher or
                        // the client certificate is required send the CertificateRequest message
-                       if (this.context.Cipher.ExchangeAlgorithmType == ExchangeAlgorithmType.RsaKeyX ||
-                               ((ServerContext)this.context).ClientCertificateRequired)
+                       if (this.context.Negotiating.Cipher.IsExportable ||
+                               ((ServerContext)this.context).ClientCertificateRequired ||
+                               ((ServerContext)this.context).RequestClientCertificate)
                        {
                                this.protocol.SendRecord(HandshakeType.CertificateRequest);
-                               certRequested = true;
                        }
 
                        // Send ServerHelloDone message
                        this.protocol.SendRecord(HandshakeType.ServerHelloDone);
 
                        // Receive client response, until the Client Finished message
-                       // is received
+                       // is received. IE can be interrupted at this stage and never
+                       // complete the handshake
                        while (this.context.LastHandshakeMsg != HandshakeType.Finished)
                        {
-                               this.protocol.ReceiveRecord(this.innerStream);
-                       }
-
-                       if (certRequested && (this.context.ClientSettings.ClientCertificate == null))
-                       {
-                               // we asked for a certificate but didn't receive one
-                               // e.g. wget for SSL3
-                               if (!RaiseClientCertificateValidation(null, new int[0]))
+                               byte[] record = this.protocol.ReceiveRecord(this.innerStream);
+                               if ((record == null) || (record.Length == 0))
                                {
                                        throw new TlsException(
-                                               AlertDescription.BadCertificate,
-                                               "No certificate received from client.");
+                                               AlertDescription.HandshakeFailiure,
+                                               "The client stopped the handshake.");
                                }
                        }
 
                        // Send ChangeCipherSpec and ServerFinished messages
                        this.protocol.SendChangeCipherSpec();
+                       this.protocol.SendRecord (HandshakeType.Finished);
 
                        // The handshake is finished
                        this.context.HandshakeState = HandshakeState.Finished;
 
+                       // Reset Handshake messages information
+                       this.context.HandshakeMessages.Reset ();
+
                        // Clear Key Info
                        this.context.ClearKeyInfo();
                }
@@ -273,6 +298,18 @@ namespace Mono.Security.Protocol.Tls
                        return (errors != null && errors.Length == 0);
                }
 
+               internal override bool HaveRemoteValidation2Callback {
+                       get { return ClientCertValidation2 != null; }
+               }
+
+               internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
+               {
+                       CertificateValidationCallback2 cb = ClientCertValidation2;
+                       if (cb != null)
+                               return cb (collection);
+                       return null;
+               }
+
                internal bool RaiseClientCertificateValidation(
                        X509Certificate certificate, 
                        int[]                   certificateErrors)