Reputation: 83
I am trying to establish a secure connection to MongoDB with the C# driver using certificate validation, but I am getting this error:
Unable to connect to server localhost:27017: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine..
Heres the error from MongoDB:
[initandlisten] connection accepted from 127.0.0.1:26163 #2 (1 connection now open)
[conn2] ERROR: no SSL certificate provided by peer; connection rejected
[conn2] SocketException handling request, closing client connection: 9001 socket exception [CONNECT_ERROR]
When I connect to MongoDB through the mongo shell with the certificate it works.
var connectionString = "mongodb://localhost";
var clientSettings = MongoClientSettings.FromUrl(new MongoUrl(connectionString));
clientSettings.SslSettings = new SslSettings();
clientSettings.UseSsl = true;
clientSettings.SslSettings.ClientCertificates = new List<X509Certificate>()
{
new X509Certificate("cert.pem")
};
clientSettings.SslSettings.EnabledSslProtocols = SslProtocols.Default;
clientSettings.SslSettings.ClientCertificateSelectionCallback =
(sender, host, certificates, certificate, issuers) => clientSettings.SslSettings.ClientCertificates.ToList()[0];
clientSettings.SslSettings.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
var client = new MongoClient(clientSettings);
Does anyone know how to get this working?
Upvotes: 8
Views: 13077
Reputation: 358
Bouncing off of tyjen's answer, it can be done entirely in C#. Assuming you have a PEM format file with both public and private key together, you can create a valid X509 cert with the following (assuming in this use case, you have a PEM file with a public key and private RSA key):
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using MongoDB.Driver;
function X509Certificate2 GetX509Pfx(String pem) {
// Note that cert is `IDisposable`
var cert = new X509Certificate2(Encoding.UTF8.GetBytes(pem)))
if (cert.HasPrivateKey) {
return cert;
} else {
// Note that rsa is `IDisposable`
var rsa = RSA.Create();
rsa.ImportFromPem(pem.AsSpan());
return cert.CopyWithPrivateKey(rsa);
}
}
function IMongoClient GetMongoClient(String connectionString, String pem) {
var cert = GetX509Pfx(pem);
var settings = MongoClientSettings.FromConnectionString(connectionString);
settings.ServerApi = new ServerApi(ServerApiVersion.V1),
settings.Credential = MongoCredential.CreateMongoX509Credential(cert.Subject),
settings.SslSettings = new SslSettings {
ClientCertificates = new List<X509Certificates> { cert }
}
return new MongoClient(settings);
}
Upvotes: 0
Reputation: 7
,ssl_ca_certs = @"/path/my.pem", added this in connection string.
settings.VerifySslCertificate = false;
Use the above line if you are testing it from local/you have root certificate but not issued to your machine, may be issued to your production host.
Put the root certificate in the absolute path and refer that path directly in connection string. Mongo driver will take care of reading private key and all. No need to put it in the certificate store or somewhere.
Upvotes: -1
Reputation: 7
//struggled a lot to figure out this
using MongoDB.Bson;
using MongoDB.Driver;
namespace Mongo_AWS
{
internal class Program
{
private static void Main(string[] args)
{
//Mention cert file in connection string itself or put at your executable location
string connectionString = @"mongodb://user:pwd@localhost:9999/?ssl=true&ssl_ca_certs=C:\Users\sivaram\Downloads\my.pem";
MongoClientSettings settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString));
//Disable certificate verification, if it is not issued for you
settings.VerifySslCertificate = false;
MongoClient client = new MongoClient(settings);
IMongoDatabase database = client.GetDatabase("test");
IMongoCollection<BsonDocument> collection = database.GetCollection<BsonDocument>("numbers");
System.Collections.Generic.List<BsonDocument> temp = collection.Find(new BsonDocument()).ToList();
BsonDocument docToInsert = new BsonDocument { { "sivaram-Pi", 3.14159 } };
collection.InsertOne(docToInsert);
}
}
}
Upvotes: 0
Reputation: 242
Realize this is out of date but for the benefit of others...
If you're not handling cert revocation lists, you need to turn that setting off since it is enabled by default.
clientSettings.SslSettings.CheckCertificateRevocation = false;
Next, the X509Certificate2 you provide to the driver must include the private key. .NET doesn't seem to pick up private keys in pem files, so you need to provide certificate in .pfx format and include the passphrase.
To create a pfx file in openssl:
openssl pkcs12 -export -in mycert.cer -inkey mycert.key -out mycert.pfx
OpenSSL will prompt you for the export passphrase, use that when creating your X509Certificate2 object:
X509Certificate2 cert = new X509Certificate2("mycert.pfx","mypassphrase");
Upvotes: 10