diff -ur mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs
--- mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs	2008-07-01 13:00:41.000000000 -0500
+++ mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs	2015-03-17 17:42:37.700848601 -0500
@@ -129,6 +129,7 @@
 			HandshakeType type, byte[] buffer)
 		{
 			ClientContext context = (ClientContext)this.context;
+			HandshakeType last = context.LastHandshakeMsg;
 
 			switch (type)
 			{
@@ -148,23 +149,44 @@
 					return null;
 
 				case HandshakeType.ServerHello:
+					if (last != HandshakeType.HelloRequest)
+						break;
 					return new TlsServerHello(this.context, buffer);
 
+					// Optional
 				case HandshakeType.Certificate:
+					if (last != HandshakeType.ServerHello)
+						break;
 					return new TlsServerCertificate(this.context, buffer);
 
+					// Optional
 				case HandshakeType.ServerKeyExchange:
-					return new TlsServerKeyExchange(this.context, buffer);
+					// only for RSA_EXPORT
+					if (last == HandshakeType.Certificate && context.Current.Cipher.IsExportable)
+						return new TlsServerKeyExchange(this.context, buffer);
+					break;
 
+					// Optional
 				case HandshakeType.CertificateRequest:
-					return new TlsServerCertificateRequest(this.context, buffer);
+					if (last == HandshakeType.ServerKeyExchange || last == HandshakeType.Certificate)
+						return new TlsServerCertificateRequest(this.context, buffer);
+					break;
 
 				case HandshakeType.ServerHelloDone:
-					return new TlsServerHelloDone(this.context, buffer);
+					if (last == HandshakeType.CertificateRequest || last == HandshakeType.Certificate || last == HandshakeType.ServerHello)
+						return new TlsServerHelloDone(this.context, buffer);
+					break;
 
 				case HandshakeType.Finished:
-					return new TlsServerFinished(this.context, buffer);
-
+					// depends if a full (ServerHelloDone) or an abbreviated handshake (ServerHello) is being done
+					bool check = context.AbbreviatedHandshake ? (last == HandshakeType.ServerHello) : (last == HandshakeType.ServerHelloDone);
+					// ChangeCipherSpecDone is not an handshake message (it's a content type) but still needs to be happens before finished
+					if (check && context.ChangeCipherSpecDone) {
+						context.ChangeCipherSpecDone = false;
+						return new TlsServerFinished (this.context, buffer);
+					}
+					break;
+					
 				default:
 					throw new TlsException(
 						AlertDescription.UnexpectedMessage,
@@ -172,6 +194,7 @@
 							"Unknown server handshake message received ({0})", 
 							type.ToString()));
 			}
+			throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));
 		}
 
 		#endregion
diff -ur mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/Context.cs mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/Context.cs
--- mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/Context.cs	2008-07-01 13:00:41.000000000 -0500
+++ mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/Context.cs	2015-03-17 17:44:59.813839314 -0500
@@ -78,6 +78,7 @@
 		private bool	abbreviatedHandshake;
 		private bool	connectionEnd;
 		private bool	protocolNegotiated;
+		private bool	changeCipherSpecDone;
 		
 		// Sequence numbers
 		private ulong	writeSequenceNumber;
@@ -121,6 +122,13 @@
 			set { this.protocolNegotiated = value; }
 		}
 
+		public bool ChangeCipherSpecDone
+		{
+			get { return this.changeCipherSpecDone; }
+			set { this.changeCipherSpecDone = value; }
+		}
+
+
 		public SecurityProtocolType SecurityProtocol
 		{
 			get 
diff -ur mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs
--- mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs	2008-07-01 13:00:41.000000000 -0500
+++ mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs	2015-03-17 17:42:37.704848601 -0500
@@ -88,6 +88,8 @@
 			} else {
 				ctx.StartSwitchingSecurityParameters (false);
 			}
+
+			ctx.ChangeCipherSpecDone = true;
 		}
 
 		public virtual HandshakeMessage GetMessage(HandshakeType type)
@@ -348,9 +350,6 @@
 				// Try to read the Record Content Type
 				int type = internalResult.InitialBuffer[0];
 
-				// Set last handshake message received to None
-				this.context.LastHandshakeMsg = HandshakeType.ClientHello;
-
 				ContentType	contentType	= (ContentType)type;
 				byte[] buffer = this.ReadRecordBuffer(type, record);
 				if (buffer == null)
diff -ur mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs
--- mono-2.0.1.orig/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs	2008-07-01 13:00:41.000000000 -0500
+++ mono-2.0.1/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs	2015-03-17 17:42:37.708848601 -0500
@@ -33,6 +33,8 @@
 {
 	internal class ServerRecordProtocol : RecordProtocol
 	{
+		TlsClientCertificate cert;
+		
 		#region Constructors
 
 		public ServerRecordProtocol(
@@ -93,30 +95,45 @@
 		private HandshakeMessage createClientHandshakeMessage(
 			HandshakeType type, byte[] buffer)
 		{
+			HandshakeType last = context.LastHandshakeMsg;
 			switch (type)
 			{
 				case HandshakeType.ClientHello:
 					return new TlsClientHello(this.context, buffer);
 
 				case HandshakeType.Certificate:
-					return new TlsClientCertificate(this.context, buffer);
+					if (last != HandshakeType.ClientHello)
+						break;
+					cert = new TlsClientCertificate(this.context, buffer);
+					return cert;
 
 				case HandshakeType.ClientKeyExchange:
-					return new TlsClientKeyExchange(this.context, buffer);
+					if (last == HandshakeType.ClientHello || last == HandshakeType.Certificate)
+						return new TlsClientKeyExchange(this.context, buffer);
+					break;
 
 				case HandshakeType.CertificateVerify:
-					return new TlsClientCertificateVerify(this.context, buffer);
+					if (last == HandshakeType.ClientKeyExchange && cert != null)
+						return new TlsClientCertificateVerify(this.context, buffer);
+					break;
 
 				case HandshakeType.Finished:
-					return new TlsClientFinished(this.context, buffer);
-
+					// Certificates are optional, but if provided, they should send a CertificateVerify
+					bool check = (cert == null) ? (last == HandshakeType.ClientKeyExchange) : (last == HandshakeType.CertificateVerify);
+					// ChangeCipherSpecDone is not an handshake message (it's a content type) but still needs to be happens before finished
+					if (check && context.ChangeCipherSpecDone) {
+						context.ChangeCipherSpecDone = false;
+						return new TlsClientFinished(this.context, buffer);
+					}
+					break;
+					
 				default:
-					throw new TlsException(
-						AlertDescription.UnexpectedMessage,
-						String.Format(CultureInfo.CurrentUICulture,
-							"Unknown server handshake message received ({0})", 
-							type.ToString()));
+					throw new TlsException(AlertDescription.UnexpectedMessage, String.Format(CultureInfo.CurrentUICulture,
+														 "Unknown server handshake message received ({0})", 
+														 type.ToString()));
+					break;
 			}
+			throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));
 		}
 
 		private HandshakeMessage createServerHandshakeMessage(
