All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.netty4.ssl.server.Netty4ServerSslConfigurations.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finagle.netty4.ssl.server

import com.twitter.finagle.netty4.ssl.FinalizedSslContext
import com.twitter.finagle.netty4.ssl.Netty4SslConfigurations
import com.twitter.finagle.ssl.ApplicationProtocols
import com.twitter.finagle.ssl.CipherSuites
import com.twitter.finagle.ssl.Engine
import com.twitter.finagle.ssl.KeyCredentials
import com.twitter.finagle.ssl.SslConfigurationException
import com.twitter.finagle.ssl.server.SslServerConfiguration
import com.twitter.finagle.ssl.server.SslServerEngineFactory
import com.twitter.util.Return
import com.twitter.util.security.PrivateKeyFile
import com.twitter.util.security.X509CertificateFile
import io.netty.buffer.ByteBufAllocator
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol
import io.netty.handler.ssl.SslContext
import io.netty.handler.ssl.SslContextBuilder
import scala.collection.JavaConverters._

/**
 * Convenience functions for setting values on a Netty `SslContextBuilder`
 * which are applicable to server configurations and engines.
 */
private[finagle] object Netty4ServerSslConfigurations {

  /**
   * Configures the application protocols of the `SslContextBuilder`. This
   * method mutates the `SslContextBuilder`, and returns it as the result.
   *
   * @note This sets which application level protocol negotiation to
   * use NPN and ALPN.
   *
   * @note This also sets the `SelectorFailureBehavior` to NO_ADVERTISE,
   * and the `SelectedListenerFailureBehavior` to ACCEPT as those are the
   * only modes supported by both JDK and Native engines.
   */
  private def configureServerApplicationProtocols(
    builder: SslContextBuilder,
    applicationProtocols: ApplicationProtocols,
    forceJdk: Boolean
  ): SslContextBuilder = {
    // JDK provider does not support NPN_AND_ALPN protocol, so if forceJDK is true we default to ALPN only
    val protocol = if (forceJdk) Protocol.ALPN else Protocol.NPN_AND_ALPN
    Netty4SslConfigurations.configureApplicationProtocols(
      builder,
      applicationProtocols,
      protocol
    )
  }

  /**
   * Creates an `SslContextBuilder` for a server with the supplied `KeyCredentials`.
   *
   * @note `KeyCredentials` must be specified, using `Unspecified` is not supported.
   * @note An `SslConfigurationException` will be thrown if there is an issue loading
   * the certificate(s) or private key.
   *
   * @note Will not validate the validity for certificates when configured
   *       with [[KeyCredentials.KeyManagerFactory]] in contrast to when
   *       configured with [[KeyCredentials.CertAndKey]], [[KeyCredentials.CertsAndKey]],
   *       or [[KeyCredentials.CertKeyAndChain]].
   */
  private def startServerWithKey(keyCredentials: KeyCredentials): SslContextBuilder = {
    val builder = keyCredentials match {
      case KeyCredentials.Unspecified =>
        throw SslConfigurationException.notSupported(
          "KeyCredentials.Unspecified",
          "Netty4ServerEngineFactory"
        )
      case KeyCredentials.CertAndKey(certFile, keyFile) =>
        for {
          key <- new PrivateKeyFile(keyFile).readPrivateKey()
          cert <- new X509CertificateFile(certFile).readX509Certificate()
        } yield SslContextBuilder.forServer(key, cert)
      case KeyCredentials.CertsAndKey(certsFile, keyFile) =>
        for {
          key <- new PrivateKeyFile(keyFile).readPrivateKey()
          certs <- new X509CertificateFile(certsFile).readX509Certificates()
        } yield SslContextBuilder.forServer(key, certs: _*)
      case KeyCredentials.CertKeyAndChain(certFile, keyFile, chainFile) =>
        for {
          key <- new PrivateKeyFile(keyFile).readPrivateKey()
          cert <- new X509CertificateFile(certFile).readX509Certificate()
          chain <- new X509CertificateFile(chainFile).readX509Certificates()
        } yield SslContextBuilder.forServer(key, cert +: chain: _*)
      case KeyCredentials.KeyManagerFactory(keyManagerFactory) =>
        Return(SslContextBuilder.forServer(keyManagerFactory))
    }
    Netty4SslConfigurations.unwrapTryContextBuilder(builder)
  }

  /**
   * Creates an `SslContext` based on the supplied `SslServerConfiguration`. This method uses
   * the `KeyCredentials`, `TrustCredentials`, `CipherSuites`, and `ApplicationProtocols` from the provided
   * configuration, and forces the JDK provider if forceJdk is true.
   */
  def createServerContext(config: SslServerConfiguration, forceJdk: Boolean): SslContext = {
    val builder = startServerWithKey(config.keyCredentials)
    val withProvider = Netty4SslConfigurations.configureProvider(builder, forceJdk)
    val withTrust = Netty4SslConfigurations.configureTrust(withProvider, config.trustCredentials)
    val withCiphers = config.cipherSuites match {
      case CipherSuites.Enabled(s) => withTrust.ciphers(s.asJava)
      case _ => withTrust
    }
    val withAppProtocols = Netty4ServerSslConfigurations.configureServerApplicationProtocols(
      withCiphers,
      config.applicationProtocols,
      forceJdk
    )

    // We only want to use the `FinalizedSslContext` if we're using the non-JDK implementation.
    if (!forceJdk) new FinalizedSslContext(withAppProtocols.build())
    else withAppProtocols.build()
  }

  /**
   * Creates an `Engine` based on the supplied `SslContext` and `ByteBufAllocator`, and then
   * configures the underlying `SSLEngine` based on the supplied `SslServerConfiguration`.
   */
  def createServerEngine(
    config: SslServerConfiguration,
    context: SslContext,
    allocator: ByteBufAllocator
  ): Engine = {
    val engine = new Engine(context.newEngine(allocator))
    SslServerEngineFactory.configureEngine(engine, config)
    engine
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy