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

标签 c# .net postgresql ssl-certificate npgsql

我在建立与 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。这些是我采取的步骤:

  1. 修改NpgsqlClosedState.cs:

    1. 删除 using Mono.Security.Protocol.Tls; 指令及其下面的指令。
    2. 添加 using System.Net.Security; 指令。
    3. 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. 修改NpgsqlConnection.cs,删除using Mono...指令。这将导致许多关于缺失类型的错误,特别是,这些错误将涉及使用 Mono 类型的 3 组委托(delegate)/事件组合。错误总是以三个为一组出现,因为这些回调都与 Mono 的 SslClientStream 类相关。删除每三个组并将其替换为单个 ValidateServerCertificate 委托(delegate)/事件。此单个事件应在上面步骤 1.3 中使用的 SslStream 类的构造函数中使用。

  3. NpgsqlConnection.cs 的更改将在其他文件 NpgsqlConnector.csNpgsqlConnectorPool.cs 等中触发更多错误,但是修复方法是相同的,用新的 ValidateServerCertificate 替换 3 个基于 Mono 的回调。

完成所有这些后,Npgsql 可以在没有 Mono 组件的情况下使用,并且(对我来说)可以使用 SSL 证书身份验证。

我在 github 上的拉取请求可以找到 here .

关于c# - 使用 Npgsql 和 SSL 证书身份验证时出现 SSL 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17123304/

相关文章:

sql - 具有大型表的公用表表达式 (CTE)

c# - 如何只从 SqlDataReader 中获取一些行?

c# - Windows 10应用-物联网系统管理能力

c# - VS2008 调试器是否保留超出范围的对象?

sql - 从 pgadmin 导出查询结果到 excel 文件

postgresql - 通过 Intellij IDEA 连接到 Postgres Heroku DB

c# - 如何在 Entity Framework 6 中包含所有关系?

c# - 该字段必须是日期 - DatePicker 验证在 Chrome 中失败 - mvc

.net - 为什么 .NET Framework 2.0 上缺少 AutoresetEvent.WaitOne 重载

.net - VB .NET SQL 删除查询不起作用