2005-04-14 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / ClientRecordProtocol.cs
1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
3
4 //
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:
12 // 
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 // 
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.
23 //
24
25 using System;
26 using System.Globalization;
27 using System.IO;
28
29 using Mono.Security.Protocol.Tls.Handshake;
30 using Mono.Security.Protocol.Tls.Handshake.Client;
31
32 namespace Mono.Security.Protocol.Tls
33 {
34         internal class ClientRecordProtocol : RecordProtocol
35         {
36                 #region Constructors
37
38                 public ClientRecordProtocol(
39                         Stream                  innerStream, 
40                         ClientContext   context) : base(innerStream, context)
41                 {
42                 }
43
44                 #endregion
45
46                 #region Send Messages
47
48                 public override void SendRecord(HandshakeType type)
49                 {
50                         // Create and process the record message
51                         HandshakeMessage msg = this.createClientHandshakeMessage(type);
52                         msg.Process();
53
54                         DebugHelper.WriteLine(">>>> Write handshake record ({0}|{1})", context.Protocol, msg.ContentType);
55
56                         // Write record
57                         this.SendRecord(msg.ContentType, msg.EncodeMessage());
58
59                         // Update session
60                         msg.Update();
61
62                         // Reset message contents
63                         msg.Reset();
64                 }
65
66                 #endregion
67
68                 #region Handshake Processing Methods
69
70                 protected override void ProcessChangeCipherSpec()
71                 {
72                         // Reset sequence numbers
73                         this.context.ReadSequenceNumber = 0;
74                 }
75
76                 protected override void ProcessHandshakeMessage(TlsStream handMsg)
77                 {
78                         HandshakeType           handshakeType   = (HandshakeType)handMsg.ReadByte();
79                         HandshakeMessage        message                 = null;
80
81                         DebugHelper.WriteLine(">>>> Processing Handshake record ({0})", handshakeType);
82
83                         // Read message length
84                         int length = handMsg.ReadInt24();
85
86                         // Read message data
87                         byte[] data = new byte[length];
88                         handMsg.Read(data, 0, length);
89
90                         // Create and process the server message
91                         message = this.createServerHandshakeMessage(handshakeType, data);
92                         message.Process();
93
94                         // Update the last handshake message
95                         this.Context.LastHandshakeMsg = handshakeType;
96
97                         // Update session
98                         if (message != null)
99                         {
100                                 message.Update();
101                         }
102                 }
103
104                 #endregion
105
106                 #region Client Handshake Message Factories
107
108                 private HandshakeMessage createClientHandshakeMessage(HandshakeType type)
109                 {
110                         switch (type)
111                         {
112                                 case HandshakeType.ClientHello:
113                                         return new TlsClientHello(this.context);
114
115                                 case HandshakeType.Certificate:
116                                         return new TlsClientCertificate(this.context);
117
118                                 case HandshakeType.ClientKeyExchange:
119                                         return new TlsClientKeyExchange(this.context);
120
121                                 case HandshakeType.CertificateVerify:
122                                         return new TlsClientCertificateVerify(this.context);
123
124                                 case HandshakeType.Finished:
125                                         return new TlsClientFinished(this.context);
126
127                                 default:
128                                         throw new InvalidOperationException("Unknown client handshake message type: " + type.ToString() );
129                         }
130                 }
131
132                 private HandshakeMessage createServerHandshakeMessage(
133                         HandshakeType type, byte[] buffer)
134                 {
135                         ClientContext context = (ClientContext)this.context;
136
137                         switch (type)
138                         {
139                                 case HandshakeType.HelloRequest:
140                                         if (context.HandshakeState != HandshakeState.Started)
141                                         {
142                                                 context.SslStream.NegotiateHandshake();
143                                         }
144                                         else
145                                         {
146                                                 this.SendAlert(
147                                                         AlertLevel.Warning,
148                                                         AlertDescription.NoRenegotiation);
149                                         }
150                                         return null;
151
152                                 case HandshakeType.ServerHello:
153                                         return new TlsServerHello(this.context, buffer);
154
155                                 case HandshakeType.Certificate:
156                                         return new TlsServerCertificate(this.context, buffer);
157
158                                 case HandshakeType.ServerKeyExchange:
159                                         return new TlsServerKeyExchange(this.context, buffer);
160
161                                 case HandshakeType.CertificateRequest:
162                                         return new TlsServerCertificateRequest(this.context, buffer);
163
164                                 case HandshakeType.ServerHelloDone:
165                                         return new TlsServerHelloDone(this.context, buffer);
166
167                                 case HandshakeType.Finished:
168                                         return new TlsServerFinished(this.context, buffer);
169
170                                 default:
171                                         throw new TlsException(
172                                                 AlertDescription.UnexpectedMessage,
173                                                 String.Format(CultureInfo.CurrentUICulture,
174                                                         "Unknown server handshake message received ({0})", 
175                                                         type.ToString()));
176                         }
177                 }
178
179                 #endregion
180         }
181 }