使用客户端证书与Twitter Finagle

3

我的服务器正在使用TLSv1.2协议,并要求客户端证书认证才能建立连接。我可以用CURL向服务器发送请求(此请求运行正常):

curl --data "SAMPLETEXT" https://myserver.com/webservice --insecure --key privkey.pem --cert certificate.cert

是的,服务器有自签名证书,并需要--insecure标志;不,我无法修复这个问题。 现在,我想创建客户端以从Scala代码发送请求。 MyClient是包含所需密码和路径的对象。为此,我创建了SSLContext

  private val keyStore = {
    //Setting up BouncyCastle provider for message signing
    Security.addProvider(new BouncyCastleProvider())
    //Loading keystore from specified file
    val clientStore = KeyStore.getInstance("JKS")
    val inputStream = new FileInputStream(MyClient.keystore)
    clientStore.load(inputStream, MyClient.keystorePassword.toCharArray)
    inputStream.close()
    clientStore
  }

  //Retrieving certificate and key
  private val cert = keyStore.getCertificate(MyClient.keyAlias).asInstanceOf[X509Certificate]
  private val key = keyStore.getKey(MyClient.keyAlias, MyClient.keystorePassword.toCharArray).asInstanceOf[PrivateKey]

  //Creating SSL context
  private val sslContext = {
    val context = SSLContext.getInstance("TLS")
    val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    val kmf: KeyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
    kmf.init(keyStore, MyClient.keystorePassword.toCharArray)
    tmf.init(keyStore)
    context.init(kmf.getKeyManagers, tmf.getTrustManagers, null)
    context
  }

然后使用它构建客户端:

  private val httpClient =
  richHttpBuilder(HttpEndpoint(baseUri))
    .hostConnectionLimit(1)
    .tlsWithoutValidation()
    .tls(sslContext, Some(MyClient.host))
    .build()

但我仍然遇到了错误:

未来返回了一个类型为:
com.twitter.finagle.ChannelWriteException的异常,信息为:
com.twitter.finagle.SslHandshakeException:常规SSLEngine问题
远程地址为:

我做错了什么?

1个回答

3

我花了一个星期才意识到我的错误。

.tlsWithoutValidation().tls(sslContext, Some(MyClient.host))选项不能同时使用,因为它们配置了构建器的相同属性(Transport.TLSClientEngine)。

有三种解决方案。

  1. Use proper server certificate. This one is unapplicable, unfortunately.

  2. Add server certificate to keystore. It will be marked as trusted, and client will happily work without tlsWithoutValidation.

  3. Use ignorant trust manager that doesn't validates anything:

      private[this] class IgnorantTrustManager extends X509TrustManager {
        def getAcceptedIssuers(): Array[X509Certificate] = new Array[X509Certificate](0)
        def checkClientTrusted(certs: Array[X509Certificate], authType: String) {
        }
        def checkServerTrusted(certs: Array[X509Certificate], authType: String) {
        }
      }
    

    Then use it as trust manager:

    context.init(kmf.getKeyManagers, new IgnorantTrustManager(), null)
    

    tlsWithoutValidation option must be removed:

      richHttpBuilder(HttpEndpoint(baseUri))
        .hostConnectionLimit(1)
        .tls(sslContext, Some(YandexClient.host))
        .build()
    

    This solution eliminates the whole purpose of certificates, so it should be used for tests only.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接