Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2019 Thunderberry.
*
* 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
*
* https://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 nl.altindag.ssl.pem.util;
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.exception.GenericIOException;
import nl.altindag.ssl.pem.decryptor.PemDecryptor;
import nl.altindag.ssl.pem.decryptor.Pkcs8Decryptor;
import nl.altindag.ssl.pem.exception.CertificateParseException;
import nl.altindag.ssl.pem.exception.PemParseException;
import nl.altindag.ssl.pem.exception.PrivateKeyParseException;
import nl.altindag.ssl.pem.exception.PublicKeyParseException;
import nl.altindag.ssl.util.KeyManagerUtils;
import nl.altindag.ssl.util.TrustManagerUtils;
import nl.altindag.ssl.util.internal.IOUtils;
import nl.altindag.ssl.util.internal.ValidationUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.X509TrustedCertificateBlock;
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Path;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import static nl.altindag.ssl.pem.util.PemType.CERTIFICATE;
import static nl.altindag.ssl.pem.util.PemType.KEY;
import static nl.altindag.ssl.util.internal.CollectorsUtils.toListAndThen;
import static nl.altindag.ssl.util.internal.CollectorsUtils.toUnmodifiableList;
import static nl.altindag.ssl.util.internal.ValidationUtils.requireNotEmpty;
import static nl.altindag.ssl.util.internal.ValidationUtils.requireNotNull;
/**
* Reads PEM formatted private keys and certificates
* as identity material and trust material and maps it
* to either a {@link X509ExtendedKeyManager} or {@link X509ExtendedTrustManager}.
*
*
* The PemUtils provides also other methods for example to:
*
* - load trusted certificates and map it into a list of {@link X509Certificate}
* - load identity material and map it into a {@link PrivateKey}
*
*
* The PemUtils serves mainly as a helper class to easily supply the PEM formatted SSL material
* for the {@link SSLFactory}, but can also be used for other purposes.
*
* @author Hakan Altindag
*/
public final class PemUtils {
private static final String EMPTY_INPUT_STREAM_EXCEPTION_MESSAGE = "Failed to load the certificate from the provided InputStream because it is null";
private static final UnaryOperator CERTIFICATE_NOT_FOUND_EXCEPTION_MESSAGE = certificatePath -> String.format("Failed to load the certificate from the classpath for the given path: [%s]", certificatePath);
private static final char[] NO_PASSWORD = null;
private static final PemUtils INSTANCE = new PemUtils(
new BouncyCastleProvider(),
new JcaPEMKeyConverter(),
new JcaX509CertificateConverter()
);
private final JcaPEMKeyConverter keyConverter;
private final JcaX509CertificateConverter certificateConverter;
PemUtils(BouncyCastleProvider bouncyCastleProvider,
JcaPEMKeyConverter keyConverter,
JcaX509CertificateConverter certificateConverter) {
Security.addProvider(bouncyCastleProvider);
this.keyConverter = keyConverter;
this.certificateConverter = certificateConverter;
}
/**
* Loads certificates from the classpath and maps it to an instance of {@link X509ExtendedTrustManager}
*/
public static X509ExtendedTrustManager loadTrustMaterial(String... certificatePaths) {
return TrustManagerUtils.createTrustManager(
loadCertificate(certificatePaths)
);
}
/**
* Loads certificates from the filesystem and maps it to an instance of {@link X509ExtendedTrustManager}
*/
public static X509ExtendedTrustManager loadTrustMaterial(Path... certificatePaths) {
return TrustManagerUtils.createTrustManager(
loadCertificate(certificatePaths)
);
}
/**
* Loads certificates from multiple InputStreams and maps it to an instance of {@link X509ExtendedTrustManager}
*/
public static X509ExtendedTrustManager loadTrustMaterial(InputStream... certificateStreams) {
return TrustManagerUtils.createTrustManager(
loadCertificate(certificateStreams)
);
}
/**
* Loads certificates from the classpath and maps it to a list of {@link X509Certificate}
*/
public static List loadCertificate(String... certificatePaths) {
return loadCertificate(
certificatePaths,
certificatePath -> ValidationUtils.requireNotNull(
IOUtils.getResourceAsStream(certificatePath),
CERTIFICATE_NOT_FOUND_EXCEPTION_MESSAGE.apply(certificatePath)
)
);
}
/**
* Loads certificates from the filesystem and maps it to a list of {@link X509Certificate}
*/
public static List loadCertificate(Path... certificatePaths) {
return loadCertificate(certificatePaths, IOUtils::getFileAsStream);
}
/**
* Loads certificates from multiple InputStreams and maps it to a list of {@link X509Certificate}
*/
public static List loadCertificate(InputStream... certificateStreams) {
return loadCertificate(
certificateStreams,
certificateStream -> requireNotNull(certificateStream, EMPTY_INPUT_STREAM_EXCEPTION_MESSAGE)
);
}
private static List loadCertificate(T[] resources, Function resourceMapper) {
return Arrays.stream(resources)
.map(resourceMapper)
.map(IOUtils::getContent)
.map(PemUtils::parseCertificate)
.flatMap(Collection::stream)
.collect(toUnmodifiableList());
}
public static List parseCertificate(String certContent) {
List certificates = parsePemContent(certContent, CERTIFICATE::equals).stream()
.map(PemUtils::extractCertificate)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toUnmodifiableList());
return requireNotEmpty(certificates, () -> new CertificateParseException("Received an unsupported certificate type"));
}
private static List