简体   繁体   English

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

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

I'm currently working on a project that involves getting an Elliptic Curve Certificate / Private Key package in either PEM or DER format from Vault and needing to import it into a Java Keystore.我目前正在从事一个项目,该项目涉及从 Vault 获取 PEM 或 DER 格式的椭圆曲线证书/私钥 package,并且需要将其导入 Java 密钥库。 I can find plenty of information on doing this with keytool, but am unable to find information about how to successfully convert a DER encoded string into a PrivateKeyEntry to insert it into the keystore.我可以找到有关使用 keytool 执行此操作的大量信息,但无法找到有关如何成功将 DER 编码字符串转换为PrivateKeyEntry以将其插入密钥库的信息。

Below is my non-working code.下面是我的非工作代码。 certificate , key , and issuingCa are all PEM or DER encoded Strings (I can specify which format I want to get back from the issuer and pass whichever I can get to work) 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;
  }

After some experimentation and research I've learned that the PrivateKey class doesn't like the "old" PEM format where the private key looks like ---- BEGIN EC PRIVATE KEY-----.经过一些实验和研究,我了解到PrivateKey class 不喜欢私钥看起来像的“旧”PEM 格式----BEGIN EC PRIVATE KEY-----。

I was eventually able to parse a PrivateKey object from a keypair like this:我最终能够从这样的密钥对中解析 PrivateKey object:

   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);

From there I get an error on setKeyEntry about the certificate algorithm not matching the private key algorithm.从那里我得到关于证书算法与私钥算法不匹配的 setKeyEntry 错误。 Upon inspection it seems that the Certificate object says the algo is EC and the PK object says the algo is ECDSA.经检查,证书 object 似乎表明算法是 EC,而 PK object 表明算法是 ECDSA。

I eventually solved it this way.我最终以这种方式解决了它。 Note the key must be in base64 encoded DER format:请注意,密钥必须采用 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);
      }
    } 
...
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM