//******************************************************************************************************// TlsClient.cs - Gbtc//// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 07/12/2012 - Stephen C. Wills// Generated original version of source code.// 12/13/2012 - Starlynn Danyelle Gilliam// Modified Header.////****************************************************************************************************** using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.ComponentModel;using System.Diagnostics;using System.IO;using System.Net;using System.Net.Security;using System.Net.Sockets;using System.Security;using System.Security.Authentication;using System.Security.Cryptography.X509Certificates;using System.Text.RegularExpressions;using System.Threading;using GSF.Configuration;using GSF.IO;using GSF.Net.Security;using GSF.Threading; namespace GSF.Communication{ /// <summary> /// Represents a TCP-based communication client with SSL authentication and encryption. /// </summary> /// <seealso cref="TcpClient"/> public class TlsClient : ClientBase { #region [ Members ] // Nested Types private sealed class ConnectState : IDisposable { public Socket Socket; public NetworkStream NetworkStream; public SslStream SslStream; public NegotiateStream NegotiateStream; public SocketAsyncEventArgs ConnectArgs = new SocketAsyncEventArgs(); public int ConnectionAttempts; public CancellationToken Token = new CancellationToken(); public void Dispose() { Dispose(ConnectArgs); Dispose(Socket); Dispose(NetworkStream); Dispose(SslStream); Dispose(NegotiateStream); } private static void Dispose(IDisposable obj) { if ((object)obj != null) obj.Dispose(); } } private sealed class ReceiveState : IDisposable { public Socket Socket; public NetworkStream NetworkStream; public SslStream SslStream; public byte[] Buffer; public int Offset; public int PayloadLength = -1; public CancellationToken Token; public void Dispose() { Dispose(Socket); Dispose(NetworkStream); Dispose(SslStream); } private static void Dispose(IDisposable obj) { if ((object)obj != null) obj.Dispose(); } } private sealed class SendState : IDisposable { public Socket Socket; public NetworkStream NetworkStream; public SslStream SslStream; public ConcurrentQueue<TlsClientPayload> SendQueue = new ConcurrentQueue<TlsClientPayload>(); public TlsClientPayload Payload; public int Sending; public CancellationToken Token; public void Dispose() { TlsClientPayload payload; Dispose(Socket); Dispose(NetworkStream); Dispose(SslStream); while (SendQueue.TryDequeue(out payload)) { payload.WaitHandle.Set(); payload.WaitHandle.Dispose(); } } private static void Dispose(IDisposable obj) { if ((object)obj != null) obj.Dispose(); } } private class TlsClientPayload { public byte[] Data; public int Offset; public int Length; public ManualResetEvent WaitHandle; } private class CancellationToken { private int m_cancelled; public bool Cancelled { get { return Interlocked.CompareExchange(ref m_cancelled, 0, 0) != 0; } } public bool Cancel() { return Interlocked.Exchange(ref m_cancelled, 1) != 0; } } // Constants /// <summary> /// Specifies the default value for the <see cref="TrustedCertificatesPath"/> property. /// </summary> public readonly string DefaultTrustedCertificatesPath = FilePath.GetAbsolutePath(@"Certs\Remotes"); /// <summary> /// Specifies the default value for the <see cref="PayloadAware"/> property. /// </summary> public const bool DefaultPayloadAware = false; /// <summary> /// Specifies the default value for the <see cref="IntegratedSecurity"/> property. /// </summary> public const bool DefaultIntegratedSecurity = false; /// <summary> /// Specifies the default value for the <see cref="IgnoreInvalidCredentials"/> property. /// </summary> public const bool DefaultIgnoreInvalidCredentials = false; /// <summary> /// Specifies the default value for the <see cref="AllowDualStackSocket"/> property. /// </summary> public const bool DefaultAllowDualStackSocket = true; /// <summary> /// Specifies the default value for the <see cref="MaxSendQueueSize"/> property. /// </summary> public const int DefaultMaxSendQueueSize = 500000; /// <summary> /// Specifies the default value for the <see cref="ClientBase.ConnectionString"/> property. /// </summary> public const string DefaultConnectionString = "Server=localhost:8888"; // Fields private readonly SimpleCertificateChecker m_defaultCertificateChecker; private ICertificateChecker m_certificateChecker; private RemoteCertificateValidationCallback m_remoteCertificateValidationCallback; private LocalCertificateSelectionCallback m_localCertificateSelectionCallback; private readonly X509Certificate2Collection m_clientCertificates; private SslProtocols m_enabledSslProtocols; private bool m_checkCertificateRevocation; private string m_trustedCertificatesPath; private string m_certificateFile; private X509Certificate m_certificate; private bool m_payloadAware; private byte[] m_payloadMarker; private bool m_integratedSecurity; private bool m_ignoreInvalidCredentials; private IPStack m_ipStack; private bool m_allowDualStackSocket; private int m_maxSendQueueSize; private ShortSynchronizedOperation m_dumpPayloadsOperation; private Dictionary<string, string> m_connectData; private ManualResetEvent m_connectWaitHandle; private NetworkCredential m_networkCredential; private ConnectState m_connectState; private ReceiveState m_receiveState; private SendState m_sendState; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="TlsClient"/> class. /// </summary> public TlsClient() : this(DefaultConnectionString) { } /// <summary> /// Initializes a new instance of the <see cref="TlsClient"/> class. /// </summary> /// <param name="connectString">Connect string of the <see cref="TlsClient"/>. See <see cref="DefaultConnectionString"/> for format.</param> public TlsClient(string connectString) : base(TransportProtocol.Tcp, connectString) { m_defaultCertificateChecker = new SimpleCertificateChecker(); m_localCertificateSelectionCallback = DefaultLocalCertificateSelectionCallback; m_clientCertificates = new X509Certificate2Collection();#if MONO // Tls12 is not supported under Mono as of v3.8.0 m_enabledSslProtocols = SslProtocols.Tls;#else m_enabledSslProtocols = SslProtocols.Tls12;#endif m_checkCertificateRevocation = true; m_trustedCertificatesPath = DefaultTrustedCertificatesPath; m_payloadAware = DefaultPayloadAware; m_payloadMarker = Payload.DefaultMarker; m_integratedSecurity = DefaultIntegratedSecurity; m_ignoreInvalidCredentials = DefaultIgnoreInvalidCredentials; m_allowDualStackSocket = DefaultAllowDualStackSocket; m_maxSendQueueSize = DefaultMaxSendQueueSize; m_dumpPayloadsOperation = new ShortSynchronizedOperation(DumpPayloads, OnSendDataException); } /// <summary> /// Initializes a new instance of the <see cref="TlsClient"/> class. /// </summary> /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="TlsClient"/>.</param> public TlsClient(IContainer container) : this() { if (container != null) container.Add(this); } #endregion #region [ Properties ] /// <summary> /// Gets or sets a boolean value that indicates whether the payload boundaries are to be preserved during transmission. /// </summary> [Category("Data"), DefaultValue(DefaultPayloadAware), Description("Indicates whether the payload boundaries are to be preserved during transmission.")] public bool PayloadAware { get { return m_payloadAware; } set { m_payloadAware = value; } } /// <summary> /// Gets or sets the byte sequence used to mark the beginning of a payload in a <see cref="PayloadAware"/> transmission. /// </summary> /// <exception cref="ArgumentNullException">The value being assigned is null or empty buffer.</exception> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public byte[] PayloadMarker { get { return m_payloadMarker; } set { if ((object)value == null || value.Length == 0) throw new ArgumentNullException("value"); m_payloadMarker = value; } } /// <summary> /// Gets or sets a boolean value that indicates whether the current Windows account credentials are used for authentication. /// </summary> /// <remarks> /// This option is ignored under Mono deployments. /// </remarks> [Category("Security"), DefaultValue(DefaultIntegratedSecurity), Description("Indicates whether the current Windows account credentials are used for authentication.")] public bool IntegratedSecurity { get { return m_integratedSecurity; } set {#if MONO if (value) throw new NotImplementedException("Not supported under Mono.");#else m_integratedSecurity = value;#endif } } /// <summary> /// Gets or sets a boolean value that indicates whether the server /// should ignore errors when the client's credentials are invalid. /// </summary> /// <remarks> /// This property should only be set to true if there is an alternative by which /// to authenticate the client when integrated security fails. /// </remarks> [Category("Security"), DefaultValue(DefaultIgnoreInvalidCredentials), Description("Indicates whether the client Windows account credentials are validated during authentication.")] public bool IgnoreInvalidCredentials { get { return m_ignoreInvalidCredentials; } set { m_ignoreInvalidCredentials = value; } } /// <summary> /// Gets or sets a boolean value that determines if dual-mode socket is allowed when endpoint address is IPv6. /// </summary> [Category("Settings"), DefaultValue(DefaultAllowDualStackSocket), Description("Determines if dual-mode socket is allowed when endpoint address is IPv6.")] public bool AllowDualStackSocket { get { return m_allowDualStackSocket; } set { m_allowDualStackSocket = value; } } /// <summary> /// Gets or sets the maximum size for the send queue before payloads are dumped from the queue. /// </summary> [Category("Settings"), DefaultValue(DefaultMaxSendQueueSize), Description("The maximum size for the send queue before payloads are dumped from the queue.")] public int MaxSendQueueSize { get { return m_maxSendQueueSize; } set { m_maxSendQueueSize = value; } } /// <summary> /// Gets the <see cref="Socket"/> object for the <see cref="TlsClient"/>. /// </summary> [Browsable(false)] public Socket Client { get { ConnectState connectState = m_connectState; if ((object)connectState != null) return connectState.Socket; return null; } } /// <summary> /// Gets the server URI of the <see cref="TlsClient"/>. /// </summary> [Browsable(false)] public override string ServerUri { get { return string.Format("{0}://{1}", TransportProtocol, m_connectData["server"]).ToLower(); } } /// <summary> /// Gets or sets network credential that is used when /// <see cref="IntegratedSecurity"/> is set to <c>true</c>. /// </summary> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public NetworkCredential NetworkCredential { get { return m_networkCredential; } set { m_networkCredential = value; } } /// <summary> /// Gets or sets the certificate checker used to validate remote certificates. /// </summary> /// <remarks> /// The certificate checker will only be used to validate certificates if /// the <see cref="RemoteCertificateValidationCallback"/> is set to null. /// </remarks> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ICertificateChecker CertificateChecker { get { return m_certificateChecker ?? m_defaultCertificateChecker; } set { m_certificateChecker = value; } } /// <summary> /// Gets or sets the callback used to verify remote certificates. /// </summary> /// <remarks> /// Setting this property overrides the validation /// callback in the <see cref="CertificateChecker"/>. /// </remarks> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { return m_remoteCertificateValidationCallback; } setLines 1–500 of 1936. Load more
//****************************************************************************************************** // TlsClient.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 07/12/2012 - Stephen C. Wills // Generated original version of source code. // 12/13/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text.RegularExpressions; using System.Threading; using GSF.Configuration; using GSF.IO; using GSF.Net.Security; using GSF.Threading; namespace GSF.Communication { /// <summary> /// Represents a TCP-based communication client with SSL authentication and encryption. /// </summary> /// <seealso cref="TcpClient"/> public class TlsClient : ClientBase { #region [ Members ] // Nested Types private sealed class ConnectState : IDisposable { public Socket Socket; public NetworkStream NetworkStream; public SslStream SslStream; public NegotiateStream NegotiateStream; public SocketAsyncEventArgs ConnectArgs = new SocketAsyncEventArgs(); public int ConnectionAttempts; public CancellationToken Token = new CancellationToken(); public void Dispose() { Dispose(ConnectArgs); Dispose(Socket); Dispose(NetworkStream); Dispose(SslStream); Dispose(NegotiateStream); } private static void Dispose(IDisposable obj) { if ((object)obj != null) obj.Dispose(); } } private sealed class ReceiveState : IDisposable { public Socket Socket; public NetworkStream NetworkStream; public SslStream SslStream; public byte[] Buffer; public int Offset; public int PayloadLength = -1; public CancellationToken Token; public void Dispose() { Dispose(Socket); Dispose(NetworkStream); Dispose(SslStream); } private static void Dispose(IDisposable obj) { if ((object)obj != null) obj.Dispose(); } } private sealed class SendState : IDisposable { public Socket Socket; public NetworkStream NetworkStream; public SslStream SslStream; public ConcurrentQueue<TlsClientPayload> SendQueue = new ConcurrentQueue<TlsClientPayload>(); public TlsClientPayload Payload; public int Sending; public CancellationToken Token; public void Dispose() { TlsClientPayload payload; Dispose(Socket); Dispose(NetworkStream); Dispose(SslStream); while (SendQueue.TryDequeue(out payload)) { payload.WaitHandle.Set(); payload.WaitHandle.Dispose(); } } private static void Dispose(IDisposable obj) { if ((object)obj != null) obj.Dispose(); } } private class TlsClientPayload { public byte[] Data; public int Offset; public int Length; public ManualResetEvent WaitHandle; } private class CancellationToken { private int m_cancelled; public bool Cancelled { get { return Interlocked.CompareExchange(ref m_cancelled, 0, 0) != 0; } } public bool Cancel() { return Interlocked.Exchange(ref m_cancelled, 1) != 0; } } // Constants /// <summary> /// Specifies the default value for the <see cref="TrustedCertificatesPath"/> property. /// </summary> public readonly string DefaultTrustedCertificatesPath = FilePath.GetAbsolutePath(@"Certs\Remotes"); /// <summary> /// Specifies the default value for the <see cref="PayloadAware"/> property. /// </summary> public const bool DefaultPayloadAware = false; /// <summary> /// Specifies the default value for the <see cref="IntegratedSecurity"/> property. /// </summary> public const bool DefaultIntegratedSecurity = false; /// <summary> /// Specifies the default value for the <see cref="IgnoreInvalidCredentials"/> property. /// </summary> public const bool DefaultIgnoreInvalidCredentials = false; /// <summary> /// Specifies the default value for the <see cref="AllowDualStackSocket"/> property. /// </summary> public const bool DefaultAllowDualStackSocket = true; /// <summary> /// Specifies the default value for the <see cref="MaxSendQueueSize"/> property. /// </summary> public const int DefaultMaxSendQueueSize = 500000; /// <summary> /// Specifies the default value for the <see cref="ClientBase.ConnectionString"/> property. /// </summary> public const string DefaultConnectionString = "Server=localhost:8888"; // Fields private readonly SimpleCertificateChecker m_defaultCertificateChecker; private ICertificateChecker m_certificateChecker; private RemoteCertificateValidationCallback m_remoteCertificateValidationCallback; private LocalCertificateSelectionCallback m_localCertificateSelectionCallback; private readonly X509Certificate2Collection m_clientCertificates; private SslProtocols m_enabledSslProtocols; private bool m_checkCertificateRevocation; private string m_trustedCertificatesPath; private string m_certificateFile; private X509Certificate m_certificate; private bool m_payloadAware; private byte[] m_payloadMarker; private bool m_integratedSecurity; private bool m_ignoreInvalidCredentials; private IPStack m_ipStack; private bool m_allowDualStackSocket; private int m_maxSendQueueSize; private ShortSynchronizedOperation m_dumpPayloadsOperation; private Dictionary<string, string> m_connectData; private ManualResetEvent m_connectWaitHandle; private NetworkCredential m_networkCredential; private ConnectState m_connectState; private ReceiveState m_receiveState; private SendState m_sendState; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="TlsClient"/> class. /// </summary> public TlsClient() : this(DefaultConnectionString) { } /// <summary> /// Initializes a new instance of the <see cref="TlsClient"/> class. /// </summary> /// <param name="connectString">Connect string of the <see cref="TlsClient"/>. See <see cref="DefaultConnectionString"/> for format.</param> public TlsClient(string connectString) : base(TransportProtocol.Tcp, connectString) { m_defaultCertificateChecker = new SimpleCertificateChecker(); m_localCertificateSelectionCallback = DefaultLocalCertificateSelectionCallback; m_clientCertificates = new X509Certificate2Collection(); #if MONO // Tls12 is not supported under Mono as of v3.8.0 m_enabledSslProtocols = SslProtocols.Tls; #else m_enabledSslProtocols = SslProtocols.Tls12; #endif m_checkCertificateRevocation = true; m_trustedCertificatesPath = DefaultTrustedCertificatesPath; m_payloadAware = DefaultPayloadAware; m_payloadMarker = Payload.DefaultMarker; m_integratedSecurity = DefaultIntegratedSecurity; m_ignoreInvalidCredentials = DefaultIgnoreInvalidCredentials; m_allowDualStackSocket = DefaultAllowDualStackSocket; m_maxSendQueueSize = DefaultMaxSendQueueSize; m_dumpPayloadsOperation = new ShortSynchronizedOperation(DumpPayloads, OnSendDataException); } /// <summary> /// Initializes a new instance of the <see cref="TlsClient"/> class. /// </summary> /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="TlsClient"/>.</param> public TlsClient(IContainer container) : this() { if (container != null) container.Add(this); } #endregion #region [ Properties ] /// <summary> /// Gets or sets a boolean value that indicates whether the payload boundaries are to be preserved during transmission. /// </summary> [Category("Data"), DefaultValue(DefaultPayloadAware), Description("Indicates whether the payload boundaries are to be preserved during transmission.")] public bool PayloadAware { get { return m_payloadAware; } set { m_payloadAware = value; } } /// <summary> /// Gets or sets the byte sequence used to mark the beginning of a payload in a <see cref="PayloadAware"/> transmission. /// </summary> /// <exception cref="ArgumentNullException">The value being assigned is null or empty buffer.</exception> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public byte[] PayloadMarker { get { return m_payloadMarker; } set { if ((object)value == null || value.Length == 0) throw new ArgumentNullException("value"); m_payloadMarker = value; } } /// <summary> /// Gets or sets a boolean value that indicates whether the current Windows account credentials are used for authentication. /// </summary> /// <remarks> /// This option is ignored under Mono deployments. /// </remarks> [Category("Security"), DefaultValue(DefaultIntegratedSecurity), Description("Indicates whether the current Windows account credentials are used for authentication.")] public bool IntegratedSecurity { get { return m_integratedSecurity; } set { #if MONO if (value) throw new NotImplementedException("Not supported under Mono."); #else m_integratedSecurity = value; #endif } } /// <summary> /// Gets or sets a boolean value that indicates whether the server /// should ignore errors when the client's credentials are invalid. /// </summary> /// <remarks> /// This property should only be set to true if there is an alternative by which /// to authenticate the client when integrated security fails. /// </remarks> [Category("Security"), DefaultValue(DefaultIgnoreInvalidCredentials), Description("Indicates whether the client Windows account credentials are validated during authentication.")] public bool IgnoreInvalidCredentials { get { return m_ignoreInvalidCredentials; } set { m_ignoreInvalidCredentials = value; } } /// <summary> /// Gets or sets a boolean value that determines if dual-mode socket is allowed when endpoint address is IPv6. /// </summary> [Category("Settings"), DefaultValue(DefaultAllowDualStackSocket), Description("Determines if dual-mode socket is allowed when endpoint address is IPv6.")] public bool AllowDualStackSocket { get { return m_allowDualStackSocket; } set { m_allowDualStackSocket = value; } } /// <summary> /// Gets or sets the maximum size for the send queue before payloads are dumped from the queue. /// </summary> [Category("Settings"), DefaultValue(DefaultMaxSendQueueSize), Description("The maximum size for the send queue before payloads are dumped from the queue.")] public int MaxSendQueueSize { get { return m_maxSendQueueSize; } set { m_maxSendQueueSize = value; } } /// <summary> /// Gets the <see cref="Socket"/> object for the <see cref="TlsClient"/>. /// </summary> [Browsable(false)] public Socket Client { get { ConnectState connectState = m_connectState; if ((object)connectState != null) return connectState.Socket; return null; } } /// <summary> /// Gets the server URI of the <see cref="TlsClient"/>. /// </summary> [Browsable(false)] public override string ServerUri { get { return string.Format("{0}://{1}", TransportProtocol, m_connectData["server"]).ToLower(); } } /// <summary> /// Gets or sets network credential that is used when /// <see cref="IntegratedSecurity"/> is set to <c>true</c>. /// </summary> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public NetworkCredential NetworkCredential { get { return m_networkCredential; } set { m_networkCredential = value; } } /// <summary> /// Gets or sets the certificate checker used to validate remote certificates. /// </summary> /// <remarks> /// The certificate checker will only be used to validate certificates if /// the <see cref="RemoteCertificateValidationCallback"/> is set to null. /// </remarks> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ICertificateChecker CertificateChecker { get { return m_certificateChecker ?? m_defaultCertificateChecker; } set { m_certificateChecker = value; } } /// <summary> /// Gets or sets the callback used to verify remote certificates. /// </summary> /// <remarks> /// Setting this property overrides the validation /// callback in the <see cref="CertificateChecker"/>. /// </remarks> [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { return m_remoteCertificateValidationCallback; } set