d04a01b18c981c7ca16cdd27d04af3fd72061ee7
[oom/platform/cert-service.git] / trustStoreMerger / src / main / java / org / onap / oom / truststoremerger / merger / model / PemTruststore.java
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
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.truststoremerger.merger.model;
21
22 import static org.onap.oom.truststoremerger.api.CertificateConstants.BOUNCY_CASTLE_PROVIDER;
23 import static org.onap.oom.truststoremerger.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.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;
47
48 public class PemTruststore extends Truststore {
49
50     private static final Logger LOGGER = LoggerFactory.getLogger(PemTruststore.class);
51
52     private static final boolean APPEND_TO_FILE = true;
53
54     private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory();
55     private final List<CertificateWithAlias> certificatesToBeSaved = new ArrayList<>();
56
57     public PemTruststore(File storeFile) {
58         super(storeFile);
59     }
60
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");
66         }
67         List<Certificate> extractedCertificate = extractCertificatesFromFile();
68         return wrapCertificates(extractedCertificate);
69     }
70
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");
77         }
78         certificatesToBeSaved.addAll(certificates);
79     }
80
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);
88     }
89
90     boolean isFileWithoutPemCertificate() throws TruststoreDataOperationException {
91         List<Certificate> certificateList = extractCertificatesFromFile();
92         return certificateList.isEmpty();
93     }
94
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);
101             }
102         } catch (IOException e) {
103             LOGGER.error("Cannot convert certificates to PEM format");
104             throw new TruststoreDataOperationException(e);
105         }
106         return sw.toString();
107     }
108
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);
117         }
118     }
119
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);
126         }
127         return generators;
128     }
129
130     private JcaMiscPEMGenerator createPemGenerator(Certificate certificate)
131         throws TruststoreDataOperationException {
132         try {
133             return new JcaMiscPEMGenerator(certificate);
134         } catch (IOException e) {
135             LOGGER.error("Cannot convert Certificate Object to PemGenerator Object");
136             throw new TruststoreDataOperationException(e);
137         }
138     }
139
140     private List<CertificateWithAlias> wrapCertificates(List<Certificate> rawCertificates) {
141         return rawCertificates.stream()
142             .map(factory::createPemCertificate)
143             .collect(Collectors.toList());
144     }
145
146     private void appendToFile(String certificatesAsString) throws WriteTruststoreFileException {
147         try {
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);
153         }
154     }
155 }