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.Runtime.ExceptionServices;
27 using System.Threading;
28 using System.Threading.Tasks;
29 using System.Security.Cryptography.X509Certificates;
31 using SD = System.Diagnostics;
32 using SSA = System.Security.Authentication;
33 using SslProtocols = System.Security.Authentication.SslProtocols;
35 namespace Mono.Net.Security
37 abstract class MobileAuthenticatedStream : AuthenticatedStream, MSI.IMonoSslStream
39 MobileTlsContext xobileTlsContext;
40 Exception lastException;
42 AsyncProtocolRequest asyncHandshakeRequest;
43 AsyncProtocolRequest asyncReadRequest;
44 AsyncProtocolRequest asyncWriteRequest;
45 BufferOffsetSize2 readBuffer;
46 BufferOffsetSize2 writeBuffer;
48 object ioLock = new object ();
51 static int uniqueNameInteger = 123;
53 public MobileAuthenticatedStream (Stream innerStream, bool leaveInnerStreamOpen,
54 MSI.MonoTlsSettings settings, MSI.MonoTlsProvider provider)
55 : base (innerStream, leaveInnerStreamOpen)
60 readBuffer = new BufferOffsetSize2 (16834);
61 writeBuffer = new BufferOffsetSize2 (16384);
64 public MSI.MonoTlsSettings Settings {
69 public MSI.MonoTlsProvider Provider {
74 MSI.MonoTlsProvider MSI.IMonoSslStream.Provider {
75 get { return Provider; }
78 internal bool HasContext {
79 get { return xobileTlsContext != null; }
82 internal MobileTlsContext Context {
85 return xobileTlsContext;
89 internal void CheckThrow (bool authSuccessCheck)
91 if (closeRequested != 0)
92 throw new InvalidOperationException ("Stream is closed.");
93 if (lastException != null)
95 if (authSuccessCheck && !IsAuthenticated)
96 throw new InvalidOperationException ("Must be authenticated.");
99 Exception SetException (Exception e)
101 e = SetException_internal (e);
102 if (e != null && xobileTlsContext != null)
103 xobileTlsContext.Dispose ();
107 Exception SetException_internal (Exception e)
109 if (lastException == null)
111 return lastException;
114 SslProtocols DefaultProtocols {
115 get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
118 public void AuthenticateAsClient (string targetHost)
120 AuthenticateAsClient (targetHost, new X509CertificateCollection (), DefaultProtocols, false);
123 public void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
125 ValidateCreateContext (false, targetHost, enabledSslProtocols, null, clientCertificates, false);
126 ProcessAuthentication (null);
129 public IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
131 return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), DefaultProtocols, false, asyncCallback, asyncState);
134 public IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
136 ValidateCreateContext (false, targetHost, enabledSslProtocols, null, clientCertificates, false);
137 var result = new LazyAsyncResult (this, asyncState, asyncCallback);
138 ProcessAuthentication (result);
142 public void EndAuthenticateAsClient (IAsyncResult asyncResult)
144 EndProcessAuthentication (asyncResult);
147 public void AuthenticateAsServer (X509Certificate serverCertificate)
149 AuthenticateAsServer (serverCertificate, false, DefaultProtocols, false);
152 public void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
154 ValidateCreateContext (true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
155 ProcessAuthentication (null);
158 public IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
160 return BeginAuthenticateAsServer (serverCertificate, false, DefaultProtocols, false, asyncCallback, asyncState);
163 public IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
165 ValidateCreateContext (true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
166 var result = new LazyAsyncResult (this, asyncState, asyncCallback);
167 ProcessAuthentication (result);
171 public void EndAuthenticateAsServer (IAsyncResult asyncResult)
173 EndProcessAuthentication (asyncResult);
176 public Task AuthenticateAsClientAsync (string targetHost)
178 return Task.Factory.FromAsync (BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null);
181 public Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
183 return Task.Factory.FromAsync ((callback, state) => BeginAuthenticateAsClient (targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsClient, null);
186 public Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
188 return Task.Factory.FromAsync (BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null);
191 public Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
193 return Task.Factory.FromAsync ((callback, state) => BeginAuthenticateAsServer (serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsServer, null);
196 public AuthenticatedStream AuthenticatedStream {
200 internal void ProcessAuthentication (LazyAsyncResult lazyResult)
202 var asyncRequest = new AsyncProtocolRequest (this, lazyResult);
203 if (Interlocked.CompareExchange (ref asyncHandshakeRequest, asyncRequest, null) != null)
204 throw new InvalidOperationException ("Invalid nested call.");
207 if (lastException != null)
209 if (xobileTlsContext == null)
210 throw new InvalidOperationException ();
213 writeBuffer.Reset ();
216 asyncRequest.StartOperation (ProcessHandshake);
217 } catch (Exception ex) {
218 ExceptionDispatchInfo.Capture (SetException (ex)).Throw ();
221 if (lazyResult == null || lastException != null) {
223 writeBuffer.Reset ();
224 asyncHandshakeRequest = null;
229 internal void EndProcessAuthentication (IAsyncResult result)
232 throw new ArgumentNullException ("asyncResult");
234 var lazyResult = (LazyAsyncResult)result;
235 if (Interlocked.Exchange (ref asyncHandshakeRequest, null) == null)
236 throw new InvalidOperationException ("Invalid end call.");
238 lazyResult.InternalWaitForCompletion ();
241 writeBuffer.Reset ();
243 var e = lazyResult.Result as Exception;
245 ExceptionDispatchInfo.Capture (SetException (e)).Throw ();
248 internal void ValidateCreateContext (bool serverMode, string targetHost, SslProtocols enabledProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool clientCertRequired)
250 if (xobileTlsContext != null)
251 throw new InvalidOperationException ();
254 if (serverCertificate == null)
255 throw new ArgumentException ("serverCertificate");
257 if (targetHost == null)
258 throw new ArgumentException ("targetHost");
259 if (targetHost.Length == 0)
260 targetHost = "?" + Interlocked.Increment (ref uniqueNameInteger).ToString (NumberFormatInfo.InvariantInfo);
263 xobileTlsContext = CreateContext (this, serverMode, targetHost, enabledProtocols, serverCertificate, clientCertificates, clientCertRequired);
266 protected abstract MobileTlsContext CreateContext (
267 MobileAuthenticatedStream parent, bool serverMode, string targetHost,
268 SSA.SslProtocols enabledProtocols, X509Certificate serverCertificate,
269 X509CertificateCollection clientCertificates, bool askForClientCert);
271 public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
273 return BeginReadOrWrite (ref asyncReadRequest, ref readBuffer, ProcessRead, new BufferOffsetSize (buffer, offset, count), asyncCallback, asyncState);
276 public override int EndRead (IAsyncResult asyncResult)
278 return (int)EndReadOrWrite (asyncResult, ref asyncReadRequest);
281 public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
283 return BeginReadOrWrite (ref asyncWriteRequest, ref writeBuffer, ProcessWrite, new BufferOffsetSize (buffer, offset, count), asyncCallback, asyncState);
286 public override void EndWrite (IAsyncResult asyncResult)
288 EndReadOrWrite (asyncResult, ref asyncWriteRequest);
291 public override int Read (byte[] buffer, int offset, int count)
293 return ProcessReadOrWrite (ref asyncReadRequest, ref readBuffer, ProcessRead, new BufferOffsetSize (buffer, offset, count), null);
296 public void Write (byte[] buffer)
298 Write (buffer, 0, buffer.Length);
300 public override void Write (byte[] buffer, int offset, int count)
302 ProcessReadOrWrite (ref asyncWriteRequest, ref writeBuffer, ProcessWrite, new BufferOffsetSize (buffer, offset, count), null);
305 IAsyncResult BeginReadOrWrite (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, BufferOffsetSize userBuffer, AsyncCallback asyncCallback, object asyncState)
307 LazyAsyncResult lazyResult = new LazyAsyncResult (this, asyncState, asyncCallback);
308 ProcessReadOrWrite (ref nestedRequest, ref internalBuffer, operation, userBuffer, lazyResult);
312 object EndReadOrWrite (IAsyncResult asyncResult, ref AsyncProtocolRequest nestedRequest)
314 if (asyncResult == null)
315 throw new ArgumentNullException("asyncResult");
317 var lazyResult = (LazyAsyncResult)asyncResult;
319 if (Interlocked.Exchange (ref nestedRequest, null) == null)
320 throw new InvalidOperationException ("Invalid end call.");
322 // No "artificial" timeouts implemented so far, InnerStream controls timeout.
323 lazyResult.InternalWaitForCompletion ();
325 Debug ("EndReadOrWrite");
327 var e = lazyResult.Result as Exception;
329 var ioEx = e as IOException;
332 throw new IOException ("read failed", e);
335 return lazyResult.Result;
338 int ProcessReadOrWrite (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, BufferOffsetSize userBuffer, LazyAsyncResult lazyResult)
340 if (userBuffer == null || userBuffer.Buffer == null)
341 throw new ArgumentNullException ("buffer");
342 if (userBuffer.Offset < 0)
343 throw new ArgumentOutOfRangeException ("offset");
344 if (userBuffer.Size < 0 || userBuffer.Offset + userBuffer.Size > userBuffer.Buffer.Length)
345 throw new ArgumentOutOfRangeException ("count");
349 var name = internalBuffer == readBuffer ? "read" : "write";
350 Debug ("ProcessReadOrWrite: {0} {1}", name, userBuffer);
352 var asyncRequest = new AsyncProtocolRequest (this, lazyResult, userBuffer);
353 return StartOperation (ref nestedRequest, ref internalBuffer, operation, asyncRequest, name);
356 int StartOperation (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, AsyncProtocolRequest asyncRequest, string name)
358 if (Interlocked.CompareExchange (ref nestedRequest, asyncRequest, null) != null)
359 throw new InvalidOperationException ("Invalid nested call.");
363 internalBuffer.Reset ();
364 asyncRequest.StartOperation (operation);
365 return asyncRequest.UserResult;
366 } catch (Exception e) {
368 if (e is IOException)
370 throw new IOException (name + " failed", e);
372 if (asyncRequest.UserAsyncResult == null || failed) {
373 internalBuffer.Reset ();
374 nestedRequest = null;
380 internal readonly int ID = ++nextId;
382 [SD.Conditional ("MARTIN_DEBUG")]
383 protected internal void Debug (string message, params object[] args)
385 Console.Error.WriteLine ("MobileAuthenticatedStream({0}): {1}", ID, string.Format (message, args));
388 #region Called back from native code via SslConnection
391 * Called from within SSLRead() and SSLHandshake(). We only access tha managed byte[] here.
393 internal int InternalRead (byte[] buffer, int offset, int size, out bool wantMore)
396 Debug ("InternalRead: {0} {1} {2} {3}", offset, size, asyncReadRequest != null, readBuffer != null);
397 var asyncRequest = asyncHandshakeRequest ?? asyncReadRequest;
398 return InternalRead (asyncRequest, readBuffer, buffer, offset, size, out wantMore);
399 } catch (Exception ex) {
400 Debug ("InternalRead failed: {0}", ex);
401 SetException_internal (ex);
407 int InternalRead (AsyncProtocolRequest asyncRequest, BufferOffsetSize internalBuffer, byte[] buffer, int offset, int size, out bool wantMore)
409 if (asyncRequest == null)
410 throw new InvalidOperationException ();
412 Debug ("InternalRead: {0} {1} {2}", internalBuffer, offset, size);
415 * One of Apple's native functions wants to read 'size' bytes of data.
417 * First, we check whether we already have enough in the internal buffer.
419 * If the internal buffer is empty (it will be the first time we're called), we save
420 * the amount of bytes that were requested and return 'SslStatus.WouldBlock' to our
421 * native caller. This native function will then return this code to managed code,
422 * where we read the requested amount of data into the internal buffer, then call the
423 * native function again.
425 if (internalBuffer.Size == 0 && !internalBuffer.Complete) {
426 Debug ("InternalRead #1: {0} {1}", internalBuffer.Offset, internalBuffer.TotalBytes);
427 internalBuffer.Offset = internalBuffer.Size = 0;
428 asyncRequest.RequestRead (size);
434 * The second time we're called, the native buffer will contain the exact amount of data that the
435 * previous call requested from us, so we should be able to return it all here. However, just in
436 * case that Apple's native function changed its mind, we can also return less.
438 * In either case, if we have any data buffered, then we return as much of it as possible - if the
439 * native code isn't satisfied, then it will call us again to request more.
441 var len = System.Math.Min (internalBuffer.Size, size);
442 Buffer.BlockCopy (internalBuffer.Buffer, internalBuffer.Offset, buffer, offset, len);
443 internalBuffer.Offset += len;
444 internalBuffer.Size -= len;
445 wantMore = !internalBuffer.Complete && len < size;
450 * We may get called from SSLWrite(), SSLHandshake() or SSLClose().
452 internal bool InternalWrite (byte[] buffer, int offset, int size)
455 Debug ("InternalWrite: {0} {1}", offset, size);
456 var asyncRequest = asyncHandshakeRequest ?? asyncWriteRequest;
457 return InternalWrite (asyncRequest, writeBuffer, buffer, offset, size);
458 } catch (Exception ex) {
459 Debug ("InternalWrite failed: {0}", ex);
460 SetException_internal (ex);
465 bool InternalWrite (AsyncProtocolRequest asyncRequest, BufferOffsetSize2 internalBuffer, byte[] buffer, int offset, int size)
467 Debug ("InternalWrite: {0} {1} {2} {3}", asyncRequest != null, internalBuffer, offset, size);
469 if (asyncRequest == null) {
471 * The only situation where 'asyncRequest' could possibly be 'null' is when we're called
472 * from within SSLClose() - which might attempt to send the close_notity notification.
473 * Since this notification message is very small, it should definitely fit into our internal
474 * buffer, so we just save it in there and after SSLClose() returns, the final call to
475 * InternalFlush() - just before closing the underlying stream - will send it out.
477 if (lastException != null)
480 if (Interlocked.Exchange (ref closeRequested, 1) == 0)
481 internalBuffer.Reset ();
482 else if (internalBuffer.Remaining == 0)
483 throw new InvalidOperationException ();
487 * Normal write - can be either SSLWrite() or SSLHandshake().
489 * It is important that we always accept all the data and queue it.
492 internalBuffer.AppendData (buffer, offset, size);
495 * Calling 'asyncRequest.RequestWrite()' here ensures that ProcessWrite() is called next
496 * time we regain control from native code.
498 * During the handshake, the native code won't actually realize (unless if attempts to send
499 * so much that the write buffer gets full) that we only buffered the data.
501 * However, it doesn't matter because it will either return with a completed handshake
502 * (and doesn't care whether the remote actually received the data) or it will expect more
503 * data from the remote and request a read. In either case, we regain control in managed
504 * code and can flush out the data.
506 * Note that a calling RequestWrite() followed by RequestRead() will first flush the write
507 * queue once we return to managed code - before attempting to read anything.
509 if (asyncRequest != null)
510 asyncRequest.RequestWrite ();
520 * Read / write data from the inner stream; we're only called from managed code and only manipulate
521 * the internal buffers.
523 internal int InnerRead (int requestedSize)
525 Debug ("InnerRead: {0} {1} {2} {3}", readBuffer.Offset, readBuffer.Size, readBuffer.Remaining, requestedSize);
527 var len = System.Math.Min (readBuffer.Remaining, requestedSize);
529 throw new InvalidOperationException ();
530 var ret = InnerStream.Read (readBuffer.Buffer, readBuffer.EndOffset, len);
531 Debug ("InnerRead done: {0} {1} - {2}", readBuffer.Remaining, len, ret);
534 readBuffer.Size += ret;
535 readBuffer.TotalBytes += ret;
539 readBuffer.Complete = true;
540 Debug ("InnerRead - end of stream!");
542 * Try to distinguish between a graceful close - first Read() returned 0 - and
543 * the remote prematurely closing the connection without sending us all data.
545 if (readBuffer.TotalBytes > 0)
549 Debug ("InnerRead done: {0} - {1} {2}", readBuffer, len, ret);
553 internal void InnerWrite ()
555 Debug ("InnerWrite: {0} {1}", writeBuffer.Offset, writeBuffer.Size);
559 internal void InnerFlush ()
561 if (writeBuffer.Size > 0) {
562 InnerStream.Write (writeBuffer.Buffer, writeBuffer.Offset, writeBuffer.Size);
563 writeBuffer.TotalBytes += writeBuffer.Size;
564 writeBuffer.Offset = writeBuffer.Size = 0;
570 #region Main async I/O loop
572 AsyncOperationStatus ProcessHandshake (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
574 Debug ("ProcessHandshake: {0}", status);
577 * The first time we're called (AsyncOperationStatus.Initialize), we need to setup the SslContext and
578 * start the handshake.
580 if (status == AsyncOperationStatus.Initialize) {
581 xobileTlsContext.StartHandshake ();
582 return AsyncOperationStatus.Continue;
583 } else if (status == AsyncOperationStatus.ReadDone) {
584 // remote prematurely closed connection.
585 throw new IOException ("Remote prematurely closed connection.");
586 } else if (status != AsyncOperationStatus.Continue) {
587 throw new InvalidOperationException ();
591 * SSLHandshake() will return repeatedly with 'SslStatus.WouldBlock', we then need
592 * to take care of I/O and call it again.
594 if (!xobileTlsContext.ProcessHandshake ()) {
596 * Flush the internal write buffer.
599 return AsyncOperationStatus.Continue;
602 xobileTlsContext.FinishHandshake ();
603 return AsyncOperationStatus.Complete;
606 AsyncOperationStatus ProcessRead (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
608 Debug ("ProcessRead - read user: {0} {1}", status, asyncRequest.UserBuffer);
613 ret = Context.Read (asyncRequest.UserBuffer.Buffer, asyncRequest.UserBuffer.Offset, asyncRequest.UserBuffer.Size, out wantMore);
615 Debug ("ProcessRead - read user done: {0} - {1} {2}", asyncRequest.UserBuffer, ret, wantMore);
618 asyncRequest.UserResult = -1;
619 return AsyncOperationStatus.Complete;
622 asyncRequest.CurrentSize += ret;
623 asyncRequest.UserBuffer.Offset += ret;
624 asyncRequest.UserBuffer.Size -= ret;
626 Debug ("Process Read - read user done #1: {0} - {1} {2}", asyncRequest.UserBuffer, asyncRequest.CurrentSize, wantMore);
628 if (wantMore && asyncRequest.CurrentSize == 0)
629 return AsyncOperationStatus.WantRead;
631 asyncRequest.ResetRead ();
632 asyncRequest.UserResult = asyncRequest.CurrentSize;
633 return AsyncOperationStatus.Complete;
636 AsyncOperationStatus ProcessWrite (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
638 Debug ("ProcessWrite - write user: {0} {1}", status, asyncRequest.UserBuffer);
640 if (asyncRequest.UserBuffer.Size == 0) {
641 asyncRequest.UserResult = asyncRequest.CurrentSize;
642 return AsyncOperationStatus.Complete;
648 ret = Context.Write (asyncRequest.UserBuffer.Buffer, asyncRequest.UserBuffer.Offset, asyncRequest.UserBuffer.Size, out wantMore);
650 Debug ("ProcessWrite - write user done: {0} - {1} {2}", asyncRequest.UserBuffer, ret, wantMore);
653 asyncRequest.UserResult = -1;
654 return AsyncOperationStatus.Complete;
657 asyncRequest.CurrentSize += ret;
658 asyncRequest.UserBuffer.Offset += ret;
659 asyncRequest.UserBuffer.Size -= ret;
661 if (wantMore || writeBuffer.Size > 0)
662 return AsyncOperationStatus.WantWrite;
664 asyncRequest.ResetWrite ();
665 asyncRequest.UserResult = asyncRequest.CurrentSize;
666 return AsyncOperationStatus.Complete;
669 AsyncOperationStatus ProcessClose (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
671 Debug ("ProcessClose: {0}", status);
674 if (xobileTlsContext == null)
675 return AsyncOperationStatus.Complete;
677 xobileTlsContext.Close ();
678 xobileTlsContext = null;
679 return AsyncOperationStatus.Continue;
683 AsyncOperationStatus ProcessFlush (AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
685 Debug ("ProcessFlush: {0}", status);
686 return AsyncOperationStatus.Complete;
691 public override bool IsServer {
692 get { return xobileTlsContext != null && xobileTlsContext.IsServer; }
695 public override bool IsAuthenticated {
696 get { return xobileTlsContext != null && lastException == null && xobileTlsContext.IsAuthenticated; }
699 public override bool IsMutuallyAuthenticated {
701 return IsAuthenticated &&
702 (Context.IsServer? Context.LocalServerCertificate: Context.LocalClientCertificate) != null &&
703 Context.IsRemoteCertificateAvailable;
707 protected override void Dispose (bool disposing)
710 lastException = new ObjectDisposedException ("MobileAuthenticatedStream");
712 if (xobileTlsContext != null) {
713 xobileTlsContext.Dispose ();
714 xobileTlsContext = null;
718 base.Dispose (disposing);
722 public override void Flush ()
725 var asyncRequest = new AsyncProtocolRequest (this, null);
726 StartOperation (ref asyncWriteRequest, ref writeBuffer, ProcessFlush, asyncRequest, "flush");
729 public override void Close ()
732 * SSLClose() is a little bit tricky as it might attempt to send a close_notify alert
733 * and thus call our write callback.
735 * It is also not thread-safe with SSLRead() or SSLWrite(), so we need to take the I/O lock here.
737 if (Interlocked.Exchange (ref closeRequested, 1) == 1)
739 if (xobileTlsContext == null)
742 var asyncRequest = new AsyncProtocolRequest (this, null);
743 StartOperation (ref asyncWriteRequest, ref writeBuffer, ProcessClose, asyncRequest, "close");
747 // 'xobileTlsContext' must not be accessed below this point.
750 public override long Seek (long offset, SeekOrigin origin)
752 throw new NotSupportedException ();
755 public override void SetLength (long value)
757 InnerStream.SetLength (value);
760 public TransportContext TransportContext {
761 get { throw new NotSupportedException (); }
764 public override bool CanRead {
765 get { return IsAuthenticated && InnerStream.CanRead; }
768 public override bool CanTimeout {
769 get { return InnerStream.CanTimeout; }
772 public override bool CanWrite {
773 get { return IsAuthenticated & InnerStream.CanWrite; }
776 public override bool CanSeek {
777 get { return false; }
780 public override long Length {
781 get { return InnerStream.Length; }
784 public override long Position {
785 get { return InnerStream.Position; }
786 set { throw new NotSupportedException (); }
789 public override bool IsEncrypted {
790 get { return IsAuthenticated; }
793 public override bool IsSigned {
794 get { return IsAuthenticated; }
797 public override int ReadTimeout {
798 get { return InnerStream.ReadTimeout; }
799 set { InnerStream.ReadTimeout = value; }
802 public override int WriteTimeout {
803 get { return InnerStream.WriteTimeout; }
804 set { InnerStream.WriteTimeout = value; }
807 public SslProtocols SslProtocol {
810 return (SslProtocols)Context.NegotiatedProtocol;
814 public X509Certificate RemoteCertificate {
817 return Context.RemoteCertificate;
821 public X509Certificate LocalCertificate {
824 return InternalLocalCertificate;
828 public X509Certificate InternalLocalCertificate {
833 return Context.IsServer ? Context.LocalServerCertificate : Context.LocalClientCertificate;
837 public MSI.MonoTlsConnectionInfo GetConnectionInfo ()
840 return Context.ConnectionInfo;
843 public SSA.CipherAlgorithmType CipherAlgorithm {
846 var info = Context.ConnectionInfo;
848 return SSA.CipherAlgorithmType.None;
849 switch (info.CipherAlgorithmType) {
850 case MSI.CipherAlgorithmType.Aes128:
851 case MSI.CipherAlgorithmType.AesGcm128:
852 return SSA.CipherAlgorithmType.Aes128;
853 case MSI.CipherAlgorithmType.Aes256:
854 case MSI.CipherAlgorithmType.AesGcm256:
855 return SSA.CipherAlgorithmType.Aes256;
857 return SSA.CipherAlgorithmType.None;
862 public SSA.HashAlgorithmType HashAlgorithm {
865 var info = Context.ConnectionInfo;
867 return SSA.HashAlgorithmType.None;
868 switch (info.HashAlgorithmType) {
869 case MSI.HashAlgorithmType.Md5:
870 case MSI.HashAlgorithmType.Md5Sha1:
871 return SSA.HashAlgorithmType.Md5;
872 case MSI.HashAlgorithmType.Sha1:
873 case MSI.HashAlgorithmType.Sha224:
874 case MSI.HashAlgorithmType.Sha256:
875 case MSI.HashAlgorithmType.Sha384:
876 case MSI.HashAlgorithmType.Sha512:
877 return SSA.HashAlgorithmType.Sha1;
879 return SSA.HashAlgorithmType.None;
884 public SSA.ExchangeAlgorithmType KeyExchangeAlgorithm {
887 var info = Context.ConnectionInfo;
889 return SSA.ExchangeAlgorithmType.None;
890 switch (info.ExchangeAlgorithmType) {
891 case MSI.ExchangeAlgorithmType.Rsa:
892 return SSA.ExchangeAlgorithmType.RsaSign;
893 case MSI.ExchangeAlgorithmType.Dhe:
894 case MSI.ExchangeAlgorithmType.EcDhe:
895 return SSA.ExchangeAlgorithmType.DiffieHellman;
897 return SSA.ExchangeAlgorithmType.None;
902 #region Need to Implement
903 public int CipherStrength {
905 throw new NotImplementedException ();
908 public int HashStrength {
910 throw new NotImplementedException ();
913 public int KeyExchangeStrength {
915 throw new NotImplementedException ();
918 public bool CheckCertRevocationStatus {
920 throw new NotImplementedException ();