Update mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng/RelaxngPattern.cs
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / SslClientStream.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 using System.Threading;
33
34 using Mono.Security.Protocol.Tls.Handshake;
35
36 namespace Mono.Security.Protocol.Tls
37 {
38         #region Delegates
39
40         public delegate bool CertificateValidationCallback(
41                 X509Certificate certificate, 
42                 int[]                   certificateErrors);
43
44         public class ValidationResult {
45                 bool trusted;
46                 bool user_denied;
47                 int error_code;
48
49                 public ValidationResult (bool trusted, bool user_denied, int error_code)
50                 {
51                         this.trusted = trusted;
52                         this.user_denied = user_denied;
53                         this.error_code = error_code;
54                 }
55
56                 public bool Trusted {
57                         get { return trusted; }
58                 }
59
60                 public bool UserDenied {
61                         get { return user_denied; }
62                 }
63
64                 public int ErrorCode {
65                         get { return error_code; }
66                 }
67         }
68
69 #if MOONLIGHT
70         internal
71 #else
72         public
73 #endif
74         delegate ValidationResult CertificateValidationCallback2 (Mono.Security.X509.X509CertificateCollection collection);
75
76         public delegate X509Certificate CertificateSelectionCallback(
77                 X509CertificateCollection       clientCertificates, 
78                 X509Certificate                         serverCertificate, 
79                 string                                          targetHost, 
80                 X509CertificateCollection       serverRequestedCertificates);
81
82         public delegate AsymmetricAlgorithm PrivateKeySelectionCallback(
83                 X509Certificate certificate, 
84                 string                  targetHost);
85
86         #endregion
87
88         public class SslClientStream : SslStreamBase
89         {
90                 #region Internal Events
91                 
92                 internal event CertificateValidationCallback    ServerCertValidation;
93                 internal event CertificateSelectionCallback             ClientCertSelection;
94                 internal event PrivateKeySelectionCallback              PrivateKeySelection;
95                 
96                 #endregion
97
98                 #region Properties
99
100                 // required by HttpsClientStream for proxy support
101                 internal Stream InputBuffer 
102                 {
103                         get { return base.inputBuffer; }
104                 }
105
106                 public X509CertificateCollection ClientCertificates
107                 {
108                         get { return this.context.ClientSettings.Certificates; }
109                 }
110
111                 public X509Certificate SelectedClientCertificate
112                 {
113                         get { return this.context.ClientSettings.ClientCertificate; }
114                 }
115
116                 #endregion
117
118                 #region Callback Properties
119
120                 public CertificateValidationCallback ServerCertValidationDelegate
121                 {
122                         get { return this.ServerCertValidation; }
123                         set { this.ServerCertValidation = value; }                      
124                 }
125
126                 public CertificateSelectionCallback ClientCertSelectionDelegate 
127                 {
128                         get { return this.ClientCertSelection; }
129                         set { this.ClientCertSelection = value; }
130                 }
131
132                 public PrivateKeySelectionCallback PrivateKeyCertSelectionDelegate
133                 {
134                         get { return this.PrivateKeySelection; }
135                         set { this.PrivateKeySelection = value; }
136                 }
137                 
138                 #endregion
139
140 #if MOONLIGHT
141                 internal event CertificateValidationCallback2 ServerCertValidation2;
142 #else
143                 public event CertificateValidationCallback2 ServerCertValidation2;
144 #endif
145
146                 #region Constructors
147                 
148                 public SslClientStream(
149                         Stream  stream, 
150                         string  targetHost, 
151                         bool    ownsStream) 
152                         : this(
153                                 stream, targetHost, ownsStream, 
154                                 SecurityProtocolType.Default, null)
155                 {
156                 }
157                 
158                 public SslClientStream(
159                         Stream                          stream, 
160                         string                          targetHost, 
161                         X509Certificate         clientCertificate) 
162                         : this(
163                                 stream, targetHost, false, SecurityProtocolType.Default, 
164                                 new X509CertificateCollection(new X509Certificate[]{clientCertificate}))
165                 {
166                 }
167
168                 public SslClientStream(
169                         Stream                                          stream,
170                         string                                          targetHost, 
171                         X509CertificateCollection clientCertificates) : 
172                         this(
173                                 stream, targetHost, false, SecurityProtocolType.Default, 
174                                 clientCertificates)
175                 {
176                 }
177
178                 public SslClientStream(
179                         Stream                                  stream,
180                         string                                  targetHost,
181                         bool                                    ownsStream,
182                         SecurityProtocolType    securityProtocolType) 
183                         : this(
184                                 stream, targetHost, ownsStream, securityProtocolType,
185                                 new X509CertificateCollection())
186                 {
187                 }
188
189                 public SslClientStream(
190                         Stream                                          stream,
191                         string                                          targetHost,
192                         bool                                            ownsStream,
193                         SecurityProtocolType            securityProtocolType,
194                         X509CertificateCollection       clientCertificates):
195                         base(stream, ownsStream)
196                 {
197                         if (targetHost == null || targetHost.Length == 0)
198                         {
199                                 throw new ArgumentNullException("targetHost is null or an empty string.");
200                         }
201
202                         this.context = new ClientContext(
203                                 this,
204                                 securityProtocolType, 
205                                 targetHost, 
206                                 clientCertificates);
207
208                         this.protocol = new ClientRecordProtocol(innerStream, (ClientContext)this.context);
209                 }
210
211                 #endregion
212
213                 #region Finalizer
214
215                 ~SslClientStream()
216                 {
217                         base.Dispose(false);
218                 }
219
220                 #endregion
221
222                 #region IDisposable Methods
223
224                 protected override void Dispose(bool disposing)
225                 {
226                         base.Dispose(disposing);
227
228                         if (disposing)
229                         {
230                                 this.ServerCertValidation = null;
231                                 this.ClientCertSelection = null;
232                                 this.PrivateKeySelection = null;
233                                 this.ServerCertValidation2 = null;
234                         }
235                 }
236
237                 #endregion
238
239                 #region Handshake Methods
240
241                 /*
242                         Client                                                                                  Server
243
244                         ClientHello                 -------->
245                                                                                                                         ServerHello
246                                                                                                                         Certificate*
247                                                                                                                         ServerKeyExchange*
248                                                                                                                         CertificateRequest*
249                                                                                 <--------                       ServerHelloDone
250                         Certificate*
251                         ClientKeyExchange
252                         CertificateVerify*
253                         [ChangeCipherSpec]
254                         Finished                    -------->
255                                                                                                                         [ChangeCipherSpec]
256                                                                                 <--------           Finished
257                         Application Data            <------->                   Application Data
258
259                                         Fig. 1 - Message flow for a full handshake              
260                 */
261
262                 internal override IAsyncResult OnBeginNegotiateHandshake(AsyncCallback callback, object state)
263                 {
264                         try
265                         {
266                                 if (this.context.HandshakeState != HandshakeState.None)
267                                 {
268                                         this.context.Clear();
269                                 }
270
271                                 // Obtain supported cipher suites
272                                 this.context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(this.context.SecurityProtocol);
273
274                                 // Set handshake state
275                                 this.context.HandshakeState = HandshakeState.Started;
276
277                                 // Send client hello
278                                 return this.protocol.BeginSendRecord(HandshakeType.ClientHello, callback, state);
279                         }
280                         catch (TlsException ex)
281                         {
282                                 this.protocol.SendAlert(ex.Alert);
283
284                                 throw new IOException("The authentication or decryption has failed.", ex);
285                         }
286                         catch (Exception ex)
287                         {
288                                 this.protocol.SendAlert(AlertDescription.InternalError);
289
290                                 throw new IOException("The authentication or decryption has failed.", ex);
291                         }
292                 }
293
294                 private void SafeReceiveRecord (Stream s)
295                 {
296                         byte[] record = this.protocol.ReceiveRecord (s);
297                         if ((record == null) || (record.Length == 0)) {
298                                 throw new TlsException (
299                                         AlertDescription.HandshakeFailiure,
300                                         "The server stopped the handshake.");
301                         }
302                 }
303
304                 internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult)
305                 {
306                         this.protocol.EndSendRecord(asyncResult);
307
308                         // Read server response
309                         while (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone) 
310                         {
311                                 // Read next record
312                                 SafeReceiveRecord (this.innerStream);
313
314                                 // special case for abbreviated handshake where no ServerHelloDone is sent from the server
315                                 if (this.context.AbbreviatedHandshake && (this.context.LastHandshakeMsg == HandshakeType.ServerHello))
316                                         break;
317                         }
318
319                         // the handshake is much easier if we can reuse a previous session settings
320                         if (this.context.AbbreviatedHandshake) 
321                         {
322                                 ClientSessionCache.SetContextFromCache (this.context);
323                                 this.context.Negotiating.Cipher.ComputeKeys ();
324                                 this.context.Negotiating.Cipher.InitializeCipher ();
325
326                                 // Send Cipher Spec protocol
327                                 this.protocol.SendChangeCipherSpec ();
328
329                                 // Read record until server finished is received
330                                 while (this.context.HandshakeState != HandshakeState.Finished) 
331                                 {
332                                         // If all goes well this will process messages:
333                                         //              Change Cipher Spec
334                                         //              Server finished
335                                         SafeReceiveRecord (this.innerStream);
336                                 }
337
338                                 // Send Finished message
339                                 this.protocol.SendRecord (HandshakeType.Finished);
340                         }
341                         else
342                         {
343                                 // Send client certificate if requested
344                                 // even if the server ask for it it _may_ still be optional
345                                 bool clientCertificate = this.context.ServerSettings.CertificateRequest;
346
347                                 // NOTE: sadly SSL3 and TLS1 differs in how they handle this and
348                                 // the current design doesn't allow a very cute way to handle 
349                                 // SSL3 alert warning for NoCertificate (41).
350                                 if (this.context.SecurityProtocol == SecurityProtocolType.Ssl3)
351                                 {
352                                         clientCertificate = ((this.context.ClientSettings.Certificates != null) &&
353                                                 (this.context.ClientSettings.Certificates.Count > 0));
354                                         // this works well with OpenSSL (but only for SSL3)
355                                 }
356
357                                 if (clientCertificate)
358                                 {
359                                         this.protocol.SendRecord(HandshakeType.Certificate);
360                                 }
361
362                                 // Send Client Key Exchange
363                                 this.protocol.SendRecord(HandshakeType.ClientKeyExchange);
364
365                                 // Now initialize session cipher with the generated keys
366                                 this.context.Negotiating.Cipher.InitializeCipher();
367
368                                 // Send certificate verify if requested (optional)
369                                 if (clientCertificate && (this.context.ClientSettings.ClientCertificate != null))
370                                 {
371                                         this.protocol.SendRecord(HandshakeType.CertificateVerify);
372                                 }
373
374                                 // Send Cipher Spec protocol
375                                 this.protocol.SendChangeCipherSpec ();
376
377                                 // Send Finished message
378                                 this.protocol.SendRecord (HandshakeType.Finished);
379
380                                 // Read record until server finished is received
381                                 while (this.context.HandshakeState != HandshakeState.Finished) {
382                                         // If all goes well this will process messages:
383                                         //              Change Cipher Spec
384                                         //              Server finished
385                                         SafeReceiveRecord (this.innerStream);
386                                 }
387                         }
388
389                         // Reset Handshake messages information
390                         this.context.HandshakeMessages.Reset ();
391
392                         // Clear Key Info
393                         this.context.ClearKeyInfo();
394
395                 }
396
397                 #endregion
398
399                 #region Event Methods
400
401                 internal override X509Certificate OnLocalCertificateSelection(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates)
402                 {
403                         if (this.ClientCertSelection != null)
404                         {
405                                 return this.ClientCertSelection(
406                                         clientCertificates,
407                                         serverCertificate,
408                                         targetHost,
409                                         serverRequestedCertificates);
410                         }
411
412                         return null;
413                 }
414
415                 internal override bool HaveRemoteValidation2Callback {
416                         get { return ServerCertValidation2 != null; }
417                 }
418
419                 internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
420                 {
421                         CertificateValidationCallback2 cb = ServerCertValidation2;
422                         if (cb != null)
423                                 return cb (collection);
424                         return null;
425                 }
426
427                 internal override bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors)
428                 {
429                         if (this.ServerCertValidation != null)
430                         {
431                                 return this.ServerCertValidation(certificate, errors);
432                         }
433
434                         return (errors != null && errors.Length == 0);
435                 }
436
437                 internal virtual bool RaiseServerCertificateValidation(
438                         X509Certificate certificate, 
439                         int[]                   certificateErrors)
440                 {
441                         return base.RaiseRemoteCertificateValidation(certificate, certificateErrors);
442                 }
443
444                 internal virtual ValidationResult RaiseServerCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
445                 {
446                         return base.RaiseRemoteCertificateValidation2 (collection);
447                 }
448
449                 internal X509Certificate RaiseClientCertificateSelection(
450                         X509CertificateCollection       clientCertificates, 
451                         X509Certificate                         serverCertificate, 
452                         string                                          targetHost, 
453                         X509CertificateCollection       serverRequestedCertificates)
454                 {
455                         return base.RaiseLocalCertificateSelection(clientCertificates, serverCertificate, targetHost, serverRequestedCertificates);
456                 }
457
458                 internal override AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost)
459                 {
460                         if (this.PrivateKeySelection != null)
461                         {
462                                 return this.PrivateKeySelection(certificate, targetHost);
463                         }
464
465                         return null;
466                 }
467
468                 internal AsymmetricAlgorithm RaisePrivateKeySelection(
469                         X509Certificate certificate,
470                         string targetHost)
471                 {
472                         return base.RaiseLocalPrivateKeySelection(certificate, targetHost);
473                 }
474
475                 #endregion
476         }
477 }