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

com.nimbusds.jose.util.X509CertUtils Maven / Gradle / Ivy

Go to download

Java library for Javascript Object Signing and Encryption (JOSE) and JSON Web Tokens (JWT)

There is a newer version: 9.48
Show newest version
/*
 * nimbus-jose-jwt
 *
 * Copyright 2012-2016, Connect2id Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License. You may obtain a copy of the
 * License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.nimbusds.jose.util;


import java.io.ByteArrayInputStream;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.*;
import java.util.UUID;


/**
 *  X.509 certificate utilities.
 *
 *  @author Vladimir Dzhuvinov
 *  @author Simon Kissane
 *  @version 2022-01-24
 */
public class X509CertUtils {


	/**
	 * The PEM start marker.
	 */
	public static final String PEM_BEGIN_MARKER = "-----BEGIN CERTIFICATE-----";


	/**
	 * The PEM end marker.
	 */
	public static final String PEM_END_MARKER = "-----END CERTIFICATE-----";


	/**
	 * The JCA provider to use for certificate operations, {@code null}
	 * implies the default provider.
	 */
	private static Provider jcaProvider;


	/**
	 * Returns the JCA provider to use for certification operations.
	 *
	 * @return The JCA provider to use for certificate operations,
	 *         {@code null} implies the default provider.
	 */
	public static Provider getProvider() {
		return jcaProvider;
	}


	/**
	 * Sets the JCA provider to use for certification operations.
	 *
	 * @param provider The JCA provider to use for certificate operations,
	 *                 {@code null} implies the default provider.
	 */
	public static void setProvider(final Provider provider) {
		jcaProvider = provider;
	}


	/**
	 * Parses a DER-encoded X.509 certificate.
	 *
	 * @param derEncodedCert The DER-encoded X.509 certificate, as a byte
	 *                       array. May be {@code null}.
	 *
	 * @return The X.509 certificate, {@code null} if not specified or
	 *         parsing failed.
	 */
	public static X509Certificate parse(final byte[] derEncodedCert) {

		try {
			return parseWithException(derEncodedCert);
		} catch (CertificateException e) {
			return null;
		}
	}


	/**
	 * Parses a DER-encoded X.509 certificate with exception handling.
	 *
	 * @param derEncodedCert The DER-encoded X.509 certificate, as a byte
	 *                       array. Empty or {@code null} if not specified.
	 *
	 * @return The X.509 certificate, {@code null} if not specified.
	 *
	 * @throws CertificateException If parsing failed.
	 */
	public static X509Certificate parseWithException(final byte[] derEncodedCert)
		throws CertificateException {

		if (derEncodedCert == null || derEncodedCert.length == 0) {
			return null;
		}

		CertificateFactory cf = jcaProvider != null ?
			CertificateFactory.getInstance("X.509", jcaProvider) :
			CertificateFactory.getInstance("X.509");
		final Certificate cert = cf.generateCertificate(new ByteArrayInputStream(derEncodedCert));

		if (! (cert instanceof X509Certificate)) {
			throw new CertificateException("Not a X.509 certificate: " + cert.getType());
		}

		return (X509Certificate)cert;
	}


	/**
	 * Parses a PEM-encoded X.509 certificate.
	 *
	 * @param pemEncodedCert The PEM-encoded X.509 certificate, as a
	 *                       string. Empty or {@code null} if not
	 *                       specified.
	 *
	 * @return The X.509 certificate, {@code null} if parsing failed.
	 */
	public static X509Certificate parse(final String pemEncodedCert) {

		if (pemEncodedCert == null || pemEncodedCert.isEmpty()) {
			return null;
		}

		final int markerStart = pemEncodedCert.indexOf(PEM_BEGIN_MARKER);

		if (markerStart < 0) {
			return null;
		}

		String buf = pemEncodedCert.substring(markerStart + PEM_BEGIN_MARKER.length());

		final int markerEnd = buf.indexOf(PEM_END_MARKER);

		if (markerEnd < 0) {
			return null;
		}

		buf = buf.substring(0, markerEnd);

		buf = buf.replaceAll("\\s", "");

		return parse(new Base64(buf).decode());
	}


	/**
	 * Parses a PEM-encoded X.509 certificate with exception handling.
	 *
	 * @param pemEncodedCert The PEM-encoded X.509 certificate, as a
	 *                       string. Empty or {@code null} if not
	 *                       specified.
	 *
	 * @return The X.509 certificate, {@code null} if parsing failed.
	 */
	public static X509Certificate parseWithException(final String pemEncodedCert)
		throws CertificateException {

		if (pemEncodedCert == null || pemEncodedCert.isEmpty()) {
			return null;
		}

		final int markerStart = pemEncodedCert.indexOf(PEM_BEGIN_MARKER);

		if (markerStart < 0) {
			throw new CertificateException("PEM begin marker not found");
		}

		String buf = pemEncodedCert.substring(markerStart + PEM_BEGIN_MARKER.length());

		final int markerEnd = buf.indexOf(PEM_END_MARKER);

		if (markerEnd < 0) {
			throw new CertificateException("PEM end marker not found");
		}

		buf = buf.substring(0, markerEnd);

		buf = buf.replaceAll("\\s", "");

		return parseWithException(new Base64(buf).decode());
	}
	
	
	/**
	 * Returns the specified X.509 certificate as PEM-encoded string.
	 *
	 * @param cert The X.509 certificate. Must not be {@code null}.
	 *
	 * @return The PEM-encoded X.509 certificate, {@code null} if encoding
	 *         failed.
	 */
	public static String toPEMString(final X509Certificate cert) {
	
		return toPEMString(cert, true);
	}
	
	
	/**
	 * Returns the specified X.509 certificate as PEM-encoded string.
	 *
	 * @param cert           The X.509 certificate. Must not be
	 *                       {@code null}.
	 * @param withLineBreaks {@code false} to suppress line breaks.
	 *
	 * @return The PEM-encoded X.509 certificate, {@code null} if encoding
	 *         failed.
	 */
	public static String toPEMString(final X509Certificate cert, final boolean withLineBreaks) {
	
		StringBuilder sb = new StringBuilder();
		sb.append(PEM_BEGIN_MARKER);
		
		if (withLineBreaks)
			sb.append('\n');
		
		try {
			sb.append(Base64.encode(cert.getEncoded()));
		} catch (CertificateEncodingException e) {
			return null;
		}
		
		if (withLineBreaks)
			sb.append('\n');
		
		sb.append(PEM_END_MARKER);
		return sb.toString();
	}
	
	
	/**
	 * Computes the X.509 certificate SHA-256 thumbprint ({@code x5t#S256}).
	 *
	 * @param cert The X.509 certificate. Must not be {@code null}.
	 *
	 * @return The SHA-256 thumbprint, BASE64URL-encoded, {@code null} if
	 *         a certificate encoding exception is encountered.
	 */
	public static Base64URL computeSHA256Thumbprint(final X509Certificate cert) {
	
		try {
			byte[] derEncodedCert = cert.getEncoded();
			MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
			return Base64URL.encode(sha256.digest(derEncodedCert));
		} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
			return null;
		}
	}
	
	
	/**
	 * Stores a private key with its associated X.509 certificate in a
	 * Java key store. The name (alias) for the stored entry is a given a
	 * random UUID.
	 *
	 * @param keyStore    The key store. Must be initialised and not
	 *                    {@code null}.
	 * @param privateKey  The private key. Must not be {@code null}.
	 * @param keyPassword The password to protect the private key, empty
	 *                    array for none. Must not be {@code null}.
	 * @param cert        The X.509 certificate, its public key and the
	 *                    private key should form a pair. Must not be
	 *                    {@code null}.
	 *
	 * @return The UUID for the stored entry.
	 */
	public static UUID store(final KeyStore keyStore,
				 final PrivateKey privateKey,
				 final char[] keyPassword,
				 final X509Certificate cert)
		throws KeyStoreException {
		
		UUID alias = UUID.randomUUID();
		keyStore.setKeyEntry(alias.toString(), privateKey, keyPassword, new Certificate[]{cert});
		return alias;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy