基于BouncyCastle正确实现DefaultTlsServer的getRSASignerCredentials()方法
问题:BouncyCastle TLS Server重写
getRSASignerCredentials()方法报错处理 我使用bctls-jdk18on-1.72.jar实现TLS Server,编写了继承DefaultTlsServer的DefaultTlsServerImpl类,并重写getRSASignerCredentials()方法,代码如下:
class DefaultTlsServerImpl extends DefaultTlsServer { ... @Override protected TlsCredentialedSigner getRSASignerCredentials() throws IOException { TlsCryptoParameters cryptoParams = new TlsCryptoParameters(context); SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(context.getServerVersion())) { signatureAndHashAlgorithm = new SignatureAndHashAlgorithm(HashAlgorithm.sha256, SignatureAlgorithm.rsa); } return new BcDefaultTlsCredentialedSigner(cryptoParams, BC_TLS_CRYPTO, PRIVATE_KEY, CERTIFICATE, signatureAndHashAlgorithm); } ... }
调用该方法后抛出如下异常:
org.bouncycastle.tls.TlsFatalAlert: internal_error(80) at org.bouncycastle.tls.DTLSServerProtocol.accept(Unknown Source) at org.bouncycastle.tls.DTLSServerProtocol.accept(Unknown Source) ... Caused by: java.lang.IllegalStateException: Invalid algorithm: {sha256(4),rsa(1)} at org.bouncycastle.tls.crypto.impl.bc.BcTlsDSSSigner.generateRawSignature(Unknown Source) at org.bouncycastle.tls.DefaultTlsCredentialedSigner.generateRawSignature(DefaultTlsCredentialedSigner.java:53) at org.bouncycastle.tls.TlsUtils.generateServerKeyExchangeSignature(TlsUtils.java:2602) at org.bouncycastle.tls.TlsECDHEKeyExchange.generateServerKeyExchange(TlsECDHEKeyExchange.java:79) at org.bouncycastle.tls.DTLSServerProtocol.serverHandshake(Unknown Source) ... 16 more
尝试改为使用与SHA256withECDSA证书对应的代码:
new SignatureAndHashAlgorithm( HashAlgorithm.sha256, SignatureAlgorithm.ecdsa );
则会抛出异常org.bouncycastle.tls.TlsFatalAlert: illegal_parameter(47)。请问该如何正确实现getRSASignerCredentials()方法?
核心问题分析
- 第一个异常原因:指定的
{sha256(4),rsa(1)}签名算法与实际使用的私钥/证书类型不匹配。异常栈中的BcTlsDSSSigner说明代码在尝试用DSS/DSA签名器处理RSA算法,证明PRIVATE_KEY或CERTIFICATE是DSA类型,而非RSA类型,导致算法兼容失败。 - 第二个异常原因:换成ECDSA算法后抛出
illegal_parameter,是因为getRSASignerCredentials()方法专门用于返回RSA类型的签名凭据,返回ECDSA类型凭据违反了方法的设计意图,TLS协议层判定参数非法。
正确实现方案
方案1:使用RSA类型的证书/私钥
确保PRIVATE_KEY和CERTIFICATE是RSA算法生成的,按以下方式实现方法:
@Override protected TlsCredentialedSigner getRSASignerCredentials() throws IOException { TlsCryptoParameters cryptoParams = new TlsCryptoParameters(context); SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; // 仅当TLS版本支持签名算法扩展时指定 if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(context.getServerVersion())) { // RSA常规证书使用RSASSA-PKCS1-v1_5,对应SignatureAlgorithm.rsa_pkcs1 signatureAndHashAlgorithm = new SignatureAndHashAlgorithm(HashAlgorithm.sha256, SignatureAlgorithm.rsa_pkcs1); } return new BcDefaultTlsCredentialedSigner(cryptoParams, BC_TLS_CRYPTO, PRIVATE_KEY, CERTIFICATE, signatureAndHashAlgorithm); }
注意:BouncyCastle中SignatureAlgorithm.rsa对应RSASSA-PSS算法,常规RSA证书需使用rsa_pkcs1。
方案2:若使用ECDSA/DSA证书,重写对应方法
如果证书是ECDSA类型,不要重写getRSASignerCredentials(),而是重写getECDSASignerCredentials():
@Override protected TlsCredentialedSigner getECDSASignerCredentials() throws IOException { TlsCryptoParameters cryptoParams = new TlsCryptoParameters(context); SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(context.getServerVersion())) { signatureAndHashAlgorithm = new SignatureAndHashAlgorithm(HashAlgorithm.sha256, SignatureAlgorithm.ecdsa); } return new BcDefaultTlsCredentialedSigner(cryptoParams, BC_TLS_CRYPTO, PRIVATE_KEY, CERTIFICATE, signatureAndHashAlgorithm); }
同理,DSA证书需重写getDSSSignerCredentials()方法。
额外注意点
- 证书与私钥算法必须一致:RSA证书对应RSA私钥,ECDSA证书对应ECDSA私钥,否则会触发算法不兼容错误。
- 检查TLS版本兼容性:确保使用的TLS版本(如TLS 1.2及以上)支持指定的签名算法扩展。
内容的提问来源于stack exchange,提问作者Horcrux7
相关产品推荐
相关产品推荐

