利用Java实现mTLS调用

编辑: admin 分类: java 发布时间: 2021-11-15 来源:互联网
目录

    本文将使用 Java作为客户端 与受 mTLS 保护的服务交互。

    为了对我们的 Java 客户端进行 ssl 配置,我们需要先设置一个 SSLContext。这简化了事情,因为 SSLContext 可用于各种 http 客户端。

    由于我们有客户端公钥和私钥,我们需要将私钥从 PEM 格式转换为 DER。

    openssl pkcs8 -topk8 -inform PEM -outform PEM -in /path/to/generated/client.key -out /path/to/generated/client.key.pkcs8 -nocrypt
    
    

    下一步是将客户端密钥加载到 Java 代码中并创建一个 KeyManagerFactory:

    String privateKeyPath = <font>"/path/to/generated/client.key.pkcs8"</font><font>;
    String publicKeyPath = </font><font>"/path/to/generated/client.crt"</font><font>;
     
    <b>final</b> byte[] publicData = Files.readAllBytes(Path.of(publicKeyPath));
    <b>final</b> byte[] privateData = Files.readAllBytes(Path.of(privateKeyPath));
     
    String privateString = <b>new</b> String(privateData, Charset.defaultCharset())
            .replace(</font><font>"-----BEGIN PRIVATE KEY-----"</font><font>, </font><font>""</font><font>)
            .replaceAll(System.lineSeparator(), </font><font>""</font><font>)
            .replace(</font><font>"-----END PRIVATE KEY-----"</font><font>, </font><font>""</font><font>);
     
    byte[] encoded = Base64.getDecoder().decode(privateString);
     
    <b>final</b> CertificateFactory certificateFactory = CertificateFactory.getInstance(</font><font>"X.509"</font><font>);
    <b>final</b> Collection<? <b>extends</b> Certificate> chain = certificateFactory.generateCertificates(
            <b>new</b> ByteArrayInputStream(publicData));
     
    Key key = KeyFactory.getInstance(</font><font>"RSA"</font><font>).generatePrivate(<b>new</b> PKCS8EncodedKeySpec(encoded));
     
    KeyStore clientKeyStore = KeyStore.getInstance(</font><font>"jks"</font><font>);
    <b>final</b> <b>char</b>[] pwdChars = </font><font>"test"</font><font>.toCharArray();
    clientKeyStore.load(<b>null</b>, <b>null</b>);
    clientKeyStore.setKeyEntry(</font><font>"test"</font><font>, key, pwdChars, chain.toArray(<b>new</b> Certificate[0]));
     
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(</font><font>"SunX509"</font><font>);
    keyManagerFactory.init(clientKeyStore, pwdChars);
    

    在上面的片段中

    • 我们从文件中读取字节。
    • 我们从公钥创建了一个证书链。
    • 我们使用私钥创建了一个密钥实例。
    • 使用链和密钥创建了一个密钥库
    • 创建了一个 KeyManagerFactory

    现在我们已经创建了一个 KeyManagerFactory 我们可以使用它来创建一个 SSLContext

    由于使用自签名证书,我们需要使用接受它们的 TrustManager。在此示例中,信任管理器将接受服务器提供的所有证书。

    TrustManager[] acceptAllTrustManager = {
                    <b>new</b> X509TrustManager() {
                        <b>public</b> X509Certificate[] getAcceptedIssuers() {
                            <b>return</b> <b>new</b> X509Certificate[0];
                        }
     
                        <b>public</b> <b>void</b> checkClientTrusted(
                                X509Certificate[] certs, String authType) {
                        }
     
                        <b>public</b> <b>void</b> checkServerTrusted(
                                X509Certificate[] certs, String authType) {
                        }
                    }
            };
    
    

    然后ssl上下文初始化。

    SSLContext sslContext = SSLContext.getInstance(<font>"TLS"</font><font>);
    sslContext.init(keyManagerFactory.getKeyManagers(), acceptAllTrustManager, <b>new</b> java.security.SecureRandom());
    
    
    

    客户端代码:

    HttpClient client = HttpClient.newBuilder()
                                         .sslContext(sslContext)
                                         .build();
     
     
     
           HttpRequest exactRequest = HttpRequest.newBuilder()
                                         .uri(URI.create(<font>"https://127.0.0.1"</font><font>))
                                         .GET()
                                         .build();
     
           <b>var</b> exactResponse = client.sendAsync(exactRequest, HttpResponse.BodyHandlers.ofString())
                                     .join();
           System.out.println(exactResponse.statusCode());
    
    
    

    我们将收到一个 404 代码,这意味着我们的请求成功进行了 mTLS 握手。

    注意:如果服务器端是使用本地 Nginx 服务,我们需要禁用主机名验证。

    <b>final</b> Properties props = System.getProperties();
    props.setProperty(<font>"jdk.internal.httpclient.disableHostnameVerification"</font><font>, Boolean.TRUE.toString());
    
    
    

    在其他客户端中,这可能需要设置一个接受所有连接的 HostVerifier

    HostnameVerifier allHostsValid = <b>new</b> HostnameVerifier() {
        <b>public</b> <b>boolean</b> verify(String hostname, SSLSession session) {
            <b>return</b> <b>true</b>;
        }
    };
    

    到此这篇关于利用Java实现mTLS调用的文章就介绍到这了,更多相关Java实现mTLS调用内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!