首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TLS 1.2握手失败与握手失败错误

TLS 1.2握手失败与握手失败错误
EN

Stack Overflow用户
提问于 2022-04-02 12:57:38
回答 1查看 2.3K关注 0票数 0

我正在尝试建立到基于Java的MQTT代理(Active MQ)的TLSV1.2连接。

我的客户拥有HSM模块中的私钥,因此我无法访问。

x509证书是可用的。

CA是自签名的.

证书详情:

签名算法: ecdsa-with-SHA256 256

公钥算法: id-ecPublicKey (256位)

曲线: prime256v1

行为观察:

服务器引发以下错误:

43 2022-04-01 23:22:26.772084 serverip clientip TLSv1.2 73 Alert (Level: Fatal, Description: Handshake Failure)

这种情况发生在客户端密钥交换之后。

41 2022-04-01 23:22:26.739193 clientip serverip TLSv1.2 303 Client Key Exchange, Certificate Verify, Change Cipher Spec, Encrypted Handshake Message

到目前为止我尝试过的:

我尝试使用由同一个CA签名的x509证书通过curl建立到同一个代理的连接。这是被接受的。因此,我的结论是,这不是一个糟糕的证书发放。

注意:我在curl命令中使用的是--不安全的,我对此没有意见,因为客户端auth是我不关心的,因为服务器正在抛出一个错误。

Observations/Assumptions:

握手失败来自服务器,发生在:

代码语言:javascript
复制
Client Hello  
Server Hello  
Server Hello, Certificate, Server Key Exchange, Certificate Request, ServerHelloDone
Certificate
Client Key Exchange, Certificate Verify, Change Cipher Spec, Encrypted Handshake Message  
Alert (Level: Fatal, Description: Handshake Failure) ( from server)

由此,我得出结论,密码套件/protocol的兼容性没有问题。

我所看到的由HSM生成的X509证书与我生成的用于验证的证书之间唯一的区别是通用的名称格式。

Wireshark说:

  • HSM生成的CN为DirectoryString: teletexString (0)
  • 手动生成的cert CN是utf-8。 CN是相同的,格式如wireshark所示不同。

我从未见过如此深入的握手,只知道TLS握手的基本知识。

服务器是托管的Kubernetes部署,因此目前很难将日志与客户端关联起来。

但是,根据观察,我看到这个消息(activemq-netty-threads)","message":"AMQ222208: SSL handshake failed for client. java.io.IOException: Sequence tag error."

我认为这是相应的代理日志。

任何前进的方向/意见都值得赞赏。

解析x509证书的结果

  1. HSM证书CN=A_00000066,OU=AA,O=Organisation Limited,L=Place,ST=State,C=C
  2. FS证书
代码语言:javascript
复制
1.2.840.113549.1.9.1=#160a726f6f74406174686572,CN=A_00000066,OU=AA,O=O,L=Place,ST=State,C=C

添加相关服务器日志

服务器上的SSL日志:

代码语言:javascript
复制
"throwable" : {
  java.security.SignatureException: Invalid encoding for signature
    at java.base/sun.security.util.ECUtil.decodeSignature(ECUtil.java:279)
    at jdk.crypto.ec/sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:477)
    at java.base/java.security.Signature$Delegate.engineVerify(Signature.java:1247)
    at java.base/java.security.Signature.verify(Signature.java:675)
    at java.base/sun.security.ssl.CertificateVerify$T12CertificateVerifyMessage.<init>(CertificateVerify.java:651)
    at java.base/sun.security.ssl.CertificateVerify$T12CertificateVerifyConsumer.consume(CertificateVerify.java:771)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:689)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
    at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1542)
    at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1556)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1440)
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1267)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1314)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:792)
    at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:475)
    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118)
  Caused by: java.io.IOException: Sequence tag error
    at java.base/sun.security.util.DerInputStream.getSequence(DerInputStream.java:336)
    at java.base/sun.security.util.ECUtil.decodeSignature(ECUtil.java:255)
    ... 32 more}

)
javax.net.ssl|WARNING|32|Thread-4 (activemq-netty-threads)|2022-04-06 10:01:32.559 UTC|SSLEngineOutputRecord.java:168|outbound has closed, ignore outbound application data

更新2:

签名已移交给锈蚀图书馆。有一个自定义函数,它使用HSM私钥根据需要对摘要签名。

示例签名: 0349003046022100838bde8a902f9ebb18cdd9bc5af263dc978a670d95770c11e2e8d29e3c7b2c28022100d345fa7245fb34c8cf710958da80a638c598c44e2cbd724571dfd9e9ade95008

实际客户端加密握手消息,之后发生故障:

代码语言:javascript
复制
Consuming ECDHE ClientKeyExchange handshake message (
"ECDH ClientKeyExchange": {
  "ecdh public": {
    0000: 04 EB B8 76 96 C5 E0 C6   20 73 F0 4C AB 93 F1 A6  ...v.... s.L....
    0010: E9 6C 64 B0 BB 72 64 A4   74 75 26 4B E2 79 C0 26  .ld..rd.tu&K.y.&
    0020: 42 C8 C8 8F D4 C5 CA EC   22 DA B5 3B 03 E8 E8 19  B......."..;....
    0030: 28 28 EF C6 9D EE 80 3A   CD A1 60 2B 62 83 52 8F  ((.....:..`+b.R.
    0040: 23 B4 5B 46 1F 76 86 00   0D DF F3 1E 6B 86 01 A4  #.[F.v......k...
    0050: 64 09 C9 80 0A 03 C6 EE   A4 AA 36 05 F4 45 7A 91  d.........6..Ez.
    0060: A5                                                 .
  },
}

更新2:更新的堆栈跟踪

代码语言:javascript
复制
javax.net.ssl|ERROR|41|Thread-16 (activemq-netty-threads)|2022-04-11 10:39:02.983 UTC|TransportContext.java:312|Fatal (HANDSHAKE_FAILURE): Invalid CertificateVerify signature (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Invalid CertificateVerify signature
      at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
      at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:307)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:254)
      at java.base/sun.security.ssl.CertificateVerify$T13CertificateVerifyMessage.<init>(CertificateVerify.java:978)
      at java.base/sun.security.ssl.CertificateVerify$T13CertificateVerifyConsumer.consume(CertificateVerify.java:1125)
      at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
      at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
      at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
      at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
      at java.base/java.security.AccessController.doPrivileged(AccessController.java:689)
      at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
      at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1542)
      at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1556)
      at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1440)
      at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1267)
      at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1314)
      at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
      at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
      at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
      at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
      at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
      at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:792)
      at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:475)
      at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
      at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
      at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
      at org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118)}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-07 04:29:25

签名已移交给锈蚀图书馆。有一个自定义函数,它使用HSM私钥根据需要对摘要签名。 示例签名: 0349003046022100838bde8a902f9ebb18cdd9bc5af263dc978a670d95770c11e2e8d29e3c7b2c28022100d345fa7245fb34c8cf710958da80a638c598c44e2cbd724571dfd9e9ade95008

假设您显示的数据实际上是二进制的十六进制,这几乎是正确的。它实际上是一个有效的(或者至少是有效格式化的) 埃克萨-西格,用于一个256位曲线,比如嵌入在(ASN.1) BITSTRING中的P-256。具体来说,03 49 00是BITSTRING的标记和长度,BITSTRING包含72个字节,没有未使用的/额外的位。这72个字节由30 46 02 21 ( 33字节) 02 21 (33字节)组成,这是一个值长度为70字节的构造序列(标记0x10 + 0x20)的正确编码,其中包含两个原始整数项(标签0x02),每个项的值长度为33个字节。

正在构建CertificateVerify消息的任何代码都应该删除前3个字节,并使用其余的。需要处理不同的长度;与本例一样,代理签名最多为72个字节,但通常为71或70个字节,有时甚至很少。比较openssl锈蚀箱: ECDSA签名大小不是64字节吗?和(在那里链接的) 如何为java.security.Signature符号方法指定签名长度和(my) Java的BouncyCastle并不总是验证OpenSSL的ECDSA签名

(PS: ClientKeyExchange消息在这里无关紧要。客户端签名总是在CertVerify消息中。对于TLS1.3以下的服务器,签名确实在ServerKeyExchange中,但这与您的情况无关。)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71717739

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档