如何正确地创建一个用于双向 TLS 的 SSLSocketFactory?(适用于 ApplePay)

huangapple go评论85阅读模式
英文:

How to properly create an SSLSocketFactory for 2 way TLS? (For ApplePay)

问题

以下是您提供的内容的翻译部分:

我正在尝试使用Java向ApplePay发出请求,但无法成功。

以下是curl请求:

$ curl -X POST --cert-type P12 --cert cert.p12 https://apple-pay-gateway-pr-pod1.apple.com/paymentservices/startSession -d '{}'
{
  "statusMessage": "Payment Services Exception Invalid session request",
  "statusCode": "400"
}

这在一定程度上是正常的,因为它能够与苹果服务器通信。

以下是我生成新的Feign客户端SSLContextFactory的代码(使用Kotlin编写):

@Bean
fun client(): Client { // 一个Feign客户端
    val keystoreFile = File("/path/to/cert.p12")

    val keyStore = KeyStore.getInstance("PKCS12")
    keyStore.load(keystoreFile.inputStream(), null)
    val keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
    keyFactory.init(keyStore, null)
    val trustManagerFactory = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm()
    )
    trustManagerFactory.init(keyStore)
    val trustManagers = trustManagerFactory.trustManagers
    val trustManager = trustManagers[0] as X509TrustManager
    val sslContext: SSLContext = SSLContext.getInstance("TLS")
    sslContext.init(keyFactory.keyManagers, trustManagers, null)

    return feign.okhttp.OkHttpClient(
        FeignConfiguration.enrichOkHttpClientBuilder(logbook)
            .sslSocketFactory(sslContext.socketFactory, trustManager)
            .connectionSpecs(
                arrayListOf(
                    ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                        .tlsVersions(TlsVersion.TLS_1_2)
                        .cipherSuites(
                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
                            CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
                            CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256
                        )
                        .build()
                )
            )
            .build()
    )
}

但是,当我尝试向相同的URL发出请求时,我收到以下错误:

feign.RetryableException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty executing POST https://apple-pay-gateway-pr-pod1.apple.com/paymentservices/startSession/paymentSession

有人知道我可能做错了什么吗?

英文:

I'm trying to make a request to ApplePay but am not able to do it with Java.

Here's the curl request:

$ curl -X POST --cert-type P12 --cert cert.p12 https://apple-pay-gateway-pr-pod1.apple.com/paymentservices/startSession -d '{}'
{
  "statusMessage": "Payment Services Exception Invalid session request",
  "statusCode": "400"
}

which is normal to the extent that it's able to communicate with the apple server.

Here's my code to generate a new Feign client SSLContextFactory (written in Kotlin):

   @Bean
    fun client(): Client { // a Feign Client
        val keystoreFile = File("/path/to/cert.p12")

        val keyStore = KeyStore.getInstance("PKCS12")
        keyStore.load(keystoreFile.inputStream(), null)
        val keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyFactory.init(keyStore, null)
        val trustManagerFactory = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm()
        )
        trustManagerFactory.init(keyStore)
        val trustManagers = trustManagerFactory.trustManagers
        val trustManager = trustManagers[0] as X509TrustManager
        val sslContext: SSLContext = SSLContext.getInstance("TLS")
        sslContext.init(keyFactory.keyManagers, trustManagers, null)

        return feign.okhttp.OkHttpClient(
            FeignConfiguration.enrichOkHttpClientBuilder(logbook)
                .sslSocketFactory(sslContext.socketFactory, trustManager)
                .connectionSpecs(
                    arrayListOf(
                        ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                            .tlsVersions(TlsVersion.TLS_1_2)
                            .cipherSuites(
                                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
                                , CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
                                , CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
                                , CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
                                , CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
                                , CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256
                                , CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256
                            )
                            .build()
                    )
                )
            .build()
        )
    }

But when I try to make a request to the same URL, I get the following error:

feign.RetryableException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty executing POST https://apple-pay-gateway-pr-pod1.apple.com/paymentservices/startSession/paymentSession

Anyone have an idea of what I may be doing wrong?

答案1

得分: 1

以下是翻译好的部分:

我的技术负责人能够帮助解决这个问题,但 @dave_thompson_085 的答案也应该有所帮助。

所以,我基本上将 feign 客户端部分之前的代码替换为:

        val keystoreStream = <stream>;

        val keyStore = KeyStore.getInstance("PKCS12")
        keyStore.load(keystoreStream, keystorePassword.toCharArray())

        val sslContext: SSLContext = SSLContexts.custom()
            .loadTrustMaterial(null, TrustSelfSignedStrategy())
            .loadKeyMaterial(keyStore, keystorePassword.toCharArray())
            .build()

        val tmf = TrustManagerFactory
            .getInstance(TrustManagerFactory.getDefaultAlgorithm())
        tmf.init(keyStore) // 可以使用 tmf 获取单独的 TrustManager
英文:

My tech lead was able to help resolve this, but @dave_thompson_085 's answer should also help.

So I basically replaced the parts before the feign client stuff with:

        val keystoreStream = &lt;stream&gt;

        val keyStore = KeyStore.getInstance(&quot;PKCS12&quot;)
        keyStore.load(keystoreStream, keystorePassword.toCharArray())

        val sslContext: SSLContext = SSLContexts.custom()
            .loadTrustMaterial(null, TrustSelfSignedStrategy())
            .loadKeyMaterial(keyStore, keystorePassword.toCharArray())
            .build()

        val tmf = TrustManagerFactory
            .getInstance(TrustManagerFactory.getDefaultAlgorithm())
        tmf.init(keyStore) // can use tmf to get individual trustmanager

huangapple
  • 本文由 发表于 2020年4月8日 12:23:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/61093306.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定