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.Security.Authentication;
27 using System.Runtime.ExceptionServices;
28 using System.Threading;
29 using System.Threading.Tasks;
30 using System.Security.Cryptography.X509Certificates;
32 using SD = System.Diagnostics;
33 using SSA = System.Security.Authentication;
34 using SslProtocols = System.Security.Authentication.SslProtocols;
36 namespace Mono.Net.Security
38 abstract class MobileAuthenticatedStream : AuthenticatedStream, MSI.IMonoSslStream
41 * This is intentionally called `xobileTlsContext'. It is a "dangerous" object
42 * that must not be touched outside the `ioLock' and we need to be very careful
45 MobileTlsContext xobileTlsContext;
46 ExceptionDispatchInfo lastException;
48 AsyncProtocolRequest asyncHandshakeRequest;
49 AsyncProtocolRequest asyncReadRequest;
50 AsyncProtocolRequest asyncWriteRequest;
51 BufferOffsetSize2 readBuffer;
52 BufferOffsetSize2 writeBuffer;
54 object ioLock = new object ();
58 static int uniqueNameInteger = 123;
60 public MobileAuthenticatedStream (Stream innerStream, bool leaveInnerStreamOpen, SslStream owner,
61 MSI.MonoTlsSettings settings, MSI.MonoTlsProvider provider)
62 : base (innerStream, leaveInnerStreamOpen)
68 readBuffer = new BufferOffsetSize2 (16834);
69 writeBuffer = new BufferOffsetSize2 (16384);
72 public SslStream SslStream {
76 public MSI.MonoTlsSettings Settings {
80 public MSI.MonoTlsProvider Provider {
84 internal bool HasContext {
85 get { return xobileTlsContext != null; }
88 internal void CheckThrow (bool authSuccessCheck, bool shutdownCheck = false)
90 if (lastException != null)
91 lastException.Throw ();
92 if (authSuccessCheck && !IsAuthenticated)
93 throw new InvalidOperationException (SR.net_auth_noauth);
94 if (shutdownCheck && shutdown)
95 throw new InvalidOperationException (SR.net_ssl_io_already_shutdown);
98 internal static Exception GetSSPIException (Exception e)
100 if (e is OperationCanceledException || e is IOException || e is ObjectDisposedException || e is AuthenticationException)
102 return new AuthenticationException (SR.net_auth_SSPI, e);
105 internal static Exception GetIOException (Exception e, string message)
107 if (e is OperationCanceledException || e is IOException || e is ObjectDisposedException || e is AuthenticationException)
109 return new IOException (message, e);
112 internal ExceptionDispatchInfo SetException (Exception e)
114 var info = ExceptionDispatchInfo.Capture (e);
115 var old = Interlocked.CompareExchange (ref lastException, info, null);
119 SslProtocols DefaultProtocols {
120 get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
129 public void AuthenticateAsClient (string targetHost)
131 AuthenticateAsClient (targetHost, new X509CertificateCollection (), DefaultProtocols, false);
134 public void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
136 var task = ProcessAuthentication (true, false, targetHost, enabledSslProtocols, null, clientCertificates, false);
140 public IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
142 return BeginAuthenticateAsClient (targetHost, new X509CertificateCollection (), DefaultProtocols, false, asyncCallback, asyncState);
145 public IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
147 var task = ProcessAuthentication (false, false, targetHost, enabledSslProtocols, null, clientCertificates, false);
148 return TaskToApm.Begin (task, asyncCallback, asyncState);
151 public void EndAuthenticateAsClient (IAsyncResult asyncResult)
153 TaskToApm.End (asyncResult);
156 public void AuthenticateAsServer (X509Certificate serverCertificate)
158 AuthenticateAsServer (serverCertificate, false, DefaultProtocols, false);
161 public void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
163 var task = ProcessAuthentication (true, true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
167 public IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
169 return BeginAuthenticateAsServer (serverCertificate, false, DefaultProtocols, false, asyncCallback, asyncState);
172 public IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
174 var task = ProcessAuthentication (false, true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
175 return TaskToApm.Begin (task, asyncCallback, asyncState);
178 public void EndAuthenticateAsServer (IAsyncResult asyncResult)
180 TaskToApm.End (asyncResult);
183 public Task AuthenticateAsClientAsync (string targetHost)
185 return ProcessAuthentication (false, false, targetHost, DefaultProtocols, null, null, false);
188 public Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
190 return ProcessAuthentication (false, false, targetHost, enabledSslProtocols, null, clientCertificates, false);
193 public Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
195 return AuthenticateAsServerAsync (serverCertificate, false, DefaultProtocols, false);
198 public Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
200 return ProcessAuthentication (false, true, string.Empty, enabledSslProtocols, serverCertificate, null, clientCertificateRequired);
203 public Task ShutdownAsync ()
205 Debug ("ShutdownAsync");
208 * SSLClose() is a little bit tricky as it might attempt to send a close_notify alert
209 * and thus call our write callback.
211 * It is also not thread-safe with SSLRead() or SSLWrite(), so we need to take the I/O lock here.
213 var asyncRequest = new AsyncShutdownRequest (this);
214 var task = StartOperation (OperationType.Shutdown, asyncRequest, CancellationToken.None);
218 public AuthenticatedStream AuthenticatedStream {
222 async Task ProcessAuthentication (
223 bool runSynchronously, bool serverMode, string targetHost, SslProtocols enabledProtocols,
224 X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool clientCertRequired)
227 if (serverCertificate == null)
228 throw new ArgumentException (nameof (serverCertificate));
230 if (targetHost == null)
231 throw new ArgumentException (nameof (targetHost));
232 if (targetHost.Length == 0)
233 targetHost = "?" + Interlocked.Increment (ref uniqueNameInteger).ToString (NumberFormatInfo.InvariantInfo);
236 if (lastException != null)
237 lastException.Throw ();
239 var asyncRequest = new AsyncHandshakeRequest (this, runSynchronously);
240 if (Interlocked.CompareExchange (ref asyncHandshakeRequest, asyncRequest, null) != null)
241 throw new InvalidOperationException ("Invalid nested call.");
242 // Make sure no other async requests can be started during the handshake.
243 if (Interlocked.CompareExchange (ref asyncReadRequest, asyncRequest, null) != null)
244 throw new InvalidOperationException ("Invalid nested call.");
245 if (Interlocked.CompareExchange (ref asyncWriteRequest, asyncRequest, null) != null)
246 throw new InvalidOperationException ("Invalid nested call.");
248 AsyncProtocolResult result;
252 if (xobileTlsContext != null)
253 throw new InvalidOperationException ();
255 writeBuffer.Reset ();
257 xobileTlsContext = CreateContext (
258 serverMode, targetHost, enabledProtocols, serverCertificate,
259 clientCertificates, clientCertRequired);
263 result = await asyncRequest.StartOperation (CancellationToken.None).ConfigureAwait (false);
264 } catch (Exception ex) {
265 result = new AsyncProtocolResult (SetException (GetSSPIException (ex)));
270 writeBuffer.Reset ();
271 asyncWriteRequest = null;
272 asyncReadRequest = null;
273 asyncHandshakeRequest = null;
277 if (result.Error != null)
278 result.Error.Throw ();
281 protected abstract MobileTlsContext CreateContext (
282 bool serverMode, string targetHost, SSA.SslProtocols enabledProtocols,
283 X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
284 bool askForClientCert);
286 public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
288 var asyncRequest = new AsyncReadRequest (this, false, buffer, offset, count);
289 var task = StartOperation (OperationType.Read, asyncRequest, CancellationToken.None);
290 return TaskToApm.Begin (task, asyncCallback, asyncState);
293 public override int EndRead (IAsyncResult asyncResult)
295 return TaskToApm.End<int> (asyncResult);
298 public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
300 var asyncRequest = new AsyncWriteRequest (this, false, buffer, offset, count);
301 var task = StartOperation (OperationType.Write, asyncRequest, CancellationToken.None);
302 return TaskToApm.Begin (task, asyncCallback, asyncState);
305 public override void EndWrite (IAsyncResult asyncResult)
307 TaskToApm.End (asyncResult);
310 public override int Read (byte[] buffer, int offset, int count)
312 var asyncRequest = new AsyncReadRequest (this, true, buffer, offset, count);
313 var task = StartOperation (OperationType.Read, asyncRequest, CancellationToken.None);
317 public void Write (byte[] buffer)
319 Write (buffer, 0, buffer.Length);
322 public override void Write (byte[] buffer, int offset, int count)
324 var asyncRequest = new AsyncWriteRequest (this, true, buffer, offset, count);
325 var task = StartOperation (OperationType.Write, asyncRequest, CancellationToken.None);
329 public override Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
331 var asyncRequest = new AsyncReadRequest (this, false, buffer, offset, count);
332 return StartOperation (OperationType.Read, asyncRequest, cancellationToken);
335 public override Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
337 var asyncRequest = new AsyncWriteRequest (this, false, buffer, offset, count);
338 return StartOperation (OperationType.Write, asyncRequest, cancellationToken);
341 async Task<int> StartOperation (OperationType type, AsyncProtocolRequest asyncRequest, CancellationToken cancellationToken)
343 CheckThrow (true, type != OperationType.Read);
344 Debug ("StartOperationAsync: {0} {1}", asyncRequest, type);
346 if (type == OperationType.Read) {
347 if (Interlocked.CompareExchange (ref asyncReadRequest, asyncRequest, null) != null)
348 throw new InvalidOperationException ("Invalid nested call.");
350 if (Interlocked.CompareExchange (ref asyncWriteRequest, asyncRequest, null) != null)
351 throw new InvalidOperationException ("Invalid nested call.");
354 AsyncProtocolResult result;
358 if (type == OperationType.Read)
361 writeBuffer.Reset ();
363 result = await asyncRequest.StartOperation (cancellationToken).ConfigureAwait (false);
364 } catch (Exception e) {
365 var info = SetException (GetIOException (e, asyncRequest.Name + " failed"));
366 result = new AsyncProtocolResult (info);
369 if (type == OperationType.Read) {
371 asyncReadRequest = null;
373 writeBuffer.Reset ();
374 asyncWriteRequest = null;
379 if (result.Error != null)
380 result.Error.Throw ();
381 return result.UserResult;
385 internal readonly int ID = ++nextId;
387 [SD.Conditional ("MONO_TLS_DEBUG")]
388 protected internal void Debug (string message, params object[] args)
390 MonoTlsProviderFactory.Debug ("MobileAuthenticatedStream({0}): {1}", ID, string.Format (message, args));
393 #region Called back from native code via SslConnection
396 * Called from within SSLRead() and SSLHandshake(). We only access tha managed byte[] here.
398 internal int InternalRead (byte[] buffer, int offset, int size, out bool outWantMore)
401 Debug ("InternalRead: {0} {1} {2} {3} {4}", offset, size,
402 asyncHandshakeRequest != null ? "handshake" : "",
403 asyncReadRequest != null ? "async" : "",
404 readBuffer != null ? readBuffer.ToString () : "");
405 var asyncRequest = asyncHandshakeRequest ?? asyncReadRequest;
406 var (ret, wantMore) = InternalRead (asyncRequest, readBuffer, buffer, offset, size);
407 outWantMore = wantMore;
409 } catch (Exception ex) {
410 Debug ("InternalRead failed: {0}", ex);
411 SetException (GetIOException (ex, "InternalRead() failed"));
417 (int, bool) InternalRead (AsyncProtocolRequest asyncRequest, BufferOffsetSize internalBuffer, byte[] buffer, int offset, int size)
419 if (asyncRequest == null)
420 throw new InvalidOperationException ();
422 Debug ("InternalRead: {0} {1} {2}", internalBuffer, offset, size);
425 * One of Apple's native functions wants to read 'size' bytes of data.
427 * First, we check whether we already have enough in the internal buffer.
429 * If the internal buffer is empty (it will be the first time we're called), we save
430 * the amount of bytes that were requested and return 'SslStatus.WouldBlock' to our
431 * native caller. This native function will then return this code to managed code,
432 * where we read the requested amount of data into the internal buffer, then call the
433 * native function again.
435 if (internalBuffer.Size == 0 && !internalBuffer.Complete) {
436 Debug ("InternalRead #1: {0} {1} {2}", internalBuffer.Offset, internalBuffer.TotalBytes, size);
437 internalBuffer.Offset = internalBuffer.Size = 0;
438 asyncRequest.RequestRead (size);
443 * The second time we're called, the native buffer will contain the exact amount of data that the
444 * previous call requested from us, so we should be able to return it all here. However, just in
445 * case that Apple's native function changed its mind, we can also return less.
447 * In either case, if we have any data buffered, then we return as much of it as possible - if the
448 * native code isn't satisfied, then it will call us again to request more.
450 var len = System.Math.Min (internalBuffer.Size, size);
451 Buffer.BlockCopy (internalBuffer.Buffer, internalBuffer.Offset, buffer, offset, len);
452 internalBuffer.Offset += len;
453 internalBuffer.Size -= len;
454 return (len, !internalBuffer.Complete && len < size);
458 * We may get called from SSLWrite(), SSLHandshake() or SSLClose().
460 internal bool InternalWrite (byte[] buffer, int offset, int size)
463 Debug ("InternalWrite: {0} {1}", offset, size);
464 var asyncRequest = asyncHandshakeRequest ?? asyncWriteRequest;
465 return InternalWrite (asyncRequest, writeBuffer, buffer, offset, size);
466 } catch (Exception ex) {
467 Debug ("InternalWrite failed: {0}", ex);
468 SetException (GetIOException (ex, "InternalWrite() failed"));
473 bool InternalWrite (AsyncProtocolRequest asyncRequest, BufferOffsetSize2 internalBuffer, byte[] buffer, int offset, int size)
475 Debug ("InternalWrite: {0} {1} {2} {3}", asyncRequest != null, internalBuffer, offset, size);
477 if (asyncRequest == null) {
479 * The only situation where 'asyncRequest' could possibly be 'null' is when we're called
480 * from within SSLClose() - which might attempt to send the close_notity notification.
481 * Since this notification message is very small, it should definitely fit into our internal
482 * buffer, so we just save it in there and after SSLClose() returns, the final call to
483 * InternalFlush() - just before closing the underlying stream - will send it out.
485 if (lastException != null)
488 if (Interlocked.Exchange (ref closeRequested, 1) == 0)
489 internalBuffer.Reset ();
490 else if (internalBuffer.Remaining == 0)
491 throw new InvalidOperationException ();
495 * Normal write - can be either SSLWrite() or SSLHandshake().
497 * It is important that we always accept all the data and queue it.
500 internalBuffer.AppendData (buffer, offset, size);
503 * Calling 'asyncRequest.RequestWrite()' here ensures that ProcessWrite() is called next
504 * time we regain control from native code.
506 * During the handshake, the native code won't actually realize (unless if attempts to send
507 * so much that the write buffer gets full) that we only buffered the data.
509 * However, it doesn't matter because it will either return with a completed handshake
510 * (and doesn't care whether the remote actually received the data) or it will expect more
511 * data from the remote and request a read. In either case, we regain control in managed
512 * code and can flush out the data.
514 * Note that a calling RequestWrite() followed by RequestRead() will first flush the write
515 * queue once we return to managed code - before attempting to read anything.
517 if (asyncRequest != null)
518 asyncRequest.RequestWrite ();
528 * Read / write data from the inner stream; we're only called from managed code and only manipulate
529 * the internal buffers.
531 internal async Task<int> InnerRead (bool sync, int requestedSize, CancellationToken cancellationToken)
533 cancellationToken.ThrowIfCancellationRequested ();
534 Debug ("InnerRead: {0} {1} {2} {3} {4}", sync, readBuffer.Offset, readBuffer.Size, readBuffer.Remaining, requestedSize);
536 var len = System.Math.Min (readBuffer.Remaining, requestedSize);
538 throw new InvalidOperationException ();
542 task = Task.Run (() => InnerStream.Read (readBuffer.Buffer, readBuffer.EndOffset, len));
544 task = InnerStream.ReadAsync (readBuffer.Buffer, readBuffer.EndOffset, len, cancellationToken);
546 var ret = await task.ConfigureAwait (false);
547 Debug ("InnerRead done: {0} {1} - {2}", readBuffer.Remaining, len, ret);
550 readBuffer.Size += ret;
551 readBuffer.TotalBytes += ret;
555 readBuffer.Complete = true;
556 Debug ("InnerRead - end of stream!");
558 * Try to distinguish between a graceful close - first Read() returned 0 - and
559 * the remote prematurely closing the connection without sending us all data.
561 if (readBuffer.TotalBytes > 0)
565 Debug ("InnerRead done: {0} - {1} {2}", readBuffer, len, ret);
569 internal async Task InnerWrite (bool sync, CancellationToken cancellationToken)
571 cancellationToken.ThrowIfCancellationRequested ();
572 Debug ("InnerWrite: {0} {1}", writeBuffer.Offset, writeBuffer.Size);
574 if (writeBuffer.Size == 0)
579 task = Task.Run (() => InnerStream.Write (writeBuffer.Buffer, writeBuffer.Offset, writeBuffer.Size));
581 task = InnerStream.WriteAsync (writeBuffer.Buffer, writeBuffer.Offset, writeBuffer.Size);
583 await task.ConfigureAwait (false);
585 writeBuffer.TotalBytes += writeBuffer.Size;
586 writeBuffer.Offset = writeBuffer.Size = 0;
591 #region Main async I/O loop
593 internal AsyncOperationStatus ProcessHandshake (AsyncOperationStatus status)
595 Debug ("ProcessHandshake: {0}", status);
599 * The first time we're called (AsyncOperationStatus.Initialize), we need to setup the SslContext and
600 * start the handshake.
602 if (status == AsyncOperationStatus.Initialize) {
603 xobileTlsContext.StartHandshake ();
604 return AsyncOperationStatus.Continue;
605 } else if (status == AsyncOperationStatus.ReadDone) {
606 throw new IOException (SR.net_auth_eof);
607 } else if (status != AsyncOperationStatus.Continue) {
608 throw new InvalidOperationException ();
612 * SSLHandshake() will return repeatedly with 'SslStatus.WouldBlock', we then need
613 * to take care of I/O and call it again.
615 var newStatus = AsyncOperationStatus.Continue;
616 if (xobileTlsContext.ProcessHandshake ()) {
617 xobileTlsContext.FinishHandshake ();
618 newStatus = AsyncOperationStatus.Complete;
621 if (lastException != null)
622 lastException.Throw ();
628 internal (int, bool) ProcessRead (BufferOffsetSize userBuffer)
631 // This operates on the internal buffer and will never block.
632 var ret = xobileTlsContext.Read (userBuffer.Buffer, userBuffer.Offset, userBuffer.Size);
633 if (lastException != null)
634 lastException.Throw ();
639 internal (int, bool) ProcessWrite (BufferOffsetSize userBuffer)
642 // This operates on the internal buffer and will never block.
643 var ret = xobileTlsContext.Write (userBuffer.Buffer, userBuffer.Offset, userBuffer.Size);
644 if (lastException != null)
645 lastException.Throw ();
650 internal AsyncOperationStatus ProcessShutdown (AsyncOperationStatus status)
652 Debug ("ProcessShutdown: {0}", status);
655 xobileTlsContext.Shutdown ();
657 return AsyncOperationStatus.Complete;
663 public override bool IsServer {
666 return xobileTlsContext != null && xobileTlsContext.IsServer;
670 public override bool IsAuthenticated {
673 // Don't use CheckThrow(), we want to return false if we're not authenticated.
674 return xobileTlsContext != null && lastException == null && xobileTlsContext.IsAuthenticated;
679 public override bool IsMutuallyAuthenticated {
682 // Don't use CheckThrow() here.
683 if (!IsAuthenticated)
685 if ((xobileTlsContext.IsServer ? xobileTlsContext.LocalServerCertificate : xobileTlsContext.LocalClientCertificate) == null)
687 return xobileTlsContext.IsRemoteCertificateAvailable;
692 protected override void Dispose (bool disposing)
696 Debug ("Dispose: {0}", xobileTlsContext != null);
697 lastException = ExceptionDispatchInfo.Capture (new ObjectDisposedException ("MobileAuthenticatedStream"));
698 if (xobileTlsContext != null) {
699 xobileTlsContext.Dispose ();
700 xobileTlsContext = null;
704 base.Dispose (disposing);
708 public override void Flush ()
710 InnerStream.Flush ();
713 public SslProtocols SslProtocol {
717 return (SslProtocols)xobileTlsContext.NegotiatedProtocol;
722 public X509Certificate RemoteCertificate {
726 return xobileTlsContext.RemoteCertificate;
731 public X509Certificate LocalCertificate {
735 return InternalLocalCertificate;
740 public X509Certificate InternalLocalCertificate {
744 if (xobileTlsContext == null)
746 return xobileTlsContext.IsServer ? xobileTlsContext.LocalServerCertificate : xobileTlsContext.LocalClientCertificate;
751 public MSI.MonoTlsConnectionInfo GetConnectionInfo ()
755 return xobileTlsContext.ConnectionInfo;
760 // 'xobileTlsContext' must not be accessed below this point.
763 public override long Seek (long offset, SeekOrigin origin)
765 throw new NotSupportedException ();
768 public override void SetLength (long value)
770 InnerStream.SetLength (value);
773 public TransportContext TransportContext {
774 get { throw new NotSupportedException (); }
777 public override bool CanRead {
778 get { return IsAuthenticated && InnerStream.CanRead; }
781 public override bool CanTimeout {
782 get { return InnerStream.CanTimeout; }
785 public override bool CanWrite {
786 get { return IsAuthenticated & InnerStream.CanWrite && !shutdown; }
789 public override bool CanSeek {
790 get { return false; }
793 public override long Length {
794 get { return InnerStream.Length; }
797 public override long Position {
798 get { return InnerStream.Position; }
799 set { throw new NotSupportedException (); }
802 public override bool IsEncrypted {
803 get { return IsAuthenticated; }
806 public override bool IsSigned {
807 get { return IsAuthenticated; }
810 public override int ReadTimeout {
811 get { return InnerStream.ReadTimeout; }
812 set { InnerStream.ReadTimeout = value; }
815 public override int WriteTimeout {
816 get { return InnerStream.WriteTimeout; }
817 set { InnerStream.WriteTimeout = value; }
820 public SSA.CipherAlgorithmType CipherAlgorithm {
823 var info = GetConnectionInfo ();
825 return SSA.CipherAlgorithmType.None;
826 switch (info.CipherAlgorithmType) {
827 case MSI.CipherAlgorithmType.Aes128:
828 case MSI.CipherAlgorithmType.AesGcm128:
829 return SSA.CipherAlgorithmType.Aes128;
830 case MSI.CipherAlgorithmType.Aes256:
831 case MSI.CipherAlgorithmType.AesGcm256:
832 return SSA.CipherAlgorithmType.Aes256;
834 return SSA.CipherAlgorithmType.None;
839 public SSA.HashAlgorithmType HashAlgorithm {
842 var info = GetConnectionInfo ();
844 return SSA.HashAlgorithmType.None;
845 switch (info.HashAlgorithmType) {
846 case MSI.HashAlgorithmType.Md5:
847 case MSI.HashAlgorithmType.Md5Sha1:
848 return SSA.HashAlgorithmType.Md5;
849 case MSI.HashAlgorithmType.Sha1:
850 case MSI.HashAlgorithmType.Sha224:
851 case MSI.HashAlgorithmType.Sha256:
852 case MSI.HashAlgorithmType.Sha384:
853 case MSI.HashAlgorithmType.Sha512:
854 return SSA.HashAlgorithmType.Sha1;
856 return SSA.HashAlgorithmType.None;
861 public SSA.ExchangeAlgorithmType KeyExchangeAlgorithm {
864 var info = GetConnectionInfo ();
866 return SSA.ExchangeAlgorithmType.None;
867 switch (info.ExchangeAlgorithmType) {
868 case MSI.ExchangeAlgorithmType.Rsa:
869 return SSA.ExchangeAlgorithmType.RsaSign;
870 case MSI.ExchangeAlgorithmType.Dhe:
871 case MSI.ExchangeAlgorithmType.EcDhe:
872 return SSA.ExchangeAlgorithmType.DiffieHellman;
874 return SSA.ExchangeAlgorithmType.None;
879 #region Need to Implement
880 public int CipherStrength {
882 throw new NotImplementedException ();
885 public int HashStrength {
887 throw new NotImplementedException ();
890 public int KeyExchangeStrength {
892 throw new NotImplementedException ();
895 public bool CheckCertRevocationStatus {
897 throw new NotImplementedException ();