Skip to content

Commit 1509226

Browse files
spouliotmigueldeicaza
authored andcommitted
TLS protocol: add handshake state validation
1 parent 48992d4 commit 1509226

File tree

4 files changed

+59
-21
lines changed

4 files changed

+59
-21
lines changed

Diff for: mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs

+28-5
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ private HandshakeMessage createServerHandshakeMessage(
129129
HandshakeType type, byte[] buffer)
130130
{
131131
ClientContext context = (ClientContext)this.context;
132+
var last = context.LastHandshakeMsg;
132133

133134
switch (type)
134135
{
@@ -148,30 +149,52 @@ private HandshakeMessage createServerHandshakeMessage(
148149
return null;
149150

150151
case HandshakeType.ServerHello:
152+
if (last != HandshakeType.HelloRequest)
153+
break;
151154
return new TlsServerHello(this.context, buffer);
152155

156+
// Optional
153157
case HandshakeType.Certificate:
158+
if (last != HandshakeType.ServerHello)
159+
break;
154160
return new TlsServerCertificate(this.context, buffer);
155161

162+
// Optional
156163
case HandshakeType.ServerKeyExchange:
157-
return new TlsServerKeyExchange(this.context, buffer);
164+
// only for RSA_EXPORT
165+
if (last == HandshakeType.Certificate && context.Current.Cipher.IsExportable)
166+
return new TlsServerKeyExchange(this.context, buffer);
167+
break;
158168

169+
// Optional
159170
case HandshakeType.CertificateRequest:
160-
return new TlsServerCertificateRequest(this.context, buffer);
171+
if (last == HandshakeType.ServerKeyExchange || last == HandshakeType.Certificate)
172+
return new TlsServerCertificateRequest(this.context, buffer);
173+
break;
161174

162175
case HandshakeType.ServerHelloDone:
163-
return new TlsServerHelloDone(this.context, buffer);
176+
if (last == HandshakeType.CertificateRequest || last == HandshakeType.Certificate || last == HandshakeType.ServerHello)
177+
return new TlsServerHelloDone(this.context, buffer);
178+
break;
164179

165180
case HandshakeType.Finished:
166-
return new TlsServerFinished(this.context, buffer);
167-
181+
// depends if a full (ServerHelloDone) or an abbreviated handshake (ServerHello) is being done
182+
bool check = context.AbbreviatedHandshake ? (last == HandshakeType.ServerHello) : (last == HandshakeType.ServerHelloDone);
183+
// ChangeCipherSpecDone is not an handshake message (it's a content type) but still needs to be happens before finished
184+
if (check && context.ChangeCipherSpecDone) {
185+
context.ChangeCipherSpecDone = false;
186+
return new TlsServerFinished (this.context, buffer);
187+
}
188+
break;
189+
168190
default:
169191
throw new TlsException(
170192
AlertDescription.UnexpectedMessage,
171193
String.Format(CultureInfo.CurrentUICulture,
172194
"Unknown server handshake message received ({0})",
173195
type.ToString()));
174196
}
197+
throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));
175198
}
176199

177200
#endregion

Diff for: mcs/class/Mono.Security/Mono.Security.Protocol.Tls/Context.cs

+2
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ public bool ProtocolNegotiated
122122
set { this.protocolNegotiated = value; }
123123
}
124124

125+
public bool ChangeCipherSpecDone { get; set; }
126+
125127
public SecurityProtocolType SecurityProtocol
126128
{
127129
get

Diff for: mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs

+2-6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ protected virtual void ProcessChangeCipherSpec ()
8888
} else {
8989
ctx.StartSwitchingSecurityParameters (false);
9090
}
91+
92+
ctx.ChangeCipherSpecDone = true;
9193
}
9294

9395
public virtual HandshakeMessage GetMessage(HandshakeType type)
@@ -348,9 +350,6 @@ private void InternalReceiveRecordCallback(IAsyncResult asyncResult)
348350
// Try to read the Record Content Type
349351
int type = internalResult.InitialBuffer[0];
350352

351-
// Set last handshake message received to None
352-
this.context.LastHandshakeMsg = HandshakeType.ClientHello;
353-
354353
ContentType contentType = (ContentType)type;
355354
byte[] buffer = this.ReadRecordBuffer(type, record);
356355
if (buffer == null)
@@ -458,9 +457,6 @@ public byte[] ReceiveRecord(Stream record)
458457
// Try to read the Record Content Type
459458
int type = recordTypeBuffer[0];
460459

461-
// Set last handshake message received to None
462-
this.context.LastHandshakeMsg = HandshakeType.ClientHello;
463-
464460
ContentType contentType = (ContentType)type;
465461
byte[] buffer = this.ReadRecordBuffer(type, record);
466462
if (buffer == null)

Diff for: mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs

+27-10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ namespace Mono.Security.Protocol.Tls
3333
{
3434
internal class ServerRecordProtocol : RecordProtocol
3535
{
36+
TlsClientCertificate cert;
37+
3638
#region Constructors
3739

3840
public ServerRecordProtocol(
@@ -93,30 +95,45 @@ protected override void ProcessHandshakeMessage(TlsStream handMsg)
9395
private HandshakeMessage createClientHandshakeMessage(
9496
HandshakeType type, byte[] buffer)
9597
{
98+
var last = context.LastHandshakeMsg;
9699
switch (type)
97100
{
98101
case HandshakeType.ClientHello:
99102
return new TlsClientHello(this.context, buffer);
100103

101104
case HandshakeType.Certificate:
102-
return new TlsClientCertificate(this.context, buffer);
105+
if (last != HandshakeType.ClientHello)
106+
break;
107+
cert = new TlsClientCertificate(this.context, buffer);
108+
return cert;
103109

104110
case HandshakeType.ClientKeyExchange:
105-
return new TlsClientKeyExchange(this.context, buffer);
111+
if (last == HandshakeType.ClientHello || last == HandshakeType.Certificate)
112+
return new TlsClientKeyExchange(this.context, buffer);
113+
break;
106114

107115
case HandshakeType.CertificateVerify:
108-
return new TlsClientCertificateVerify(this.context, buffer);
116+
if (last == HandshakeType.ClientKeyExchange && cert != null)
117+
return new TlsClientCertificateVerify(this.context, buffer);
118+
break;
109119

110120
case HandshakeType.Finished:
111-
return new TlsClientFinished(this.context, buffer);
112-
121+
// Certificates are optional, but if provided, they should send a CertificateVerify
122+
bool check = (cert == null) ? (last == HandshakeType.ClientKeyExchange) : (last == HandshakeType.CertificateVerify);
123+
// ChangeCipherSpecDone is not an handshake message (it's a content type) but still needs to be happens before finished
124+
if (check && context.ChangeCipherSpecDone) {
125+
context.ChangeCipherSpecDone = false;
126+
return new TlsClientFinished(this.context, buffer);
127+
}
128+
break;
129+
113130
default:
114-
throw new TlsException(
115-
AlertDescription.UnexpectedMessage,
116-
String.Format(CultureInfo.CurrentUICulture,
117-
"Unknown server handshake message received ({0})",
118-
type.ToString()));
131+
throw new TlsException(AlertDescription.UnexpectedMessage, String.Format(CultureInfo.CurrentUICulture,
132+
"Unknown server handshake message received ({0})",
133+
type.ToString()));
134+
break;
119135
}
136+
throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));
120137
}
121138

122139
private HandshakeMessage createServerHandshakeMessage(

0 commit comments

Comments
 (0)