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 – 未经授权:

我的问题是,我不知道,怎么了:

有人有与 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 通道绑定