我想使用Java应用程序在SSL/TLS握手期间检索已发送的Microsoft SQL server(2012/2014)的公共服务器证书。
我的环境第一:
为了以编程方式实现这一点,我使用自己的信任管理器实现。请参见此处的相关代码摘录:
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握手期间,服务器将其公钥证书发送给客户端。"
经过一周的搜索,我发现了这个问题。此处可以看到不起作用/只是一种解决方法: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.java
将enableEncryption()
更改为:
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也必须这样做。java
s构造函数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文件。任何解决方案!!