New test.
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / SslServerStream.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.Collections;
27 using System.IO;
28 using System.Net;
29 using System.Net.Sockets;
30 using System.Security.Cryptography;
31 using System.Security.Cryptography.X509Certificates;
32
33 using Mono.Security.Protocol.Tls.Handshake;
34
35 namespace Mono.Security.Protocol.Tls
36 {
37         public class SslServerStream : SslStreamBase
38         {
39                 #region Internal Events
40                 
41                 internal event CertificateValidationCallback    ClientCertValidation;
42                 internal event PrivateKeySelectionCallback              PrivateKeySelection;
43                 
44                 #endregion
45
46                 #region Properties
47
48                 public X509Certificate ClientCertificate
49                 {
50                         get
51                         {
52                                 if (this.context.HandshakeState == HandshakeState.Finished)
53                                 {
54                                         return this.context.ClientSettings.ClientCertificate;
55                                 }
56
57                                 return null;
58                         }
59                 }
60
61                 #endregion
62
63                 #region Callback Properties
64
65                 public CertificateValidationCallback ClientCertValidationDelegate 
66                 {
67                         get { return this.ClientCertValidation; }
68                         set { this.ClientCertValidation = value; }
69                 }
70
71                 public PrivateKeySelectionCallback PrivateKeyCertSelectionDelegate
72                 {
73                         get { return this.PrivateKeySelection; }
74                         set { this.PrivateKeySelection = value; }
75                 }
76
77                 #endregion
78
79                 #region Constructors
80
81                 public SslServerStream(
82                         Stream                  stream, 
83                         X509Certificate serverCertificate) : this(
84                         stream, 
85                         serverCertificate, 
86                         false, 
87                         false, 
88                         SecurityProtocolType.Default)
89                 {
90                 }
91
92                 public SslServerStream(
93                         Stream                  stream,
94                         X509Certificate serverCertificate,
95                         bool                    clientCertificateRequired,
96                         bool                    ownsStream): this(
97                         stream, 
98                         serverCertificate, 
99                         clientCertificateRequired, 
100                         ownsStream, 
101                         SecurityProtocolType.Default)
102                 {
103                 }
104
105                 public SslServerStream(
106                         Stream                                  stream,
107                         X509Certificate                 serverCertificate,
108                         bool                                    clientCertificateRequired,
109                         bool                                    ownsStream,
110                         SecurityProtocolType    securityProtocolType)
111                         : base(stream, ownsStream)
112                 {
113                         this.context = new ServerContext(
114                                 this,
115                                 securityProtocolType,
116                                 serverCertificate,
117                                 clientCertificateRequired);
118
119                         this.protocol = new ServerRecordProtocol(innerStream, (ServerContext)this.context);
120                 }
121
122                 #endregion
123
124                 #region Finalizer
125
126                 ~SslServerStream()
127                 {
128                         this.Dispose(false);
129                 }
130
131                 #endregion
132
133                 #region IDisposable Methods
134
135                 protected override void Dispose(bool disposing)
136                 {
137                         base.Dispose(disposing);
138
139                         if (disposing)
140                         {
141                                 this.ClientCertValidation = null;
142                                 this.PrivateKeySelection = null;
143                         }
144                 }
145
146                 #endregion
147
148                 #region Handsake Methods
149
150                 /*
151                         Client                                                                                  Server
152
153                         ClientHello                 -------->
154                                                                                                                         ServerHello
155                                                                                                                         Certificate*
156                                                                                                                         ServerKeyExchange*
157                                                                                                                         CertificateRequest*
158                                                                                 <--------                       ServerHelloDone
159                         Certificate*
160                         ClientKeyExchange
161                         CertificateVerify*
162                         [ChangeCipherSpec]
163                         Finished                    -------->
164                                                                                                                         [ChangeCipherSpec]
165                                                                                 <--------           Finished
166                         Application Data            <------->                   Application Data
167
168                                         Fig. 1 - Message flow for a full handshake              
169                 */
170
171                 internal override IAsyncResult OnBeginNegotiateHandshake(AsyncCallback callback, object state)
172                 {
173                         // Reset the context if needed
174                         if (this.context.HandshakeState != HandshakeState.None)
175                         {
176                                 this.context.Clear();
177                         }
178
179                         // Obtain supported cipher suites
180                         this.context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(this.context.SecurityProtocol);
181
182                         // Set handshake state
183                         this.context.HandshakeState = HandshakeState.Started;
184
185                         // Receive Client Hello message
186                         return this.protocol.BeginReceiveRecord(this.innerStream, callback, state);
187
188                 }
189
190                 internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult)
191                 {
192                         // Receive Client Hello message and ignore it
193                         this.protocol.EndReceiveRecord(asyncResult);
194
195                         // If received message is not an ClientHello send a
196                         // Fatal Alert
197                         if (this.context.LastHandshakeMsg != HandshakeType.ClientHello)
198                         {
199                                 this.protocol.SendAlert(AlertDescription.UnexpectedMessage);
200                         }
201
202                         // Send ServerHello message
203                         this.protocol.SendRecord(HandshakeType.ServerHello);
204
205                         // Send ServerCertificate message
206                         this.protocol.SendRecord(HandshakeType.Certificate);
207
208                         // If the negotiated cipher is a KeyEx cipher send ServerKeyExchange
209                         if (this.context.Negotiating.Cipher.IsExportable)
210                         {
211                                 this.protocol.SendRecord(HandshakeType.ServerKeyExchange);
212                         }
213
214                         bool certRequested = false;
215
216                         // If the negotiated cipher is a KeyEx cipher or
217                         // the client certificate is required send the CertificateRequest message
218                         if (this.context.Negotiating.Cipher.IsExportable ||
219                                 ((ServerContext)this.context).ClientCertificateRequired)
220                         {
221                                 this.protocol.SendRecord(HandshakeType.CertificateRequest);
222                                 certRequested = true;
223                         }
224
225                         // Send ServerHelloDone message
226                         this.protocol.SendRecord(HandshakeType.ServerHelloDone);
227
228                         // Receive client response, until the Client Finished message
229                         // is received. IE can be interrupted at this stage and never
230                         // complete the handshake
231                         while (this.context.LastHandshakeMsg != HandshakeType.Finished)
232                         {
233                                 byte[] record = this.protocol.ReceiveRecord(this.innerStream);
234                                 if ((record == null) || (record.Length == 0))
235                                 {
236                                         throw new TlsException(
237                                                 AlertDescription.HandshakeFailiure,
238                                                 "The client stopped the handshake.");
239                                 }
240                         }
241
242                         if (certRequested && (this.context.ClientSettings.ClientCertificate == null))
243                         {
244                                 // we asked for a certificate but didn't receive one
245                                 // e.g. wget for SSL3
246                                 if (!RaiseClientCertificateValidation(null, new int[0]))
247                                 {
248                                         throw new TlsException(
249                                                 AlertDescription.BadCertificate,
250                                                 "No certificate received from client.");
251                                 }
252                         }
253
254                         // Send ChangeCipherSpec and ServerFinished messages
255                         this.protocol.SendChangeCipherSpec();
256                         this.protocol.SendRecord (HandshakeType.Finished);
257
258                         // The handshake is finished
259                         this.context.HandshakeState = HandshakeState.Finished;
260
261                         // Reset Handshake messages information
262                         this.context.HandshakeMessages.Reset ();
263
264                         // Clear Key Info
265                         this.context.ClearKeyInfo();
266                 }
267
268                 #endregion
269
270                 #region Event Methods
271
272                 internal override X509Certificate OnLocalCertificateSelection(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates)
273                 {
274                         throw new NotSupportedException();
275                 }
276
277                 internal override bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors)
278                 {
279                         if (this.ClientCertValidation != null)
280                         {
281                                 return this.ClientCertValidation(certificate, errors);
282                         }
283
284                         return (errors != null && errors.Length == 0);
285                 }
286
287                 internal bool RaiseClientCertificateValidation(
288                         X509Certificate certificate, 
289                         int[]                   certificateErrors)
290                 {
291                         return base.RaiseRemoteCertificateValidation(certificate, certificateErrors);
292                 }
293
294                 internal override AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost)
295                 {
296                         if (this.PrivateKeySelection != null)
297                         {
298                                 return this.PrivateKeySelection(certificate, targetHost);
299                         }
300
301                         return null;
302                 }
303
304                 internal AsymmetricAlgorithm RaisePrivateKeySelection(
305                         X509Certificate certificate,
306                         string targetHost)
307                 {
308                         return base.RaiseLocalPrivateKeySelection(certificate, targetHost);
309                 }
310
311                 #endregion
312         }
313 }