簡體   English   中英

將證書加載到KeyStore(JAVA)

[英]Load certificate to KeyStore (JAVA)

我在將證書加載到密鑰存儲區時遇到問題。 我可以使用以下命令在控制台中創建該證書openssl pkcs12 -export -out cloudCA.p12 -inkey Cloud\\ privateLey.key -in cloudCa.pem -certfile rootCa.pem -name "cloudCA"我想出了如何加載cloudCA.pem與privateKey.key,但我找不到方法如何在其中添加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;
}

首先,使用openssl pkcs12 -export創建的PKCS12文件已經是Java密鑰庫; 盡管低於9的Java版本的密鑰庫默認為JKS格式,但它們也支持PKCS12,而現在的j9 up默認為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文件包含PEM塊,其中由文件創建的OpenSSL之前額外“注釋”信息經常這樣做,你需要一個相當新的Java版本(IIRC J6或J7可能)來處理

或者,如果您將證書串聯在一起(在文件或內存中),則可以使用CertificateFactory.generateCertificates (請注意s)將它們都讀取到Collection ,然后將其轉換為數組。 同樣,這已經處理了PEM,因此您不必解析和轉換它。 請注意,您可以將CollectionList (如上面的代碼中一樣)直接轉換為數組,而無需先通過Stream

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM