diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs index 441476d4..d1aafab3 100644 --- a/websocket-sharp/Ext.cs +++ b/websocket-sharp/Ext.cs @@ -554,10 +554,10 @@ namespace WebSocketSharp this TcpClient tcpClient, string protocol, bool secure, - X509Certificate certificate, + ServerCertAuthConfiguration certificateConfig, Logger logger) { - return new TcpListenerWebSocketContext (tcpClient, protocol, secure, certificate, logger); + return new TcpListenerWebSocketContext (tcpClient, protocol, secure, certificateConfig, logger); } internal static byte[] InternalToByteArray (this ushort value, ByteOrder order) diff --git a/websocket-sharp/Net/ClientCertAuthConfiguration.cs b/websocket-sharp/Net/ClientCertAuthConfiguration.cs new file mode 100644 index 00000000..6cabd20b --- /dev/null +++ b/websocket-sharp/Net/ClientCertAuthConfiguration.cs @@ -0,0 +1,44 @@ +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace WebSocketSharp +{ + public class ClientCertAuthConfiguration + { + /// + /// Gets or sets the certificate configuration used to authenticate the clients on the secure connection. + /// + /// + /// A that represents the certificate collection used to authenticate + /// the clients. + /// + public X509CertificateCollection clientCertificates { get; set; } + + /// + /// Gets or sets the Ssl protocols type enabled. + /// + /// + /// The value that represents the protocol used for authentication. + /// + public SslProtocols EnabledSslProtocols { get; set; } + + /// + /// Gets or sets the verification of certificate revocation option. + /// + /// + /// A Boolean value that specifies whether the certificate revocation list is checked during authentication. + /// + public bool CheckCertificateRevocation { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public ClientCertAuthConfiguration(X509CertificateCollection clientCertificates, + SslProtocols enabledSslProtocols = SslProtocols.Default, bool checkCertificateRevocation = false) + { + this.clientCertificates = clientCertificates; + this.EnabledSslProtocols = enabledSslProtocols; + this.CheckCertificateRevocation = checkCertificateRevocation; + } + } +} \ No newline at end of file diff --git a/websocket-sharp/Net/EndPointListener.cs b/websocket-sharp/Net/EndPointListener.cs index 74d52a98..46e6a7dc 100644 --- a/websocket-sharp/Net/EndPointListener.cs +++ b/websocket-sharp/Net/EndPointListener.cs @@ -54,7 +54,7 @@ namespace WebSocketSharp.Net #region Private Fields private List _all; // host == '+' - private X509Certificate2 _cert; + private ServerCertAuthConfiguration _certConfig; private static readonly string _defaultCertFolderPath; private IPEndPoint _endpoint; private Dictionary _prefixes; @@ -83,13 +83,13 @@ namespace WebSocketSharp.Net int port, bool secure, string certificateFolderPath, - X509Certificate2 defaultCertificate, + ServerCertAuthConfiguration defaultCertificate, bool reuseAddress) { if (secure) { _secure = secure; - _cert = getCertificate (port, certificateFolderPath, defaultCertificate); - if (_cert == null) + _certConfig = getCertificate (port, certificateFolderPath, defaultCertificate); + if (_certConfig == null) throw new ArgumentException ("No server certificate could be found."); } @@ -116,9 +116,10 @@ namespace WebSocketSharp.Net #region Public Properties - public X509Certificate2 Certificate { + public ServerCertAuthConfiguration CertificateConfig + { get { - return _cert; + return _certConfig; } } @@ -173,8 +174,8 @@ namespace WebSocketSharp.Net return rsa; } - private static X509Certificate2 getCertificate ( - int port, string certificateFolderPath, X509Certificate2 defaultCertificate) + private static ServerCertAuthConfiguration getCertificate( + int port, string certificateFolderPath, ServerCertAuthConfiguration defaultCertificate) { if (certificateFolderPath == null || certificateFolderPath.Length == 0) certificateFolderPath = _defaultCertFolderPath; @@ -186,7 +187,7 @@ namespace WebSocketSharp.Net var cert = new X509Certificate2 (cer); cert.PrivateKey = createRSAFromFile (key); - return cert; + return new ServerCertAuthConfiguration(cert); } } catch { diff --git a/websocket-sharp/Net/EndPointManager.cs b/websocket-sharp/Net/EndPointManager.cs index f0b2b1e0..8b135bf8 100644 --- a/websocket-sharp/Net/EndPointManager.cs +++ b/websocket-sharp/Net/EndPointManager.cs @@ -107,7 +107,7 @@ namespace WebSocketSharp.Net port, secure, httpListener.CertificateFolderPath, - httpListener.DefaultCertificate, + httpListener.DefaultCertificateConfig, httpListener.ReuseAddress); eps[port] = epl; diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs index b1b4f064..03e92a7a 100644 --- a/websocket-sharp/Net/HttpConnection.cs +++ b/websocket-sharp/Net/HttpConnection.cs @@ -87,7 +87,10 @@ namespace WebSocketSharp.Net var netStream = new NetworkStream (socket, false); if (_secure) { var sslStream = new SslStream (netStream, false); - sslStream.AuthenticateAsServer (listener.Certificate); + var certificateConfig = listener.CertificateConfig; + sslStream.AuthenticateAsServer(certificateConfig.ServerCertificate, + certificateConfig.ClientCertificateRequired, certificateConfig.EnabledSslProtocols, + certificateConfig.CheckCertificateRevocation); _stream = sslStream; } else { diff --git a/websocket-sharp/Net/HttpListener.cs b/websocket-sharp/Net/HttpListener.cs index de253457..3b5e9f55 100644 --- a/websocket-sharp/Net/HttpListener.cs +++ b/websocket-sharp/Net/HttpListener.cs @@ -64,7 +64,7 @@ namespace WebSocketSharp.Net private Dictionary _ctxRegistry; private object _ctxRegistrySync; private Func _credFinder; - private X509Certificate2 _defaultCert; + private ServerCertAuthConfiguration _defaultCert; private bool _disposed; private bool _ignoreWriteExceptions; private bool _listening; @@ -224,7 +224,8 @@ namespace WebSocketSharp.Net /// /// This listener has been closed. /// - public X509Certificate2 DefaultCertificate { + public ServerCertAuthConfiguration DefaultCertificateConfig + { get { CheckDisposed (); return _defaultCert; diff --git a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs index d571d557..38d615f4 100644 --- a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs @@ -61,7 +61,7 @@ namespace WebSocketSharp.Net.WebSockets #region Internal Constructors internal TcpListenerWebSocketContext ( - TcpClient tcpClient, string protocol, bool secure, X509Certificate certificate, Logger logger) + TcpClient tcpClient, string protocol, bool secure, ServerCertAuthConfiguration certificateConfig, Logger logger) { _tcpClient = tcpClient; _secure = secure; @@ -69,7 +69,9 @@ namespace WebSocketSharp.Net.WebSockets var netStream = tcpClient.GetStream (); if (secure) { var sslStream = new SslStream (netStream, false); - sslStream.AuthenticateAsServer (certificate); + sslStream.AuthenticateAsServer(certificateConfig.ServerCertificate, + certificateConfig.ClientCertificateRequired, certificateConfig.EnabledSslProtocols, + certificateConfig.CheckCertificateRevocation); _stream = sslStream; } else { diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs index 35a54729..1157683c 100644 --- a/websocket-sharp/Server/HttpServer.cs +++ b/websocket-sharp/Server/HttpServer.cs @@ -187,9 +187,10 @@ namespace WebSocketSharp.Server /// A that represents the certificate used to authenticate /// the server. /// - public X509Certificate2 Certificate { + public ServerCertAuthConfiguration CertificateConfig + { get { - return _listener.DefaultCertificate; + return _listener.DefaultCertificateConfig; } set { @@ -202,7 +203,7 @@ namespace WebSocketSharp.Server if (EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath)) _logger.Warn ("The server certificate associated with the port number already exists."); - _listener.DefaultCertificate = value; + _listener.DefaultCertificateConfig = value; } } @@ -508,7 +509,7 @@ namespace WebSocketSharp.Server { return _secure && !EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath) && - _listener.DefaultCertificate == null + _listener.DefaultCertificateConfig == null ? "The secure connection requires a server certificate." : null; } diff --git a/websocket-sharp/Server/ServerCertAuthConfiguration.cs b/websocket-sharp/Server/ServerCertAuthConfiguration.cs new file mode 100644 index 00000000..2f1252a1 --- /dev/null +++ b/websocket-sharp/Server/ServerCertAuthConfiguration.cs @@ -0,0 +1,53 @@ +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace WebSocketSharp +{ + public class ServerCertAuthConfiguration + { + /// + /// Gets or sets the certificate used to authenticate the server on the secure connection. + /// + /// + /// A that represents the certificate used to authenticate + /// the server. + /// + public X509Certificate2 ServerCertificate { get; set; } + + /// + /// Gets or sets the client certificate request option. + /// + /// + /// A Boolean value that specifies whether the client must supply a certificate for authentication. + /// + public bool ClientCertificateRequired { get; set; } + + /// + /// Gets or sets the Ssl protocols type enabled. + /// + /// + /// The value that represents the protocol used for authentication. + /// + public SslProtocols EnabledSslProtocols { get; set; } + + /// + /// Gets or sets the verification of certificate revocation option. + /// + /// + /// A Boolean value that specifies whether the certificate revocation list is checked during authentication. + /// + public bool CheckCertificateRevocation { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public ServerCertAuthConfiguration(X509Certificate2 serverCertificate, bool clientCertificateRequired = false, + SslProtocols enabledSslProtocols = SslProtocols.Default, bool checkCertificateRevocation = false) + { + this.ServerCertificate = serverCertificate; + this.ClientCertificateRequired = clientCertificateRequired; + this.EnabledSslProtocols = enabledSslProtocols; + this.CheckCertificateRevocation = checkCertificateRevocation; + } + } +} \ No newline at end of file diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs index 1e9b7065..efede111 100644 --- a/websocket-sharp/Server/WebSocketServer.cs +++ b/websocket-sharp/Server/WebSocketServer.cs @@ -60,7 +60,7 @@ namespace WebSocketSharp.Server private System.Net.IPAddress _address; private AuthenticationSchemes _authSchemes; - private X509Certificate2 _certificate; + private ServerCertAuthConfiguration _certificateConfig; private Func _credentialsFinder; private TcpListener _listener; private Logger _logger; @@ -312,15 +312,16 @@ namespace WebSocketSharp.Server } /// - /// Gets or sets the certificate used to authenticate the server on the secure connection. + /// Gets or sets the certificate configuration used to authenticate the server on the secure connection. /// /// - /// A that represents the certificate used to authenticate + /// A that represents the certificate configuration used to authenticate /// the server. /// - public X509Certificate2 Certificate { + public ServerCertAuthConfiguration CertificateConfig + { get { - return _certificate; + return _certificateConfig; } set { @@ -330,7 +331,7 @@ namespace WebSocketSharp.Server return; } - _certificate = value; + _certificateConfig = value; } } @@ -587,7 +588,8 @@ namespace WebSocketSharp.Server private string checkIfCertificateExists () { - return _secure && _certificate == null + return _secure && (_certificateConfig == null + || _certificateConfig != null && _certificateConfig.ServerCertificate == null) ? "The secure connection requires a server certificate." : null; } @@ -638,7 +640,7 @@ namespace WebSocketSharp.Server ThreadPool.QueueUserWorkItem ( state => { try { - var ctx = cl.GetWebSocketContext (null, _secure, _certificate, _logger); + var ctx = cl.GetWebSocketContext (null, _secure, _certificateConfig, _logger); if (_authSchemes != AuthenticationSchemes.Anonymous && !authenticateRequest (_authSchemes, ctx)) return; diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index e8056a47..2c5acaeb 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -71,6 +71,8 @@ namespace WebSocketSharp private string _base64Key; private LocalCertificateSelectionCallback _certSelectionCallback; + private ClientCertAuthConfiguration + _certificateConfig; private RemoteCertificateValidationCallback _certValidationCallback; private bool _client; @@ -461,6 +463,40 @@ namespace WebSocketSharp } } + /// + /// Gets or sets the certificate configuration used to authenticate the client on the secure connection. + /// + /// + /// A that represents the certificate configuration used to authenticate + /// the client. + /// + public ClientCertAuthConfiguration CertificateConfig + { + get + { + return _certificateConfig; + } + + set + { + lock (_forConn) + { + var msg = checkIfAvailable(false, false); + if (msg != null) + { + _logger.Error(msg); + error( + "An error has occurred in setting the server certificate configuration.", + null); + + return; + } + + _certificateConfig = value; + } + } + } + /// /// Gets or sets the callback used to validate the certificate supplied by the server. /// @@ -1343,7 +1379,13 @@ namespace WebSocketSharp ((sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => null)); - sslStream.AuthenticateAsClient (_uri.DnsSafeHost); + if (_certificateConfig == null) + sslStream.AuthenticateAsClient(_uri.DnsSafeHost); + else + { + sslStream.AuthenticateAsClient(_uri.DnsSafeHost, _certificateConfig.clientCertificates, + _certificateConfig.EnabledSslProtocols, _certificateConfig.CheckCertificateRevocation); + } _stream = sslStream; } } diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 047df93a..72dd9ae1 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -1,4 +1,4 @@ - + Debug @@ -67,6 +67,8 @@ + +