CVE-2015-2318 (C#, published 2018-01-08T19:29Z)
Description: value: The TLS stack in Mono before 3.12.1 allows man-in-the-middle attackers to conduct message skipping attacks and consequently impersonate clients by leveraging missing handshake state validation, aka a "SMACK SKIP-TLS" issue.
Severity: MEDIUM (CVSS v3 base score: 8.1)
Weakness: CWE-295 \u2014 Improper Certificate Validation
The product does not validate, or incorrectly validates, a certificate.
Repository: https://github.com/mono/mono
Files changed:
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/Context.cs
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs
Commit message: TLS protocol: add handshake state validation


Vulnerable code:
					return new TlsServerKeyExchange(this.context, buffer);
					return new TlsServerCertificateRequest(this.context, buffer);
					return new TlsServerHelloDone(this.context, buffer);
					return new TlsServerFinished(this.context, buffer);

				// Set last handshake message received to None
				this.context.LastHandshakeMsg = HandshakeType.ClientHello;

			// Set last handshake message received to None
			this.context.LastHandshakeMsg = HandshakeType.ClientHello;

					return new TlsClientCertificate(this.context, buffer);
					return new TlsClientKeyExchange(this.context, buffer);
					return new TlsClientCertificateVerify(this.context, buffer);
					return new TlsClientFinished(this.context, buffer);

					throw new TlsException(
						AlertDescription.UnexpectedMessage,
						String.Format(CultureInfo.CurrentUICulture,
							"Unknown server handshake message received ({0})", 
							type.ToString()));

Fixed code:
			var last = context.LastHandshakeMsg;
					if (last != HandshakeType.HelloRequest)
						break;
					// Optional
					if (last != HandshakeType.ServerHello)
						break;
					// Optional
					// only for RSA_EXPORT
					if (last == HandshakeType.Certificate && context.Current.Cipher.IsExportable)
						return new TlsServerKeyExchange(this.context, buffer);
					break;
					// Optional
					if (last == HandshakeType.ServerKeyExchange || last == HandshakeType.Certificate)
						return new TlsServerCertificateRequest(this.context, buffer);
					break;
					if (last == HandshakeType.CertificateRequest || last == HandshakeType.Certificate || last == HandshakeType.ServerHello)
						return new TlsServerHelloDone(this.context, buffer);
					break;
					// 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;
					
			throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));
		public bool ChangeCipherSpecDone { get; set; }


			ctx.ChangeCipherSpecDone = true;
		TlsClientCertificate cert;
		
			var last = context.LastHandshakeMsg;
					if (last != HandshakeType.ClientHello)
						break;
					cert = new TlsClientCertificate(this.context, buffer);
					return cert;
					if (last == HandshakeType.ClientHello || last == HandshakeType.Certificate)
						return new TlsClientKeyExchange(this.context, buffer);
					break;
					if (last == HandshakeType.ClientKeyExchange && cert != null)
						return new TlsClientCertificateVerify(this.context, buffer);
					break;
					// 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;
					
					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));