1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 using System.Globalization;
29 using Mono.Security.Protocol.Tls.Handshake;
30 using Mono.Security.Protocol.Tls.Handshake.Client;
32 namespace Mono.Security.Protocol.Tls
34 internal class ClientRecordProtocol : RecordProtocol
38 public ClientRecordProtocol(
40 ClientContext context) : base(innerStream, context)
48 public override HandshakeMessage GetMessage(HandshakeType type)
50 HandshakeMessage msg = this.createClientHandshakeMessage(type);
57 #region Handshake Processing Methods
59 protected override void ProcessHandshakeMessage(TlsStream handMsg)
61 HandshakeType handshakeType = (HandshakeType)handMsg.ReadByte();
62 HandshakeMessage message = null;
64 DebugHelper.WriteLine(">>>> Processing Handshake record ({0})", handshakeType);
66 // Read message length
67 int length = handMsg.ReadInt24();
73 data = new byte[length];
74 handMsg.Read (data, 0, length);
77 // Create and process the server message
78 message = this.createServerHandshakeMessage(handshakeType, data);
84 // Update the last handshake message
85 this.Context.LastHandshakeMsg = handshakeType;
91 this.Context.HandshakeMessages.WriteByte ((byte) handshakeType);
92 this.Context.HandshakeMessages.WriteInt24 (length);
95 this.Context.HandshakeMessages.Write (data, 0, data.Length);
102 #region Client Handshake Message Factories
104 private HandshakeMessage createClientHandshakeMessage(HandshakeType type)
108 case HandshakeType.ClientHello:
109 return new TlsClientHello(this.context);
111 case HandshakeType.Certificate:
112 return new TlsClientCertificate(this.context);
114 case HandshakeType.ClientKeyExchange:
115 return new TlsClientKeyExchange(this.context);
117 case HandshakeType.CertificateVerify:
118 return new TlsClientCertificateVerify(this.context);
120 case HandshakeType.Finished:
121 return new TlsClientFinished(this.context);
124 throw new InvalidOperationException("Unknown client handshake message type: " + type.ToString() );
128 private HandshakeMessage createServerHandshakeMessage(
129 HandshakeType type, byte[] buffer)
131 ClientContext context = (ClientContext)this.context;
132 var last = context.LastHandshakeMsg;
136 case HandshakeType.HelloRequest:
137 if (context.HandshakeState != HandshakeState.Started)
139 context.HandshakeState = HandshakeState.None;
140 // re-negotiation will occur at next read/write
141 // (i.e. not during an existing encode/decode op)
147 AlertDescription.NoRenegotiation);
151 case HandshakeType.ServerHello:
152 if (last != HandshakeType.HelloRequest)
154 return new TlsServerHello(this.context, buffer);
157 case HandshakeType.Certificate:
158 if (last != HandshakeType.ServerHello)
160 return new TlsServerCertificate(this.context, buffer);
163 case HandshakeType.ServerKeyExchange:
164 // only for RSA_EXPORT
165 if (last == HandshakeType.Certificate && context.Current.Cipher.IsExportable)
166 return new TlsServerKeyExchange(this.context, buffer);
170 case HandshakeType.CertificateRequest:
171 if (last == HandshakeType.ServerKeyExchange || last == HandshakeType.Certificate)
172 return new TlsServerCertificateRequest(this.context, buffer);
175 case HandshakeType.ServerHelloDone:
176 if (last == HandshakeType.CertificateRequest || last == HandshakeType.Certificate || last == HandshakeType.ServerHello)
177 return new TlsServerHelloDone(this.context, buffer);
180 case HandshakeType.Finished:
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);
191 throw new TlsException(
192 AlertDescription.UnexpectedMessage,
193 String.Format(CultureInfo.CurrentUICulture,
194 "Unknown server handshake message received ({0})",
197 throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));