对如何将证书包含到 Bouncy Castle TLSSocketConnectionFactory 中有疑问?
例如,我在以前的版本中使用过这段代码,它在 TLS1.0 中运行良好:
SSLContext sslcontext = SSLContext.getInstance("TLS");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream is = new FileInputStream("c:/cert/test-tls.cer");
InputStream caInput = new BufferedInputStream(is);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
TrustManager[] tm = tmf.getTrustManagers();
sslcontext.init(kmf.getKeyManagers(), tm, null);
SSLSocketFactory sslSocketFactory = sslcontext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
Run Code Online (Sandbox Code Playgroud)
现在我必须使用 Bouncy Castle 因为 Java 1.6 不支持 TLS1.1 / TLS1.2
所以第一步是扩展 SSLSocketFactory 类..
我的是:
@Override
public void startHandshake() throws IOException {
tlsClientProtocol.connect(new DefaultTlsClient() {
@Override
public Hashtable<Integer, byte[]> getClientExtensions() throws IOException {
Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions();
if (clientExtensions == null) {
clientExtensions = new Hashtable<Integer, byte[]>();
}
//Add host_name
byte[] host_name = host.getBytes();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final DataOutputStream dos = new DataOutputStream(baos);
dos.writeShort(host_name.length + 3); // entry size
dos.writeByte(0); // name type = hostname
dos.writeShort(host_name.length);
dos.write(host_name);
dos.close();
clientExtensions.put(ExtensionType.server_name, baos.toByteArray());
return clientExtensions;
}
@Override
public TlsAuthentication getAuthentication()
throws IOException {
return new TlsAuthentication() {
@Override
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream is = new FileInputStream("c:/ascert/test-tls.cer"); //"c:/cert/test-tls.cer");
InputStream caInput = new BufferedInputStream(is);
java.security.cert.Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((java.security.cert.X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
for (org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) {
certs.add(cf.generateCertificate(new ByteArrayInputStream(c.getEncoded())));
System.out.println(c.getIssuer());
}
peertCerts = certs.toArray(new java.security.cert.Certificate[0]);
} catch (Exception e) {
System.out.println("Failed to cache server certs" + e);
throw new IOException(e);
}
}
@Override
public TlsCredentials getClientCredentials(CertificateRequest arg0)
throws IOException {
return null;
}
};
Run Code Online (Sandbox Code Playgroud)
当我运行一个简单的例子时:
public class Test {
public static void main(String[] args)
{
String url = "https://blagajne-test.fu.gov.si:9002/v1/cash_registers";
try {
URLConnection connection = new URL(url).openConnection();
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;
httpsURLConnection.setSSLSocketFactory(new TSLSocketConnectionFactory());
int responseCode = httpsURLConnection.getResponseCode();
} catch (MalformedURLException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
Run Code Online (Sandbox Code Playgroud)
}
我收到此错误:
SEVERE: null
org.bouncycastle.crypto.tls.TlsFatalAlertReceived: handshake_failure(40)
at org.bouncycastle.crypto.tls.TlsProtocol.handleAlertMessage(Unknown Source)
我不知道如何正确编写 SSLSocketFactory 以使用证书进行远程服务器的身份验证。感谢您的任何帮助。
BouncyCastle 的最新版本org.bouncycastle.jsse.provider.BouncyCastleJsseProvider在 bctls-jdk15on-159 jar 中包含一个 JSSE 提供程序(“BCJSSE”,在类中)。如果您安装此提供程序的优先级高于默认提供程序,那么您的原始代码示例应自动选择 BCJSSE 提供程序。
BCJSSE 支持 TLS 1.2 回到 JDK 1.5。在 org.bouncycastle.jsse 包中还有一些特定于 BCJSSE 的扩展,用于访问早期 JDK 中(或根本不支持)SunJSSE 不支持的 TLS 功能,例如服务器名称指示。
与 SunJSSE 相比,仍然缺少一些小功能,但对于大多数用户来说,它应该是一个简单的替代品,当然比自己实现 SSLSocketFactory 更好。
| 归档时间: |
|
| 查看次数: |
3971 次 |
| 最近记录: |