package com.intrbiz.bergamot.crypto.util; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.CertificationRequest; import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x500.style.IETFUtils; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; public class PEMUtil { static { // as much as I dislike this, we need the BC provider to load a PEM formatted cert reliably! Security.addProvider(new BouncyCastleProvider()); } public static String saveCertificate(Certificate cert) { StringWriter sw = new StringWriter(); try (JcaPEMWriter pw = new JcaPEMWriter(sw)) { pw.writeObject(cert); } catch (IOException e) { } return sw.toString(); } public static void saveCertificate(Certificate cert, Writer to) throws IOException { try (JcaPEMWriter pw = new JcaPEMWriter(to)) { pw.writeObject(cert); } } public static void saveCertificate(Certificate cert, File to) throws IOException { try (JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(to))) { pw.writeObject(cert); } } public static Certificate loadCertificate(Reader reader) throws IOException { try { try (PEMParser pr = new PEMParser(reader)) { X509CertificateHolder theCertHolder = (X509CertificateHolder) pr.readObject(); // extract the actual fucking certificate X509Certificate theCert = new JcaX509CertificateConverter().getCertificate(theCertHolder); return theCert; } } catch (Exception e) { throw new IOException("Failed to parse PEM formatted certificate", e); } } public static Certificate loadCertificate(File file) throws IOException { return loadCertificate(new FileReader(file)); } public static Certificate loadCertificate(String data) throws IOException { return loadCertificate(new StringReader(data)); } public static PrivateKey loadKey(File file) throws IOException { try { // need to use some BC classes to parse PEM files // fecking Java, POS at times try (PemReader pr = new PemReader(new FileReader(file))) { PemObject obj = pr.readPemObject(); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(obj.getContent())); return key; } } catch (Exception e) { throw new IOException("Error loading key", e); } } public static PrivateKey loadKey(String data) throws IOException { try { // need to use some BC classes to parse PEM files // fecking Java, POS at times try (PemReader pr = new PemReader(new StringReader(data))) { PemObject obj = pr.readPemObject(); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(obj.getContent())); return key; } } catch (Exception e) { throw new IOException("Error loading key", e); } } public static String saveKey(PrivateKey key) { StringWriter sw = new StringWriter(); try (JcaPEMWriter pw = new JcaPEMWriter(sw)) { pw.writeObject(key); } catch (IOException e) { } return sw.toString(); } public static void saveKey(PrivateKey key, Writer to) throws IOException { try (JcaPEMWriter pw = new JcaPEMWriter(to)) { pw.writeObject(key); } } public static void saveKey(PrivateKey key, File to) throws IOException { try (JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(to))) { pw.writeObject(key); } } public static CertificateRequest loadCertificateRequest(Reader reader) throws IOException { try (PEMParser pr = new PEMParser(reader)) { CertificationRequest req = (CertificationRequest) pr.readObject(); // get the CN String cn = IETFUtils.valueToString(req.getCertificationRequestInfo().getSubject().getRDNs(BCStyle.CN)[0].getFirst().getValue()); // build the key KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey key = kf.generatePublic(new RSAPublicKeySpec( ((ASN1Integer)((DERSequence) req.getCertificationRequestInfo().getSubjectPublicKeyInfo().parsePublicKey()).getObjectAt(0)).getValue(), ((ASN1Integer)((DERSequence) req.getCertificationRequestInfo().getSubjectPublicKeyInfo().parsePublicKey()).getObjectAt(1)).getValue() )); return new CertificateRequest(cn, key); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new IOException("Failed to parse certificate request", e); } } public static CertificateRequest loadCertificateRequest(File file) throws IOException { return loadCertificateRequest(new FileReader(file)); } public static CertificateRequest loadCertificateRequest(String data) throws IOException { return loadCertificateRequest(new StringReader(data)); } public static String savePublicKey(PublicKey key) throws IOException { StringWriter sw = new StringWriter(); try (JcaPEMWriter pw = new JcaPEMWriter(sw)) { pw.writeObject(key); } return sw.toString(); } public static void savePublicKey(PublicKey key, Writer to) throws IOException { try (JcaPEMWriter pw = new JcaPEMWriter(to)) { pw.writeObject(key); } } public static void savePublicKey(PublicKey key, File to) throws IOException { savePublicKey(key, new FileWriter(to)); } public static PublicKey loadPublicKey(Reader from) throws IOException { try { // need to use some BC classes to parse PEM files // fecking Java, POS at times try (PemReader pr = new PemReader(from)) { // System.out.println(pr.readPemObject().getType()); PemObject obj = pr.readPemObject(); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey key = kf.generatePublic(new X509EncodedKeySpec(obj.getContent())); return key; } } catch (Exception e) { throw new IOException("Error loading key", e); } } public static PublicKey loadPublicKey(String data) throws IOException { return loadPublicKey(new StringReader(data)); } public static PublicKey loadPublicKey(File data) throws IOException { return loadPublicKey(new FileReader(data)); } }