Tcp через TLS с Akka BidiFlow - PullRequest
       8

Tcp через TLS с Akka BidiFlow

0 голосов
/ 05 декабря 2018

Мы пытаемся добавить поддержку TLS для Tcp в Akka, используя BidiFlow.Нам удалось установить соединения и передать сообщения, однако, кажется, есть части рукопожатия, которые мы не можем понять.

Видимо, ограничения, которые мы сделали в коде (такие как только TLSv1.2 и 4определенные наборы шифров) не применяются на уровне рукопожатия, но мы видим ошибки при попытке передать сообщения, когда ограничения не соблюдаются.Это означает, что клиент TLSv1 может подключаться к нашему серверу TLSv1.2 (мы просто видим closing output в журнале), но клиент не уведомляется о том, что протокол не поддерживается (то же самое с неподдерживаемыми шифровальными наборами);сообщения НЕ проходят через.

Во время анализа TLS все инструменты сообщают, как будто сервер поддерживает TLSv1, v1.1 и т. д., в то время как мы хотим только v1.2

. Мы обнаружили, чтоЕдинственный способ действительно ограничить соединение - это добавить фильтры в файл java.security в jdk.

Это ожидаемое поведение?

Вот код, который выполняет согласование:

object Tls {

  def getGraph(tlsConfig: TlsConfig, role: TLSRole):
  BidiFlow[ByteString, ByteString, ByteString, ByteString, NotUsed] = {
    val sslContext = createSslContext(tlsConfig)
    val firstSession = createFirstSession(sslContext)
    createGraph(sslContext, firstSession, role)
  }

  private def createFirstSession(sslContext: SSLContext): NegotiateNewSession = {
    val negotiatedSession = TLSProtocol.NegotiateNewSession
      .withProtocols("TLSv1.2")
      .withCipherSuites(
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"
      )
      .withParameters(sslContext.getDefaultSSLParameters)

    negotiatedSession
  }

  private def createSslContext(tlsConfig: TlsConfig): SSLContext = {
    val ksTrust = createKeyStore(tlsConfig.trustStoreType, tlsConfig.trustStoreFile, tlsConfig.trustStorePass)
    val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    trustManagerFactory.init(ksTrust)

    val ksKeys = createKeyStore(tlsConfig.keyStoreType, tlsConfig.keyStoreFile, tlsConfig.keyStorePass)
    val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
    keyManagerFactory.init(ksKeys, tlsConfig.keyStorePass.toCharArray)

    val sslContext = SSLContext.getInstance("TLSv1.2")
    sslContext.init(keyManagerFactory.getKeyManagers, trustManagerFactory.getTrustManagers, new SecureRandom)
    sslContext
  }

  private def createKeyStore(storeType: String, file: String, password: String): KeyStore = {
    val keyStore: KeyStore = KeyStore.getInstance(storeType)
    keyStore.load(new FileInputStream(file), password.toCharArray)
    keyStore
  }

  private def createGraph(
                           sslContext: SSLContext,
                           firstSession: NegotiateNewSession,
                           role: TLSRole)
  : BidiFlow[ByteString, ByteString, ByteString, ByteString, NotUsed] = {

    val tls: BidiFlow[TLSProtocol.SslTlsOutbound, ByteString, ByteString, TLSProtocol.SslTlsInbound, NotUsed] =
      TLS(sslContext, firstSession, role)

    val tlsSupport: BidiFlow[ByteString, TLSProtocol.SslTlsOutbound, TLSProtocol.SslTlsInbound, ByteString, NotUsed] =
      BidiFlow.fromFlows(
        Flow[ByteString].map(TLSProtocol.SendBytes),
        Flow[TLSProtocol.SslTlsInbound].map {
          case TLSProtocol.SessionBytes(_, bytes) => bytes
          case TLSProtocol.SessionTruncated =>
            throw ProcessingException("TLS session truncated")
          case _ =>
            throw ProcessingException("Unexpected type received from TLS pipeline")
        })

    tlsSupport.atop(tls)
  }
}
...