Загрузить сертификат в KeyStore (JAVA) - PullRequest
0 голосов
/ 24 мая 2018

У меня проблема с загрузкой сертификата в хранилище ключей.Я могу создать этот сертификат в консоли с помощью этой команды 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;
}

1 Ответ

0 голосов
/ 24 мая 2018

Во-первых, ваш файл PKCS12, созданный с помощью openssl pkcs12 -export, уже - хранилище ключей Java;хотя версии Java ниже 9 по умолчанию в формате JKS для хранилищ ключей, они также поддерживают PKCS12, а по умолчанию j9 по умолчанию - PKCS12.Итак, вы можете просто использовать хранилище ключей PKCS12, и все готово.Но SO касается программирования, поэтому решение, которое вообще ничего не требует, может быть не по теме:)

Если вы хотите (или как-то нужно) создать хранилище ключей самостоятельно, и у вас есть сертификат сущностив одном файле (если на самом деле подчиненный ЦС, как подсказывает ваше имя и непосредственно под корнем) и корневой сертификат в другом, вы можете прочитать каждый из них и сформировать цепочку, например:

// 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, поэтому вам не нужно анализировать и преобразовывать его.Обратите внимание, что вы можете преобразовать либо Collection, либо List (как в коде выше) в массив напрямую, без необходимости сначала проходить Stream.

...