Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / ServerRecordProtocol.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.Server;
31
32 namespace Mono.Security.Protocol.Tls
33 {
34         internal class ServerRecordProtocol : RecordProtocol
35         {
36                 TlsClientCertificate cert;
37                 
38                 #region Constructors
39
40                 public ServerRecordProtocol(
41                         Stream                  innerStream, 
42                         ServerContext   context) : base(innerStream, context)
43                 {
44                 }
45
46                 #endregion
47
48                 #region Send Messages
49
50                 public override HandshakeMessage GetMessage(HandshakeType type)
51                 {
52                         // Create and process the record message
53                         HandshakeMessage msg = this.createServerHandshakeMessage(type);
54
55                         return msg;
56                 }
57
58                 #endregion
59
60                 #region Handshake Processing Methods
61
62                 protected override void ProcessHandshakeMessage(TlsStream handMsg)
63                 {
64                         HandshakeType           handshakeType   = (HandshakeType)handMsg.ReadByte();
65                         HandshakeMessage        message                 = null;
66
67                         // Read message length
68                         int length = handMsg.ReadInt24();
69
70                         // Read message data
71                         byte[] data = new byte[length];
72                         handMsg.Read(data, 0, length);
73
74                         // Create and process the server message
75                         message = this.createClientHandshakeMessage(handshakeType, data);
76                         message.Process();
77
78                         // Update the last handshake message
79                         this.Context.LastHandshakeMsg = handshakeType;
80
81                         // Update session
82                         if (message != null)
83                         {
84                                 message.Update();
85                                 this.Context.HandshakeMessages.WriteByte ((byte) handshakeType);
86                                 this.Context.HandshakeMessages.WriteInt24 (length);
87                                 this.Context.HandshakeMessages.Write (data, 0, data.Length);
88                         }
89                 }
90
91                 #endregion
92
93                 #region Server Handshake Message Factories
94
95                 private HandshakeMessage createClientHandshakeMessage(
96                         HandshakeType type, byte[] buffer)
97                 {
98                         var last = context.LastHandshakeMsg;
99                         switch (type)
100                         {
101                                 case HandshakeType.ClientHello:
102                                         return new TlsClientHello(this.context, buffer);
103
104                                 case HandshakeType.Certificate:
105                                         if (last != HandshakeType.ClientHello)
106                                                 break;
107                                         cert = new TlsClientCertificate(this.context, buffer);
108                                         return cert;
109
110                                 case HandshakeType.ClientKeyExchange:
111                                         if (last == HandshakeType.ClientHello || last == HandshakeType.Certificate)
112                                                 return new TlsClientKeyExchange(this.context, buffer);
113                                         break;
114
115                                 case HandshakeType.CertificateVerify:
116                                         if (last == HandshakeType.ClientKeyExchange && cert != null)
117                                                 return new TlsClientCertificateVerify(this.context, buffer);
118                                         break;
119
120                                 case HandshakeType.Finished:
121                                         // Certificates are optional, but if provided, they should send a CertificateVerify
122                                         bool hasCert = cert != null && cert.HasCertificate;
123                                         bool check = hasCert ? (last == HandshakeType.CertificateVerify) : (last == HandshakeType.ClientKeyExchange);
124                                         // ChangeCipherSpecDone is not an handshake message (it's a content type) but still needs to be happens before finished
125                                         if (check && context.ChangeCipherSpecDone) {
126                                                 context.ChangeCipherSpecDone = false;
127                                                 return new TlsClientFinished(this.context, buffer);
128                                         }
129                                         break;
130                                         
131                                 default:
132                                         throw new TlsException(AlertDescription.UnexpectedMessage, String.Format(CultureInfo.CurrentUICulture,
133                                                                                                                  "Unknown server handshake message received ({0})", 
134                                                                                                                  type.ToString()));
135                         }
136                         throw new TlsException (AlertDescription.HandshakeFailiure, String.Format ("Protocol error, unexpected protocol transition from {0} to {1}", last, type));
137                 }
138
139                 private HandshakeMessage createServerHandshakeMessage(
140                         HandshakeType type)
141                 {
142                         switch (type)
143                         {
144                                 case HandshakeType.HelloRequest:
145                                         this.SendRecord(HandshakeType.ClientHello);
146                                         return null;
147
148                                 case HandshakeType.ServerHello:
149                                         return new TlsServerHello(this.context);
150
151                                 case HandshakeType.Certificate:
152                                         return new TlsServerCertificate(this.context);
153
154                                 case HandshakeType.ServerKeyExchange:
155                                         return new TlsServerKeyExchange(this.context);
156
157                                 case HandshakeType.CertificateRequest:
158                                         return new TlsServerCertificateRequest(this.context);
159
160                                 case HandshakeType.ServerHelloDone:
161                                         return new TlsServerHelloDone(this.context);
162
163                                 case HandshakeType.Finished:
164                                         return new TlsServerFinished(this.context);
165
166                                 default:
167                                         throw new InvalidOperationException("Unknown server handshake message type: " + type.ToString() );                                      
168                         }
169                 }
170
171                 #endregion
172         }
173 }