1 /*============LICENSE_START=======================================================
2 * oom-certservice-client
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.certservice.client.certification;
22 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.COMMON_NAME;
23 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.COUNTRY;
24 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.LOCATION;
25 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.ORGANIZATION;
26 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.ORGANIZATION_UNIT;
27 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.SIGN_ALGORITHM;
28 import static org.onap.oom.certservice.client.certification.EncryptionAlgorithmConstants.STATE;
30 import java.io.IOException;
31 import java.io.StringWriter;
32 import java.security.KeyPair;
33 import java.util.List;
34 import java.util.Optional;
35 import java.util.stream.Collectors;
36 import javax.security.auth.x500.X500Principal;
37 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
38 import org.bouncycastle.asn1.x509.Extension;
39 import org.bouncycastle.asn1.x509.Extensions;
40 import org.bouncycastle.asn1.x509.ExtensionsGenerator;
41 import org.bouncycastle.asn1.x509.GeneralName;
42 import org.bouncycastle.asn1.x509.GeneralNames;
43 import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
44 import org.bouncycastle.operator.ContentSigner;
45 import org.bouncycastle.operator.OperatorCreationException;
46 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
47 import org.bouncycastle.pkcs.PKCS10CertificationRequest;
48 import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
49 import org.onap.oom.certservice.client.certification.exception.CsrGenerationException;
50 import org.onap.oom.certservice.client.configuration.model.CsrConfiguration;
51 import org.onap.oom.certservice.client.configuration.model.San;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 public class CsrFactory {
58 private static final Logger LOGGER = LoggerFactory.getLogger(CsrFactory.class);
59 private final CsrConfiguration configuration;
62 public CsrFactory(CsrConfiguration configuration) {
63 this.configuration = configuration;
67 public String createCsrInPem(KeyPair keyPair) throws CsrGenerationException {
68 LOGGER.info("Creation of CSR has been started with following parameters: {}", configuration.toString());
69 String csrParameters = getMandatoryParameters().append(getOptionalParameters()).toString();
70 X500Principal subject = new X500Principal(csrParameters);
71 PKCS10CertificationRequest request = createPkcs10Csr(subject, keyPair);
73 LOGGER.info("Creation of CSR has been completed successfully");
74 return convertPkcs10CsrToPem(request);
77 private StringBuilder getMandatoryParameters() {
78 return new StringBuilder(String.format("%s=%s, %s=%s, %s=%s, %s=%s",
79 COMMON_NAME, configuration.getCommonName(),
80 COUNTRY, configuration.getCountry(),
81 STATE, configuration.getState(),
82 ORGANIZATION, configuration.getOrganization()));
85 private String getOptionalParameters() {
86 StringBuilder optionalParameters = new StringBuilder();
87 Optional.ofNullable(configuration.getOrganizationUnit())
88 .filter(CsrFactory::isParameterPresent)
89 .map(unit -> optionalParameters.append(String.format(", %s=%s", ORGANIZATION_UNIT, unit)));
90 Optional.ofNullable(configuration.getLocation())
91 .filter(CsrFactory::isParameterPresent)
92 .map(location -> optionalParameters.append(String.format(", %s=%s", LOCATION, location)));
93 return optionalParameters.toString();
96 private PKCS10CertificationRequest createPkcs10Csr(X500Principal subject, KeyPair keyPair)
97 throws CsrGenerationException {
98 JcaPKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(subject,
101 if (!configuration.getSans().isEmpty()) {
102 builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, generateSansExtension());
105 return builder.build(getContentSigner(keyPair));
108 private ContentSigner getContentSigner(KeyPair keyPair) throws CsrGenerationException {
109 ContentSigner contentSigner;
111 contentSigner = new JcaContentSignerBuilder(SIGN_ALGORITHM).build(keyPair.getPrivate());
112 } catch (OperatorCreationException e) {
113 LOGGER.error("Creation of PKCS10Csr failed, exception message: {}", e.getMessage());
114 throw new CsrGenerationException(e);
117 return contentSigner;
120 private String convertPkcs10CsrToPem(PKCS10CertificationRequest request) throws CsrGenerationException {
121 final StringWriter stringWriter = new StringWriter();
122 try (JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
123 LOGGER.info("Conversion of CSR to PEM has been started");
124 pemWriter.writeObject(request);
125 } catch (IOException e) {
126 LOGGER.error("Conversion to PEM failed, exception message: {}", e.getMessage());
127 throw new CsrGenerationException(e);
129 return stringWriter.toString();
132 private Extensions generateSansExtension() throws CsrGenerationException {
133 ExtensionsGenerator generator = new ExtensionsGenerator();
135 generator.addExtension(Extension.subjectAlternativeName, false, createGeneralNames());
136 } catch (IOException e) {
137 LOGGER.error("Generation of SANs parameter failed, exception message: {}", e.getMessage());
138 throw new CsrGenerationException(e);
140 return generator.generate();
143 private GeneralNames createGeneralNames() {
144 List<San> sans = this.configuration.getSans();
145 GeneralName[] generalNames = sans.stream()
146 .map(san -> new GeneralName(san.getType(), san.getValue()))
147 .collect(Collectors.toList())
148 .toArray(GeneralName[]::new);
149 return new GeneralNames(generalNames);
152 private static Boolean isParameterPresent(String parameter) {
153 return parameter != null && !"".equals(parameter);