/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. * */ /* * Copyright 2021 floragunn GmbH * * 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 org.opensearch.test.framework.certificate; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.security.PrivateKey; import java.security.SecureRandom; import com.google.common.base.Strings; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.openssl.PKCS8Generator; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.OutputEncryptor; import org.bouncycastle.util.io.pem.PemGenerationException; import org.bouncycastle.util.io.pem.PemObject; import static java.util.Objects.requireNonNull; /** * The class provides a method useful for converting certificate and private key into PEM format * @see RFC 1421 */ class PemConverter { private PemConverter() {} private static final Logger log = LogManager.getLogger(PemConverter.class); private static final SecureRandom secureRandom = new SecureRandom(); /** * It converts certificate represented by {@link X509CertificateHolder} object to PEM format * @param certificate is a certificate to convert * @return {@link String} which contains PEM encoded certificate */ public static String toPem(X509CertificateHolder certificate) { StringWriter stringWriter = new StringWriter(); try (JcaPEMWriter writer = new JcaPEMWriter(stringWriter)) { writer.writeObject(requireNonNull(certificate, "Certificate is required.")); } catch (Exception e) { throw new RuntimeException("Cannot write certificate in PEM format", e); } return stringWriter.toString(); } /** * It converts private key represented by class {@link PrivateKey} to PEM format. * @param privateKey is a private key, cannot be null * @param privateKeyPassword is a password used to encode private key, null for unencrypted private key * @return {@link String} which contains PEM encoded private key */ public static String toPem(PrivateKey privateKey, String privateKeyPassword) { try (StringWriter stringWriter = new StringWriter()) { savePrivateKey(stringWriter, requireNonNull(privateKey, "Private key is required."), privateKeyPassword); return stringWriter.toString(); } catch (IOException e) { throw new RuntimeException("Cannot convert private key into PEM format.", e); } } private static void savePrivateKey(Writer out, PrivateKey privateKey, String privateKeyPassword) { try (JcaPEMWriter writer = new JcaPEMWriter(out)) { writer.writeObject(createPkcs8PrivateKeyPem(privateKey, privateKeyPassword)); } catch (Exception e) { log.error("Error while writing private key.", e); throw new RuntimeException("Error while writing private key ", e); } } private static PemObject createPkcs8PrivateKeyPem(PrivateKey privateKey, String password) { try { OutputEncryptor outputEncryptor = password == null ? null : getPasswordEncryptor(password); return new PKCS8Generator(PrivateKeyInfo.getInstance(privateKey.getEncoded()), outputEncryptor).generate(); } catch (PemGenerationException | OperatorCreationException e) { log.error("Creating PKCS8 private key failed", e); throw new RuntimeException("Creating PKCS8 private key failed", e); } } private static OutputEncryptor getPasswordEncryptor(String password) throws OperatorCreationException { if (!Strings.isNullOrEmpty(password)) { JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.PBE_SHA1_3DES); encryptorBuilder.setRandom(secureRandom); encryptorBuilder.setPassword(password.toCharArray()); return encryptorBuilder.build(); } return null; } }