Handle ENETDOWN error if defined.
[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                         // If the negotiated cipher is a KeyEx cipher or
238                         // the client certificate is required send the CertificateRequest message
239                         if (this.context.Negotiating.Cipher.IsExportable ||
240                                 ((ServerContext)this.context).ClientCertificateRequired ||
241                                 ((ServerContext)this.context).RequestClientCertificate)
242                         {
243                                 this.protocol.SendRecord(HandshakeType.CertificateRequest);
244                         }
245
246                         // Send ServerHelloDone message
247                         this.protocol.SendRecord(HandshakeType.ServerHelloDone);
248
249                         // Receive client response, until the Client Finished message
250                         // is received. IE can be interrupted at this stage and never
251                         // complete the handshake
252                         while (this.context.LastHandshakeMsg != HandshakeType.Finished)
253                         {
254                                 byte[] record = this.protocol.ReceiveRecord(this.innerStream);
255                                 if ((record == null) || (record.Length == 0))
256                                 {
257                                         throw new TlsException(
258                                                 AlertDescription.HandshakeFailiure,
259                                                 "The client stopped the handshake.");
260                                 }
261                         }
262
263                         // Send ChangeCipherSpec and ServerFinished messages
264                         this.protocol.SendChangeCipherSpec();
265                         this.protocol.SendRecord (HandshakeType.Finished);
266
267                         // The handshake is finished
268                         this.context.HandshakeState = HandshakeState.Finished;
269
270                         // Reset Handshake messages information
271                         this.context.HandshakeMessages.Reset ();
272
273                         // Clear Key Info
274                         this.context.ClearKeyInfo();
275                 }
276
277                 #endregion
278
279                 #region Event Methods
280
281                 internal override X509Certificate OnLocalCertificateSelection(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates)
282                 {
283                         throw new NotSupportedException();
284                 }
285
286                 internal override bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors)
287                 {
288                         if (this.ClientCertValidation != null)
289                         {
290                                 return this.ClientCertValidation(certificate, errors);
291                         }
292
293                         return (errors != null && errors.Length == 0);
294                 }
295
296                 internal override bool HaveRemoteValidation2Callback {
297                         get { return ClientCertValidation2 != null; }
298                 }
299
300                 internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
301                 {
302                         CertificateValidationCallback2 cb = ClientCertValidation2;
303                         if (cb != null)
304                                 return cb (collection);
305                         return null;
306                 }
307
308                 internal bool RaiseClientCertificateValidation(
309                         X509Certificate certificate, 
310                         int[]                   certificateErrors)
311                 {
312                         return base.RaiseRemoteCertificateValidation(certificate, certificateErrors);
313                 }
314
315                 internal override AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost)
316                 {
317                         if (this.PrivateKeySelection != null)
318                         {
319                                 return this.PrivateKeySelection(certificate, targetHost);
320                         }
321
322                         return null;
323                 }
324
325                 internal AsymmetricAlgorithm RaisePrivateKeySelection(
326                         X509Certificate certificate,
327                         string targetHost)
328                 {
329                         return base.RaiseLocalPrivateKeySelection(certificate, targetHost);
330                 }
331
332                 #endregion
333         }
334 }