2017-03-08 3 views
1

Ich habe ein selbstsigniertes Client-Zertifikat-Kit erhalten, das verwendet werden soll, um über HTTPS auf einen Server zuzugreifen. Das Kit besteht aus folgenden PEM-Dateien:Wie erstellt man eine SSLSocketFactory aus PEM-Zertifikat und Schlüssel, ohne in Keystore zu konvertieren?

  1. client.crt (Client-Zertifikat)
  2. client.key (Client private Schlüssel)
  3. ca.crt (CA-Zertifikat)

One Weg, um die Aufgabe zu lösen, ist ein Java-Schlüsselspeicher zu generieren:

openssl
  1. Verwenden zu konvertieren Client-Zertifikat und Schlüssel zu PKCS12 Keystor
  2. Verwenden keytool CA-Zertifikat in den Laden zu importieren

... und dann Code wie den folgenden verwenden SSLSocketFactory Instanz zu bauen:

InputStream stream = new ByteArrayInputStream(pksData);   
KeyStore keyStore = KeyStore.getInstance("PKCS12"); 
keyStore.load(stream, password); 

KeyManagerFactory kmf = KeyManagerFactory.getInstance(
    KeyManagerFactory.getDefaultAlgorithm()); 
kmf.init(keyStore, password.toCharArray()); 
KeyManager[] keyManagers = kmf.getKeyManagers(); 

TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm()); 
tmfactory.init(keyStore); 
TrustManager[] trustManagers = tmfactory.getTrustManagers(); 

SSLContext sslContext = SSLContext.getInstance("TLS"); 
sslContext.init(keyManagers, trustManagers, null); 
sslSocketFactory = sslContext.getSocketFactory(); 

..., die später verwendet wird, um die init http-Bibliothek.

So erhalten wir einen KeyStore, dann init KeyManagers und TrustManagers mit seiner Hilfe und schließlich erstellen wir SSLSocketFactory-Instanz mit ihnen.

Die Frage ist: Gibt es eine Möglichkeit, dass die Schlüsselspeicherdatei Schöpfung zu vermeiden und irgendwie SSLSocketFactory baut mit PublicKey und Certificate-Instanz starten (die zum Beispiel aus PEM-Dateien mit bouncycastle des PemReader erhalten werden)?

+0

Nr genommen Sie haben eine PKCS # 12 oder JKS Schlüsselspeicher zu bauen. Aber du hättest keinen privaten Schlüssel bekommen sollen. Du hättest alles selbst generieren sollen. Hier besteht ein ernsthaftes Sicherheitsproblem. Dein privater Schlüssel ist nicht privat, also wer immer er dir gab, kann dich im juristischen Sinne verkörpern. Tu das nicht. – EJP

+0

Ja, danke, wir wissen, dass wir selbst private Schlüssel generieren sollten. Aber die Institution, mit der wir hier arbeiten, diktiert ihre Regeln und hört niemandem zu: Sie erzeugen nur alle Schlüssel selbst. Es ist jedoch keine technische Angelegenheit. –

Antwort

2

Es stellte sich heraus, dass eine KeyStore-Instanz noch erstellt werden muss, aber es kann im Speicher ausgeführt werden (beginnend mit PEM-Dateien als Eingabe), ohne eine intermediäre Keystore-Datei mit keytool zu erstellen.

Um sicherzustellen, dass In-Memory-Schlüsselspeicher, Code wie die folgenden Aufbau verwendet werden kann:

private static final String TEMPORARY_KEY_PASSWORD = "changeit"; 

private KeyStore getKeyStore() throws ConfigurationException { 
    try { 
     Certificate clientCertificate = loadCertificate(certificatePem); 
     PrivateKey privateKey = loadPrivateKey(privateKeyPem); 
     Certificate caCertificate = loadCertificate(caPem); 

     KeyStore keyStore = KeyStore.getInstance("JKS"); 
     keyStore.load(null, null); 
     keyStore.setCertificateEntry("ca-cert", caCertificate); 
     keyStore.setCertificateEntry("client-cert", clientCertificate); 
     keyStore.setKeyEntry("client-key", privateKey, TEMPORARY_KEY_PASSWORD.toCharArray(), new Certificate[]{clientCertificate}); 
     return keyStore; 
    } catch (GeneralSecurityException | IOException e) { 
     throw new ConfigurationException("Cannot build keystore", e); 
    } 
} 

private Certificate loadCertificate(String certificatePem) throws IOException, GeneralSecurityException { 
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X509"); 
    final byte[] content = readPemContent(certificatePem); 
    return certificateFactory.generateCertificate(new ByteArrayInputStream(content)); 
} 

private PrivateKey loadPrivateKey(String privateKeyPem) throws IOException, GeneralSecurityException { 
    return pemLoadPrivateKeyPkcs1OrPkcs8Encoded(privateKeyPem); 
} 

private byte[] readPemContent(String pem) throws IOException { 
    final byte[] content; 
    try (PemReader pemReader = new PemReader(new StringReader(pem))) { 
     final PemObject pemObject = pemReader.readPemObject(); 
     content = pemObject.getContent(); 
    } 
    return content; 
} 

private static PrivateKey pemLoadPrivateKeyPkcs1OrPkcs8Encoded(
     String privateKeyPem) throws GeneralSecurityException, IOException { 
    // PKCS#8 format 
    final String PEM_PRIVATE_START = "-----BEGIN PRIVATE KEY-----"; 
    final String PEM_PRIVATE_END = "-----END PRIVATE KEY-----"; 

    // PKCS#1 format 
    final String PEM_RSA_PRIVATE_START = "-----BEGIN RSA PRIVATE KEY-----"; 
    final String PEM_RSA_PRIVATE_END = "-----END RSA PRIVATE KEY-----"; 

    if (privateKeyPem.contains(PEM_PRIVATE_START)) { // PKCS#8 format 
     privateKeyPem = privateKeyPem.replace(PEM_PRIVATE_START, "").replace(PEM_PRIVATE_END, ""); 
     privateKeyPem = privateKeyPem.replaceAll("\\s", ""); 

     byte[] pkcs8EncodedKey = Base64.getDecoder().decode(privateKeyPem); 

     KeyFactory factory = KeyFactory.getInstance("RSA"); 
     return factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey)); 

    } else if (privateKeyPem.contains(PEM_RSA_PRIVATE_START)) { // PKCS#1 format 

     privateKeyPem = privateKeyPem.replace(PEM_RSA_PRIVATE_START, "").replace(PEM_RSA_PRIVATE_END, ""); 
     privateKeyPem = privateKeyPem.replaceAll("\\s", ""); 

     DerInputStream derReader = new DerInputStream(Base64.getDecoder().decode(privateKeyPem)); 

     DerValue[] seq = derReader.getSequence(0); 

     if (seq.length < 9) { 
      throw new GeneralSecurityException("Could not parse a PKCS1 private key."); 
     } 

     // skip version seq[0]; 
     BigInteger modulus = seq[1].getBigInteger(); 
     BigInteger publicExp = seq[2].getBigInteger(); 
     BigInteger privateExp = seq[3].getBigInteger(); 
     BigInteger prime1 = seq[4].getBigInteger(); 
     BigInteger prime2 = seq[5].getBigInteger(); 
     BigInteger exp1 = seq[6].getBigInteger(); 
     BigInteger exp2 = seq[7].getBigInteger(); 
     BigInteger crtCoef = seq[8].getBigInteger(); 

     RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, 
       exp1, exp2, crtCoef); 

     KeyFactory factory = KeyFactory.getInstance("RSA"); 

     return factory.generatePrivate(keySpec); 
    } 

    throw new GeneralSecurityException("Not supported format of a private key"); 
} 

Die Idee von Programmatically Obtain KeyStore from PEM

Verwandte Themen