[英]tls mutual authentication between zuul and microservice with certificates
[英]how to add SSL certificates to okHttp mutual TLS connection?
我已经有一个 .pem 和一个 .key 文件,我不想在本地安装/导入它,只需告诉我的客户使用它们,这可能吗? 它不是自签名证书
基本上,在我的 curl 我做这样的事情:
curl --key mykey.key --cert mycert.pem https://someurl.com/my-endpoint
我已经检查了这个答案
如何在 Retrofit 中使用 ssl 证书发出 https 请求
还有这个https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java (但可能没有意义,因为我没有得到类型的对象我需要)
基本上我有我的 okHttpClient
val okHttpClient = OkHttpClient.Builder()
.sslSocketFactory(?, ?) //here I tried to call sslSocketFactory, trustManager following the example from the CustomTrust.java
.build()
任何解决方案的想法?
也检查了此文档,但 ssl 部分没有完成,也没有在示例中完成
https://square.github.io/okhttp/https/#customizing-trusted-certificates-kt-java
所以我尝试这样做(基于 okhttp 示例)
private fun trustedCertificatesInputStream(): InputStream {
val comodoRsaCertificationAuthority = (""
+ "-----BEGIN CERTIFICATE-----\n" +
"-----END CERTIFICATE-----")
return Buffer()
.writeUtf8(comodoRsaCertificationAuthority)
.inputStream()
}
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
fun createClient() : OkHttpClient {
val trustManager: X509TrustManager
val sslSocketFactory: SSLSocketFactory
try {
trustManager = trustManagerForCertificates(trustedCertificatesInputStream())
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
sslSocketFactory = sslContext.socketFactory
} catch (e: GeneralSecurityException) {
throw RuntimeException(e)
}
return OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.connectTimeout(45, TimeUnit.SECONDS)
.readTimeout(45, TimeUnit.SECONDS)
.protocols(listOf(Protocol.HTTP_1_1))
.addInterceptor(loggingInterceptor)
.build()
}
@Throws(GeneralSecurityException::class)
private fun trustManagerForCertificates(input: InputStream): X509TrustManager {
val certificateFactory: CertificateFactory = CertificateFactory.getInstance("X.509")
val certificates: Collection<Certificate?> = certificateFactory.generateCertificates(input)
val password = "password".toCharArray() // Any password will work.
val keyStore = newEmptyKeyStore(password)
for ((index, certificate) in certificates.withIndex()) {
val certificateAlias = index.toString()
keyStore.setCertificateEntry(certificateAlias, certificate)
}
// Use it to build an X509 trust manager.
val keyManagerFactory: KeyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
keyManagerFactory.init(keyStore, password)
val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(keyStore)
val trustManagers: Array<TrustManager> = trustManagerFactory.getTrustManagers()
return trustManagers[0]!! as X509TrustManager
}
@Throws(GeneralSecurityException::class)
private fun newEmptyKeyStore(password: CharArray): KeyStore {
return try {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
val inputStream: InputStream? = null // By convention, 'null' creates an empty key store.
keyStore.load(inputStream, password)
keyStore
} catch (e: IOException) {
throw AssertionError(e)
}
}
我得到一个错误
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
搜索错误似乎我应该在本地安装 SSL,我应该避免这样做,因为我无法在服务器中以这种方式安装它,有什么办法可以使它工作?
我想您想配置 TLS 相互身份验证,这就是他们的关键吗?
看看okhttp-tls ,它具有用于将证书和私钥转换为相应 Java 对象的 API。
查看您的curl
命令和java
代码,我发现它们的配置不同。 让我们先看看你的 curl 命令并分析它:
你的 curl 命令:
curl --key mykey.key --cert mycert.pem https://someurl.com/my-endpoint
curl 选项解释:
您的cacert
选项为空,因此如果您的 curl 通过,则意味着它与基于 curl 中可用的default trusted certificates
的服务器证书匹配。 curl 中的默认可信证书可能与 java 中的默认可信证书不同,因此可能导致不同的行为。 我建议将服务器证书添加到 curl 命令和 java 代码片段。
根据您的 curl 命令,我们可以将选项转换为 java:
从 curl 到 java 的映射
默认的 java 类对解析 pem 格式的私钥的支持有限。 据我所知,它只能解析未加密的私钥。 我可以推荐 Bouncy Castle 来轻松解析加密的 pem 格式的私钥。 下面的示例假设您有一个未加密的私钥。
选项1
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class App {
public static void main(String[] args) throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream trustedCertificateAsInputStream = Files.newInputStream(Paths.get("/path/to/server-certificate.pem"), StandardOpenOption.READ);
Certificate trustedCertificate = certificateFactory.generateCertificate(trustedCertificateAsInputStream);
KeyStore trustStore = createEmptyKeyStore("secret".toCharArray());
trustStore.setCertificateEntry("server-certificate", trustedCertificate);
String privateKeyContent = new String(Files.readAllBytes(Paths.get("/path/to/mykey.key")), Charset.defaultCharset())
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PRIVATE KEY-----", "");
byte[] privateKeyAsBytes = Base64.getDecoder().decode(privateKeyContent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyAsBytes);
InputStream certificateChainAsInputStream = Files.newInputStream(Paths.get("/path/to/mycert.pem"), StandardOpenOption.READ);
Certificate certificateChain = certificateFactory.generateCertificate(certificateChainAsInputStream);
KeyStore identityStore = createEmptyKeyStore("secret".toCharArray());
identityStore.setKeyEntry("client", keyFactory.generatePrivate(keySpec), "secret".toCharArray(), new Certificate[]{certificateChain});
trustedCertificateAsInputStream.close();
certificateChainAsInputStream.close();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(identityStore, "secret".toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient okHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManagers[0])
.build();
}
public static KeyStore createEmptyKeyStore(char[] keyStorePassword) throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, keyStorePassword);
return keyStore;
}
}
代码有点冗长,但它应该可以为您解决问题。
选项 2
如果您更喜欢不那么冗长的替代方案,您可以尝试以下代码片段:
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(Paths.get("/path/to/mycert.pem"), Paths.get("/path/to/mycert.pem"));
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(Paths.get("/path/to/server-certificate.pem"));
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
SSLSocketFactory sslSocketFactory = sslFactory.getSslSocketFactory();
X509ExtendedtrustManager trustManager = sslFactory.getTrustManager().orElseThrow();
OkHttpClient okHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build();
上面的库由我维护,你可以在这里找到它: GitHub - SSLContext Kickstart
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.