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