2 // MobileAuthenticatedStream.cs
5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2015 Xamarin, Inc.
11 #if MONO_SECURITY_ALIAS
12 extern alias MonoSecurity;
15 #if MONO_SECURITY_ALIAS
16 using MSI = MonoSecurity::Mono.Security.Interface;
18 using MSI = Mono.Security.Interface;
24 using System.Net.Security;
25 using System.Globalization;
26 using System.Threading;
27 using System.Threading.Tasks;
28 using System.Security.Cryptography.X509Certificates;
30 using SD = System.Diagnostics;
31 using SSA = System.Security.Authentication;
32 using SslProtocols = System.Security.Authentication.SslProtocols;
34 namespace Mono.Net.Security
36 abstract class MobileAuthenticatedStream : AuthenticatedStream, MSI.IMonoSslStream
38 MobileTlsContext xobileTlsContext;
39 Exception lastException;
41 AsyncProtocolRequest asyncHandshakeRequest;
42 AsyncProtocolRequest asyncReadRequest;
43 AsyncProtocolRequest asyncWriteRequest;
44 BufferOffsetSize2 readBuffer;
45 BufferOffsetSize2 writeBuffer;
47 object ioLock = new object ();
50 static int uniqueNameInteger = 123;
52 public MobileAuthenticatedStream (Stream innerStream, bool leaveInnerStreamOpen,
53 MSI.MonoTlsSettings settings, MSI.MonoTlsProvider provider)
54 : base (innerStream, leaveInnerStreamOpen)
59 readBuffer = new BufferOffsetSize2 (16834);
60 writeBuffer = new BufferOffsetSize2 (16384);
63 public MSI.MonoTlsSettings Settings {
68 public MSI.MonoTlsProvider Provider {
73 MSI.MonoTlsProvider MSI.IMonoSslStream.Provider {
74 get { return Provider; }
77 internal bool HasContext {
78 get { return xobileTlsContext != null; }
81 internal MobileTlsContext Context {
84 return xobileTlsContext;
88 internal void CheckThrow (bool authSuccessCheck)
90 if (closeRequested != 0)
91 throw new InvalidOperationException ("Stream is closed.");
92 if (lastException != null)
94 if (authSuccessCheck && !IsAuthenticated)
95 throw new InvalidOperationException ("Must be authenticated.");
98 Exception SetException (Exception e)
100 e = SetException_internal (e);
101 if (e != null && xobileTlsContext != null)
102 xobileTlsContext.Dispose ();
106 Exception SetException_internal (Exception e)
108 if (lastException == null)
110 return lastException;
113 SslProtocols DefaultProtocols {
114 get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
117 public void AuthenticateAsClient (string targetHost)
119 AuthenticateAsClient (targetHost, new X509CertificateCollection (), DefaultProtocols, false);
122 public void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
124 ValidateCreateContext (false, targetHost, enabledSslProtocols, null, clientCertificates, false);
125 ProcessAuthentication (null);
128 public IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
130 return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), DefaultProtocols, false, asyncCallback, asyncState);
133 public IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
135 ValidateCreateContext (false, targetHost, enabledSslProtocols, null, clientCertificates, false);
136 var result = new LazyAsyncResult (this, asyncState, asyncCallback);
137 ProcessAuthentication (result);
141 public void EndAuthenticateAsClient (IAsyncResult asyncResult)
143 EndProcessAuthentication (asyncResult);
146 public void AuthenticateAsServer (X509Certificate serverCertificate)
148 AuthenticateAsServer (serverCertificate, false, DefaultProtocols, false);
151 public void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
153 ValidateCreateContext (true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
154 ProcessAuthentication (null);
157 public IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
159 return BeginAuthenticateAsServer (serverCertificate, false, DefaultProtocols, false, asyncCallback, asyncState);
162 public IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
164 ValidateCreateContext (true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
165 var result = new LazyAsyncResult (this, asyncState, asyncCallback);
166 ProcessAuthentication (result);
170 public void EndAuthenticateAsServer (IAsyncResult asyncResult)
172 EndProcessAuthentication (asyncResult);
175 public Task AuthenticateAsClientAsync (string targetHost)
177 return Task.Factory.FromAsync (BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null);
180 public Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
182 return Task.Factory.FromAsync ((callback, state) => BeginAuthenticateAsClient (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsClient, null);
185 public Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
187 return Task.Factory.FromAsync (BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null);
190 public Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
192 return Task.Factory.FromAsync ((callback, state) => BeginAuthenticateAsServer (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsServer, null);
195 public AuthenticatedStream AuthenticatedStream {
199 internal void ProcessAuthentication (LazyAsyncResult lazyResult)
201 var asyncRequest = new AsyncProtocolRequest (this, lazyResult);
202 if (Interlocked.CompareExchange (ref asyncHandshakeRequest, asyncRequest, null) != null)
203 throw new InvalidOperationException ("Invalid nested call.");
206 if (lastException != null)
208 if (xobileTlsContext == null)
209 throw new InvalidOperationException ();
212 writeBuffer.Reset ();
215 asyncRequest.StartOperation (ProcessHandshake);
216 } catch (Exception ex) {
217 throw SetException (ex);
220 if (lazyResult == null || lastException != null) {
222 writeBuffer.Reset ();
223 asyncHandshakeRequest = null;
228 internal void EndProcessAuthentication (IAsyncResult result)
231 throw new ArgumentNullException ("asyncResult");
233 var lazyResult = (LazyAsyncResult)result;
234 if (Interlocked.Exchange (ref asyncHandshakeRequest, null) == null)
235 throw new InvalidOperationException ("Invalid end call.");
237 lazyResult.InternalWaitForCompletion ();
240 writeBuffer.Reset ();
242 var e = lazyResult.Result as Exception;
244 throw SetException (e);
247 internal void ValidateCreateContext (bool serverMode, string targetHost, SslProtocols enabledProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool clientCertRequired)
249 if (xobileTlsContext != null)
250 throw new InvalidOperationException ();
253 if (serverCertificate == null)
254 throw new ArgumentException ("serverCertificate");
256 if (targetHost == null)
257 throw new ArgumentException ("targetHost");
258 if (targetHost.Length == 0)
259 targetHost = "?" + Interlocked.Increment (ref uniqueNameInteger).ToString (NumberFormatInfo.InvariantInfo);
262 xobileTlsContext = CreateContext (this, serverMode, targetHost, enabledProtocols, serverCertificate, clientCertificates, clientCertRequired);
265 protected abstract MobileTlsContext CreateContext (
266 MobileAuthenticatedStream parent, bool serverMode, string targetHost,
267 SSA.SslProtocols enabledProtocols, X509Certificate serverCertificate,
268 X509CertificateCollection clientCertificates, bool askForClientCert);
270 public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
272 return BeginReadOrWrite (ref asyncReadRequest, ref readBuffer, ProcessRead, new BufferOffsetSize (buffer, offset, count), asyncCallback, asyncState);
275 public override int EndRead (IAsyncResult asyncResult)
277 return (int)EndReadOrWrite (asyncResult, ref asyncReadRequest);
280 public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
282 return BeginReadOrWrite (ref asyncWriteRequest, ref writeBuffer, ProcessWrite, new BufferOffsetSize (buffer, offset, count), asyncCallback, asyncState);
285 public override void EndWrite (IAsyncResult asyncResult)
287 EndReadOrWrite (asyncResult, ref asyncWriteRequest);
290 public override int Read (byte[] buffer, int offset, int count)
292 return ProcessReadOrWrite (ref asyncReadRequest, ref readBuffer, ProcessRead, new BufferOffsetSize (buffer, offset, count), null);
295 public void Write (byte[] buffer)
297 Write (buffer, 0, buffer.Length);
299 public override void Write (byte[] buffer, int offset, int count)
301 ProcessReadOrWrite (ref asyncWriteRequest, ref writeBuffer, ProcessWrite, new BufferOffsetSize (buffer, offset, count), null);
304 IAsyncResult BeginReadOrWrite (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, BufferOffsetSize userBuffer, AsyncCallback asyncCallback, object asyncState)
306 LazyAsyncResult lazyResult = new LazyAsyncResult (this, asyncState, asyncCallback);
307 ProcessReadOrWrite (ref nestedRequest, ref internalBuffer, operation, userBuffer, lazyResult);
311 object EndReadOrWrite (IAsyncResult asyncResult, ref AsyncProtocolRequest nestedRequest)
313 if (asyncResult == null)
314 throw new ArgumentNullException("asyncResult");
316 var lazyResult = (LazyAsyncResult)asyncResult;
318 if (Interlocked.Exchange (ref nestedRequest, null) == null)
319 throw new InvalidOperationException ("Invalid end call.");
321 // No "artificial" timeouts implemented so far, InnerStream controls timeout.
322 lazyResult.InternalWaitForCompletion ();
324 Debug ("EndReadOrWrite");
326 var e = lazyResult.Result as Exception;
328 var ioEx = e as IOException;
331 throw new IOException ("read failed", e);
334 return lazyResult.Result;
337 int ProcessReadOrWrite (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, BufferOffsetSize userBuffer, LazyAsyncResult lazyResult)
339 if (userBuffer == null || userBuffer.Buffer == null)
340 throw new ArgumentNullException ("buffer");
341 if (userBuffer.Offset < 0)
342 throw new ArgumentOutOfRangeException ("offset");
343 if (userBuffer.Size < 0 || userBuffer.Offset + userBuffer.Size > userBuffer.Buffer.Length)
344 throw new ArgumentOutOfRangeException ("count");
348 var name = internalBuffer == readBuffer ? "read" : "write";
349 Debug ("ProcessReadOrWrite: {0} {1}", name, userBuffer);
351 var asyncRequest = new AsyncProtocolRequest (this, lazyResult, userBuffer);
352 return StartOperation (ref nestedRequest, ref internalBuffer, operation, asyncRequest, name);
355 int StartOperation (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, AsyncProtocolRequest asyncRequest, string name)
357 if (Interlocked.CompareExchange (ref nestedRequest, asyncRequest, null) != null)
358 throw new InvalidOperationException ("Invalid nested call.");
362 internalBuffer.Reset ();
363 asyncRequest.StartOperation (operation);
364 return asyncRequest.UserResult;
365 } catch (Exception e) {
367 if (e is IOException)
369 throw new IOException (name + " failed", e);
371 if (asyncRequest.UserAsyncResult == null || failed) {
372 internalBuffer.Reset ();
373 nestedRequest = null;
379 internal readonly int ID = ++nextId;
381 [SD.Conditional ("MARTIN_DEBUG")]
382 protected internal void Debug (string message, params object[] args)
384 Console.Error.WriteLine ("MobileAuthenticatedStream({0}): {1}", ID, string.Format (message, args));
387 #region Called back from native code via SslConnection
390 * Called from within SSLRead() and SSLHandshake(). We only access tha managed byte[] here.
392 internal int InternalRead (byte[] buffer, int offset, int size, out bool wantMore)
395 Debug ("InternalRead: {0} {1} {2} {3}", offset, size, asyncReadRequest != null, readBuffer != null);
396 var asyncRequest = asyncHandshakeRequest ?? asyncReadRequest;
397 return InternalRead (asyncRequest, readBuffer, buffer, offset, size, out wantMore);
398 } catch (Exception ex) {
399 Debug ("InternalRead failed: {0}", ex);
400 SetException_internal (ex);
406 int InternalRead (AsyncProtocolRequest asyncRequest, BufferOffsetSize internalBuffer, byte[] buffer, int offset, int size, out bool wantMore)
408 if (asyncRequest == null)
409 throw new InvalidOperationException ();
411 Debug ("InternalRead: {0} {1} {2}", internalBuffer, offset, size);
414 * One of Apple's native functions wants to read 'size' bytes of data.
416 * First, we check whether we already have enough in the internal buffer.
418 * If the internal buffer is empty (it will be the first time we're called), we save
419 * the amount of bytes that were requested and return 'SslStatus.WouldBlock' to our
420 * native caller. This native function will then return this code to managed code,
421 * where we read the requested amount of data into the internal buffer, then call the
422 * native function again.
424 if (internalBuffer.Size == 0 && !internalBuffer.Complete) {
425 Debug ("InternalRead #1: {0} {1}", internalBuffer.Offset, internalBuffer.TotalBytes);
426 internalBuffer.Offset = internalBuffer.Size = 0;
427 asyncRequest.RequestRead (size);
433 * The second time we're called, the native buffer will contain the exact amount of data that the
434 * previous call requested from us, so we should be able to return it all here. However, just in
435 * case that Apple's native function changed its mind, we can also return less.
437 * In either case, if we have any data buffered, then we return as much of it as possible - if the
438 * native code isn't satisfied, then it will call us again to request more.
440 var len = System.Math.Min (internalBuffer.Size, size);
441 Buffer.BlockCopy (internalBuffer.Buffer, internalBuffer.Offset, buffer, offset, len);
442 internalBuffer.Offset += len;
443 internalBuffer.Size -= len;
444 wantMore = !internalBuffer.Complete && len < size;
449 * We may get called from SSLWrite(), SSLHandshake() or SSLClose().
451 internal bool InternalWrite (byte[] buffer, int offset, int size)
454 Debug ("InternalWrite: {0} {1}", offset, size);
455 var asyncRequest = asyncHandshakeRequest ?? asyncWriteRequest;
456 return InternalWrite (asyncRequest, writeBuffer, buffer, offset, size);
457 } catch (Exception ex) {
458 Debug ("InternalWrite failed: {0}", ex);
459 SetException_internal (ex);
464 bool InternalWrite (AsyncProtocolRequest asyncRequest, BufferOffsetSize2 internalBuffer, byte[] buffer, int offset, int size)
466 Debug ("InternalWrite: {0} {1} {2} {3}", asyncRequest != null, internalBuffer, offset, size);
468 if (asyncRequest == null) {
470 * The only situation where 'asyncRequest' could possibly be 'null' is when we're called
471 * from within SSLClose() - which might attempt to send the close_notity notification.
472 * Since this notification message is very small, it should definitely fit into our internal
473 * buffer, so we just save it in there and after SSLClose() returns, the final call to
474 * InternalFlush() - just before closing the underlying stream - will send it out.
476 if (lastException != null)
479 if (Interlocked.Exchange (ref closeRequested, 1) == 0)
480 internalBuffer.Reset ();
481 else if (internalBuffer.Remaining == 0)
482 throw new InvalidOperationException ();
486 * Normal write - can be either SSLWrite() or SSLHandshake().
488 * It is important that we always accept all the data and queue it.
491 internalBuffer.AppendData (buffer, offset, size);
494 * Calling 'asyncRequest.RequestWrite()' here ensures that ProcessWrite() is called next
495 * time we regain control from native code.
497 * During the handshake, the native code won't actually realize (unless if attempts to send
498 * so much that the write buffer gets full) that we only buffered the data.
500 * However, it doesn't matter because it will either return with a completed handshake
501 * (and doesn't care whether the remote actually received the data) or it will expect more
502 * data from the remote and request a read. In either case, we regain control in managed
503 * code and can flush out the data.
505 * Note that a calling RequestWrite() followed by RequestRead() will first flush the write
506 * queue once we return to managed code - before attempting to read anything.
508 if (asyncRequest != null)
509 asyncRequest.RequestWrite ();
519 * Read / write data from the inner stream; we're only called from managed code and only manipulate
520 * the internal buffers.
522 internal int InnerRead (int requestedSize)
524 Debug ("InnerRead: {0} {1} {2} {3}", readBuffer.Offset, readBuffer.Size, readBuffer.Remaining, requestedSize);
526 var len = System.Math.Min (readBuffer.Remaining, requestedSize);
528 throw new InvalidOperationException ();
529 var ret = InnerStream.Read (readBuffer.Buffer, readBuffer.EndOffset, len);
530 Debug ("InnerRead done: {0} {1} - {2}", readBuffer.Remaining, len, ret);
533 readBuffer.Size += ret;
534 readBuffer.TotalBytes += ret;
538 readBuffer.Complete = true;
539 Debug ("InnerRead - end of stream!");
541 * Try to distinguish between a graceful close - first Read() returned 0 - and
542 * the remote prematurely closing the connection without sending us all data.
544 if (readBuffer.TotalBytes > 0)
548 Debug ("InnerRead done: {0} - {1} {2}", readBuffer, len, ret);
552 internal void InnerWrite ()
554 Debug ("InnerWrite: {0} {1}", writeBuffer.Offset, writeBuffer.Size);
558 internal void InnerFlush ()
560 if (writeBuffer.Size > 0) {
561 InnerStream.Write (writeBuffer.Buffer, writeBuffer.Offset, writeBuffer.Size);
562 writeBuffer.TotalBytes += writeBuffer.Size;
563 writeBuffer.Offset = writeBuffer.Size = 0;
569 #region Main async I/O loop
571 AsyncOperationStatus ProcessHandshake (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
573 Debug ("ProcessHandshake: {0}", status);
576 * The first time we're called (AsyncOperationStatus.Initialize), we need to setup the SslContext and
577 * start the handshake.
579 if (status == AsyncOperationStatus.Initialize) {
580 xobileTlsContext.StartHandshake ();
581 return AsyncOperationStatus.Continue;
582 } else if (status == AsyncOperationStatus.ReadDone) {
583 // remote prematurely closed connection.
584 throw new IOException ("Remote prematurely closed connection.");
585 } else if (status != AsyncOperationStatus.Continue) {
586 throw new InvalidOperationException ();
590 * SSLHandshake() will return repeatedly with 'SslStatus.WouldBlock', we then need
591 * to take care of I/O and call it again.
593 if (!xobileTlsContext.ProcessHandshake ()) {
595 * Flush the internal write buffer.
598 return AsyncOperationStatus.Continue;
601 xobileTlsContext.FinishHandshake ();
602 return AsyncOperationStatus.Complete;
605 AsyncOperationStatus ProcessRead (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
607 Debug ("ProcessRead - read user: {0} {1}", status, asyncRequest.UserBuffer);
612 ret = Context.Read (asyncRequest.UserBuffer.Buffer, asyncRequest.UserBuffer.Offset, asyncRequest.UserBuffer.Size, out wantMore);
614 Debug ("ProcessRead - read user done: {0} - {1} {2}", asyncRequest.UserBuffer, ret, wantMore);
617 asyncRequest.UserResult = -1;
618 return AsyncOperationStatus.Complete;
621 asyncRequest.CurrentSize += ret;
622 asyncRequest.UserBuffer.Offset += ret;
623 asyncRequest.UserBuffer.Size -= ret;
625 Debug ("Process Read - read user done #1: {0} - {1} {2}", asyncRequest.UserBuffer, asyncRequest.CurrentSize, wantMore);
627 if (wantMore && asyncRequest.CurrentSize == 0)
628 return AsyncOperationStatus.WantRead;
630 asyncRequest.ResetRead ();
631 asyncRequest.UserResult = asyncRequest.CurrentSize;
632 return AsyncOperationStatus.Complete;
635 AsyncOperationStatus ProcessWrite (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
637 Debug ("ProcessWrite - write user: {0} {1}", status, asyncRequest.UserBuffer);
639 if (asyncRequest.UserBuffer.Size == 0) {
640 asyncRequest.UserResult = asyncRequest.CurrentSize;
641 return AsyncOperationStatus.Complete;
647 ret = Context.Write (asyncRequest.UserBuffer.Buffer, asyncRequest.UserBuffer.Offset, asyncRequest.UserBuffer.Size, out wantMore);
649 Debug ("ProcessWrite - write user done: {0} - {1} {2}", asyncRequest.UserBuffer, ret, wantMore);
652 asyncRequest.UserResult = -1;
653 return AsyncOperationStatus.Complete;
656 asyncRequest.CurrentSize += ret;
657 asyncRequest.UserBuffer.Offset += ret;
658 asyncRequest.UserBuffer.Size -= ret;
660 if (wantMore || writeBuffer.Size > 0)
661 return AsyncOperationStatus.WantWrite;
663 asyncRequest.ResetWrite ();
664 asyncRequest.UserResult = asyncRequest.CurrentSize;
665 return AsyncOperationStatus.Complete;
668 AsyncOperationStatus ProcessClose (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
670 Debug ("ProcessClose: {0}", status);
673 if (xobileTlsContext == null)
674 return AsyncOperationStatus.Complete;
676 xobileTlsContext.Close ();
677 xobileTlsContext = null;
678 return AsyncOperationStatus.Continue;
682 AsyncOperationStatus ProcessFlush (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
684 Debug ("ProcessFlush: {0}", status);
685 return AsyncOperationStatus.Complete;
690 public override bool IsServer {
691 get { return xobileTlsContext != null && xobileTlsContext.IsServer; }
694 public override bool IsAuthenticated {
695 get { return xobileTlsContext != null && lastException == null && xobileTlsContext.IsAuthenticated; }
698 public override bool IsMutuallyAuthenticated {
700 return IsAuthenticated &&
701 (Context.IsServer? Context.LocalServerCertificate: Context.LocalClientCertificate) != null &&
702 Context.IsRemoteCertificateAvailable;
706 protected override void Dispose (bool disposing)
709 lastException = new ObjectDisposedException ("MobileAuthenticatedStream");
711 if (xobileTlsContext != null) {
712 xobileTlsContext.Dispose ();
713 xobileTlsContext = null;
717 base.Dispose (disposing);
721 public override void Flush ()
724 var asyncRequest = new AsyncProtocolRequest (this, null);
725 StartOperation (ref asyncWriteRequest, ref writeBuffer, ProcessFlush, asyncRequest, "flush");
728 public override void Close ()
731 * SSLClose() is a little bit tricky as it might attempt to send a close_notify alert
732 * and thus call our write callback.
734 * It is also not thread-safe with SSLRead() or SSLWrite(), so we need to take the I/O lock here.
736 if (Interlocked.Exchange (ref closeRequested, 1) == 1)
738 if (xobileTlsContext == null)
741 var asyncRequest = new AsyncProtocolRequest (this, null);
742 StartOperation (ref asyncWriteRequest, ref writeBuffer, ProcessClose, asyncRequest, "close");
746 // 'xobileTlsContext' must not be accessed below this point.
749 public override long Seek (long offset, SeekOrigin origin)
751 throw new NotSupportedException ();
754 public override void SetLength (long value)
756 InnerStream.SetLength (value);
759 public TransportContext TransportContext {
760 get { throw new NotSupportedException (); }
763 public override bool CanRead {
764 get { return IsAuthenticated && InnerStream.CanRead; }
767 public override bool CanTimeout {
768 get { return InnerStream.CanTimeout; }
771 public override bool CanWrite {
772 get { return IsAuthenticated & InnerStream.CanWrite; }
775 public override bool CanSeek {
776 get { return false; }
779 public override long Length {
780 get { return InnerStream.Length; }
783 public override long Position {
784 get { return InnerStream.Position; }
785 set { throw new NotSupportedException (); }
788 public override bool IsEncrypted {
789 get { return IsAuthenticated; }
792 public override bool IsSigned {
793 get { return IsAuthenticated; }
796 public override int ReadTimeout {
797 get { return InnerStream.ReadTimeout; }
798 set { InnerStream.ReadTimeout = value; }
801 public override int WriteTimeout {
802 get { return InnerStream.WriteTimeout; }
803 set { InnerStream.WriteTimeout = value; }
806 public SslProtocols SslProtocol {
809 return (SslProtocols)Context.NegotiatedProtocol;
813 public X509Certificate RemoteCertificate {
816 return Context.RemoteCertificate;
820 public X509Certificate LocalCertificate {
823 return InternalLocalCertificate;
827 public X509Certificate InternalLocalCertificate {
832 return Context.IsServer ? Context.LocalServerCertificate : Context.LocalClientCertificate;
836 public MSI.MonoTlsConnectionInfo GetConnectionInfo ()
839 return Context.ConnectionInfo;
842 public SSA.CipherAlgorithmType CipherAlgorithm {
845 var info = Context.ConnectionInfo;
847 return SSA.CipherAlgorithmType.None;
848 switch (info.CipherAlgorithmType) {
849 case MSI.CipherAlgorithmType.Aes128:
850 case MSI.CipherAlgorithmType.AesGcm128:
851 return SSA.CipherAlgorithmType.Aes128;
852 case MSI.CipherAlgorithmType.Aes256:
853 case MSI.CipherAlgorithmType.AesGcm256:
854 return SSA.CipherAlgorithmType.Aes256;
856 return SSA.CipherAlgorithmType.None;
861 public SSA.HashAlgorithmType HashAlgorithm {
864 var info = Context.ConnectionInfo;
866 return SSA.HashAlgorithmType.None;
867 switch (info.HashAlgorithmType) {
868 case MSI.HashAlgorithmType.Md5:
869 case MSI.HashAlgorithmType.Md5Sha1:
870 return SSA.HashAlgorithmType.Md5;
871 case MSI.HashAlgorithmType.Sha1:
872 case MSI.HashAlgorithmType.Sha224:
873 case MSI.HashAlgorithmType.Sha256:
874 case MSI.HashAlgorithmType.Sha384:
875 case MSI.HashAlgorithmType.Sha512:
876 return SSA.HashAlgorithmType.Sha1;
878 return SSA.HashAlgorithmType.None;
883 public SSA.ExchangeAlgorithmType KeyExchangeAlgorithm {
886 var info = Context.ConnectionInfo;
888 return SSA.ExchangeAlgorithmType.None;
889 switch (info.ExchangeAlgorithmType) {
890 case MSI.ExchangeAlgorithmType.Rsa:
891 return SSA.ExchangeAlgorithmType.RsaSign;
892 case MSI.ExchangeAlgorithmType.Dhe:
893 case MSI.ExchangeAlgorithmType.EcDhe:
894 return SSA.ExchangeAlgorithmType.DiffieHellman;
896 return SSA.ExchangeAlgorithmType.None;
901 #region Need to Implement
902 public int CipherStrength {
904 throw new NotImplementedException ();
907 public int HashStrength {
909 throw new NotImplementedException ();
912 public int KeyExchangeStrength {
914 throw new NotImplementedException ();
917 public bool CheckCertRevocationStatus {
919 throw new NotImplementedException ();