1 /*============LICENSE_START=======================================================
2 * oom-truststore-merger
3 * ================================================================================
4 * Copyright (C) 2020 Nokia. All rights reserved.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ============LICENSE_END=========================================================
20 package org.onap.oom.truststoremerger.merger.model;
22 import static org.onap.oom.truststoremerger.api.CertificateConstants.BOUNCY_CASTLE_PROVIDER;
23 import static org.onap.oom.truststoremerger.api.CertificateConstants.X_509_CERTIFICATE;
26 import java.io.FileInputStream;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.StringWriter;
30 import java.security.Security;
31 import java.security.cert.Certificate;
32 import java.security.cert.CertificateFactory;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.stream.Collectors;
36 import org.bouncycastle.jce.provider.BouncyCastleProvider;
37 import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
38 import org.bouncycastle.util.io.pem.PemObjectGenerator;
39 import org.bouncycastle.util.io.pem.PemWriter;
40 import org.onap.oom.truststoremerger.merger.exception.MissingTruststoreException;
41 import org.onap.oom.truststoremerger.merger.exception.TruststoreDataOperationException;
42 import org.onap.oom.truststoremerger.merger.exception.WriteTruststoreFileException;
43 import org.onap.oom.truststoremerger.merger.model.certificate.CertificateWithAlias;
44 import org.onap.oom.truststoremerger.merger.model.certificate.CertificateWithAliasFactory;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 public class PemTruststore extends Truststore {
50 private static final Logger LOGGER = LoggerFactory.getLogger(PemTruststore.class);
52 private static final boolean APPEND_TO_FILE = true;
54 private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory();
55 private final List<CertificateWithAlias> certificatesToBeSaved = new ArrayList<>();
57 public PemTruststore(File storeFile) {
61 public List<CertificateWithAlias> getCertificates()
62 throws TruststoreDataOperationException, MissingTruststoreException {
63 LOGGER.debug("Attempt to read certificates from file: {}", storeFile.getPath());
64 if (isFileWithoutPemCertificate()) {
65 throw new MissingTruststoreException("File does not contain any certificate");
67 List<Certificate> extractedCertificate = extractCertificatesFromFile();
68 return wrapCertificates(extractedCertificate);
71 public void addCertificates(List<CertificateWithAlias> certificates)
72 throws TruststoreDataOperationException, MissingTruststoreException {
73 LOGGER.debug("Attempt to add certificates for saving to file");
74 if (isFileWithoutPemCertificate()) {
75 LOGGER.error("File does not contain any certificate. File path: {} ", storeFile.getPath());
76 throw new MissingTruststoreException("File does not contain any certificate");
78 certificatesToBeSaved.addAll(certificates);
81 public void saveFile() throws WriteTruststoreFileException, TruststoreDataOperationException {
82 LOGGER.debug("Attempt to save file: {}", storeFile.getPath());
83 List<Certificate> certificates = certificatesToBeSaved.stream()
84 .map(CertificateWithAlias::getCertificate)
85 .collect(Collectors.toList());
86 String certificatesAsString = transformToStringInPemFormat(certificates);
87 appendToFile(certificatesAsString);
90 boolean isFileWithoutPemCertificate() throws TruststoreDataOperationException {
91 List<Certificate> certificateList = extractCertificatesFromFile();
92 return certificateList.isEmpty();
95 String transformToStringInPemFormat(List<Certificate> certificates) throws TruststoreDataOperationException {
96 StringWriter sw = new StringWriter();
97 List<PemObjectGenerator> generators = transformToPemGenerators(certificates);
98 try (PemWriter pemWriter = new PemWriter(sw)) {
99 for (PemObjectGenerator generator : generators) {
100 pemWriter.writeObject(generator);
102 } catch (IOException e) {
103 LOGGER.error("Cannot convert certificates to PEM format");
104 throw new TruststoreDataOperationException(e);
106 return sw.toString();
109 private List<Certificate> extractCertificatesFromFile() throws TruststoreDataOperationException {
110 try (FileInputStream inputStream = new FileInputStream(storeFile)) {
111 Security.addProvider(new BouncyCastleProvider());
112 CertificateFactory factory = CertificateFactory.getInstance(X_509_CERTIFICATE, BOUNCY_CASTLE_PROVIDER);
113 return new ArrayList<>(factory.generateCertificates(inputStream));
114 } catch (Exception e) {
115 LOGGER.error("Cannot read certificates from file: {}", storeFile.getPath());
116 throw new TruststoreDataOperationException(e);
120 private List<PemObjectGenerator> transformToPemGenerators(List<Certificate> certificates)
121 throws TruststoreDataOperationException {
122 List<PemObjectGenerator> generators = new ArrayList<>();
123 for (Certificate certificate : certificates) {
124 PemObjectGenerator generator = createPemGenerator(certificate);
125 generators.add(generator);
130 private JcaMiscPEMGenerator createPemGenerator(Certificate certificate)
131 throws TruststoreDataOperationException {
133 return new JcaMiscPEMGenerator(certificate);
134 } catch (IOException e) {
135 LOGGER.error("Cannot convert Certificate Object to PemGenerator Object");
136 throw new TruststoreDataOperationException(e);
140 private List<CertificateWithAlias> wrapCertificates(List<Certificate> rawCertificates) {
141 return rawCertificates.stream()
142 .map(factory::createPemCertificate)
143 .collect(Collectors.toList());
146 private void appendToFile(String certificatesAsString) throws WriteTruststoreFileException {
148 FileOutputStream fileOutputStream = new FileOutputStream(storeFile, APPEND_TO_FILE);
149 fileOutputStream.write(certificatesAsString.getBytes());
150 } catch (Exception e) {
151 LOGGER.error("Cannot write certificates to file");
152 throw new WriteTruststoreFileException(e);