//******************************************************************************************************// TlsServer.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 GSF.Configuration;using GSF.IO;using GSF.Net.Security;using GSF.Threading;using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.ComponentModel;using System.Diagnostics;using System.IO;using System.Linq;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.Security.Principal;using System.Text;using System.Threading; #if MONO#pragma warning disable 649#endif namespace GSF.Communication{ /// <summary> /// Represents a TCP-based communication server with SSL authentication and encryption. /// </summary> public class TlsServer : ServerBase { #region [ Members ] // Nested Types /// <summary> /// Represents a socket that has been wrapped /// in an <see cref="SslStream"/> for encryption. /// </summary> public sealed class TlsSocket : IDisposable { /// <summary> /// Gets the <see cref="Socket"/> connected to the remote host. /// </summary> public Socket Socket; /// <summary> /// Gets the stream through which data is passed when /// sending to or receiving from the remote host. /// </summary> public SslStream SslStream; /// <summary> /// The end point of the remote client connecting to this server. /// </summary> public IPEndPoint RemoteEndPoint; /// <summary> /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { Socket?.Dispose(); SslStream?.Dispose(); } } private class TlsClientInfo { public TransportProvider<TlsSocket> Client; public ICancellationToken TimeoutToken; public int Sending; public object SendLock; public ConcurrentQueue<TlsServerPayload> SendQueue; public ShortSynchronizedOperation DumpPayloadsOperation; public NegotiateStream NegotiateStream; public WindowsPrincipal ClientPrincipal; } private class TlsServerPayload { // Per payload state public byte[] Data; public int Offset; public int Length; public ManualResetEventSlim WaitHandle; // Per client state public TlsClientInfo ClientInfo; } // 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="NoDelay"/> property. /// </summary> public const bool DefaultNoDelay = false; /// <summary> /// Specifies the default value for the <see cref="ServerBase.ConfigurationString"/> property. /// </summary> public const string DefaultConfigurationString = "Port=8888"; // Fields private readonly SimpleCertificateChecker m_defaultCertificateChecker; private ICertificateChecker m_certificateChecker; private string m_certificateFile; private SslProtocols m_enabledSslProtocols; private byte[] m_payloadMarker; private EndianOrder m_payloadEndianOrder; private IPStack m_ipStack; private SocketAsyncEventArgs m_acceptArgs; private readonly ConcurrentDictionary<Guid, TlsClientInfo> m_clientInfoLookup; private Dictionary<string, string> m_configData; private readonly EventHandler<SocketAsyncEventArgs> m_acceptHandler; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="TcpServer"/> class. /// </summary> public TlsServer() : this(DefaultConfigurationString) { } /// <summary> /// Initializes a new instance of the <see cref="TcpServer"/> class. /// </summary> /// <param name="configString">Config string of the <see cref="TcpServer"/>. See <see cref="DefaultConfigurationString"/> for format.</param> public TlsServer(string configString) : base(TransportProtocol.Tcp, configString) { m_defaultCertificateChecker = new SimpleCertificateChecker(); LocalCertificateSelectionCallback = DefaultLocalCertificateSelectionCallback; m_enabledSslProtocols = SslProtocols.Tls12; CheckCertificateRevocation = true; TrustedCertificatesPath = DefaultTrustedCertificatesPath; PayloadAware = DefaultPayloadAware; m_payloadMarker = Payload.DefaultMarker; m_payloadEndianOrder = EndianOrder.LittleEndian; IntegratedSecurity = DefaultIntegratedSecurity; IgnoreInvalidCredentials = DefaultIgnoreInvalidCredentials; AllowDualStackSocket = DefaultAllowDualStackSocket; MaxSendQueueSize = DefaultMaxSendQueueSize; NoDelay = DefaultNoDelay; m_clientInfoLookup = new ConcurrentDictionary<Guid, TlsClientInfo>(); m_acceptHandler = (sender, args) => ProcessAccept(args); } /// <summary> /// Initializes a new instance of the <see cref="TcpServer"/> class. /// </summary> /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="TcpServer"/>.</param> public TlsServer(IContainer container) : this() => 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; set; } /// <summary> /// Gets or sets the byte sequence used to mark the beginning of a payload in a <see cref="PayloadAware"/> transmission. /// </summary> /// <remarks> /// Setting property to <c>null</c> will create a zero-length payload marker. /// </remarks> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public byte[] PayloadMarker { get => m_payloadMarker; set => m_payloadMarker = value ?? Array.Empty<byte>(); } /// <summary> /// Gets or sets the endian order to apply for encoding and decoding payload size in a <see cref="PayloadAware"/> transmission. /// </summary> /// <remarks> /// Setting property to <c>null</c> will force use of little-endian encoding. /// </remarks> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public EndianOrder PayloadEndianOrder { get => m_payloadEndianOrder; set => m_payloadEndianOrder = value ?? EndianOrder.LittleEndian; } /// <summary> /// Gets or sets a boolean value that indicates whether the client 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 client Windows account credentials are used for authentication.")] public bool IntegratedSecurity { get; set; } /// <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. When this is set /// to true, if the client's credentials are invalid, the <see cref="TryGetClientPrincipal"/> /// method will return true for that client, but the principal will still be null. /// </remarks> [Category("Security")] [DefaultValue(DefaultIgnoreInvalidCredentials)] [Description("Indicates whether the client Windows account credentials are validated during authentication.")] public bool IgnoreInvalidCredentials { get; set; } /// <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; set; } /// <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; set; } /// <summary> /// Gets or sets a boolean value that determines if small packets are delivered to the remote host without delay. /// </summary> [Category("Settings")] [DefaultValue(DefaultNoDelay)] [Description("Determines if small packets are delivered to the remote host without delay.")] public bool NoDelay { get; set; } /// <summary> /// Gets the <see cref="Socket"/> object for the <see cref="TcpServer"/>. /// </summary> [Browsable(false)] public Socket Server { get; private set; } /// <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 => m_certificateChecker ?? m_defaultCertificateChecker; set => m_certificateChecker = value; } /// <summary> /// Gets or sets the callback used to validate remote certificates. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } /// <summary> /// Gets or sets the callback used to select local certificates. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; } /// <summary> /// Gets or sets the path to the certificate used for authentication. /// </summary> [Category("Settings")] [DefaultValue(null)] [Description("Path to the local certificate used by this server for authentication.")] public string CertificateFile { get => m_certificateFile; set { if (string.IsNullOrWhiteSpace(value)) { m_certificateFile = null; Certificate = null; } else { m_certificateFile = FilePath.GetAbsolutePath(value); if (File.Exists(m_certificateFile)) Certificate = new X509Certificate2(m_certificateFile); } } } /// <summary> /// Gets or sets the certificate used to identify this server. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public X509Certificate Certificate { get; set; } /// <summary> /// Gets or sets a set of flags which determine the enabled <see cref="SslProtocols"/>. /// </summary> /// <exception cref="SecurityException">Failed to write event log entry for security warning about use of less secure TLS/SSL protocols.</exception> [Category("Settings")] [DefaultValue(SslProtocols.Tls12)] [Description("The set of SSL protocols that are enabled for this server.")] public SslProtocols EnabledSslProtocols { get => m_enabledSslProtocols; set { m_enabledSslProtocols = value; // As of July 2014, Tls12 is the latest and most secure TLS protocol - all other protocols // represent a security risk when used, as such we log a security message when any of the // older protocols are being used. if (m_enabledSslProtocols >= SslProtocols.Tls12) return; try { string applicationName; // Get application name try { // Attempt to retrieve application name as defined in common security settings - this name // is typically preconfigured as the desired event source for event log entries ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings["SecurityProvider"]; applicationName = settings["ApplicationName"].Value; } catch { applicationName = null; } // Fall back on running executable name if (string.IsNullOrWhiteSpace(applicationName)) applicationName = FilePath.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName); string message = $"One or more less secure TLS/SSL protocols \"{m_enabledSslProtocols}\" are being used by an instance of the TlsServer in {applicationName}"; EventLog.WriteEntry(applicationName, message, EventLogEntryType.Warning, 1); } catch (Exception ex) { throw new SecurityException($"Failed to write event log entry for security warning about use of less secure TLS/SSL protocols \"{m_enabledSslProtocols}\": {ex.Message}", ex); } } } /// <summary> /// Gets or sets a flag that determines whether a client certificate is required during authentication. /// </summary> [Category("Settings")] [DefaultValue(false)] [Description("True if the client certificate is required during authentication, otherwise False.")] public bool RequireClientCertificate { get; set; } /// <summary> /// Gets or sets a boolean value that determines whether the certificate revocation list is checked during authentication. /// </summary> [Category("Settings")] [DefaultValue(true)] [Description("True if the certificate revocation list is to be checked during authentication, otherwise False.")] public bool CheckCertificateRevocation { get; set; } /// <summary> /// Gets or sets the path to the directory containing the trusted certificates. /// </summary> [Category("Settings")] [DefaultValue("Trusted Certificates")] [Description("Path to the directory containing the trusted remote certificates.")] public string TrustedCertificatesPath { get; set; } /// <summary> /// Gets or sets the set of valid policy errors when validating remote certificates. /// </summary> [Category("Settings")] [DefaultValue(SslPolicyErrors.None)] [Description("Set of valid policy errors when validating remote certificates.")] public SslPolicyErrors ValidPolicyErrors { get => m_defaultCertificateChecker.ValidPolicyErrors; set => m_defaultCertificateChecker.ValidPolicyErrors = value; } /// <summary> /// Gets or sets the set of valid chain flags used when validating remote certificates. /// </summary> [Category("Settings")] [DefaultValue(X509ChainStatusFlags.NoError)] [Description("Set of valid chain flags used when validating remote certificates.")] public X509ChainStatusFlags ValidChainFlags { get => m_defaultCertificateChecker.ValidChainFlags; set => m_defaultCertificateChecker.ValidChainFlags = value; } /// <summary> /// Gets the descriptive status of the server. /// </summary> public override string Status { get { StringBuilder statusBuilder = new StringBuilder(base.Status); int count = 0; foreach (ConcurrentQueue<TlsServerPayload> sendQueue in m_clientInfoLookup.Values.Select(clientInfo => clientInfo.SendQueue)) { statusBuilder.AppendFormat(" Queued payloads: {0} for client {1}", sendQueue.Count, ++count); statusBuilder.AppendLine(); } return statusBuilder.ToString(); } } #endregion #region [ Methods ]Lines 1–500 of 1392. Load more
//****************************************************************************************************** // TlsServer.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 GSF.Configuration; using GSF.IO; using GSF.Net.Security; using GSF.Threading; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; 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.Security.Principal; using System.Text; using System.Threading; #if MONO #pragma warning disable 649 #endif namespace GSF.Communication { /// <summary> /// Represents a TCP-based communication server with SSL authentication and encryption. /// </summary> public class TlsServer : ServerBase { #region [ Members ] // Nested Types /// <summary> /// Represents a socket that has been wrapped /// in an <see cref="SslStream"/> for encryption. /// </summary> public sealed class TlsSocket : IDisposable { /// <summary> /// Gets the <see cref="Socket"/> connected to the remote host. /// </summary> public Socket Socket; /// <summary> /// Gets the stream through which data is passed when /// sending to or receiving from the remote host. /// </summary> public SslStream SslStream; /// <summary> /// The end point of the remote client connecting to this server. /// </summary> public IPEndPoint RemoteEndPoint; /// <summary> /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { Socket?.Dispose(); SslStream?.Dispose(); } } private class TlsClientInfo { public TransportProvider<TlsSocket> Client; public ICancellationToken TimeoutToken; public int Sending; public object SendLock; public ConcurrentQueue<TlsServerPayload> SendQueue; public ShortSynchronizedOperation DumpPayloadsOperation; public NegotiateStream NegotiateStream; public WindowsPrincipal ClientPrincipal; } private class TlsServerPayload { // Per payload state public byte[] Data; public int Offset; public int Length; public ManualResetEventSlim WaitHandle; // Per client state public TlsClientInfo ClientInfo; } // 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="NoDelay"/> property. /// </summary> public const bool DefaultNoDelay = false; /// <summary> /// Specifies the default value for the <see cref="ServerBase.ConfigurationString"/> property. /// </summary> public const string DefaultConfigurationString = "Port=8888"; // Fields private readonly SimpleCertificateChecker m_defaultCertificateChecker; private ICertificateChecker m_certificateChecker; private string m_certificateFile; private SslProtocols m_enabledSslProtocols; private byte[] m_payloadMarker; private EndianOrder m_payloadEndianOrder; private IPStack m_ipStack; private SocketAsyncEventArgs m_acceptArgs; private readonly ConcurrentDictionary<Guid, TlsClientInfo> m_clientInfoLookup; private Dictionary<string, string> m_configData; private readonly EventHandler<SocketAsyncEventArgs> m_acceptHandler; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="TcpServer"/> class. /// </summary> public TlsServer() : this(DefaultConfigurationString) { } /// <summary> /// Initializes a new instance of the <see cref="TcpServer"/> class. /// </summary> /// <param name="configString">Config string of the <see cref="TcpServer"/>. See <see cref="DefaultConfigurationString"/> for format.</param> public TlsServer(string configString) : base(TransportProtocol.Tcp, configString) { m_defaultCertificateChecker = new SimpleCertificateChecker(); LocalCertificateSelectionCallback = DefaultLocalCertificateSelectionCallback; m_enabledSslProtocols = SslProtocols.Tls12; CheckCertificateRevocation = true; TrustedCertificatesPath = DefaultTrustedCertificatesPath; PayloadAware = DefaultPayloadAware; m_payloadMarker = Payload.DefaultMarker; m_payloadEndianOrder = EndianOrder.LittleEndian; IntegratedSecurity = DefaultIntegratedSecurity; IgnoreInvalidCredentials = DefaultIgnoreInvalidCredentials; AllowDualStackSocket = DefaultAllowDualStackSocket; MaxSendQueueSize = DefaultMaxSendQueueSize; NoDelay = DefaultNoDelay; m_clientInfoLookup = new ConcurrentDictionary<Guid, TlsClientInfo>(); m_acceptHandler = (sender, args) => ProcessAccept(args); } /// <summary> /// Initializes a new instance of the <see cref="TcpServer"/> class. /// </summary> /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="TcpServer"/>.</param> public TlsServer(IContainer container) : this() => 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; set; } /// <summary> /// Gets or sets the byte sequence used to mark the beginning of a payload in a <see cref="PayloadAware"/> transmission. /// </summary> /// <remarks> /// Setting property to <c>null</c> will create a zero-length payload marker. /// </remarks> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public byte[] PayloadMarker { get => m_payloadMarker; set => m_payloadMarker = value ?? Array.Empty<byte>(); } /// <summary> /// Gets or sets the endian order to apply for encoding and decoding payload size in a <see cref="PayloadAware"/> transmission. /// </summary> /// <remarks> /// Setting property to <c>null</c> will force use of little-endian encoding. /// </remarks> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public EndianOrder PayloadEndianOrder { get => m_payloadEndianOrder; set => m_payloadEndianOrder = value ?? EndianOrder.LittleEndian; } /// <summary> /// Gets or sets a boolean value that indicates whether the client 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 client Windows account credentials are used for authentication.")] public bool IntegratedSecurity { get; set; } /// <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. When this is set /// to true, if the client's credentials are invalid, the <see cref="TryGetClientPrincipal"/> /// method will return true for that client, but the principal will still be null. /// </remarks> [Category("Security")] [DefaultValue(DefaultIgnoreInvalidCredentials)] [Description("Indicates whether the client Windows account credentials are validated during authentication.")] public bool IgnoreInvalidCredentials { get; set; } /// <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; set; } /// <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; set; } /// <summary> /// Gets or sets a boolean value that determines if small packets are delivered to the remote host without delay. /// </summary> [Category("Settings")] [DefaultValue(DefaultNoDelay)] [Description("Determines if small packets are delivered to the remote host without delay.")] public bool NoDelay { get; set; } /// <summary> /// Gets the <see cref="Socket"/> object for the <see cref="TcpServer"/>. /// </summary> [Browsable(false)] public Socket Server { get; private set; } /// <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 => m_certificateChecker ?? m_defaultCertificateChecker; set => m_certificateChecker = value; } /// <summary> /// Gets or sets the callback used to validate remote certificates. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } /// <summary> /// Gets or sets the callback used to select local certificates. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; } /// <summary> /// Gets or sets the path to the certificate used for authentication. /// </summary> [Category("Settings")] [DefaultValue(null)] [Description("Path to the local certificate used by this server for authentication.")] public string CertificateFile { get => m_certificateFile; set { if (string.IsNullOrWhiteSpace(value)) { m_certificateFile = null; Certificate = null; } else { m_certificateFile = FilePath.GetAbsolutePath(value); if (File.Exists(m_certificateFile)) Certificate = new X509Certificate2(m_certificateFile); } } } /// <summary> /// Gets or sets the certificate used to identify this server. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public X509Certificate Certificate { get; set; } /// <summary> /// Gets or sets a set of flags which determine the enabled <see cref="SslProtocols"/>. /// </summary> /// <exception cref="SecurityException">Failed to write event log entry for security warning about use of less secure TLS/SSL protocols.</exception> [Category("Settings")] [DefaultValue(SslProtocols.Tls12)] [Description("The set of SSL protocols that are enabled for this server.")] public SslProtocols EnabledSslProtocols { get => m_enabledSslProtocols; set { m_enabledSslProtocols = value; // As of July 2014, Tls12 is the latest and most secure TLS protocol - all other protocols // represent a security risk when used, as such we log a security message when any of the // older protocols are being used. if (m_enabledSslProtocols >= SslProtocols.Tls12) return; try { string applicationName; // Get application name try { // Attempt to retrieve application name as defined in common security settings - this name // is typically preconfigured as the desired event source for event log entries ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings["SecurityProvider"]; applicationName = settings["ApplicationName"].Value; } catch { applicationName = null; } // Fall back on running executable name if (string.IsNullOrWhiteSpace(applicationName)) applicationName = FilePath.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName); string message = $"One or more less secure TLS/SSL protocols \"{m_enabledSslProtocols}\" are being used by an instance of the TlsServer in {applicationName}"; EventLog.WriteEntry(applicationName, message, EventLogEntryType.Warning, 1); } catch (Exception ex) { throw new SecurityException($"Failed to write event log entry for security warning about use of less secure TLS/SSL protocols \"{m_enabledSslProtocols}\": {ex.Message}", ex); } } } /// <summary> /// Gets or sets a flag that determines whether a client certificate is required during authentication. /// </summary> [Category("Settings")] [DefaultValue(false)] [Description("True if the client certificate is required during authentication, otherwise False.")] public bool RequireClientCertificate { get; set; } /// <summary> /// Gets or sets a boolean value that determines whether the certificate revocation list is checked during authentication. /// </summary> [Category("Settings")] [DefaultValue(true)] [Description("True if the certificate revocation list is to be checked during authentication, otherwise False.")] public bool CheckCertificateRevocation { get; set; } /// <summary> /// Gets or sets the path to the directory containing the trusted certificates. /// </summary> [Category("Settings")] [DefaultValue("Trusted Certificates")] [Description("Path to the directory containing the trusted remote certificates.")] public string TrustedCertificatesPath { get; set; } /// <summary> /// Gets or sets the set of valid policy errors when validating remote certificates. /// </summary> [Category("Settings")] [DefaultValue(SslPolicyErrors.None)] [Description("Set of valid policy errors when validating remote certificates.")] public SslPolicyErrors ValidPolicyErrors { get => m_defaultCertificateChecker.ValidPolicyErrors; set => m_defaultCertificateChecker.ValidPolicyErrors = value; } /// <summary> /// Gets or sets the set of valid chain flags used when validating remote certificates. /// </summary> [Category("Settings")] [DefaultValue(X509ChainStatusFlags.NoError)] [Description("Set of valid chain flags used when validating remote certificates.")] public X509ChainStatusFlags ValidChainFlags { get => m_defaultCertificateChecker.ValidChainFlags; set => m_defaultCertificateChecker.ValidChainFlags = value; } /// <summary> /// Gets the descriptive status of the server. /// </summary> public override string Status { get { StringBuilder statusBuilder = new StringBuilder(base.Status); int count = 0; foreach (ConcurrentQueue<TlsServerPayload> sendQueue in m_clientInfoLookup.Values.Select(clientInfo => clientInfo.SendQueue)) { statusBuilder.AppendFormat(" Queued payloads: {0} for client {1}", sendQueue.Count, ++count); statusBuilder.AppendLine(); } return statusBuilder.ToString(); } } #endregion #region [ Methods ]