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