将证书加载到KeyStore(JAVA)

时间:2018-05-24 16:57:01

标签: java openssl certificate ssl-certificate keystore

将certifiacate加载到密钥存储区时遇到问题。我可以使用此命令openssl pkcs12 -export -out cloudCA.p12 -inkey Cloud\ privateLey.key -in cloudCa.pem -certfile rootCa.pem -name "cloudCA"在控制台中创建该证书 我想出了如何使用privateKey.key加载cloudCA.pem,但我找不到如何添加rootCA.pem的方法。这是我目前的代码。感谢帮助。

//Regular patterns for certificate.
private static final Pattern CERT_PATTERN = Pattern.compile(
        "-+BEGIN\\s+.*CERTIFICATE[^-]*-+(?:\\s|\\r|\\n)+" + // Header
                "([a-z0-9+/=\\r\\n]+)" +                    // Base64 text
                "-+END\\s+.*CERTIFICATE[^-]*-+",            // Footer
        CASE_INSENSITIVE);

private static final Pattern KEY_PATTERN = Pattern.compile(
        "-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+" + // Header
                "([a-z0-9+/=\\r\\n]+)" +                       // Base64 text
                "-+END\\s+.*PRIVATE\\s+KEY[^-]*-+",            // Footer
        CASE_INSENSITIVE);


public static KeyStore loadKeyStore(String certificate, String privateKey, Optional<String> keyPassword)
        throws IOException, GeneralSecurityException {

    List<X509Certificate> certificateChain = readCertificateChain(certificate);
    if (certificateChain.isEmpty()) {
        throw new CertificateException("Certificate file string does not contain any certificates: ");
    }

    //Load and customize key string to byte array.
    byte[] data = Base64.getDecoder().decode(privateKey.replace("\n","")
            .replace("-----BEGIN RSA PRIVATE KEY-----", "")
            .replace("-----END RSA PRIVATE KEY-----", "")
            .replace(" ", ""));

    /* Add PKCS#8 formatting */
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new ASN1Integer(0));
    ASN1EncodableVector v2 = new ASN1EncodableVector();
    v2.add(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()));
    v2.add(DERNull.INSTANCE);
    v.add(new DERSequence(v2));
    v.add(new DEROctetString(data));
    ASN1Sequence seq = new DERSequence(v);
    byte[] privKey = seq.getEncoded("DER");

    PKCS8EncodedKeySpec spec = new  PKCS8EncodedKeySpec(privKey);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey key = fact.generatePrivate(spec);

    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(null, null);
    keyStore.setKeyEntry("CloudCA", key, keyPassword.orElse("").toCharArray(), certificateChain.stream().toArray(Certificate[]::new));
    return keyStore;
}


private static List<X509Certificate> readCertificateChain(String contents) throws GeneralSecurityException {

    Matcher matcher = CERT_PATTERN.matcher(contents);
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    List<X509Certificate> certificates = new ArrayList<>();

    int start = 0;
    while (matcher.find(start)) {
        byte[] buffer = Base64.getMimeDecoder().decode(matcher.group(1).getBytes(US_ASCII));
        certificates.add((X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(buffer)));
        start = matcher.end();
    }

    return certificates;
}

1 个答案:

答案 0 :(得分:0)

首先,使用openssl pkcs12 -export创建的PKCS12文件已经一个Java密钥库;虽然Java版本低于9 默认到JKS格式的密钥库,但它们也支持PKCS12,而j9现在默认为PKCS12。所以你可以使用PKCS12密钥库,你就完成了。但是SO是关于编程的,所以一个根本不需要做任何事情的解决方案可能是偏离主题的:)

如果您希望(或以某种方式需要)自己构建密钥库,并且您将实体证书放在一个文件中(如果您的名字确实是真正的从属CA,并且直接位于根目录下),则将根证书放在另一个文件中,你可以阅读它们中的每一个并形成链条,如:

// read privatekey, reformat to PKCS8 and process-in as you do now

CertificateFactory fact = CertificateFactory.getInstance("X.509");
InputStream file1 = new FileInputStream("mycert.pem"), file2 = new FileInputStream("rootcert.pem");
Certificate[] chain = { fact.generateCertificate(file1), fact.generateCertificate(file2) };
file1.close(); file2.close(); // or use try-with-resources
// if already in memory use ByteArrayInputStream's instead, 
// and maybe don't bother closing

// basically unchanged
KeyStore keyStore = KeyStore.getInstance("JKS"); // or maybe "PKCS12" ?
keyStore.load(null, null);
keyStore.setKeyEntry("name", key, (keypass), chain);

// either use this keystore as is, or store it (to a file, 
// or maybe somewhere else like a database) for later use

请注意,您不需要删除PEM标题/预告片并自行将base64转换为二进制文件,CertificateFactory自上个世纪以来就能够读取PEM。虽然您的PEM文件包含额外的评论&#39;在PEM块之前的信息,OpenSSL创建的文件经常这样做,你需要一个相当新的Java版本(IIRC j6或者j7)来处理那个

或者,如果您连接证书 - 无论是在文件中还是在内存中 - 您可以使用CertificateFactory.generateCertificates(注意s)将它们读取到Collection然后转换为Collection到一个数组。这又处理了PEM,因此您不必解析和转换它。请注意,您可以直接将ListStream(如上面的代码中所示)转换为数组,而无需先通过s = 'cyqfjhcclkbxpbojgkar' res = '' tmp = '' for i in range(len(s)): tmp += s[i] if len(tmp) > len(res): res = tmp if i > len(s)-2: break if s[i] > s[i+1]: tmp = '' print("Longest substring in alphabetical order is: {}".format(res))