EST 与充气城堡
EST with Bouncy Castle
我尝试通过 EST 协议从 EST 测试服务 URL“https://testrfc7030.com/”请求新证书。该程序为此使用了 Bouncy Castle。
我已经配置了 EST 服务的 TA 和我从他们那里获得的客户端证书。我还使用 BC JSSE 提供程序来访问“tls-unique”通道绑定值。
eSTService = new JsseESTServiceBuilder(Config.CredAdmin.caHost, trustManagers)
.withKeyManagers(keyManagers)
.withProvider(BouncyCastleJsseProvider.PROVIDER_NAME)
.withChannelBindingProvider(new ChannelBindingProvider() {
//Use an anonymous binding provider that supports linking
//Identity and POP Information (RFC7030, Section 3.5.), that
//relies on Channel Bindings for TLS (RFC5929) using "tls-unique".
public boolean canAccessChannelBinding(Socket sock) {
boolean ret = sock instanceof BCSSLSocket;
if (!ret)
//should never happen
MyUtils.LambdaLogger.error("Can't get channel binding value, check if BouncyCastleJsseProvider could be loaded.");
return ret;
}
public byte[] getChannelBinding(Socket sock, String binding) {
BCSSLConnection bcon = ((BCSSLSocket)sock).getConnection();
if (bcon == null) {
//should never happen
MyUtils.LambdaLogger.error("Can't get \"%s\" channel binding value, check if BouncyCastleJsseProvider could be loaded.", binding);
return null;
}
byte[] ret = bcon.getChannelBinding(binding);
MyUtils.LambdaLogger.debug("retrieved %d bytes \"%s\" channel binding value", ret.length, binding);
return ret;
}
})
.build();
和
Security.addProvider(new BouncyCastleJsseProvider());
当我配置 EST 服务端口 9443 时——这需要我的客户端证书但不需要 TLS 通道绑定——我确实获得了一个新证书:
然而,当我配置端口 443 时——它也需要 TLS 通道绑定——虽然我从 BC JSSE 获得了 12 个字节的“tls-unique”,但这些不会被 EST 服务接受 testrfc7030.com ,所以它给了我一个 HTTP 401 – 未经授权:
我的问题是,我不知道,怎么了:
- 我的代码
- “tls-unique”的 BC JSSE 实现 (RFC 5929)
- EST 服务实现“tls-unique”(RFC 5929)?
有人有与 EST 服务“testrfc7030.com:443”一起工作的实现吗?艺术至少有一个想法,怎么了?
---更新 1---
我正在创建 ContentSigner
如下:
ContentSigner signer =
new JcaContentSignerBuilder(MyUtils.Crypto.sha256WithRSAEncryption)
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(keyPair.getPrivate());
和 csrBuilder
:
PKCS10CertificationRequestBuilder csrBuilder =
new PKCS10CertificationRequestBuilder(
new X500Name(subjectDN),
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
和
ExtensionsGenerator extGen = new ExtensionsGenerator();
...
然后我们使用如下:
EnrollmentResponse resp = eSTService.simpleEnrollPoP(false, cb.csrBuilder, cb.signer, null);
根据 Peter 的意见,我们能够按如下方式解决此问题:
//just for testrfc7030.com
ESTAuth auth = new JcaHttpAuthBuilder(null, "estuser", "estpwd".toCharArray())
.setNonceGenerator(new SecureRandom())
.setProvider("BC")
.build();
EnrollmentResponse resp = eSTService.simpleEnrollPoP(false, cb.csrBuilder, cb.signer, auth);
事实证明,testrfc3070 需要以下身份验证方案:
- 端口 443:需要 HTTP 用户身份验证 + 身份 POP 链接
- 端口 8443:需要 HTTP 用户身份验证但没有身份 POP 链接
- 端口 9443:需要用户通过客户端证书(通过端口 8443 或端口 443 获得)进行身份验证,但没有身份 POP 链接
身份 POP 链接 = TLS 通道绑定
我尝试通过 EST 协议从 EST 测试服务 URL“https://testrfc7030.com/”请求新证书。该程序为此使用了 Bouncy Castle。
我已经配置了 EST 服务的 TA 和我从他们那里获得的客户端证书。我还使用 BC JSSE 提供程序来访问“tls-unique”通道绑定值。
eSTService = new JsseESTServiceBuilder(Config.CredAdmin.caHost, trustManagers)
.withKeyManagers(keyManagers)
.withProvider(BouncyCastleJsseProvider.PROVIDER_NAME)
.withChannelBindingProvider(new ChannelBindingProvider() {
//Use an anonymous binding provider that supports linking
//Identity and POP Information (RFC7030, Section 3.5.), that
//relies on Channel Bindings for TLS (RFC5929) using "tls-unique".
public boolean canAccessChannelBinding(Socket sock) {
boolean ret = sock instanceof BCSSLSocket;
if (!ret)
//should never happen
MyUtils.LambdaLogger.error("Can't get channel binding value, check if BouncyCastleJsseProvider could be loaded.");
return ret;
}
public byte[] getChannelBinding(Socket sock, String binding) {
BCSSLConnection bcon = ((BCSSLSocket)sock).getConnection();
if (bcon == null) {
//should never happen
MyUtils.LambdaLogger.error("Can't get \"%s\" channel binding value, check if BouncyCastleJsseProvider could be loaded.", binding);
return null;
}
byte[] ret = bcon.getChannelBinding(binding);
MyUtils.LambdaLogger.debug("retrieved %d bytes \"%s\" channel binding value", ret.length, binding);
return ret;
}
})
.build();
和
Security.addProvider(new BouncyCastleJsseProvider());
当我配置 EST 服务端口 9443 时——这需要我的客户端证书但不需要 TLS 通道绑定——我确实获得了一个新证书:
然而,当我配置端口 443 时——它也需要 TLS 通道绑定——虽然我从 BC JSSE 获得了 12 个字节的“tls-unique”,但这些不会被 EST 服务接受 testrfc7030.com ,所以它给了我一个 HTTP 401 – 未经授权:
我的问题是,我不知道,怎么了:
- 我的代码
- “tls-unique”的 BC JSSE 实现 (RFC 5929)
- EST 服务实现“tls-unique”(RFC 5929)?
有人有与 EST 服务“testrfc7030.com:443”一起工作的实现吗?艺术至少有一个想法,怎么了?
---更新 1---
我正在创建 ContentSigner
如下:
ContentSigner signer =
new JcaContentSignerBuilder(MyUtils.Crypto.sha256WithRSAEncryption)
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(keyPair.getPrivate());
和 csrBuilder
:
PKCS10CertificationRequestBuilder csrBuilder =
new PKCS10CertificationRequestBuilder(
new X500Name(subjectDN),
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
和
ExtensionsGenerator extGen = new ExtensionsGenerator();
...
然后我们使用如下:
EnrollmentResponse resp = eSTService.simpleEnrollPoP(false, cb.csrBuilder, cb.signer, null);
根据 Peter 的意见,我们能够按如下方式解决此问题:
//just for testrfc7030.com
ESTAuth auth = new JcaHttpAuthBuilder(null, "estuser", "estpwd".toCharArray())
.setNonceGenerator(new SecureRandom())
.setProvider("BC")
.build();
EnrollmentResponse resp = eSTService.simpleEnrollPoP(false, cb.csrBuilder, cb.signer, auth);
事实证明,testrfc3070 需要以下身份验证方案:
- 端口 443:需要 HTTP 用户身份验证 + 身份 POP 链接
- 端口 8443:需要 HTTP 用户身份验证但没有身份 POP 链接
- 端口 9443:需要用户通过客户端证书(通过端口 8443 或端口 443 获得)进行身份验证,但没有身份 POP 链接
身份 POP 链接 = TLS 通道绑定