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