当前位置: 首页 > 知识库问答 >
问题:

在握手期间检索公共服务器证书密钥

闽康安
2023-03-14

我想使用Java应用程序在SSL/TLS握手期间检索已发送的Microsoft SQL server(2012/2014)的公共服务器证书。

我的环境第一:

  • MS SQL设置为使用强制加密

为了以编程方式实现这一点,我使用自己的信任管理器实现。请参见此处的相关代码摘录:

SSLSocket sslSocket = (SSLSocket) getFactory().createSocket(socket, host, port, true);
sslSocket.startHandshake();

getFactory():

private SSLSocketFactory getFactory() throws IOException
{
    // irrelevant code removed here
    return factory();
}

工厂():

private static SSLSocketFactory factory() throws NoSuchAlgorithmException, KeyManagementException 
{
    SSLSocketFactory factorySingleton;
    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(null, getTrustManager(), null);
    factorySingleton = ctx.getSocketFactory();

    return factorySingleton;
}

getTrustManager():

private static TrustManager[] getTrustManager()
{
    X509Certificate[] server = null;
    X509Certificate[] client = null;
    X509TrustManager tm = new X509TrustManager()
    {
        X509Certificate[] server1 = null;
        X509Certificate[] client1 = null;
        public X509Certificate[] getAcceptedIssuers()
        {
            return new X509Certificate[0];
        }

        public void checkServerTrusted(X509Certificate[] chain, String x)
        {
            server1 = chain;
            Logger.println("X509 Certificate chain: " + chain);
        }

        public void checkClientTrusted(X509Certificate[] chain, String x)
        {
            client1 = chain;
            Logger.println("X509 Certificate chain: " + chain);
        }
    };

    return new X509TrustManager[]{tm};
}

我希望调用startHandshake()会在某个时候使我的应用程序从我的SQL server接收不同的证书,并尝试调用我的自定义信任管理器来验证它们。此时,我将拥有证书(X509Certificate[]链)。但是我的信任管理器没有被调用,或者至少两个checker方法中的断点没有被调用。

这是我用来参考的MS文档之一:https://msdn.microsoft.com/en-us/library/bb879919(v=sql.110)。aspx#锚定1

"在SSL握手期间,服务器将其公钥证书发送给客户端。"

共有1个答案

淳于枫
2023-03-14

经过一周的搜索,我发现了这个问题。此处可以看到不起作用/只是一种解决方法:https://superuser.com/questions/1042525/retrieve-server-certificate-from-sql-server-2012-to-trust

问题/问题是微软使用的TDS(表格数据流)协议,这是一个包裹下面所有层和连接的应用层协议。这意味着当连接到MicrosoftSQL服务器或赛贝斯(TDS最初由赛贝斯创建)时,驱动程序必须实现此TDS协议。FreeTDS就是这样一个实现,Java有jTDS,不幸的是它大部分都死了。jTDS可以在这里找到:https://sourceforge.net/projects/jtds/files/但是在Java1.8中,数据类型发生了变化,导致jTDS发送256字节的废话到MSSQL,从而使SSL/TLS不可能。这是固定在r1286(https://sourceforge.net/p/jtds/code/commit_browser)

应用这些更改并至少使用连接字符串属性SSL=require后,请在net\sourceforge\jtds\SSL\SocketFactories中使用自定义信任管理器。java

private static TrustManager[] trustManagers()
{
    X509TrustManager tm = new X509TrustManager()
    {
        public X509Certificate[] getAcceptedIssuers()
        {
            return new X509Certificate[0];
        }

        public void checkServerTrusted(X509Certificate[] chain, String x)
        {
            // Dummy method
        }

        public void checkClientTrusted(X509Certificate[] chain, String x)
        {
            // Dummy method
        }
    };

    return new X509TrustManager[]{tm};
}

将被称为。有了这个,OP中描述的方法可以用来从服务器检索证书。这不是预期的用法,所以需要添加一些丑陋的getter/setter和诡计来实际获得证书,这种方法是以下更改:

net\Source ceforge\jtds\jdbc\SharedSocket.javaenableEncryption()更改为:

void enableEncryption(String ssl) throws IOException
{
  Logger.println("Enabling TLS encryption");
  SocketFactory sf = SocketFactories.getSocketFactory(ssl, socket);
  sslSocket = sf.createSocket(getHost(), getPort());
  SSLSocket s = (SSLSocket) sslSocket;
  s.startHandshake();
  setX509Certificates(s.getSession().getPeerCertificateChain());

  setOut(new DataOutputStream(sslSocket.getOutputStream()));
  setIn(new DataInputStream(sslSocket.getInputStream()));
}

并添加以下字段及其getter/setter:

private javax.security.cert.X509Certificate[] x509Certificates;

private void setX509Certificates(javax.security.cert.X509Certificate[] certs)
{
  x509Certificates = certs;
}

public javax.security.cert.X509Certificate[] getX509Certificates()
{
  return x509Certificates;
}

net\sourceforge\jtds\jdbc\TdsCore中。java更改negotiateSSL()以便将其包括在内:

if (sslMode != SSL_NO_ENCRYPT)
{
    socket.enableEncryption(ssl);
    setX509Certificate(socket.getX509Certificates());
}

并且再次使用与getter/setter完全相同的字段:

public javax.security.cert.X509Certificate[] getX509Certificate()
{
    return x509Certificate;
}

public void setX509Certificate(javax.security.cert.X509Certificate[] x509Certificate)
{
    this.x509Certificate = x509Certificate;
}

private javax.security.cert.X509Certificate[] x509Certificate;

对于net\sourceforge\jtds\jdbc\JtdsConnection也必须这样做。javas构造函数JtdsConnection()

调用setX509证书(BaseTds.getX509证书())后,在构造函数内部调用BaseTds.negotiateSSL()。这个类还必须包含getter/setter:

public javax.security.cert.X509Certificate[] getX509Certificates()
{
    return x509Certificates;
}

public void setX509Certificates(javax.security.cert.X509Certificate[] x509Certificates)
{
    this.x509Certificates = x509Certificates;
}

private javax.security.cert.X509Certificate[] x509Certificates;

最后,您可以创建自己的实用程序类来利用所有这些添加,如下所示:

JtdsConnection jtdsConnection = new JtdsConnection(url, <properties to be inserted>);
X509Certificate[] certs = jtdsConnection.getX509Certificates()

对于属性(它们不是您通常为jdbc找到的所有标准属性),请使用提供的DefaultProperties。addDefaultProperties()然后在新属性()对象中更改用户、密码、主机等。

附言:有人可能想知道为什么所有这些繁琐的变化。。。例如,由于许可的原因,不能提供Microsofts jdbc驱动程序,或者不想/不能使用它,这提供了一种新的选择。

 类似资料:
  • 问题内容: 我正在连接到以前成功使用过的Web服务,但是现在他们已经更改了主机名并向我发送了两个.pem文件。一个是CA,另一个是我的新客户证书。 (我将Java 1.5,Spring + Spring Web Services与Apache httpclient一起使用,但是我怀疑我的问题是证书,密钥和SSL本身。) 我已经导入了.pem文件以及从Firefox导出到cacerts中的主机的.c

  • 我有一个Spring SAML项目,它有一个JKS,其中加载了IDP的公共证书。我有一个理论问题: 如果我将发出请求的根CA或中间CA加载到JKS中,这是否足以信任IDP并验证IDP SAML消息?这样做的好处是,将来有一个共同发行人的IDP将被信任,而无需加载他们的证书。 我的理解是,IDP的实际公共证书需要在JDK中,这样Spring SAML才能验证请求,然而,请求中的X509是否足以完成这

  • 我们如何加载他们的公钥?

  • 在SSL握手期间,当客户机中启用SNI扩展时,服务器不会选择并向客户机返回所需的证书。 我有一个证书链,我已经导入到服务器上JVM的密钥库中。 由内部中间颁发CA颁发的服务器证书。 内部根CA颁发的中间证书。 自签名根CA证书。 我使用“OpenSSL s_client”进行测试。 我不知道在SSL握手过程中证书选择在服务器上是如何工作的。

  • 问题内容: 我正在尝试连接到安全的Web服务。 即使我的密钥库和信任库已正确设置,我也遇到了握手故障。 经过几天的挫败,无休止的谷歌搜索并询问周围的所有人,我发现唯一的问题是java选择在握手期间不将客户端证书发送到服务器。 特别: 服务器请求了客户端证书(CN = RootCA)-即“给我一个由根CA签名的证书” Java查看密钥库,只发现我的客户端证书由“ SubCA”签名,该证书又由“ Ro

  • 在我的应用程序中,我需要实现双向握手。以下是我使用的代码: 我有一个PEM文件,我必须从中生成密钥库。 服务器证书是本地存储的. pk12证书。 问题在于握手过程中未附加客户端证书。我使用wireshark分析数据包,它显示客户端证书长度为0。 如果我使用. pk12文件作为客户端证书,它被正确地附加。但是我必须使用PEM文件。任何解决方案!!