当前位置: 首页 > 知识库问答 >
问题:

stunnel-如何在不中断的情况下更换服务器证书

司马渝
2023-03-14

我试图理解在stunnel上用于证书到期时替换的过程。因此,我在Windows上安装了一个stunnel,配置很简单:

[test1]
accept = 127.0.0.1:21234
connect = 127.0.0.1:21235
cert = p1.pem

p1.pem文件的结构如下:

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD1f+2n88ThTvLn ....
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIEFjCCAv6gAwIBAgIUHD/p+ctiyaWxZCd1LiFqC5vzKGQwDQYJKoZIhvcNAQEL ....
-----END CERTIFICATE-----

使用java客户端应用程序,我可以成功地打开到端口21234的SSL连接。

p1。pem证书是使用openssl创建的自签名证书。在p1之前。pem证书将过期。我们需要一段时间,服务器将接受两个证书(例如p1.pem和p2.pem)。

我尝试将两个文件连接到p1p2.pem其中的结构:

-----BEGIN PRIVATE KEY-----
p1 key
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
p1 cert
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
p2 key
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
p2 cert
-----END CERTIFICATE-----

当我尝试相同的java客户端应用程序时,它与p1的公共证书一起工作,但与p2的公共证书一起工作,它返回

Exception in thread "main"
javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find v alid certification path to requested target at
sun.security.ssl.Alerts.getSSLException(Unknown Source) at
sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) at
sun.security.ssl.Handshaker.fatalSE(Unknown Source) at
sun.security.ssl.Handshaker.fatalSE(Unknown Source) at
sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source) at
sun.security.ssl.ClientHandshaker.processMessage(Unknown Source) at
sun.security.ssl.Handshaker.processLoop(Unknown Source) at
sun.security.ssl.Handshaker.process_record(Unknown Source) at
sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source) at
sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) at
sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source) at
sun.security.ssl.AppOutputStream.write(Unknown Source) at
java.io.OutputStream.write(Unknown Source) at clt.main(clt.java:16) Caused by:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at
sun.security.validator.PKIXValidator.doBuild(Unknown Source) at
sun.security.validator.PKIXValidator.engineValidate(Unknown Source) at
sun.security.validator.Validator.validate(Unknown Source) at
sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source) at
sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source) at
sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) ... 10 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target at
sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source) at
sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) at
java.security.cert.CertPathBuilder.build(Unknown Source) ... 16 more

共有1个答案

葛志国
2023-03-14

TLDR:您无法转换服务器

TLS服务器(包括stunnel)一次只使用一个证书和密钥,或者如果客户端发送SNI,则可以选择每个SNI(即主机域名)使用一个证书和密钥,浏览器通常会发送SNI(至少从2010年开始),而Java的最新版本(IIRC大约在8年中期)通常会发送SNI,但这可能取决于代码如何设置和打开SSLSocket,你没有展示或描述。(如有可能,查看获取网络跟踪(如果在Windows上,则可能不是针对loopback/localhost)或使用syspropjavax运行Java。网调试=ssl,握手并查看。)这是因为客户端不向服务器提供任何有关其“想要”的CA或其他证书的信息;在1.2和1.3中,它可以指定它将接受的签名算法,但这通常不会区分旧证书和新证书。

stunnel尤其只使用cert=(或key=,如果指定)文件中的第一个私钥,虽然它可以在cert=文件中使用多个链证书,但对于给定的“服务”和SNI,它只使用第一个作为实体证书。还有你的p2。证书可能不是p1的有效链证书。证书,所以你发布的stunnel配置总是使用p1。键和p1。证书。如果“…java客户端应用程序…具有p2的公共证书”意味着您将p2而不是p1放在客户端的信任库中,那么该客户端当然不会验证与使用p1的服务器的连接。

续订或以其他方式转换(服务器)证书的正常方法是在长期有效的CA下使用CA颁发的证书,以便可以向服务器颁发新证书,并且客户端将信任该证书,因为CA继续有效且未过期。

如果您必须更换自签名证书,唯一可以在中断最少的情况下工作的方法是:

>

  • 配置客户端或所有客户端接受旧的和新的证书(这可能涉及也可能不涉及暂时关闭每个客户端,但是多个客户端可以在不同的时间完成,特别是如果它们是一个池或集群或否则共同提供某种高可用性能力),

    然后将服务器从旧的更改为新的(可以在不关机的情况下重新加载),

    然后可选地从客户端中删除old(如果有必要,这可以等到他们因其他原因下一次停机,甚至直到下一次证书替换)。

    但你可能不需要这样做。假设您使用的是具有正确含义的“自签名”——一个证书使用它包含的相同密钥签名,而不仅仅是由您签名,因此必须在客户机信任库中进行配置,因为上面没有可以用来验证它的证书——然后通过测试一个默认Java客户机(也就是说,一个使用默认验证器的客户机,正如您的代码所明确做的,并且不在外部添加任何其他验证,我们无法从这里判断),然后,即使在到期后,它也会在信任库中接受自签名证书。(奇怪的是,因为官方的APICertPathValidator确实拒绝了它。我将在以后进一步研究。)设置一个测试机器(可能是一个VM,这样你就不会有损坏任何重要文件的风险)并提前跳转它的日期,看看它是否有效,这样你就可以避免整个问题。

  •  类似资料:
    • 在我的代码中进行一系列计算后,我有了一个,其值为 然后,我需要将这个乘以,我希望计算出的值为

    • 我有一个Spring boot项目,它有使用kafka进行日志记录的依赖项。我无法摆脱所述依赖项,因为我的逻辑需要来自该依赖项的代码 我已尝试禁用自动配置 我尝试通过bean配置将missingTopicsFatal设置为false 但很明显,设置已经是假的,因为我的应用程序运行时没有失败,只是tomcat不想打开侦听端口 应用程序启动,但spring拒绝打开侦听端口,并继续使用错误进行循环 在本

    • 我有一个包含不和谐机器人代码的Python脚本。当我运行它时,它会激活不和谐机器人,并显示机器人的在线状态。但是,当我结束python脚本时,它会禁用bot。即使离线,我如何在不使用服务器的情况下保持机器人活动?

    • 问题内容: 我需要一个解决方案将String转换为字节数组,而无需像这样更改: 输入: 输出: 当我使用 那么回复是 但我希望回复是 问题答案: 您应始终确保序列化和反序列化使用相同的字符集,这会将字符映射到字节序列,反之亦然。默认情况下,String.getBytes()和新的String(bytes)使用默认字符集,该字符集可能是特定于语言环境的。 使用getBytes(Charset)重载

    • 问题内容: 我有一系列的Java小数,例如: 我希望将所有小数点后5位保留下来。这怎么可能? 问题答案: 如果您想让事情变得简单快捷。;) 版画

    • 问题内容: 我正在从数据库中获取UTC时间戳,这是我设置为JodaTime 实例的时间 它完美地存储了时间,但带有本地时区。例如,我处于IST时区,即UTC的+5:30 我尝试了很多更改时区的方法,但每件事都会通过使用+5:30时差将时间从其他时间更改为其他时间 有什么方法可以更改TimeZone而不影响当前时间 编辑:如果我当前时间是: 以下是我使用这个的结果 以下是当我使用它的结果; 问题答案