我在建立与 PostgreSQL 数据库的连接时遇到问题,该数据库配置为仅接受有效的 SSL 证书。我可以使用 pgAdmin III 以及适当的证书和 key 进行连接,但我无法使其与 Npgsql 一起使用。当我尝试打开与数据库的连接时,出现 System.IO.IOException: 身份验证或解密失败
。这是我的代码:
NpgsqlConnectionStringBuilder csb = new NpgsqlConnectionStringBuilder();
csb.Database = "database";
csb.Host = "psql-server";
csb.UserName = "dreamlax"; // must match Common Name of client certificate
csb.SSL = true;
csb.SslMode = SslMode.Require;
NpgsqlConnection conn = new NpgsqlConnection(csb.ConnectionString);
conn.ProvideClientCertificatesCallback += new ProvideClientCertificatesCallback(Database_ProvideClientCertificatesCallback);
conn.CertificateSelectionCallback += new CertificateSelectionCallback(Database_CertificateSelectionCallback);
conn.CertificateValidationCallback += new CertificateValidationCallback(Database_CertificateValidationCallback);
conn.PrivateKeySelectionCallback += new PrivateKeySelectionCallback(Database_PrivateKeySelectionCallback);
conn.Open(); //System.IO.IOException: The authentication or decryption has failed
回调定义如下:
static void Database_ProvideClientCertificates(X509CertificateCollection clienteCertis)
{
X509Certificate2 cert = new X509Certificate2("mycert.pfx", "passphrase");
clienteCertis.Add(cert);
}
static X509Certificate Database_CertificateSelectionCallback(X509CertificateCollection clientCerts, X509Certificate serverCert, string host, X509CertificateCollection serverRequestedCerts)
{
return clienteCertis[0];
}
static AsymmetricAlgorithm Database_PrivateKeySelectionCallback(X509Certificate cert, string host)
{
X509Cerficate2 thisCert = cert as X509Certificate2;
if (cert != null)
return cert.PrivateKey;
else
return null;
}
static bool MyCertificateValidationCallback(X509Certificate certificate, int[] certificateErrors)
{
// forego server validation for now
return true;
}
我设置了断点,确认每个回调都返回有效的内容,但仍然抛出 IOException。
最佳答案
我通过修改 Npgsql 源解决了这个问题。我没有使用 Mono 的 Mono.Security.Protocol.Tls.SslClientStream
,而是将其更改为使用 System.Net.Security.SslStream
。这些是我采取的步骤:
修改
NpgsqlClosedState.cs
:- 删除
using Mono.Security.Protocol.Tls;
指令及其下面的指令。 - 添加
using System.Net.Security;
指令。 在
NpgsqlClosedState.Open()
方法中,将if (response == 'S')
更改为:if (response == 'S') { //create empty collection X509CertificateCollection clientCertificates = new X509CertificateCollection(); //trigger the callback to fetch some certificates context.DefaultProvideClientCertificatesCallback(clientCertificates); // Create SslStream, wrapping around NpgsqlStream SslStream sstream = new SslStream(stream, true, delegate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors) { // Create callback to validate server cert here return true; }); sstream.AuthenticateAsClient(context.Host, clientCertificates, System.Security.Authentication.SslProtocols.Default, false); stream = sstream; }
- 删除
修改
NpgsqlConnection.cs
,删除using Mono...
指令。这将导致许多关于缺失类型的错误,特别是,这些错误将涉及使用 Mono 类型的 3 组委托(delegate)/事件组合。错误总是以三个为一组出现,因为这些回调都与 Mono 的SslClientStream
类相关。删除每三个组并将其替换为单个 ValidateServerCertificate 委托(delegate)/事件。此单个事件应在上面步骤 1.3 中使用的SslStream
类的构造函数中使用。对
NpgsqlConnection.cs
的更改将在其他文件NpgsqlConnector.cs
、NpgsqlConnectorPool.cs
等中触发更多错误,但是修复方法是相同的,用新的ValidateServerCertificate
替换 3 个基于 Mono 的回调。
完成所有这些后,Npgsql 可以在没有 Mono 组件的情况下使用,并且(对我来说)可以使用 SSL 证书身份验证。
我在 github 上的拉取请求可以找到 here .
关于c# - 使用 Npgsql 和 SSL 证书身份验证时出现 SSL 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17123304/