Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / SslServerStream.cs
index 03010d878bc3a728532ac90975fbf778295d89dd..2a9d7623223f71458dbb9f885d730fc640f27d8d 100644 (file)
@@ -76,6 +76,7 @@ namespace Mono.Security.Protocol.Tls
 
                #endregion
 
+               public event CertificateValidationCallback2 ClientCertValidation2;
                #region Constructors
 
                public SslServerStream(
@@ -102,19 +103,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);
                }
@@ -206,52 +229,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 (this.context.LastHandshakeMsg == HandshakeType.Certificate)
-                                       certRequested = false;
-                       }
-
-                       if (certRequested)
-                       {
-                               // 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();
                }
@@ -275,6 +293,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)