Created
November 10, 2020 20:07
-
-
Save ThexXTURBOXx/15e2f704480b68dc224aaf2930d748d4 to your computer and use it in GitHub Desktop.
Import PKCS12 certificate chain directly in Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.ByteArrayInputStream; | |
import java.io.File; | |
import java.io.IOException; | |
import java.nio.file.Files; | |
import java.security.KeyFactory; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.cert.CertificateException; | |
import java.security.cert.CertificateFactory; | |
import java.security.cert.X509Certificate; | |
import java.security.interfaces.RSAPrivateKey; | |
import java.security.spec.InvalidKeySpecException; | |
import java.security.spec.PKCS8EncodedKeySpec; | |
import java.util.ArrayList; | |
import java.util.List; | |
import javax.xml.bind.DatatypeConverter; | |
import org.eclipse.jetty.util.ssl.SslContextFactory; | |
/** | |
* Helper class providing utility methods for SSL. | |
*/ | |
public final class SSLUtil { | |
/** | |
* The temporary password for the converted keystore. | |
*/ | |
private static final String TEMP_PW = "temppw12345678"; | |
private SSLUtil() { | |
} | |
/** | |
* Creates a {@link SslContextFactory} with the given certificate and | |
* private key. | |
* | |
* @param cert The certificate's location to use. | |
* @param privateKey The private key's location to use. | |
* @return A {@link SslContextFactory} instance with the given keystore. | |
*/ | |
public static SslContextFactory createSslContextFactory(File cert, | |
File privateKey) { | |
try { | |
byte[][] certBytes = parseDERFromPEM( | |
Files.readAllBytes(cert.toPath()), | |
"-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"); | |
byte[][] keyBytes = parseDERFromPEM( | |
Files.readAllBytes(privateKey.toPath()), | |
"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"); | |
X509Certificate[] xCerts = new X509Certificate[certBytes.length]; | |
RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes[0]); | |
for (int i = 0; i < certBytes.length; i++) { | |
xCerts[i] = generateCertificateFromDER(certBytes[i]); | |
} | |
KeyStore keystore = KeyStore.getInstance("PKCS12"); | |
keystore.load(null); | |
keystore.setCertificateEntry("cert-alias", xCerts[0]); | |
keystore.setKeyEntry("key-alias", key, TEMP_PW.toCharArray(), | |
xCerts); | |
SslContextFactory sslContextFactory | |
= new SslContextFactory.Server(); | |
sslContextFactory.setKeyStore(keystore); | |
sslContextFactory.setKeyStorePassword(TEMP_PW); | |
return sslContextFactory; | |
} catch (IOException | KeyStoreException | InvalidKeySpecException | |
| NoSuchAlgorithmException | CertificateException e) { | |
throw new IllegalArgumentException(e); | |
} | |
} | |
/** | |
* Parses the given PEM certificate (chain) to DER certificates. | |
* | |
* @param pem The PEM certificate (chain) to convert. | |
* @param beginDelimiter The begin delimiter of the certificate. | |
* @param endDelimiter The end delimiter of the certificate. | |
* @return An array containing all certificates as binary (byte[]) data. | |
*/ | |
private static byte[][] parseDERFromPEM(byte[] pem, String beginDelimiter, | |
String endDelimiter) { | |
String data = new String(pem); | |
String[] tokens = data.split(beginDelimiter); | |
List<String> newTokens = new ArrayList<>(); | |
for (int i = 1; i < tokens.length; i++) { | |
newTokens.add(tokens[i].split(endDelimiter)[0]); | |
} | |
byte[][] ders = new byte[2][]; | |
for (int i = 0; i < newTokens.size(); i++) { | |
ders[i] = DatatypeConverter.parseBase64Binary(newTokens.get(i)); | |
} | |
return ders; | |
} | |
/** | |
* Generates a {@link RSAPrivateKey} from the given DER key. | |
* | |
* @param keyBytes The private key as binary (byte[]) data. | |
* @return An {@link RSAPrivateKey} instance representing the key. | |
* @throws InvalidKeySpecException The key is inappropriate. | |
* @throws NoSuchAlgorithmException No provider supports RSA. | |
*/ | |
private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) | |
throws InvalidKeySpecException, NoSuchAlgorithmException { | |
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); | |
KeyFactory factory = KeyFactory.getInstance("RSA"); | |
return (RSAPrivateKey) factory.generatePrivate(spec); | |
} | |
/** | |
* Generates an {@link X509Certificate} from the given DER certificate. | |
* | |
* @param certBytes The certificate as binary (byte[]) data. | |
* @return An {@link X509Certificate} instance representing the certificate. | |
* @throws CertificateException No provider supports X.509. | |
*/ | |
private static X509Certificate generateCertificateFromDER(byte[] certBytes) | |
throws CertificateException { | |
CertificateFactory factory = CertificateFactory.getInstance("X.509"); | |
return (X509Certificate) factory.generateCertificate( | |
new ByteArrayInputStream(certBytes)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment