All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.peterphi.std.crypto.PEMHelper Maven / Gradle / Ivy

There is a newer version: 10.1.5
Show newest version
package com.peterphi.std.crypto;

import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

/**
 * PEM handling utilities
 */
public class PEMHelper
{
	private PEMHelper()
	{
	}


	/**
	 * Load one or more X.509 Certificates from a PEM file
	 *
	 * @param pemFile
	 * 		A PKCS8 PEM file containing only CERTIFICATE / X.509 CERTIFICATE blocks
	 *
	 * @return a JKS KeyStore with the certificate aliases "certindex" where index is the 0-based index of the
	 * certificate in the PEM
	 *
	 * @throws RuntimeException
	 * 		if a problem occurs
	 */
	public static KeyStore loadCertificates(final File pemFile)
	{
		try (final PemReader pem = new PemReader(new FileReader(pemFile)))
		{
			final KeyStore ks = createEmptyKeyStore();

			int certIndex = 0;
			Object obj;
			while ((obj = parse(pem.readPemObject())) != null)
			{
				if (obj instanceof Certificate)
				{
					final Certificate cert = (Certificate) obj;

					ks.setCertificateEntry("cert" + Integer.toString(certIndex++), cert);
				}
				else
				{
					throw new RuntimeException("Unknown PEM contents: " + obj + ". Expected a Certificate");
				}
			}

			return ks;
		}
		catch (Exception e)
		{
			throw new RuntimeException("Error parsing PEM " + pemFile, e);
		}
	}


	/**
	 * Parse a PemObject. Currently only supports  CERTIFICATE / X.509 CERTIFICATE types
	 *
	 * @param obj
	 * 		a PemObject with a type and with contents
	 *
	 * @return a parsed object (or null if the input is null)
	 *
	 * @throws GeneralSecurityException
	 * 		if there is a parsing problem
	 * @throws IllegalArgumentException
	 * 		if the PemObject cannot be recognised
	 */
	public static Object parse(final PemObject obj) throws GeneralSecurityException
	{
		if (obj == null)
		{
			return null;
		}
		else if (obj.getType() == null)
		{
			throw new RuntimeException("Encountered invalid PemObject with null type: " + obj);
		}
		else if (obj.getType().equalsIgnoreCase("CERTIFICATE") || obj.getType().equalsIgnoreCase("X.509 CERTIFICATE"))
		{
			return parseX509Certificate(obj);
		}
		else
		{
			throw new IllegalArgumentException("Unknown PEM contents: encountered unsupported entry of type " +
			                                   obj.getType() +
			                                   " (expected CERTIFICATE or X.509 CERTIFICATE)");
		}
	}


	private static Certificate parseX509Certificate(final PemObject obj) throws CertificateException
	{
		final CertificateFactory factory = CertificateFactory.getInstance("X.509");

		return factory.generateCertificate(new ByteArrayInputStream(obj.getContent()));
	}


	private static KeyStore createEmptyKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
	{
		final KeyStore ks = KeyStore.getInstance("JKS");

		// Initialise as empty
		ks.load(null);

		return ks;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy