无法验证ECDH ServerKeyExchange签名问题排查求助
阿里云云鉴权initFaceVerify接口SSL握手异常排查方案
问题描述
调用阿里云云鉴权initFaceVerify接口时出现SSL握手异常,错误提示为无法验证ECDH ServerKeyExchange签名。
环境信息
- 目标域名:
cloudauth.aliyuncs.com - 依赖组件:
okhttp-3.12.13.jartea-util-0.2.21.jartea-1.2.0.jar
- 操作系统:Alpine 3.9.4
- OpenJDK版本:
1.8.0_275
异常栈信息
com.aliyun.tea.TeaUnretryableException: 无法验证ECDH ServerKeyExchange签名 at com.aliyun.teaopenapi.Client.doRequest(Client.java:865) at com.aliyun.teaopenapi.Client.callApi(Client.java:1022) at com.aliyun.cloudauth20190307.Client.initFaceVerifyWithOptions(Client.java:893) at com.aliyun.cloudauth20190307.Client.initFaceVerify(Client.java:898) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: com.aliyun.tea.TeaRetryableException: 无法验证ECDH ServerKeyExchange签名 at com.aliyun.tea.Tea.doAction(Tea.java:70) at com.aliyun.tea.Tea.doAction(Tea.java:82) at com.aliyun.teaopenapi.Client.doRequest(Client.java:784) ... 48 common frames omitted Caused by: javax.net.ssl.SSLHandshakeException: 无法验证ECDH ServerKeyExchange签名 at sun.security.ssl.Alert.createSSLException(Alert.java:131) at sun.security.ssl.TransportContext.fatal(TransportContext.java:324) at sun.security.ssl.TransportContext.fatal(TransportContext.java:267) at sun.security.ssl.ECDHServerKeyExchange$ECDHServerKeyExchangeMessage.<init>(ECDHServerKeyExchange.java:325) at sun.security.ssl.ECDHServerKeyExchange$ECDHServerKeyExchangeConsumer.consume(ECDHServerKeyExchange.java:527) at sun.security.ssl.ServerKeyExchange$ServerKeyExchangeConsumer.consume(ServerKeyExchange.java:111) at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:377) at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444) at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:422) at sun.security.ssl.TransportContext.dispatch(TransportContext.java:182) at sun.security.ssl.SSLTransport.decode(SSLTransport.java:149) at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1143) at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1054) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:394) at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:320) at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:284) at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:169) at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:258) at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135) at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114) at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:127) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:257) at okhttp3.RealCall.execute(RealCall.java:93) at com.aliyun.tea.Tea.doAction(Tea.java:67) ... 50 common frames omitted Caused by: java.security.SignatureException: 无法验证签名 at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:413) at java.security.Signature$Delegate.engineVerify(Signature.java:1394) at java.security.Signature.verify(Signature.java:771) at sun.security.ssl.ECDHServerKeyExchange$ECDHServerKeyExchangeMessage.<init>(ECDHServerKeyExchange.java:320) ... 83 common frames omitted Caused by: java.security.InvalidAlgorithmParameterException: null at sun.security.ec.ECDSASignature.verifySignedDigest(Native Method) at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:408) ... 86 common frames omitted
排查解决方案
1. 升级OpenJDK版本
当前使用的OpenJDK 1.8.0_275存在ECDSA签名验证的已知缺陷,尤其在Alpine系统下表现明显。建议升级至OpenJDK 8u301或更高版本,该版本修复了相关算法参数验证问题。
2. 替换加密算法实现
Alpine默认采用musl libc,部分加密算法支持不完善。可尝试:
- 切换至基于GNU libc的OpenJDK版本
- 引入BouncyCastle加密库作为替代实现:
- 添加
bcprov-jdk15on依赖包 - 在代码中注册提供者:
import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; // 程序启动时注册 Security.addProvider(new BouncyCastleProvider());
- 添加
3. 调整OkHttp SSL配置
强制OkHttp使用TLS 1.2+版本,并过滤不兼容的ECDH曲线:
import okhttp3.ConnectionSpec; import okhttp3.OkHttpClient; import javax.net.ssl.SSLSocketFactory; import java.util.Collections; // 自定义SSLSocketFactory实现,过滤不兼容曲线 class SSLSocketFactoryCompat extends SSLSocketFactory { // 实现逻辑:包装默认工厂,移除不支持的ECDH曲线 } OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(new SSLSocketFactoryCompat(), X509TrustManagerUtil.getDefault()) .connectionSpecs(Collections.singletonList(ConnectionSpec.MODERN_TLS)) .build();
4. 升级依赖版本
- 将
tea-1.2.0.jar、tea-util-0.2.21.jar升级至阿里云SDK最新稳定版 - OkHttp升级到3.14.x版本(兼容JDK8),该版本修复了部分TLS握手兼容性问题
5. 验证服务器EC曲线支持
使用openssl s_client -connect cloudauth.aliyuncs.com:443命令查看服务器使用的EC曲线,若当前JDK不支持该曲线,需升级JDK或通过JVM参数启用对应曲线支持。
内容的提问来源于stack exchange,提问作者t _ liang
相关产品推荐
相关产品推荐

