简体   繁体   English

使用Npgsql和SSL证书身份验证时出现SSL错误

[英]SSL errors when using Npgsql and SSL certificate authentication

I'm having trouble establishing a connection to a PostgreSQL database that is configured only to accept a valid SSL certificate. 我在建立与PostgreSQL数据库的连接时遇到问题,该数据库仅配置为接受有效的SSL证书。 I can connect using pgAdmin III with the appropriate certificate and key, but I cannot get it working with Npgsql. 我可以使用pgAdmin III连接相应的证书和密钥,但我无法使用Npgsql。 When I try to open a connection to the database, I get System.IO.IOException: The authentication or decryption has failed . 当我尝试打开与数据库的连接时,我得到System.IO.IOException: The authentication or decryption has failed Here is my code: 这是我的代码:

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

The callbacks are defined like this: 回调定义如下:

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;
}

I set breakpoints confirming that each callback was returning something valid, but still the IOException is thrown. 我设置了断点,确认每个回调都返回了有效的东西,但仍抛出IOException。

I fixed this problem by modifying the Npgsql source. 我通过修改Npgsql源来解决这个问题。 Rather than using Mono's Mono.Security.Protocol.Tls.SslClientStream , I changed it to use System.Net.Security.SslStream instead. 而不是使用Mono的Mono.Security.Protocol.Tls.SslClientStream ,我将其更改为使用System.Net.Security.SslStream These were the steps I took: 这些是我采取的步骤:

  1. Modify NpgsqlClosedState.cs : 修改NpgsqlClosedState.cs

    1. Remove the using Mono.Security.Protocol.Tls; 删除using Mono.Security.Protocol.Tls; directive and the one below it. 指令和它下面的指令。
    2. Add a using System.Net.Security; using System.Net.Security;添加一个using System.Net.Security; directive. 指示。
    3. In the NpgsqlClosedState.Open() method, where it says if (response == 'S') , changed it to: 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; } 
  2. Modify NpgsqlConnection.cs , remove the using Mono... directives. 修改NpgsqlConnection.cs ,删除using Mono...指令。 This will cause a number of errors regarding missing types, in particular, these will be regarding 3 sets of delegate/event combos that use Mono types. 这将导致关于缺失类型的许多错误,特别是这些将涉及使用Mono类型的3组委托/事件组合。 The errors will always appear in groups of three because these callbacks all tie in with Mono's SslClientStream class. 错误总是以三个为一组出现,因为这些回调都与Mono的SslClientStream类相关。 Remove each group of three and replace it with a single ValidateServerCertificate delegate/event. 删除每组三个并用一个ValidateServerCertificate委托/事件替换它。 This single event should be used in the constructor for the SslStream class that was used in step 1.3 above. 应在上面步骤1.3中使用的SslStream类的构造函数中使用此单个事件。

  3. The changes to NpgsqlConnection.cs will trigger more errors in other files NpgsqlConnector.cs , NpgsqlConnectorPool.cs etc. but the fix is the same, replace the 3 Mono-based callbacks with the new ValidateServerCertificate . NpgsqlConnection.cs的更改将在其他文件NpgsqlConnector.csNpgsqlConnectorPool.cs等中触发更多错误,但修复方法相同,用新的ValidateServerCertificate替换3个基于Mono的回调。

Once all that is done, Npgsql can be used without Mono components and with (for me) working SSL certificate authentication. 完成所有操作后,Npgsql可以在没有Mono组件的情况下使用,并且(对我来说)可以使用SSL证书身份验证。

My pull request on github can be found here . 我在github上的拉取请求可以在这里找到。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM