New test.
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / SslClientStream.cs
index 0f4e3b44e477b637d409daa0d68cb5f43c200ca9..03d37d79ba2474339461c06d6b2a0acac31c26f8 100644 (file)
@@ -252,60 +252,104 @@ namespace Mono.Security.Protocol.Tls
                        }
                }
 
+               private void SafeReceiveRecord (Stream s)
+               {
+                       byte[] record = this.protocol.ReceiveRecord (s);
+                       if ((record == null) || (record.Length == 0)) {
+                               throw new TlsException (
+                                       AlertDescription.HandshakeFailiure,
+                                       "The server stopped the handshake.");
+                       }
+               }
+
                internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult)
                {
                        this.protocol.EndSendRecord(asyncResult);
 
                        // Read server response
-                       while (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone)
+                       while (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone) 
                        {
                                // Read next record
-                               this.protocol.ReceiveRecord(this.innerStream);
-                       }
-
-                       // Send client certificate if requested
-                       // even if the server ask for it it _may_ still be optional
-                       bool clientCertificate = this.context.ServerSettings.CertificateRequest;
+                               SafeReceiveRecord (this.innerStream);
 
-                       // NOTE: sadly SSL3 and TLS1 differs in how they handle this and
-                       // the current design doesn't allow a very cute way to handle 
-                       // SSL3 alert warning for NoCertificate (41).
-                       if (this.context.SecurityProtocol == SecurityProtocolType.Ssl3)
-                       {
-                               clientCertificate = ((this.context.ClientSettings.Certificates != null) &&
-                                       (this.context.ClientSettings.Certificates.Count > 0));
-                               // this works well with OpenSSL (but only for SSL3)
+                               // special case for abbreviated handshake where no ServerHelloDone is sent from the server
+                               if (this.context.AbbreviatedHandshake && (this.context.LastHandshakeMsg == HandshakeType.ServerHello))
+                                       break;
                        }
 
-                       if (clientCertificate)
+                       // the handshake is much easier if we can reuse a previous session settings
+                       if (this.context.AbbreviatedHandshake) 
                        {
-                               this.protocol.SendRecord(HandshakeType.Certificate);
-                       }
+                               ClientSessionCache.SetContextFromCache (this.context);
+                               this.context.Negotiating.Cipher.ComputeKeys ();
+                               this.context.Negotiating.Cipher.InitializeCipher ();
 
-                       // Send Client Key Exchange
-                       this.protocol.SendRecord(HandshakeType.ClientKeyExchange);
+                               // Send Cipher Spec protocol
+                               this.protocol.SendChangeCipherSpec ();
 
-                       // Now initialize session cipher with the generated keys
-                       this.context.Cipher.InitializeCipher();
+                               // Read record until server finished is received
+                               while (this.context.HandshakeState != HandshakeState.Finished) 
+                               {
+                                       // If all goes well this will process messages:
+                                       //              Change Cipher Spec
+                                       //              Server finished
+                                       SafeReceiveRecord (this.innerStream);
+                               }
 
-                       // Send certificate verify if requested (optional)
-                       if (clientCertificate && (this.context.ClientSettings.ClientCertificate != null))
-                       {
-                               this.protocol.SendRecord(HandshakeType.CertificateVerify);
+                               // Send Finished message
+                               this.protocol.SendRecord (HandshakeType.Finished);
                        }
+                       else
+                       {
+                               // Send client certificate if requested
+                               // even if the server ask for it it _may_ still be optional
+                               bool clientCertificate = this.context.ServerSettings.CertificateRequest;
+
+                               // NOTE: sadly SSL3 and TLS1 differs in how they handle this and
+                               // the current design doesn't allow a very cute way to handle 
+                               // SSL3 alert warning for NoCertificate (41).
+                               if (this.context.SecurityProtocol == SecurityProtocolType.Ssl3)
+                               {
+                                       clientCertificate = ((this.context.ClientSettings.Certificates != null) &&
+                                               (this.context.ClientSettings.Certificates.Count > 0));
+                                       // this works well with OpenSSL (but only for SSL3)
+                               }
 
-                       // Send Cipher Spec protocol
-                       this.protocol.SendChangeCipherSpec();
+                               if (clientCertificate)
+                               {
+                                       this.protocol.SendRecord(HandshakeType.Certificate);
+                               }
 
-                       // Read record until server finished is received
-                       while (this.context.HandshakeState != HandshakeState.Finished)
-                       {
-                               // If all goes well this will process messages:
-                               //              Change Cipher Spec
-                               //              Server finished
-                               this.protocol.ReceiveRecord(this.innerStream);
+                               // Send Client Key Exchange
+                               this.protocol.SendRecord(HandshakeType.ClientKeyExchange);
+
+                               // Now initialize session cipher with the generated keys
+                               this.context.Negotiating.Cipher.InitializeCipher();
+
+                               // Send certificate verify if requested (optional)
+                               if (clientCertificate && (this.context.ClientSettings.ClientCertificate != null))
+                               {
+                                       this.protocol.SendRecord(HandshakeType.CertificateVerify);
+                               }
+
+                               // Send Cipher Spec protocol
+                               this.protocol.SendChangeCipherSpec ();
+
+                               // Send Finished message
+                               this.protocol.SendRecord (HandshakeType.Finished);
+
+                               // Read record until server finished is received
+                               while (this.context.HandshakeState != HandshakeState.Finished) {
+                                       // If all goes well this will process messages:
+                                       //              Change Cipher Spec
+                                       //              Server finished
+                                       SafeReceiveRecord (this.innerStream);
+                               }
                        }
 
+                       // Reset Handshake messages information
+                       this.context.HandshakeMessages.Reset ();
+
                        // Clear Key Info
                        this.context.ClearKeyInfo();