Skip to content

Commit 55f6902

Browse files
author
Matthias Radestock
committed
allow applications to decide which SslPolicyErrors to ignore
...and thus being able to connect over ssl w/o validating the server cert, and/or w/o performing the host==cn check
1 parent dfa415d commit 55f6902

File tree

4 files changed

+86
-126
lines changed

4 files changed

+86
-126
lines changed

projects/client/RabbitMQ.Client/src/client/api/SslHelper.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,46 @@ namespace RabbitMQ.Client
7171
public class SslHelper
7272
{
7373

74-
static X509Certificate CertificateSelectionCallback(object sender,
75-
string targetHost,
76-
X509CertificateCollection localCertificates,
77-
X509Certificate remoteCertificate,
78-
string[] acceptableIssuers)
74+
private SslOption m_sslOption;
75+
76+
private X509Certificate CertificateSelectionCallback(object sender,
77+
string targetHost,
78+
X509CertificateCollection localCertificates,
79+
X509Certificate remoteCertificate,
80+
string[] acceptableIssuers)
7981
{
8082
return localCertificates[0];
8183
}
8284

85+
private bool CertificateValidationCallback(object sender,
86+
X509Certificate certificate,
87+
X509Chain chain,
88+
SslPolicyErrors sslPolicyErrors)
89+
{
90+
return (sslPolicyErrors & ~m_sslOption.AcceptablePolicyErrors) == SslPolicyErrors.None;
91+
}
92+
8393
///<summary>Upgrade a Tcp stream to an Ssl stream using the SSL options
8494
///provided</summary>
8595
public static Stream TcpUpgrade(Stream tcpStream, SslOption sslOption)
8696
{
97+
SslHelper helper = new SslHelper(sslOption);
8798
SslStream sslStream = new SslStream(tcpStream, false,
88-
null,
89-
new LocalCertificateSelectionCallback(CertificateSelectionCallback));
99+
new RemoteCertificateValidationCallback(helper.CertificateValidationCallback),
100+
new LocalCertificateSelectionCallback(helper.CertificateSelectionCallback));
90101

91102
sslStream.AuthenticateAsClient(sslOption.ServerName,
92-
sslOption.Certs,
93-
sslOption.Version,
94-
false);
103+
sslOption.Certs,
104+
sslOption.Version,
105+
false);
95106

96107
return sslStream;
97108
}
98109

110+
private SslHelper(SslOption sslOption)
111+
{
112+
m_sslOption = sslOption;
113+
}
114+
99115
}
100116
}

projects/client/RabbitMQ.Client/src/client/api/SslOption.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
//---------------------------------------------------------------------------
5757
using System;
5858
using System.Collections;
59+
using System.Net.Security;
5960
using System.Security.Authentication;
6061
using System.Security.Cryptography.X509Certificates;
6162
using RabbitMQ.Client.Impl;
@@ -134,6 +135,15 @@ public string ServerName
134135
set { m_serverName = value; }
135136
}
136137

138+
private SslPolicyErrors m_acceptablePolicyErrors = SslPolicyErrors.None;
139+
140+
///<summary>Retrieve or set the set of ssl policy errors that
141+
///are deemed acceptable</summary>
142+
public SslPolicyErrors AcceptablePolicyErrors
143+
{
144+
get { return m_acceptablePolicyErrors; }
145+
set { m_acceptablePolicyErrors = value; }
146+
}
137147

138148

139149
///<summary>Construct an SslOption specifying both the server cannonical name

projects/client/Unit/src/unit/TestSslEndpointUnverified.cs renamed to projects/client/Unit/src/unit/TestSsl.cs

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -56,51 +56,70 @@
5656
//---------------------------------------------------------------------------
5757
using NUnit.Framework;
5858
using System;
59+
using System.Net.Security;
5960
using RabbitMQ.Client;
6061

6162
[TestFixture]
62-
public class TestSslEndpointUnverified {
63+
public class TestSsl {
6364

64-
public void SendReceive(IConnection conn) {
65-
string message = "Hello C# SSL Client World";
65+
public void SendReceive(ConnectionFactory cf) {
66+
IProtocol proto = Protocols.DefaultProtocol;
67+
using (IConnection conn = cf.CreateConnection(proto, "localhost", 5671)) {
68+
IModel ch = conn.CreateModel();
69+
70+
ch.ExchangeDeclare("Exchange_TestSslEndPoint", ExchangeType.Direct);
71+
ch.QueueDeclare("Queue_TestSslEndpoint");
72+
ch.QueueBind("Queue_TestSslEndpoint", "Exchange_TestSslEndPoint", "Key_TestSslEndpoint", false, null);
73+
74+
string message = "Hello C# SSL Client World";
75+
byte[] msgBytes = System.Text.Encoding.UTF8.GetBytes(message);
76+
ch.BasicPublish("Exchange_TestSslEndPoint", "Key_TestSslEndpoint", null, msgBytes);
6677

67-
IModel ch = conn.CreateModel();
78+
bool noAck = false;
79+
BasicGetResult result = ch.BasicGet("Queue_TestSslEndpoint", noAck);
80+
byte[] body = result.Body;
81+
string resultMessage = System.Text.Encoding.UTF8.GetString(body);
6882

69-
ch.ExchangeDeclare("Exchange_TestSslEndPoint", ExchangeType.Direct);
70-
ch.QueueDeclare("Queue_TestSslEndpoint");
71-
ch.QueueBind("Queue_TestSslEndpoint", "Exchange_TestSslEndPoint", "Key_TestSslEndpoint", false, null);
72-
73-
byte[] msgBytes = System.Text.Encoding.UTF8.GetBytes(message);
74-
ch.BasicPublish("Exchange_TestSslEndPoint", "Key_TestSslEndpoint", null, msgBytes);
75-
76-
bool noAck = false;
83+
Assert.AreEqual(message, resultMessage);
84+
}
85+
}
7786

78-
BasicGetResult result = ch.BasicGet("Queue_TestSslEndpoint", noAck);
79-
byte[] body = result.Body;
87+
[Test]
88+
public void TestServerVerifiedIgnoringNameMismatch() {
89+
string sslDir = Environment.GetEnvironmentVariable("SSL_CERTS_DIR");
90+
if (null == sslDir) return;
8091

81-
string resultMessage = System.Text.Encoding.UTF8.GetString(body);
92+
ConnectionFactory cf = new ConnectionFactory();
93+
cf.Parameters.Ssl.ServerName = "*";
94+
cf.Parameters.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch;
95+
cf.Parameters.Ssl.Enabled = true;
96+
SendReceive(cf);
97+
}
8298

83-
ch.Close(200, "Closing the channel");
84-
conn.Close();
99+
[Test]
100+
public void TestServerVerified() {
101+
string sslDir = Environment.GetEnvironmentVariable("SSL_CERTS_DIR");
102+
if (null == sslDir) return;
85103

86-
Assert.AreEqual(message, resultMessage);
104+
ConnectionFactory cf = new ConnectionFactory();
105+
cf.Parameters.Ssl.ServerName = System.Net.Dns.GetHostName();
106+
cf.Parameters.Ssl.Enabled = true;
107+
SendReceive(cf);
87108
}
88109

89-
90110
[Test]
91-
public virtual void TestHostWithPort() {
111+
public void TestClientAndServerVerified() {
92112
string sslDir = Environment.GetEnvironmentVariable("SSL_CERTS_DIR");
93-
if (null == sslDir) {
94-
return;
95-
} else {
96-
ConnectionFactory cf = new ConnectionFactory();
97-
98-
cf.Parameters.Ssl.ServerName = System.Net.Dns.GetHostName();
99-
cf.Parameters.Ssl.Enabled = true;
113+
if (null == sslDir) return;
100114

101-
IProtocol proto = Protocols.DefaultProtocol;
102-
IConnection conn = cf.CreateConnection(proto, "localhost", 5671);
103-
SendReceive(conn);
104-
}
115+
ConnectionFactory cf = new ConnectionFactory();
116+
cf.Parameters.Ssl.ServerName = System.Net.Dns.GetHostName();
117+
Assert.IsNotNull(sslDir);
118+
cf.Parameters.Ssl.CertPath = sslDir + "/client/keycert.p12";
119+
string p12Password = Environment.GetEnvironmentVariable("PASSWORD");
120+
Assert.IsNotNull(p12Password, "missing PASSWORD env var");
121+
cf.Parameters.Ssl.CertPassphrase = p12Password;
122+
cf.Parameters.Ssl.Enabled = true;
123+
SendReceive(cf);
105124
}
106125
}

projects/client/Unit/src/unit/TestSslEndpointVerified.cs

Lines changed: 0 additions & 85 deletions
This file was deleted.

0 commit comments

Comments
 (0)