diff options
Diffstat (limited to 'certService/src/main/java/org/onap/aaf/certservice/certification/adapter')
5 files changed, 350 insertions, 0 deletions
diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/CSRMetaBuilder.java b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/CSRMetaBuilder.java new file mode 100644 index 00000000..184d724a --- /dev/null +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/CSRMetaBuilder.java @@ -0,0 +1,87 @@ +/* + * ============LICENSE_START======================================================= + * Cert Service + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aaf.certservice.certification.adapter; + +import java.security.KeyPair; +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x500.style.IETFUtils; +import org.bouncycastle.cert.CertException; +import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server; +import org.onap.aaf.certservice.certification.model.CsrModel; +import org.onap.aaf.certservice.cmpv2client.external.CSRMeta; +import org.onap.aaf.certservice.cmpv2client.external.RDN; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +class CSRMetaBuilder { + + private static final Logger LOGGER = LoggerFactory.getLogger(CSRMetaBuilder.class); + + /** + * Creates CSRMeta from CsrModel and Cmpv2Server + * + * @param csrModel Certificate Signing Request from Service external API + * @param server Cmp Server configuration from cmpServers.json + * @return AAF native model for CSR metadata + */ + CSRMeta build(CsrModel csrModel, Cmpv2Server server) { + CSRMeta csrMeta = createCsrMeta(csrModel); + addSans(csrModel, csrMeta); + csrMeta.keyPair(new KeyPair(csrModel.getPublicKey(), csrModel.getPrivateKey())); + csrMeta.password(server.getAuthentication().getIak()); + csrMeta.setIssuerName(server.getIssuerDN()); + csrMeta.caUrl(server.getUrl()); + csrMeta.setName(csrModel.getSubjectData()); + csrMeta.senderKid(server.getAuthentication().getRv()); + return csrMeta; + } + + private CSRMeta createCsrMeta(CsrModel csrModel) { + return new CSRMeta((Arrays.stream(csrModel.getSubjectData().getRDNs()).map(this::convertFromBcRDN) + .filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList()))); + } + + private void addSans(CsrModel csrModel, CSRMeta csrMeta) { + csrModel.getSans().forEach(csrMeta::san); + } + + private String convertRDNToString(org.bouncycastle.asn1.x500.RDN rdn) { + return BCStyle.INSTANCE.oidToDisplayName(rdn.getFirst().getType()) + "=" + IETFUtils.valueToString( + rdn.getFirst().getValue()); + } + + private Optional<RDN> convertFromBcRDN(org.bouncycastle.asn1.x500.RDN rdn) { + RDN result = null; + try { + result = new RDN(convertRDNToString(rdn)); + } catch (CertException e) { + LOGGER.error("Exception occurred during convert of RDN", e); + } + return Optional.ofNullable(result); + } + +} diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/CertificateFactoryProvider.java b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/CertificateFactoryProvider.java new file mode 100644 index 00000000..79f59363 --- /dev/null +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/CertificateFactoryProvider.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * Cert Service + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aaf.certservice.certification.adapter; + +import java.io.InputStream; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.springframework.stereotype.Component; + +@Component +public class CertificateFactoryProvider { + + static { + Security.addProvider(new BouncyCastleProvider()); + } + + X509Certificate generateCertificate(InputStream inStream) throws CertificateException, NoSuchProviderException { + return (X509Certificate) CertificateFactory.getInstance("X.509", "BC").generateCertificate(inStream); + } +} diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/Cmpv2ClientAdapter.java b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/Cmpv2ClientAdapter.java new file mode 100644 index 00000000..be39f1f3 --- /dev/null +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/Cmpv2ClientAdapter.java @@ -0,0 +1,120 @@ +/* + * ============LICENSE_START======================================================= + * Cert Service + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aaf.certservice.certification.adapter; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.stream.Collectors; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.util.io.pem.PemObjectGenerator; +import org.bouncycastle.util.io.pem.PemWriter; +import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server; +import org.onap.aaf.certservice.certification.exception.Cmpv2ClientAdapterException; +import org.onap.aaf.certservice.certification.model.CertificationModel; +import org.onap.aaf.certservice.certification.model.CsrModel; +import org.onap.aaf.certservice.cmpv2client.api.CmpClient; +import org.onap.aaf.certservice.cmpv2client.exceptions.CmpClientException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class Cmpv2ClientAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(Cmpv2ClientAdapter.class); + + private final CmpClient cmpClient; + private final CSRMetaBuilder csrMetaBuilder; + private final RSAContentSignerBuilder rsaContentSignerBuilder; + private final X509CertificateBuilder x509CertificateBuilder; + private final CertificateFactoryProvider certificateFactoryProvider; + + @Autowired + public Cmpv2ClientAdapter(CmpClient cmpClient, CSRMetaBuilder csrMetaBuilder, + RSAContentSignerBuilder rsaContentSignerBuilder, X509CertificateBuilder x509CertificateBuilder, + CertificateFactoryProvider certificateFactoryProvider) { + this.cmpClient = cmpClient; + this.csrMetaBuilder = csrMetaBuilder; + this.rsaContentSignerBuilder = rsaContentSignerBuilder; + this.x509CertificateBuilder = x509CertificateBuilder; + this.certificateFactoryProvider = certificateFactoryProvider; + } + + /** + * Uses CmpClient to call to Cmp Server and gather certificates data + * + * @param csrModel Certificate Signing Request from Service external API + * @param server Cmp Server configuration from cmpServers.json + * @return container for returned certificates + * @throws CmpClientException Exceptions which comes from Cmp Client + * @throws Cmpv2ClientAdapterException Exceptions which comes from Adapter itself + */ + public CertificationModel callCmpClient(CsrModel csrModel, Cmpv2Server server) + throws CmpClientException, Cmpv2ClientAdapterException { + List<List<X509Certificate>> certificates = cmpClient.createCertificate(server.getCaName(), + server.getCaMode().getProfile(), csrMetaBuilder.build(csrModel, server), + convertCSRToX509Certificate(csrModel.getCsr(), csrModel.getPrivateKey())); + return new CertificationModel(convertFromX509CertificateListToPEMList(certificates.get(0)), + convertFromX509CertificateListToPEMList(certificates.get(1))); + } + + private String convertFromX509CertificateToPEM(X509Certificate certificate) { + StringWriter sw = new StringWriter(); + try (PemWriter pw = new PemWriter(sw)) { + PemObjectGenerator gen = new JcaMiscPEMGenerator(certificate); + pw.writeObject(gen); + } catch (IOException e) { + LOGGER.error("Exception occurred during convert of X509 certificate", e); + } + return sw.toString(); + } + + private X509Certificate convertCSRToX509Certificate(PKCS10CertificationRequest csr, PrivateKey privateKey) + throws Cmpv2ClientAdapterException { + try { + X509v3CertificateBuilder certificateGenerator = x509CertificateBuilder.build(csr); + ContentSigner signer = rsaContentSignerBuilder.build(csr, privateKey); + X509CertificateHolder holder = certificateGenerator.build(signer); + return certificateFactoryProvider + .generateCertificate(new ByteArrayInputStream(holder.toASN1Structure().getEncoded())); + } catch (IOException | CertificateException | OperatorCreationException | NoSuchProviderException e) { + throw new Cmpv2ClientAdapterException(e); + } + } + + private List<String> convertFromX509CertificateListToPEMList(List<X509Certificate> certificates) { + return certificates.stream().map(this::convertFromX509CertificateToPEM).filter(cert -> !cert.isEmpty()) + .collect(Collectors.toList()); + } + +} diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/RSAContentSignerBuilder.java b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/RSAContentSignerBuilder.java new file mode 100644 index 00000000..266c22e2 --- /dev/null +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/RSAContentSignerBuilder.java @@ -0,0 +1,45 @@ +/* + * ============LICENSE_START======================================================= + * Cert Service + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.certservice.certification.adapter; + +import java.io.IOException; +import java.security.PrivateKey; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.util.PrivateKeyFactory; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.springframework.stereotype.Component; + +@Component +public class RSAContentSignerBuilder { + + ContentSigner build(PKCS10CertificationRequest csr, PrivateKey privateKey) + throws IOException, OperatorCreationException { + AlgorithmIdentifier sigAlgId = csr.getSignatureAlgorithm(); + AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId); + + return new BcRSAContentSignerBuilder(sigAlgId, digAlgId) + .build(PrivateKeyFactory.createKey(privateKey.getEncoded())); + } + +} diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/X509CertificateBuilder.java b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/X509CertificateBuilder.java new file mode 100644 index 00000000..f96cec8e --- /dev/null +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/adapter/X509CertificateBuilder.java @@ -0,0 +1,56 @@ +/* + * ============LICENSE_START======================================================= + * Cert Service + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aaf.certservice.certification.adapter; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.springframework.stereotype.Component; + +@Component +public class X509CertificateBuilder { + + private static final int SECURE_NEXT_BYTES = 16; + private static final int VALID_PERIOD_IN_DAYS = 365; + + X509v3CertificateBuilder build(PKCS10CertificationRequest csr) throws IOException { + return new X509v3CertificateBuilder(csr.getSubject(), createSerial(), + Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), + Date.from(LocalDateTime.now().plusDays(VALID_PERIOD_IN_DAYS).toInstant(ZoneOffset.UTC)), + new PKCS10CertificationRequest(csr.getEncoded()).getSubject(), + SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(csr.getSubjectPublicKeyInfo().getEncoded()))); + + } + + private BigInteger createSerial() { + byte[] serial = new byte[SECURE_NEXT_BYTES]; + new SecureRandom().nextBytes(serial); + return new BigInteger(serial).abs(); + } + +} |