我正在尝试添加自定义逻辑以接受使用 Ktor 服务器和 Netty 到服务器的 tls 连接,我没有找到修改
trustManger
或 sslContext
的方法。
val environment = applicationEngineEnvironment {
connector {
port = 8080
}
sslConnector(
keyStore = keystore,
keyAlias = "selfsigned",
keyStorePassword = { "".toCharArray() },
privateKeyPassword = { "changeit".toCharArray() }
) {
port = 8443
trustStore = clientkeystore
}
module {
routing {
get("/204") {
call.response.status(HttpStatusCode.NoContent)
}
}
}
}
embeddedServer(Netty, environment).start(true)
这是使用密钥库的mtls,但我想控制接受客户端证书的逻辑,例如忽略客户端证书的有效性,这就是为什么我需要提供
trustManager
。
我查了源码,好像
sslContext
和trustManger
是在NettyChannelInitializer中设置的
public class NettyChannelInitializer(
private val enginePipeline: EnginePipeline,
private val environment: ApplicationEngineEnvironment,
private val callEventGroup: EventExecutorGroup,
private val engineContext: CoroutineContext,
private val userContext: CoroutineContext,
private val connector: EngineConnectorConfig,
private val requestQueueLimit: Int,
private val runningLimit: Int,
private val responseWriteTimeout: Int,
private val requestReadTimeout: Int,
private val httpServerCodec: () -> HttpServerCodec,
private val channelPipelineConfig: ChannelPipeline.() -> Unit
) : ChannelInitializer<SocketChannel>() {
private var sslContext: SslContext? = null
init {
if (connector is EngineSSLConnectorConfig) {
// It is better but netty-openssl doesn't support it
// val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
// kmf.init(ktorConnector.keyStore, password)
// password.fill('\u0000')
@Suppress("UNCHECKED_CAST")
val chain1 = connector.keyStore.getCertificateChain(connector.keyAlias).toList() as List<X509Certificate>
val certs = chain1.toList().toTypedArray()
val password = connector.privateKeyPassword()
val pk = connector.keyStore.getKey(connector.keyAlias, password) as PrivateKey
password.fill('\u0000')
sslContext = SslContextBuilder.forServer(pk, *certs).apply {
if (alpnProvider != null) {
sslProvider(alpnProvider)
ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
applicationProtocolConfig(
ApplicationProtocolConfig(
ApplicationProtocolConfig.Protocol.ALPN,
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
ApplicationProtocolNames.HTTP_2,
ApplicationProtocolNames.HTTP_1_1
)
)
}
connector.trustManagerFactory()?.let { this.trustManager(it) }
}
.build()
}
}
有没有办法使用
channelPipelineConfig
或 configureBootstrap
配置逻辑?或者我需要创建自定义 netty 引擎?
我尝试过使用
childHandler
但它从未被调用过,也许我错过了一些东西。
embeddedServer(Netty, port = 8443, configure = {
configureBootstrap = {
val certsChain = keystore2.getCertificateChain("selfsigned").toList() as List<X509Certificate>
val certs = certsChain.toTypedArray()
val password = "changeit".toCharArray()
val privateKey = keystore2.getKey("selfsigned", password) as PrivateKey
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
.also { it.init(keystore2) }
childHandler(object : ChannelInitializer<SocketChannel>() {
override fun initChannel(ch: SocketChannel) {
println("initChannel")
val sslContext = SslContextBuilder.forServer(privateKey, *certs)
.trustManager(trustManagerFactory)
.build()
val sslEngine = sslContext.newEngine(ch.alloc()).apply {
useClientMode = false
needClientAuth = false
}
ch.pipeline().addLast(SslHandler(sslEngine))
}
})
}
}, module = {
routing {
get("/204") {
call.response.status(HttpStatusCode.NoContent)
}
}
}).start(wait = true)
我已经成功使用
channelPipelineConfig
将 sslContext 添加到 Netty
embeddedServer(Netty, port = 8443, configure = {
val certsChain = keystore2.getCertificateChain("selfsigned").toList() as List<X509Certificate>
val certs = certsChain.toTypedArray()
val password = "changeit".toCharArray()
val privateKey = keystore2.getKey("selfsigned", password) as PrivateKey
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
.also { it.init(keystore2) }
channelPipelineConfig = {
val sslContext = SslContextBuilder.forServer(privateKey, *certs)
.trustManager(trustManagerFactory)
.build()
val sslEngine = sslContext.newEngine(channel().alloc()).apply {
useClientMode = false
needClientAuth = true
}
addFirst("ssl", SslHandler(sslEngine))
}
}, module = {
routing {
get("/204") {
call.response.status(HttpStatusCode.NoContent)
}
}
}).start(wait = true)