Merge pull request #2127 from joelmartinez/mdoc-multiassembly-squashed
[mono.git] / mcs / class / System / System.Net.Security / SslStream.cs
1 //
2 // System.Net.Security.SslStream.cs
3 //
4 // Authors:
5 //      Tim Coleman (tim@timcoleman.com)
6 //      Atsushi Enomoto (atsushi@ximian.com)
7 //      Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright (C) Tim Coleman, 2004
10 // (c) 2004,2007 Novell, Inc. (http://www.novell.com)
11 // Copyright 2011 Xamarin Inc.
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 #if SECURITY_DEP && !MONO_FEATURE_NEW_TLS
36
37 #if MONO_X509_ALIAS
38 extern alias PrebuiltSystem;
39 #endif
40 #if MONO_SECURITY_ALIAS
41 extern alias MonoSecurity;
42 #endif
43
44 #if MONO_SECURITY_ALIAS
45 using MonoCipherAlgorithmType = MonoSecurity::Mono.Security.Protocol.Tls.CipherAlgorithmType;
46 using MonoHashAlgorithmType = MonoSecurity::Mono.Security.Protocol.Tls.HashAlgorithmType;
47 using MonoExchangeAlgorithmType = MonoSecurity::Mono.Security.Protocol.Tls.ExchangeAlgorithmType;
48 using MonoSecurityProtocolType = MonoSecurity::Mono.Security.Protocol.Tls.SecurityProtocolType;
49 using MonoSecurity::Mono.Security.Protocol.Tls;
50 using MonoSecurity::Mono.Security.Interface;
51 #else
52 using MonoCipherAlgorithmType = Mono.Security.Protocol.Tls.CipherAlgorithmType;
53 using MonoHashAlgorithmType = Mono.Security.Protocol.Tls.HashAlgorithmType;
54 using MonoExchangeAlgorithmType = Mono.Security.Protocol.Tls.ExchangeAlgorithmType;
55 using MonoSecurityProtocolType = Mono.Security.Protocol.Tls.SecurityProtocolType;
56 using Mono.Security.Protocol.Tls;
57 using Mono.Security.Interface;
58 #endif
59 #if MONO_X509_ALIAS
60 using X509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
61 #endif
62
63 using CipherAlgorithmType = System.Security.Authentication.CipherAlgorithmType;
64 using HashAlgorithmType = System.Security.Authentication.HashAlgorithmType;
65 using ExchangeAlgorithmType = System.Security.Authentication.ExchangeAlgorithmType;
66
67 using System;
68 using System.IO;
69 using System.Net;
70 using System.Security.Authentication;
71 using System.Security.Cryptography.X509Certificates;
72 using System.Security.Principal;
73 using System.Security.Cryptography;
74
75 using System.Threading.Tasks;
76 using MNS = Mono.Net.Security;
77
78 namespace System.Net.Security 
79 {
80         /*
81          * These two are defined by the referencesource; add them heere to make
82          * it easy to switch between the two implementations.
83          */
84
85         internal delegate bool RemoteCertValidationCallback (
86                 string host,
87                 X509Certificate certificate,
88                 X509Chain chain,
89                 SslPolicyErrors sslPolicyErrors);
90
91         internal delegate X509Certificate LocalCertSelectionCallback (
92                 string targetHost,
93                 X509CertificateCollection localCertificates,
94                 X509Certificate remoteCertificate,
95                 string[] acceptableIssuers);
96
97         [MonoTODO ("Non-X509Certificate2 certificate is not supported")]
98         public class SslStream : AuthenticatedStream
99         {
100                 #region Fields
101
102                 SslStreamBase ssl_stream;
103                 RemoteCertificateValidationCallback validation_callback;
104                 LocalCertificateSelectionCallback selection_callback;
105
106                 #endregion // Fields
107
108                 #region Constructors
109
110                 public SslStream (Stream innerStream)
111                         : this (innerStream, false)
112                 {
113                 }
114
115                 public SslStream (Stream innerStream, bool leaveInnerStreamOpen)
116                         : base (innerStream, leaveInnerStreamOpen)
117                 {
118                 }
119
120                 [MonoTODO ("userCertificateValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
121                 public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback)
122                         : this (innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, null)
123                 {
124                 }
125
126                 [MonoTODO ("userCertificateValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
127                 public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback)
128                         : base (innerStream, leaveInnerStreamOpen)
129                 {
130                         // they are nullable.
131                         validation_callback = userCertificateValidationCallback;
132                         selection_callback = userCertificateSelectionCallback;
133                 }
134                 #endregion // Constructors
135
136                 #region Properties
137
138                 public override bool CanRead {
139                         get { return InnerStream.CanRead; }
140                 }
141
142                 public override bool CanSeek {
143                         get { return InnerStream.CanSeek; }
144                 }
145
146                 public override bool CanTimeout {
147                         get { return InnerStream.CanTimeout; }
148                 }
149
150                 public override bool CanWrite {
151                         get { return InnerStream.CanWrite; }
152                 }
153
154                 public override long Length {
155                         get { return InnerStream.Length; }
156                 }
157
158                 public override long Position {
159                         get { return InnerStream.Position; }
160                         set {
161                                 throw new NotSupportedException ("This stream does not support seek operations");
162                         }
163                 }
164
165                 // AuthenticatedStream overrides
166
167                 public override bool IsAuthenticated { 
168                         get { return ssl_stream != null; }
169                 }
170
171                 public override bool IsEncrypted { 
172                         get { return IsAuthenticated; }
173                 }
174
175                 public override bool IsMutuallyAuthenticated { 
176                         get { return IsAuthenticated && (IsServer ? RemoteCertificate != null : LocalCertificate != null); }
177                 }
178
179                 public override bool IsServer { 
180                         get { return ssl_stream is SslServerStream; }
181                 }
182
183                 public override bool IsSigned { 
184                         get { return IsAuthenticated; }
185                 }
186
187                 public override int ReadTimeout {
188                         get { return InnerStream.ReadTimeout; }
189                         set { InnerStream.ReadTimeout = value; }
190                 }
191
192                 public override int WriteTimeout {
193                         get { return InnerStream.WriteTimeout; }
194                         set { InnerStream.WriteTimeout = value; }
195                 }
196
197                 // SslStream
198
199                 public virtual bool CheckCertRevocationStatus {
200                         get {
201                                 if (!IsAuthenticated)
202                                         return false;
203
204                                 return ssl_stream.CheckCertRevocationStatus;
205                         }
206                 }
207
208                 public virtual CipherAlgorithmType CipherAlgorithm  {
209                         get {
210                                 CheckConnectionAuthenticated ();
211
212                                 switch (ssl_stream.CipherAlgorithm) {
213                                 case MonoCipherAlgorithmType.Des:
214                                         return CipherAlgorithmType.Des;
215                                 case MonoCipherAlgorithmType.None:
216                                         return CipherAlgorithmType.None;
217                                 case MonoCipherAlgorithmType.Rc2:
218                                         return CipherAlgorithmType.Rc2;
219                                 case MonoCipherAlgorithmType.Rc4:
220                                         return CipherAlgorithmType.Rc4;
221                                 case MonoCipherAlgorithmType.SkipJack:
222                                         break;
223                                 case MonoCipherAlgorithmType.TripleDes:
224                                         return CipherAlgorithmType.TripleDes;
225                                 case MonoCipherAlgorithmType.Rijndael:
226                                         switch (ssl_stream.CipherStrength) {
227                                         case 128:
228                                                 return CipherAlgorithmType.Aes128;
229                                         case 192:
230                                                 return CipherAlgorithmType.Aes192;
231                                         case 256:
232                                                 return CipherAlgorithmType.Aes256;
233                                         }
234                                         break;
235                                 }
236
237                                 throw new InvalidOperationException ("Not supported cipher algorithm is in use. It is likely a bug in SslStream.");
238                         }
239                 }
240
241                 public virtual int CipherStrength  {
242                         get {
243                                 CheckConnectionAuthenticated ();
244
245                                 return ssl_stream.CipherStrength;
246                         }
247                 }
248
249                 public virtual HashAlgorithmType HashAlgorithm  {
250                         get {
251                                 CheckConnectionAuthenticated ();
252
253                                 switch (ssl_stream.HashAlgorithm) {
254                                 case MonoHashAlgorithmType.Md5:
255                                         return HashAlgorithmType.Md5;
256                                 case MonoHashAlgorithmType.None:
257                                         return HashAlgorithmType.None;
258                                 case MonoHashAlgorithmType.Sha1:
259                                         return HashAlgorithmType.Sha1;
260                                 }
261
262                                 throw new InvalidOperationException ("Not supported hash algorithm is in use. It is likely a bug in SslStream.");
263                         }
264                 }
265
266                 public virtual int HashStrength  {
267                         get {
268                                 CheckConnectionAuthenticated ();
269
270                                 return ssl_stream.HashStrength;
271                         }
272                 }
273
274                 public virtual ExchangeAlgorithmType KeyExchangeAlgorithm { 
275                         get {
276                                 CheckConnectionAuthenticated ();
277
278                                 switch (ssl_stream.KeyExchangeAlgorithm) {
279                                 case MonoExchangeAlgorithmType.DiffieHellman:
280                                         return ExchangeAlgorithmType.DiffieHellman;
281                                 case MonoExchangeAlgorithmType.Fortezza:
282                                         break;
283                                 case MonoExchangeAlgorithmType.None:
284                                         return ExchangeAlgorithmType.None;
285                                 case MonoExchangeAlgorithmType.RsaKeyX:
286                                         return ExchangeAlgorithmType.RsaKeyX;
287                                 case MonoExchangeAlgorithmType.RsaSign:
288                                         return ExchangeAlgorithmType.RsaSign;
289                                 }
290
291                                 throw new InvalidOperationException ("Not supported exchange algorithm is in use. It is likely a bug in SslStream.");
292                         }
293                 }
294
295                 public virtual int KeyExchangeStrength { 
296                         get {
297                                 CheckConnectionAuthenticated ();
298
299                                 return ssl_stream.KeyExchangeStrength;
300                         }
301                 }
302
303                 public virtual X509Certificate LocalCertificate {
304                         get {
305                                 CheckConnectionAuthenticated ();
306
307                                 return IsServer ? ssl_stream.ServerCertificate : ((SslClientStream) ssl_stream).SelectedClientCertificate;
308                         }
309                 }
310
311                 public virtual X509Certificate RemoteCertificate {
312                         get {
313                                 CheckConnectionAuthenticated ();
314                                 return !IsServer ? ssl_stream.ServerCertificate : ((SslServerStream) ssl_stream).ClientCertificate;
315                         }
316                 }
317
318                 public virtual SslProtocols SslProtocol {
319                         get {
320                                 CheckConnectionAuthenticated ();
321
322                                 switch (ssl_stream.SecurityProtocol) {
323                                 case MonoSecurityProtocolType.Default:
324                                         return SslProtocols.Default;
325                                 case MonoSecurityProtocolType.Ssl2:
326                                         return SslProtocols.Ssl2;
327                                 case MonoSecurityProtocolType.Ssl3:
328                                         return SslProtocols.Ssl3;
329                                 case MonoSecurityProtocolType.Tls:
330                                         return SslProtocols.Tls;
331                                 }
332
333                                 throw new InvalidOperationException ("Not supported SSL/TLS protocol is in use. It is likely a bug in SslStream.");
334                         }
335                 }
336
337                 #endregion // Properties
338
339                 #region Methods
340 /*
341                 AsymmetricAlgorithm GetPrivateKey (X509Certificate cert, string targetHost)
342                 {
343                         // FIXME: what can I do for non-X509Certificate2 ?
344                         X509Certificate2 cert2 = cert as X509Certificate2;
345                         return cert2 != null ? cert2.PrivateKey : null;
346                 }
347 */
348                 X509Certificate OnCertificateSelection (X509CertificateCollection clientCerts, X509Certificate serverCert, string targetHost, X509CertificateCollection serverRequestedCerts)
349                 {
350                         string [] acceptableIssuers = new string [serverRequestedCerts != null ? serverRequestedCerts.Count : 0];
351                         for (int i = 0; i < acceptableIssuers.Length; i++)
352                                 acceptableIssuers [i] = serverRequestedCerts [i].GetIssuerName ();
353                         return selection_callback (this, targetHost, clientCerts, serverCert, acceptableIssuers);
354                 }
355
356                 public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
357                 {
358                         return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false, asyncCallback, asyncState);
359                 }
360
361                 public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
362                 {
363                         if (IsAuthenticated)
364                                 throw new InvalidOperationException ("This SslStream is already authenticated");
365
366                         SslClientStream s = new SslClientStream (InnerStream, targetHost, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols), clientCertificates);
367                         s.CheckCertRevocationStatus = checkCertificateRevocation;
368
369                         // Due to the Mono.Security internal, it cannot reuse
370                         // the delegated argument, as Mono.Security creates 
371                         // another instance of X509Certificate which lacks 
372                         // private key but is filled the private key via this
373                         // delegate.
374                         s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string host) {
375                                 string hash = cert.GetCertHashString ();
376                                 // ... so, we cannot use the delegate argument.
377                                 foreach (X509Certificate cc in clientCertificates) {
378                                         if (cc.GetCertHashString () != hash)
379                                                 continue;
380                                         X509Certificate2 cert2 = cc as X509Certificate2;
381                                         cert2 = cert2 ?? new X509Certificate2 (cc);
382                                         return cert2.PrivateKey;
383                                 }
384                                 return null;
385                         };
386
387                         // Even if validation_callback is null this allows us to verify requests where the user
388                         // does not provide a verification callback but attempts to authenticate with the website
389                         // as a client (see https://bugzilla.xamarin.com/show_bug.cgi?id=18962 for an example)
390                         var settings = new MonoTlsSettings ();
391                         settings.ServerCertificateValidationCallback = MNS.Private.CallbackHelpers.PublicToMono (validation_callback);
392                         var helper = MNS.ChainValidationHelper.Create (ref settings, null);
393                         s.ServerCertValidation2 += (certs) => helper.ValidateChain (targetHost, certs);
394                         if (selection_callback != null)
395                                 s.ClientCertSelectionDelegate = OnCertificateSelection;
396
397                         ssl_stream = s;
398
399                         return BeginWrite (new byte [0], 0, 0, asyncCallback, asyncState);
400                 }
401
402                 public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
403                 {
404                         CheckConnectionAuthenticated ();
405
406                         return ssl_stream.BeginRead (buffer, offset, count, asyncCallback, asyncState);
407                 }
408
409                 public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
410                 {
411                         return BeginAuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false, asyncCallback, asyncState);
412                 }
413
414                 public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
415                 {
416                         if (IsAuthenticated)
417                                 throw new InvalidOperationException ("This SslStream is already authenticated");
418
419                         SslServerStream s = new SslServerStream (InnerStream, serverCertificate, clientCertificateRequired, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols));
420                         s.CheckCertRevocationStatus = checkCertificateRevocation;
421                         // Due to the Mono.Security internal, it cannot reuse
422                         // the delegated argument, as Mono.Security creates 
423                         // another instance of X509Certificate which lacks 
424                         // private key but is filled the private key via this
425                         // delegate.
426                         s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string targetHost) {
427                                 // ... so, we cannot use the delegate argument.
428                                 X509Certificate2 cert2 = serverCertificate as X509Certificate2 ?? new X509Certificate2 (serverCertificate);
429                                 return cert2 != null ? cert2.PrivateKey : null;
430                         };
431
432                         if (validation_callback != null)
433                                 s.ClientCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
434                                         X509Chain chain = null;
435                                         if (cert is X509Certificate2) {
436                                                 chain = new X509Chain ();
437                                                 chain.Build ((X509Certificate2) cert);
438                                         }
439                                         // FIXME: SslPolicyErrors is incomplete
440                                         SslPolicyErrors errors = certErrors.Length > 0 ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None;
441                                         return validation_callback (this, cert, chain, errors);
442                                 };
443
444                         ssl_stream = s;
445
446                         return BeginWrite (new byte[0], 0, 0, asyncCallback, asyncState);
447                 }
448
449                 MonoSecurityProtocolType GetMonoSslProtocol (SslProtocols ms)
450                 {
451                         switch (ms) {
452                         case SslProtocols.Ssl2:
453                                 return MonoSecurityProtocolType.Ssl2;
454                         case SslProtocols.Ssl3:
455                                 return MonoSecurityProtocolType.Ssl3;
456                         case SslProtocols.Tls:
457                                 return MonoSecurityProtocolType.Tls;
458                         default:
459                                 return MonoSecurityProtocolType.Default;
460                         }
461                 }
462
463                 public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
464                 {
465                         CheckConnectionAuthenticated ();
466
467                         return ssl_stream.BeginWrite (buffer, offset, count, asyncCallback, asyncState);
468                 }
469
470                 public virtual void AuthenticateAsClient (string targetHost)
471                 {
472                         AuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false);
473                 }
474
475                 public virtual void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
476                 {
477                         EndAuthenticateAsClient (BeginAuthenticateAsClient (
478                                 targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, null, null));
479                 }
480
481                 public virtual void AuthenticateAsServer (X509Certificate serverCertificate)
482                 {
483                         AuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false);
484                 }
485
486                 public virtual void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
487                 {
488                         EndAuthenticateAsServer (BeginAuthenticateAsServer (
489                                 serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, null, null));
490                 }
491
492                 protected override void Dispose (bool disposing)
493                 {
494                         if (disposing) {
495                                 if (ssl_stream != null)
496                                         ssl_stream.Dispose ();
497                                 ssl_stream = null;
498                         }
499                         base.Dispose (disposing);
500                 }
501
502                 public virtual void EndAuthenticateAsClient (IAsyncResult asyncResult)
503                 {
504                         CheckConnectionAuthenticated ();
505
506                         if (CanRead)
507                                 ssl_stream.EndRead (asyncResult);
508                         else
509                                 ssl_stream.EndWrite (asyncResult);
510                 }
511
512                 public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
513                 {
514                         CheckConnectionAuthenticated ();
515
516                         if (CanRead)
517                                 ssl_stream.EndRead (asyncResult);
518                         else
519                                 ssl_stream.EndWrite (asyncResult);
520                 }
521
522                 public override int EndRead (IAsyncResult asyncResult)
523                 {
524                         CheckConnectionAuthenticated ();
525
526                         return ssl_stream.EndRead (asyncResult);
527                 }
528
529                 public override void EndWrite (IAsyncResult asyncResult)
530                 {
531                         CheckConnectionAuthenticated ();
532
533                         ssl_stream.EndWrite (asyncResult);
534                 }
535
536                 public override void Flush ()
537                 {
538                         CheckConnectionAuthenticated ();
539
540                         InnerStream.Flush ();
541                 }
542
543                 public override int Read (byte[] buffer, int offset, int count)
544                 {
545                         return EndRead (BeginRead (buffer, offset, count, null, null));
546                 }
547
548                 public override long Seek (long offset, SeekOrigin origin)
549                 {
550                         throw new NotSupportedException ("This stream does not support seek operations");
551                 }
552
553                 public override void SetLength (long value)
554                 {
555                         InnerStream.SetLength (value);
556                 }
557
558                 public override void Write (byte[] buffer, int offset, int count)
559                 {
560                         EndWrite (BeginWrite (buffer, offset, count, null, null));
561                 }
562
563                 public void Write (byte[] buffer)
564                 {
565                         Write (buffer, 0, buffer.Length);
566                 }
567
568                 void CheckConnectionAuthenticated ()
569                 {
570                         if (!IsAuthenticated)
571                                 throw new InvalidOperationException ("This operation is invalid until it is successfully authenticated");
572                 }
573
574                 public virtual Task AuthenticateAsClientAsync (string targetHost)
575                 {
576                         return Task.Factory.FromAsync (BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null);
577                 }
578
579                 public virtual Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
580                 {
581                         var t = Tuple.Create (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, this);
582
583                         return Task.Factory.FromAsync ((callback, state) => {
584                                 var d = (Tuple<string, X509CertificateCollection, SslProtocols, bool, SslStream>) state;
585                                 return d.Item5.BeginAuthenticateAsClient (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
586                         }, EndAuthenticateAsClient, t);
587                 }
588
589                 public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
590                 {
591                         return Task.Factory.FromAsync (BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null);
592                 }
593
594                 public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
595                 {
596                         var t = Tuple.Create (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, this);
597
598                         return Task.Factory.FromAsync ((callback, state) => {
599                                 var d = (Tuple<X509Certificate, bool, SslProtocols, bool, SslStream>) state;
600                                 return d.Item5.BeginAuthenticateAsServer (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
601                         }, EndAuthenticateAsServer, t);
602                 }
603
604                 #endregion // Methods
605         }
606 }
607
608 #endif