需要使用Spring和具有多别名的密钥库调用SSL双向(X509)的API rest

kr98yfug  于 2023-08-02  发布在  Spring
关注(0)|答案(1)|浏览(116)

我需要使用Spring调用一个带有SSL双向(X509)的API REST。我的JKS文件得到多别名(强制性)。
我从以下代码开始创建一个rest模板:

KeyStore clientTrustStore = getStore(trustStore, pwdTrustStore.toCharArray());
        KeyStore clientKeyStore = getStore(keyStore, pwdKeyStore.toCharArray());

        SSLContext sslContext = new SSLContextBuilder()
            .setKeyStoreType(JAVA_KEYSTORE)
//.setKeyManagerFactoryAlgorithm(...)
            .loadKeyMaterial(clientKeyStore, aliasPwd.toCharArray(), new KeyStrategy(alias))
            .loadTrustMaterial(clientTrustStore, new TrustSelfSignedStrategy())
            .build();
        SSLConnectionSocketFactory sslConFactory = new SSLConnectionSocketFactory(sslContext);
        try (CloseableHttpClient httpClient =      HttpClients.custom().setSSLSocketFactory(sslConFactory).build()) {

            restTemplateBuilder.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient));
        }

        this.restTemplate = restTemplateBuilder.build();

字符串
对于那些知道它是如何工作的人来说,它使用SunX509KeyManagerImpl.class(JDK 8)来使用该算法解析密钥库

SunX509KeyManagerImpl(KeyStore ks, char[] password)
            throws KeyStoreException,
            NoSuchAlgorithmException, UnrecoverableKeyException {

        credentialsMap = new HashMap<String,X509Credentials>();
        serverAliasCache = Collections.synchronizedMap(
                            new HashMap<String,String[]>());
        if (ks == null) {
            return;
        }

        for (Enumeration<String> aliases = ks.aliases();
                                        aliases.hasMoreElements(); ) {
            String alias = aliases.nextElement();
            if (!ks.isKeyEntry(alias)) {
                continue;
            }
            Key key = ks.getKey(alias, password);
            if (key instanceof PrivateKey == false) {
                continue;
            }
            Certificate[] certs = ks.getCertificateChain(alias);
            if ((certs == null) || (certs.length == 0) ||
                    !(certs[0] instanceof X509Certificate)) {
                continue;
            }
            if (!(certs instanceof X509Certificate[])) {
                Certificate[] tmp = new X509Certificate[certs.length];
                System.arraycopy(certs, 0, tmp, 0, certs.length);
                certs = tmp;
            }

            X509Credentials cred = new X509Credentials((PrivateKey)key,
                (X509Certificate[])certs);
            credentialsMap.put(alias, cred);
            if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
                SSLLogger.fine("found key for : " + alias, (Object[])certs);
            }
        }
    }


正如您在for旁边看到的,它使用枚举提取别名列表,并使用密码和列表的第一个随机别名执行getKey。当duo别名/pwd错误时,它会抛出异常java.security.UnrecoverableKeyException: Cannot recover key
我不明白为什么我不能过滤将要测试的别名,或者所有的别名必须有相同的密码?:).我看到我可以使用setKeyManagerFactoryAlgorithm来创建一个自定义的KeyManager(不使用de SunX 509 KeyManagerImpl),但我想知道它是否是真实的的好解决方案,以达到我的目标.
我不想重新发明轮子
谢谢你的回复

vh0rcniy

vh0rcniy1#

看起来我可以从密钥存储库中提取密钥,并在内存中创建只有一个别名的密钥存储库。

private static KeyStore createUnaryKeyStore(String alias, String aliasPwd, KeyStore clientKeyStore) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, CertificateException {
    Key key = clientKeyStore.getKey(alias, aliasPwd.toCharArray());
    Certificate[] certificateChain = clientKeyStore.getCertificateChain(alias);

    KeyStore tempUnaryKeystore = KeyStore.getInstance(JAVA_KEYSTORE);
    tempUnaryKeystore.load(null);
    tempUnaryKeystore.setKeyEntry (alias, key, aliasPwd.toCharArray(), certificateChain);
    return tempUnaryKeystore;
}

字符串
所以我将用它来调用我的REST API

相关问题