642721cc7d86e3fa94f10ac7e3dc43e2b96fdad8
[oom/platform/cert-service.git] / certServicePostProcessor / src / main / java / org / onap / oom / certservice / postprocessor / merger / model / PemTruststore.java
1 /*============LICENSE_START=======================================================
2  * oom-truststore-merger
3  * ================================================================================
4  * Copyright (C) 2020-2021 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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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=========================================================
18  */
19
20 package org.onap.oom.certservice.postprocessor.merger.model;
21
22 import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.BOUNCY_CASTLE_PROVIDER;
23 import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.X_509_CERTIFICATE;
24
25 import java.io.File;
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.certservice.postprocessor.common.FileTools;
41 import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException;
42 import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreDataOperationException;
43 import org.onap.oom.certservice.postprocessor.merger.exception.WriteTruststoreFileException;
44 import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias;
45 import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAliasFactory;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class PemTruststore extends Truststore {
50
51     private static final Logger LOGGER = LoggerFactory.getLogger(PemTruststore.class);
52
53     private static final boolean APPEND_TO_FILE = true;
54
55     private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory();
56     private final List<CertificateWithAlias> certificatesToBeSaved = new ArrayList<>();
57
58     public PemTruststore(File storeFile) {
59         super(storeFile, new FileTools());
60     }
61
62     public List<CertificateWithAlias> getCertificates()
63         throws TruststoreDataOperationException, MissingTruststoreException {
64         LOGGER.debug("Attempt to read certificates from file: {}", storeFile.getPath());
65         if (isFileWithoutPemCertificate()) {
66             throw new MissingTruststoreException("File does not contain any certificate");
67         }
68         List<Certificate> extractedCertificate = extractCertificatesFromFile();
69         return wrapCertificates(extractedCertificate);
70     }
71
72     public void addCertificates(List<CertificateWithAlias> certificates)
73         throws TruststoreDataOperationException, MissingTruststoreException {
74         LOGGER.debug("Attempt to add certificates for saving to file");
75         if (isFileWithoutPemCertificate()) {
76             LOGGER.error("File does not contain any certificate. File path: {} ", storeFile.getPath());
77             throw new MissingTruststoreException("File does not contain any certificate");
78         }
79         certificatesToBeSaved.addAll(certificates);
80     }
81
82     public void saveFile() throws WriteTruststoreFileException, TruststoreDataOperationException {
83         LOGGER.debug("Attempt to save file: {}", storeFile.getPath());
84         List<Certificate> certificates = certificatesToBeSaved.stream()
85             .map(CertificateWithAlias::getCertificate)
86             .collect(Collectors.toList());
87         String certificatesAsString = transformToStringInPemFormat(certificates);
88         appendToFile(certificatesAsString);
89     }
90
91     boolean isFileWithoutPemCertificate() throws TruststoreDataOperationException {
92         List<Certificate> certificateList = extractCertificatesFromFile();
93         return certificateList.isEmpty();
94     }
95
96     String transformToStringInPemFormat(List<Certificate> certificates) throws TruststoreDataOperationException {
97         StringWriter sw = new StringWriter();
98         List<PemObjectGenerator> generators = transformToPemGenerators(certificates);
99         try (PemWriter pemWriter = new PemWriter(sw)) {
100             for (PemObjectGenerator generator : generators) {
101                 pemWriter.writeObject(generator);
102             }
103         } catch (IOException e) {
104             LOGGER.error("Cannot convert certificates to PEM format");
105             throw new TruststoreDataOperationException(e);
106         }
107         return sw.toString();
108     }
109
110     private List<Certificate> extractCertificatesFromFile() throws TruststoreDataOperationException {
111         try (FileInputStream inputStream = new FileInputStream(storeFile)) {
112             Security.addProvider(new BouncyCastleProvider());
113             CertificateFactory certFactory = CertificateFactory.getInstance(X_509_CERTIFICATE, BOUNCY_CASTLE_PROVIDER);
114             return new ArrayList<>(certFactory.generateCertificates(inputStream));
115         } catch (Exception e) {
116             LOGGER.error("Cannot read certificates from file: {}", storeFile.getPath());
117             throw new TruststoreDataOperationException(e);
118         }
119     }
120
121     private List<PemObjectGenerator> transformToPemGenerators(List<Certificate> certificates)
122         throws TruststoreDataOperationException {
123         List<PemObjectGenerator> generators = new ArrayList<>();
124         for (Certificate certificate : certificates) {
125             PemObjectGenerator generator = createPemGenerator(certificate);
126             generators.add(generator);
127         }
128         return generators;
129     }
130
131     private JcaMiscPEMGenerator createPemGenerator(Certificate certificate)
132         throws TruststoreDataOperationException {
133         try {
134             return new JcaMiscPEMGenerator(certificate);
135         } catch (IOException e) {
136             LOGGER.error("Cannot convert Certificate Object to PemGenerator Object");
137             throw new TruststoreDataOperationException(e);
138         }
139     }
140
141     private List<CertificateWithAlias> wrapCertificates(List<Certificate> rawCertificates) {
142         return rawCertificates.stream()
143             .map(factory::createPemCertificate)
144             .collect(Collectors.toList());
145     }
146
147     private void appendToFile(String certificatesAsString) throws WriteTruststoreFileException {
148         try (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);
153         }
154     }
155 }