【问题标题】:Add a certificate to BouncyCastle TLSSocketConnectionFactory向 BouncyCastle TLSSocketConnectionFactory 添加证书
【发布时间】:2018-03-19 10:05:37
【问题描述】:

对如何在 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);

现在我必须使用 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;
                    }

                };

当我运行一个简单的例子时:

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

}

}

我收到此错误: SEVERE: null org.bouncycastle.crypto.tls.TlsFatalAlertReceived: handshake_failure(40) at org.bouncycastle.crypto.tls.TlsProtocol.handleAlertMessage(Unknown Source)

我不知道如何正确编写 SSLSocketFactory 以使用证书与远程服务器进行身份验证。感谢您的帮助。

【问题讨论】:

    标签: java bouncycastle


    【解决方案1】:

    最新版本的 BouncyCastle 在 bctls-jdk15on-159 jar 中包含一个 JSSE 提供程序(“BCJSSE”,在 org.bouncycastle.jsse.provider.BouncyCastleJsseProvider 类中)。如果您安装此提供程序的优先级高于默认提供程序,那么您的原始代码示例应自动选择 BCJSSE 提供程序。

    BCJSSE 支持 TLS 1.2 到 JDK 1.5。 org.bouncycastle.jsse 包中还有一些特定于 BCJSSE 的扩展,用于访问 SunJSSE 在早期 JDK(或根本不支持)中不支持的 TLS 功能,例如服务器名称指示。

    与 SunJSSE 相比,仍然缺少一些小功能,但对于大多数用户来说,它应该是一个直接的替代品,肯定比自己实现 SSLSocketFactory 更好。

    【讨论】:

    • 嗨彼得,你能告诉我怎么做吗?我已将 Security.addProvider(new BouncyCastleProvider()) 添加到静态块中。问题出在我的位置:SSLContext sslcontext = SSLContext.getInstance("TLS");
    • 如果我添加 security.provider.1=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider,那么我得到:20.3.2018 10:02:18 org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertRaised WARNING :客户端引发致命(2)内部错误(80)警报:无法读取记录 java.lang.IllegalStateException:java.security.InvalidKeyException:org.bouncycastle.tls.crypto.impl.jcajce.JceAEADCipherImpl.init 处的密钥大小非法(未知来源)
    • 您是否为正在使用的 JDK 安装了 JCE Unlimited Strength Jurisdiction Policy Files?
    • 好的。已经从 Oracle 网页下载了一个文件,并将 US_export_policy.jar 和 local_policy.jar 解压缩到我的 JAVA_HOME\jre\lib\security 文件夹中。(我已经用存档中的这个文件覆盖了现有文件)。但我得到相同的错误:javax.net.ssl.SSLHandshakeException:收到致命警报:com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) 上的握手失败。 ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) 位于 com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720) (该异常过长,无法在此处发布)。 .
    • 这是我的例子:docs.google.com/document/d/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2013-08-09
    相关资源
    最近更新 更多