使用 java.security.KeyStore 将椭圆曲线证书和私钥导入 Java 密钥库

Import elliptic curve Certificate and Private Key into Java Keystore using java.security.KeyStore

我目前正在从事一个项目,该项目涉及从 Vault 获取 PEM 或 DER 格式的椭圆曲线证书/私钥包,并需要将其导入 Java 密钥库。我可以找到大量有关使用 keytool 执行此操作的信息,但无法找到有关如何成功将 DER 编码字符串转换为 PrivateKeyEntry 以将其插入密钥库的信息。

下面是我的非工作代码。 certificatekeyissuingCa 都是 PEM 或 DER 编码的字符串(我可以指定我想从发行者那里取回哪种格式并传递我可以开始工作的任何格式)


private KeyStore packKeystore(String certificate, String key, String issuingCa, String name) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
    // Create the keystore 
    KeyStore retVal = KeyStore.getInstance(KeyStore.getDefaultType());
    retVal.load(null, sslKeystorePassword.toCharArray());
    var cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
    var cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certificate.getBytes()));
    retVal.setCertificateEntry(name, cert);
    Certificate issuer = null;
    if (issuingCa != null) {
      issuer = cf.generateCertificate(new ByteArrayInputStream(issuingCa.getBytes(StandardCharsets.UTF_8)));
    }
    if (key != null) {
      var certs = new HashSet<Certificate>();
      certs.add(issuer);
      certs.add(cert);
      PrivateKeyEntry pk = /// How do I create this from what I have???? 
     
      retVal.setKeyEntry( pk, certs.toArray());
    }

    return retVal;
  }

经过一些实验和研究,我了解到 PrivateKey class 不喜欢私钥看起来像的“旧”PEM 格式 ---- BEGIN EC PRIVATE KEY -----.

我最终能够像这样从密钥对中解析 PrivateKey 对象:

   var parsedKey = new org.bouncycastle.openssl.PEMParser(new StringReader(key)).readObject();
      var pair = new org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter().getKeyPair((org.bouncycastle.openssl.PEMKeyPair) parsedKey);
      retVal.setKeyEntry(name, pair.getPrivate(), "".toCharArray(), certArray);

从那里我在 setKeyEntry 上收到关于证书算法与私钥算法不匹配的错误。经检查,Certificate 对象似乎表示算法是 EC,而 PK 对象表示算法是 ECDSA。

我最终是这样解决的。注意密钥必须是 base64 编码的 DER 格式:

 private PrivateKey convertECPrivateKeyString(String key) {
   ...
    byte[] keyBytes = null;
    if (key != null) {
      keyBytes = Base64.getDecoder().decode(key);
    }
    try (var asnStream = new ASN1InputStream(keyBytes)) {
      var primitive = asnStream.readObject();
      asnStream.close();

      if (primitive instanceof ASN1Sequence) {
        var sequence = (ASN1Sequence) primitive;
        var pKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(sequence);
        var pkInfo = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()), pKey);
        return new JcaPEMKeyConverter().getPrivateKey(pkInfo);
      }
    } 
...
  }