Merge pull request #347 from JamesB7/master
[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
36
37 #if !MOONLIGHT
38 extern alias PrebuiltSystem;
39 using X509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
40 #endif
41
42 using System;
43 using System.IO;
44 using System.Net;
45 using System.Security.Authentication;
46 using System.Security.Cryptography.X509Certificates;
47 using System.Security.Principal;
48 using System.Security.Cryptography;
49 using Mono.Security.Protocol.Tls;
50
51 using CipherAlgorithmType = System.Security.Authentication.CipherAlgorithmType;
52 using HashAlgorithmType = System.Security.Authentication.HashAlgorithmType;
53 using ExchangeAlgorithmType = System.Security.Authentication.ExchangeAlgorithmType;
54
55 using MonoCipherAlgorithmType = Mono.Security.Protocol.Tls.CipherAlgorithmType;
56 using MonoHashAlgorithmType = Mono.Security.Protocol.Tls.HashAlgorithmType;
57 using MonoExchangeAlgorithmType = Mono.Security.Protocol.Tls.ExchangeAlgorithmType;
58 using MonoSecurityProtocolType = Mono.Security.Protocol.Tls.SecurityProtocolType;
59
60 #if NET_4_5
61 using System.Threading.Tasks;
62 #endif
63
64 namespace System.Net.Security 
65 {
66         [MonoTODO ("Non-X509Certificate2 certificate is not supported")]
67         public class SslStream : AuthenticatedStream
68         {
69                 #region Fields
70
71                 SslStreamBase ssl_stream;
72                 RemoteCertificateValidationCallback validation_callback;
73                 LocalCertificateSelectionCallback selection_callback;
74
75                 #endregion // Fields
76
77                 #region Constructors
78
79                 public SslStream (Stream innerStream)
80                         : this (innerStream, false)
81                 {
82                 }
83
84                 public SslStream (Stream innerStream, bool leaveInnerStreamOpen)
85                         : base (innerStream, leaveInnerStreamOpen)
86                 {
87                 }
88
89                 [MonoTODO ("userCertificateValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
90                 public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback)
91                         : this (innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, null)
92                 {
93                 }
94
95                 [MonoTODO ("userCertificateValidationCallback is not passed X509Chain and SslPolicyErrors correctly")]
96                 public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback)
97                         : base (innerStream, leaveInnerStreamOpen)
98                 {
99                         // they are nullable.
100                         validation_callback = userCertificateValidationCallback;
101                         selection_callback = userCertificateSelectionCallback;
102                 }
103                 #endregion // Constructors
104
105                 #region Properties
106
107                 public override bool CanRead {
108                         get { return InnerStream.CanRead; }
109                 }
110
111                 public override bool CanSeek {
112                         get { return InnerStream.CanSeek; }
113                 }
114
115                 public override bool CanTimeout {
116                         get { return InnerStream.CanTimeout; }
117                 }
118
119                 public override bool CanWrite {
120                         get { return InnerStream.CanWrite; }
121                 }
122
123                 public override long Length {
124                         get { return InnerStream.Length; }
125                 }
126
127                 public override long Position {
128                         get { return InnerStream.Position; }
129                         set {
130                                 throw new NotSupportedException ("This stream does not support seek operations");
131                         }
132                 }
133
134                 // AuthenticatedStream overrides
135
136                 public override bool IsAuthenticated { 
137                         get { return ssl_stream != null; }
138                 }
139
140                 public override bool IsEncrypted { 
141                         get { return IsAuthenticated; }
142                 }
143
144                 public override bool IsMutuallyAuthenticated { 
145                         get { return IsAuthenticated && (IsServer ? RemoteCertificate != null : LocalCertificate != null); }
146                 }
147
148                 public override bool IsServer { 
149 #if MOONLIGHT
150                         get { return false; }
151 #else
152                         get { return ssl_stream is SslServerStream; }
153 #endif
154                 }
155
156                 public override bool IsSigned { 
157                         get { return IsAuthenticated; }
158                 }
159
160                 public override int ReadTimeout {
161                         get { return InnerStream.ReadTimeout; }
162                         set { InnerStream.ReadTimeout = value; }
163                 }
164
165                 public override int WriteTimeout {
166                         get { return InnerStream.WriteTimeout; }
167                         set { InnerStream.WriteTimeout = value; }
168                 }
169
170                 // SslStream
171
172                 public virtual bool CheckCertRevocationStatus {
173                         get {
174                                 if (!IsAuthenticated)
175                                         return false;
176
177                                 return ssl_stream.CheckCertRevocationStatus;
178                         }
179                 }
180
181                 public virtual CipherAlgorithmType CipherAlgorithm  {
182                         get {
183                                 CheckConnectionAuthenticated ();
184
185                                 switch (ssl_stream.CipherAlgorithm) {
186                                 case MonoCipherAlgorithmType.Des:
187                                         return CipherAlgorithmType.Des;
188                                 case MonoCipherAlgorithmType.None:
189                                         return CipherAlgorithmType.None;
190                                 case MonoCipherAlgorithmType.Rc2:
191                                         return CipherAlgorithmType.Rc2;
192                                 case MonoCipherAlgorithmType.Rc4:
193                                         return CipherAlgorithmType.Rc4;
194                                 case MonoCipherAlgorithmType.SkipJack:
195                                         break;
196                                 case MonoCipherAlgorithmType.TripleDes:
197                                         return CipherAlgorithmType.TripleDes;
198                                 case MonoCipherAlgorithmType.Rijndael:
199                                         switch (ssl_stream.CipherStrength) {
200                                         case 128:
201                                                 return CipherAlgorithmType.Aes128;
202                                         case 192:
203                                                 return CipherAlgorithmType.Aes192;
204                                         case 256:
205                                                 return CipherAlgorithmType.Aes256;
206                                         }
207                                         break;
208                                 }
209
210                                 throw new InvalidOperationException ("Not supported cipher algorithm is in use. It is likely a bug in SslStream.");
211                         }
212                 }
213
214                 public virtual int CipherStrength  {
215                         get {
216                                 CheckConnectionAuthenticated ();
217
218                                 return ssl_stream.CipherStrength;
219                         }
220                 }
221
222                 public virtual HashAlgorithmType HashAlgorithm  {
223                         get {
224                                 CheckConnectionAuthenticated ();
225
226                                 switch (ssl_stream.HashAlgorithm) {
227                                 case MonoHashAlgorithmType.Md5:
228                                         return HashAlgorithmType.Md5;
229                                 case MonoHashAlgorithmType.None:
230                                         return HashAlgorithmType.None;
231                                 case MonoHashAlgorithmType.Sha1:
232                                         return HashAlgorithmType.Sha1;
233                                 }
234
235                                 throw new InvalidOperationException ("Not supported hash algorithm is in use. It is likely a bug in SslStream.");
236                         }
237                 }
238
239                 public virtual int HashStrength  {
240                         get {
241                                 CheckConnectionAuthenticated ();
242
243                                 return ssl_stream.HashStrength;
244                         }
245                 }
246
247                 public virtual ExchangeAlgorithmType KeyExchangeAlgorithm { 
248                         get {
249                                 CheckConnectionAuthenticated ();
250
251                                 switch (ssl_stream.KeyExchangeAlgorithm) {
252                                 case MonoExchangeAlgorithmType.DiffieHellman:
253                                         return ExchangeAlgorithmType.DiffieHellman;
254                                 case MonoExchangeAlgorithmType.Fortezza:
255                                         break;
256                                 case MonoExchangeAlgorithmType.None:
257                                         return ExchangeAlgorithmType.None;
258                                 case MonoExchangeAlgorithmType.RsaKeyX:
259                                         return ExchangeAlgorithmType.RsaKeyX;
260                                 case MonoExchangeAlgorithmType.RsaSign:
261                                         return ExchangeAlgorithmType.RsaSign;
262                                 }
263
264                                 throw new InvalidOperationException ("Not supported exchange algorithm is in use. It is likely a bug in SslStream.");
265                         }
266                 }
267
268                 public virtual int KeyExchangeStrength { 
269                         get {
270                                 CheckConnectionAuthenticated ();
271
272                                 return ssl_stream.KeyExchangeStrength;
273                         }
274                 }
275
276                 public virtual X509Certificate LocalCertificate {
277                         get {
278                                 CheckConnectionAuthenticated ();
279
280                                 return IsServer ? ssl_stream.ServerCertificate : ((SslClientStream) ssl_stream).SelectedClientCertificate;
281                         }
282                 }
283
284                 public virtual X509Certificate RemoteCertificate {
285                         get {
286                                 CheckConnectionAuthenticated ();
287 #if MOONLIGHT
288                                 return ssl_stream.ServerCertificate;
289 #else
290                                 return !IsServer ? ssl_stream.ServerCertificate : ((SslServerStream) ssl_stream).ClientCertificate;
291 #endif
292                         }
293                 }
294
295                 public virtual SslProtocols SslProtocol {
296                         get {
297                                 CheckConnectionAuthenticated ();
298
299                                 switch (ssl_stream.SecurityProtocol) {
300                                 case MonoSecurityProtocolType.Default:
301                                         return SslProtocols.Default;
302                                 case MonoSecurityProtocolType.Ssl2:
303                                         return SslProtocols.Ssl2;
304                                 case MonoSecurityProtocolType.Ssl3:
305                                         return SslProtocols.Ssl3;
306                                 case MonoSecurityProtocolType.Tls:
307                                         return SslProtocols.Tls;
308                                 }
309
310                                 throw new InvalidOperationException ("Not supported SSL/TLS protocol is in use. It is likely a bug in SslStream.");
311                         }
312                 }
313
314                 #endregion // Properties
315
316                 #region Methods
317 /*
318                 AsymmetricAlgorithm GetPrivateKey (X509Certificate cert, string targetHost)
319                 {
320                         // FIXME: what can I do for non-X509Certificate2 ?
321                         X509Certificate2 cert2 = cert as X509Certificate2;
322                         return cert2 != null ? cert2.PrivateKey : null;
323                 }
324 */
325                 X509Certificate OnCertificateSelection (X509CertificateCollection clientCerts, X509Certificate serverCert, string targetHost, X509CertificateCollection serverRequestedCerts)
326                 {
327                         string [] acceptableIssuers = new string [serverRequestedCerts != null ? serverRequestedCerts.Count : 0];
328                         for (int i = 0; i < acceptableIssuers.Length; i++)
329                                 acceptableIssuers [i] = serverRequestedCerts [i].GetIssuerName ();
330                         return selection_callback (this, targetHost, clientCerts, serverCert, acceptableIssuers);
331                 }
332
333                 public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
334                 {
335                         return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false, asyncCallback, asyncState);
336                 }
337
338                 public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
339                 {
340                         if (IsAuthenticated)
341                                 throw new InvalidOperationException ("This SslStream is already authenticated");
342
343                         SslClientStream s = new SslClientStream (InnerStream, targetHost, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols), clientCertificates);
344                         s.CheckCertRevocationStatus = checkCertificateRevocation;
345
346                         // Due to the Mono.Security internal, it cannot reuse
347                         // the delegated argument, as Mono.Security creates 
348                         // another instance of X509Certificate which lacks 
349                         // private key but is filled the private key via this
350                         // delegate.
351                         s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string host) {
352                                 string hash = cert.GetCertHashString ();
353                                 // ... so, we cannot use the delegate argument.
354                                 foreach (X509Certificate cc in clientCertificates) {
355                                         if (cc.GetCertHashString () != hash)
356                                                 continue;
357                                         X509Certificate2 cert2 = cc as X509Certificate2;
358                                         cert2 = cert2 ?? new X509Certificate2 (cc);
359                                         return cert2.PrivateKey;
360                                 }
361                                 return null;
362                         };
363
364                         if (validation_callback != null)
365                                 s.ServerCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
366                                         X509Chain chain = new X509Chain ();
367                                         X509Certificate2 x2 = (cert as X509Certificate2);
368                                         if (x2 == null)
369                                                 x2 = new X509Certificate2 (cert);
370
371                                         if (!ServicePointManager.CheckCertificateRevocationList)
372                                                 chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
373
374                                         // SSL specific checks (done by Mono.Security.dll SSL/TLS implementation) 
375                                         SslPolicyErrors errors = SslPolicyErrors.None;
376                                         foreach (int i in certErrors) {
377                                                 switch (i) {
378                                                 case -2146762490: // CERT_E_PURPOSE
379                                                         errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
380                                                         break;
381                                                 case -2146762481: // CERT_E_CN_NO_MATCH
382                                                         errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
383                                                         break;
384                                                 default:
385                                                         errors |= SslPolicyErrors.RemoteCertificateChainErrors;
386                                                         break;
387                                                 }
388                                         }
389
390                                         chain.Build (x2);
391
392                                         // non-SSL specific X509 checks (i.e. RFC3280 related checks)
393                                         foreach (X509ChainStatus status in chain.ChainStatus) {
394                                                 if (status.Status == X509ChainStatusFlags.NoError)
395                                                         continue;
396                                                 if ((status.Status & X509ChainStatusFlags.PartialChain) != 0)
397                                                         errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
398                                                 else
399                                                         errors |= SslPolicyErrors.RemoteCertificateChainErrors;
400                                         }
401
402                                         return validation_callback (this, cert, chain, errors);
403                                 };
404                         if (selection_callback != null)
405                                 s.ClientCertSelectionDelegate = OnCertificateSelection;
406
407                         ssl_stream = s;
408
409                         return BeginWrite (new byte [0], 0, 0, asyncCallback, asyncState);
410                 }
411
412                 public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
413                 {
414                         CheckConnectionAuthenticated ();
415
416                         return ssl_stream.BeginRead (buffer, offset, count, asyncCallback, asyncState);
417                 }
418 #if !MOONLIGHT
419                 public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
420                 {
421                         return BeginAuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false, asyncCallback, asyncState);
422                 }
423
424                 public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
425                 {
426                         if (IsAuthenticated)
427                                 throw new InvalidOperationException ("This SslStream is already authenticated");
428
429                         SslServerStream s = new SslServerStream (InnerStream, serverCertificate, clientCertificateRequired, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols));
430                         s.CheckCertRevocationStatus = checkCertificateRevocation;
431                         // Due to the Mono.Security internal, it cannot reuse
432                         // the delegated argument, as Mono.Security creates 
433                         // another instance of X509Certificate which lacks 
434                         // private key but is filled the private key via this
435                         // delegate.
436                         s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string targetHost) {
437                                 // ... so, we cannot use the delegate argument.
438                                 X509Certificate2 cert2 = serverCertificate as X509Certificate2 ?? new X509Certificate2 (serverCertificate);
439                                 return cert2 != null ? cert2.PrivateKey : null;
440                         };
441
442                         if (validation_callback != null)
443                                 s.ClientCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
444                                         X509Chain chain = null;
445                                         if (cert is X509Certificate2) {
446                                                 chain = new X509Chain ();
447                                                 chain.Build ((X509Certificate2) cert);
448                                         }
449                                         // FIXME: SslPolicyErrors is incomplete
450                                         SslPolicyErrors errors = certErrors.Length > 0 ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None;
451                                         return validation_callback (this, cert, chain, errors);
452                                 };
453
454                         ssl_stream = s;
455
456                         return BeginWrite (new byte[0], 0, 0, asyncCallback, asyncState);
457                 }
458 #endif
459                 MonoSecurityProtocolType GetMonoSslProtocol (SslProtocols ms)
460                 {
461                         switch (ms) {
462                         case SslProtocols.Ssl2:
463                                 return MonoSecurityProtocolType.Ssl2;
464                         case SslProtocols.Ssl3:
465                                 return MonoSecurityProtocolType.Ssl3;
466                         case SslProtocols.Tls:
467                                 return MonoSecurityProtocolType.Tls;
468                         default:
469                                 return MonoSecurityProtocolType.Default;
470                         }
471                 }
472
473                 public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
474                 {
475                         CheckConnectionAuthenticated ();
476
477                         return ssl_stream.BeginWrite (buffer, offset, count, asyncCallback, asyncState);
478                 }
479
480                 public virtual void AuthenticateAsClient (string targetHost)
481                 {
482                         AuthenticateAsClient (targetHost, new X509CertificateCollection (), SslProtocols.Tls, false);
483                 }
484
485                 public virtual void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
486                 {
487                         EndAuthenticateAsClient (BeginAuthenticateAsClient (
488                                 targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, null, null));
489                 }
490 #if !MOONLIGHT
491                 public virtual void AuthenticateAsServer (X509Certificate serverCertificate)
492                 {
493                         AuthenticateAsServer (serverCertificate, false, SslProtocols.Tls, false);
494                 }
495
496                 public virtual void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
497                 {
498                         EndAuthenticateAsServer (BeginAuthenticateAsServer (
499                                 serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, null, null));
500                 }
501 #endif
502                 protected override void Dispose (bool disposing)
503                 {
504                         if (disposing) {
505                                 if (ssl_stream != null)
506                                         ssl_stream.Dispose ();
507                                 ssl_stream = null;
508                         }
509                         base.Dispose (disposing);
510                 }
511
512                 public virtual void EndAuthenticateAsClient (IAsyncResult asyncResult)
513                 {
514                         CheckConnectionAuthenticated ();
515
516                         if (CanRead)
517                                 ssl_stream.EndRead (asyncResult);
518                         else
519                                 ssl_stream.EndWrite (asyncResult);
520                 }
521 #if !MOONLIGHT
522                 public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
523                 {
524                         CheckConnectionAuthenticated ();
525
526                         if (CanRead)
527                                 ssl_stream.EndRead (asyncResult);
528                         else
529                                 ssl_stream.EndWrite (asyncResult);
530                 }
531 #endif
532                 public override int EndRead (IAsyncResult asyncResult)
533                 {
534                         CheckConnectionAuthenticated ();
535
536                         return ssl_stream.EndRead (asyncResult);
537                 }
538
539                 public override void EndWrite (IAsyncResult asyncResult)
540                 {
541                         CheckConnectionAuthenticated ();
542
543                         ssl_stream.EndWrite (asyncResult);
544                 }
545
546                 public override void Flush ()
547                 {
548                         CheckConnectionAuthenticated ();
549
550                         InnerStream.Flush ();
551                 }
552
553                 public override int Read (byte[] buffer, int offset, int count)
554                 {
555                         return EndRead (BeginRead (buffer, offset, count, null, null));
556                 }
557
558                 public override long Seek (long offset, SeekOrigin origin)
559                 {
560                         throw new NotSupportedException ("This stream does not support seek operations");
561                 }
562
563                 public override void SetLength (long value)
564                 {
565                         InnerStream.SetLength (value);
566                 }
567
568                 public override void Write (byte[] buffer, int offset, int count)
569                 {
570                         EndWrite (BeginWrite (buffer, offset, count, null, null));
571                 }
572
573                 public void Write (byte[] buffer)
574                 {
575                         Write (buffer, 0, buffer.Length);
576                 }
577
578                 void CheckConnectionAuthenticated ()
579                 {
580                         if (!IsAuthenticated)
581                                 throw new InvalidOperationException ("This operation is invalid until it is successfully authenticated");
582                 }
583
584 #if NET_4_5
585                 public virtual Task AuthenticateAsClientAsync (string targetHost)
586                 {
587                         return Task.Factory.FromAsync (BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null);
588                 }
589
590                 public virtual Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
591                 {
592                         var t = Tuple.Create (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, this);
593
594                         return Task.Factory.FromAsync ((callback, state) => {
595                                 var d = (Tuple<string, X509CertificateCollection, SslProtocols, bool, SslStream>) state;
596                                 return d.Item5.BeginAuthenticateAsClient (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
597                         }, EndAuthenticateAsClient, t);
598                 }
599
600                 public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
601                 {
602                         return Task.Factory.FromAsync (BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null);
603                 }
604
605                 public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
606                 {
607                         var t = Tuple.Create (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, this);
608
609                         return Task.Factory.FromAsync ((callback, state) => {
610                                 var d = (Tuple<X509Certificate, bool, SslProtocols, bool, SslStream>) state;
611                                 return d.Item5.BeginAuthenticateAsServer (d.Item1, d.Item2, d.Item3, d.Item4, callback, null);
612                         }, EndAuthenticateAsServer, t);
613                 }
614 #endif
615
616                 #endregion // Methods
617         }
618 }
619
620 #endif