Add SslStream Configuration for Client & Server

This commit is contained in:
Adrien JUND 2014-10-27 17:15:55 +01:00
parent 72867a26da
commit cc0ab61eb9
12 changed files with 182 additions and 31 deletions

View File

@ -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)

View File

@ -0,0 +1,44 @@
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace WebSocketSharp
{
public class ClientCertAuthConfiguration
{
/// <summary>
/// Gets or sets the certificate configuration used to authenticate the clients on the secure connection.
/// </summary>
/// <value>
/// A <see cref="X509CertificateCollection"/> that represents the certificate collection used to authenticate
/// the clients.
/// </value>
public X509CertificateCollection clientCertificates { get; set; }
/// <summary>
/// Gets or sets the Ssl protocols type enabled.
/// </summary>
/// <value>
/// The <see cref="SslProtocols"/> value that represents the protocol used for authentication.
/// </value>
public SslProtocols EnabledSslProtocols { get; set; }
/// <summary>
/// Gets or sets the verification of certificate revocation option.
/// </summary>
/// <value>
/// A Boolean value that specifies whether the certificate revocation list is checked during authentication.
/// </value>
public bool CheckCertificateRevocation { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ClientCertAuthConfiguration"/> class.
/// </summary>
public ClientCertAuthConfiguration(X509CertificateCollection clientCertificates,
SslProtocols enabledSslProtocols = SslProtocols.Default, bool checkCertificateRevocation = false)
{
this.clientCertificates = clientCertificates;
this.EnabledSslProtocols = enabledSslProtocols;
this.CheckCertificateRevocation = checkCertificateRevocation;
}
}
}

View File

@ -54,7 +54,7 @@ namespace WebSocketSharp.Net
#region Private Fields
private List<HttpListenerPrefix> _all; // host == '+'
private X509Certificate2 _cert;
private ServerCertAuthConfiguration _certConfig;
private static readonly string _defaultCertFolderPath;
private IPEndPoint _endpoint;
private Dictionary<HttpListenerPrefix, HttpListener> _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 {

View File

@ -107,7 +107,7 @@ namespace WebSocketSharp.Net
port,
secure,
httpListener.CertificateFolderPath,
httpListener.DefaultCertificate,
httpListener.DefaultCertificateConfig,
httpListener.ReuseAddress);
eps[port] = epl;

View File

@ -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 {

View File

@ -64,7 +64,7 @@ namespace WebSocketSharp.Net
private Dictionary<HttpListenerContext, HttpListenerContext> _ctxRegistry;
private object _ctxRegistrySync;
private Func<IIdentity, NetworkCredential> _credFinder;
private X509Certificate2 _defaultCert;
private ServerCertAuthConfiguration _defaultCert;
private bool _disposed;
private bool _ignoreWriteExceptions;
private bool _listening;
@ -224,7 +224,8 @@ namespace WebSocketSharp.Net
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public X509Certificate2 DefaultCertificate {
public ServerCertAuthConfiguration DefaultCertificateConfig
{
get {
CheckDisposed ();
return _defaultCert;

View File

@ -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 {

View File

@ -187,9 +187,10 @@ namespace WebSocketSharp.Server
/// A <see cref="X509Certificate2"/> that represents the certificate used to authenticate
/// the server.
/// </value>
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;
}

View File

@ -0,0 +1,53 @@
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace WebSocketSharp
{
public class ServerCertAuthConfiguration
{
/// <summary>
/// Gets or sets the certificate used to authenticate the server on the secure connection.
/// </summary>
/// <value>
/// A <see cref="X509Certificate2"/> that represents the certificate used to authenticate
/// the server.
/// </value>
public X509Certificate2 ServerCertificate { get; set; }
/// <summary>
/// Gets or sets the client certificate request option.
/// </summary>
/// <value>
/// A Boolean value that specifies whether the client must supply a certificate for authentication.
/// </value>
public bool ClientCertificateRequired { get; set; }
/// <summary>
/// Gets or sets the Ssl protocols type enabled.
/// </summary>
/// <value>
/// The <see cref="SslProtocols"/> value that represents the protocol used for authentication.
/// </value>
public SslProtocols EnabledSslProtocols { get; set; }
/// <summary>
/// Gets or sets the verification of certificate revocation option.
/// </summary>
/// <value>
/// A Boolean value that specifies whether the certificate revocation list is checked during authentication.
/// </value>
public bool CheckCertificateRevocation { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerCertAuthConfiguration"/> class.
/// </summary>
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;
}
}
}

View File

@ -60,7 +60,7 @@ namespace WebSocketSharp.Server
private System.Net.IPAddress _address;
private AuthenticationSchemes _authSchemes;
private X509Certificate2 _certificate;
private ServerCertAuthConfiguration _certificateConfig;
private Func<IIdentity, NetworkCredential> _credentialsFinder;
private TcpListener _listener;
private Logger _logger;
@ -312,15 +312,16 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// 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.
/// </summary>
/// <value>
/// A <see cref="X509Certificate2"/> that represents the certificate used to authenticate
/// A <see cref="ServerCertAuthConfiguration"/> that represents the certificate configuration used to authenticate
/// the server.
/// </value>
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;

View File

@ -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
}
}
/// <summary>
/// Gets or sets the certificate configuration used to authenticate the client on the secure connection.
/// </summary>
/// <value>
/// A <see cref="ClientCertAuthConfiguration"/> that represents the certificate configuration used to authenticate
/// the client.
/// </value>
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;
}
}
}
/// <summary>
/// Gets or sets the callback used to validate the certificate supplied by the server.
/// </summary>
@ -1343,7 +1379,13 @@ namespace WebSocketSharp
((sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =>
null));
if (_certificateConfig == null)
sslStream.AuthenticateAsClient(_uri.DnsSafeHost);
else
{
sslStream.AuthenticateAsClient(_uri.DnsSafeHost, _certificateConfig.clientCertificates,
_certificateConfig.EnabledSslProtocols, _certificateConfig.CheckCertificateRevocation);
}
_stream = sslStream;
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -67,6 +67,8 @@
<Compile Include="CloseEventArgs.cs" />
<Compile Include="ByteOrder.cs" />
<Compile Include="ErrorEventArgs.cs" />
<Compile Include="Net\ClientCertAuthConfiguration.cs" />
<Compile Include="Server\ServerCertAuthConfiguration.cs" />
<Compile Include="WebSocket.cs" />
<Compile Include="Server\WebSocketServer.cs" />
<Compile Include="Net\AuthenticationSchemes.cs" />