Moved chain building and validation from Mono.Security to System
[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                 public event CertificateValidationCallback2 ClientCertValidation2;
80                 #region Constructors
81
82                 public SslServerStream(
83                         Stream                  stream, 
84                         X509Certificate serverCertificate) : this(
85                         stream, 
86                         serverCertificate, 
87                         false, 
88                         false, 
89                         SecurityProtocolType.Default)
90                 {
91                 }
92
93                 public SslServerStream(
94                         Stream                  stream,
95                         X509Certificate serverCertificate,
96                         bool                    clientCertificateRequired,
97                         bool                    ownsStream): this(
98                         stream, 
99                         serverCertificate, 
100                         clientCertificateRequired, 
101                         ownsStream, 
102                         SecurityProtocolType.Default)
103                 {
104                 }
105
106                 public SslServerStream(
107                         Stream                  stream,
108                         X509Certificate serverCertificate,
109                         bool                    clientCertificateRequired,
110                         bool                    requestClientCertificate,
111                         bool                    ownsStream)
112                                 : this (stream, serverCertificate, clientCertificateRequired, requestClientCertificate, ownsStream, SecurityProtocolType.Default)
113                 {
114                 }
115
116                 public SslServerStream(
117                         Stream                                  stream,
118                         X509Certificate                 serverCertificate,
119                         bool                                    clientCertificateRequired,
120                         bool                                    ownsStream,
121                         SecurityProtocolType    securityProtocolType)
122                         : this (stream, serverCertificate, clientCertificateRequired, false, ownsStream, securityProtocolType)
123                 {
124                 }
125
126                 public SslServerStream(
127                         Stream                                  stream,
128                         X509Certificate                 serverCertificate,
129                         bool                                    clientCertificateRequired,
130                         bool                                    requestClientCertificate,
131                         bool                                    ownsStream,
132                         SecurityProtocolType    securityProtocolType)
133                         : base(stream, ownsStream)
134                 {
135                         this.context = new ServerContext(
136                                 this,
137                                 securityProtocolType,
138                                 serverCertificate,
139                                 clientCertificateRequired,
140                                 requestClientCertificate);
141
142                         this.protocol = new ServerRecordProtocol(innerStream, (ServerContext)this.context);
143                 }
144
145                 #endregion
146
147                 #region Finalizer
148
149                 ~SslServerStream()
150                 {
151                         this.Dispose(false);
152                 }
153
154                 #endregion
155
156                 #region IDisposable Methods
157
158                 protected override void Dispose(bool disposing)
159                 {
160                         base.Dispose(disposing);
161
162                         if (disposing)
163                         {
164                                 this.ClientCertValidation = null;
165                                 this.PrivateKeySelection = null;
166                         }
167                 }
168
169                 #endregion
170
171                 #region Handsake Methods
172
173                 /*
174                         Client                                                                                  Server
175
176                         ClientHello                 -------->
177                                                                                                                         ServerHello
178                                                                                                                         Certificate*
179                                                                                                                         ServerKeyExchange*
180                                                                                                                         CertificateRequest*
181                                                                                 <--------                       ServerHelloDone
182                         Certificate*
183                         ClientKeyExchange
184                         CertificateVerify*
185                         [ChangeCipherSpec]
186                         Finished                    -------->
187                                                                                                                         [ChangeCipherSpec]
188                                                                                 <--------           Finished
189                         Application Data            <------->                   Application Data
190
191                                         Fig. 1 - Message flow for a full handshake              
192                 */
193
194                 internal override IAsyncResult OnBeginNegotiateHandshake(AsyncCallback callback, object state)
195                 {
196                         // Reset the context if needed
197                         if (this.context.HandshakeState != HandshakeState.None)
198                         {
199                                 this.context.Clear();
200                         }
201
202                         // Obtain supported cipher suites
203                         this.context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(this.context.SecurityProtocol);
204
205                         // Set handshake state
206                         this.context.HandshakeState = HandshakeState.Started;
207
208                         // Receive Client Hello message
209                         return this.protocol.BeginReceiveRecord(this.innerStream, callback, state);
210
211                 }
212
213                 internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult)
214                 {
215                         // Receive Client Hello message and ignore it
216                         this.protocol.EndReceiveRecord(asyncResult);
217
218                         // If received message is not an ClientHello send a
219                         // Fatal Alert
220                         if (this.context.LastHandshakeMsg != HandshakeType.ClientHello)
221                         {
222                                 this.protocol.SendAlert(AlertDescription.UnexpectedMessage);
223                         }
224
225                         // Send ServerHello message
226                         this.protocol.SendRecord(HandshakeType.ServerHello);
227
228                         // Send ServerCertificate message
229                         this.protocol.SendRecord(HandshakeType.Certificate);
230
231                         // If the negotiated cipher is a KeyEx cipher send ServerKeyExchange
232                         if (this.context.Negotiating.Cipher.IsExportable)
233                         {
234                                 this.protocol.SendRecord(HandshakeType.ServerKeyExchange);
235                         }
236
237                         bool certRequested = false;
238
239                         // If the negotiated cipher is a KeyEx cipher or
240                         // the client certificate is required send the CertificateRequest message
241                         if (this.context.Negotiating.Cipher.IsExportable ||
242                                 ((ServerContext)this.context).ClientCertificateRequired ||
243                                 ((ServerContext)this.context).RequestClientCertificate)
244                         {
245                                 this.protocol.SendRecord(HandshakeType.CertificateRequest);
246                                 certRequested = true;
247                         }
248
249                         // Send ServerHelloDone message
250                         this.protocol.SendRecord(HandshakeType.ServerHelloDone);
251
252                         // Receive client response, until the Client Finished message
253                         // is received. IE can be interrupted at this stage and never
254                         // complete the handshake
255                         while (this.context.LastHandshakeMsg != HandshakeType.Finished)
256                         {
257                                 byte[] record = this.protocol.ReceiveRecord(this.innerStream);
258                                 if ((record == null) || (record.Length == 0))
259                                 {
260                                         throw new TlsException(
261                                                 AlertDescription.HandshakeFailiure,
262                                                 "The client stopped the handshake.");
263                                 }
264                         }
265
266                         if (certRequested) {
267                                 X509Certificate client_cert = this.context.ClientSettings.ClientCertificate;
268                                 if (client_cert == null && ((ServerContext)this.context).ClientCertificateRequired)
269                                         throw new TlsException (AlertDescription.BadCertificate, "No certificate received from client.");
270
271                                 if (!RaiseClientCertificateValidation (client_cert, new int[0]))
272                                         throw new TlsException (AlertDescription.BadCertificate, "Client certificate not accepted.");
273                         }
274
275                         // Send ChangeCipherSpec and ServerFinished messages
276                         this.protocol.SendChangeCipherSpec();
277                         this.protocol.SendRecord (HandshakeType.Finished);
278
279                         // The handshake is finished
280                         this.context.HandshakeState = HandshakeState.Finished;
281
282                         // Reset Handshake messages information
283                         this.context.HandshakeMessages.Reset ();
284
285                         // Clear Key Info
286                         this.context.ClearKeyInfo();
287                 }
288
289                 #endregion
290
291                 #region Event Methods
292
293                 internal override X509Certificate OnLocalCertificateSelection(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates)
294                 {
295                         throw new NotSupportedException();
296                 }
297
298                 internal override bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors)
299                 {
300                         if (this.ClientCertValidation != null)
301                         {
302                                 return this.ClientCertValidation(certificate, errors);
303                         }
304
305                         return (errors != null && errors.Length == 0);
306                 }
307
308                 internal override bool HaveRemoteValidation2Callback {
309                         get { return ClientCertValidation2 != null; }
310                 }
311
312                 internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
313                 {
314                         CertificateValidationCallback2 cb = ClientCertValidation2;
315                         if (cb != null)
316                                 return cb (collection);
317                         return null;
318                 }
319
320                 internal bool RaiseClientCertificateValidation(
321                         X509Certificate certificate, 
322                         int[]                   certificateErrors)
323                 {
324                         return base.RaiseRemoteCertificateValidation(certificate, certificateErrors);
325                 }
326
327                 internal override AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost)
328                 {
329                         if (this.PrivateKeySelection != null)
330                         {
331                                 return this.PrivateKeySelection(certificate, targetHost);
332                         }
333
334                         return null;
335                 }
336
337                 internal AsymmetricAlgorithm RaisePrivateKeySelection(
338                         X509Certificate certificate,
339                         string targetHost)
340                 {
341                         return base.RaiseLocalPrivateKeySelection(certificate, targetHost);
342                 }
343
344                 #endregion
345         }
346 }