[OOM-CERT-SERVICE] Refactor CertService API code
[oom/platform/cert-service.git] / certService / src / main / java / org / onap / oom / certservice / cmpv2client / impl / CmpClientImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2020 Nordix Foundation.
4  * ================================================================================
5  * Modification copyright 2021 Nokia
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.oom.certservice.cmpv2client.impl;
24
25 import org.apache.http.impl.client.CloseableHttpClient;
26 import org.bouncycastle.asn1.cmp.CMPCertificate;
27 import org.bouncycastle.asn1.cmp.CertRepMessage;
28 import org.bouncycastle.asn1.cmp.CertResponse;
29 import org.bouncycastle.asn1.cmp.PKIBody;
30 import org.bouncycastle.asn1.cmp.PKIMessage;
31 import org.bouncycastle.asn1.x509.Certificate;
32 import org.bouncycastle.jce.provider.BouncyCastleProvider;
33 import org.onap.oom.certservice.certification.configuration.model.Cmpv2Server;
34 import org.onap.oom.certservice.certification.model.CsrModel;
35 import org.onap.oom.certservice.certification.model.OldCertificateModel;
36 import org.onap.oom.certservice.cmpv2client.api.CmpClient;
37 import org.onap.oom.certservice.cmpv2client.exceptions.CmpClientException;
38 import org.onap.oom.certservice.cmpv2client.impl.protections.PasswordBasedProtection;
39 import org.onap.oom.certservice.cmpv2client.impl.protections.PkiMessageProtection;
40 import org.onap.oom.certservice.cmpv2client.impl.protections.SignatureProtection;
41 import org.onap.oom.certservice.cmpv2client.model.Cmpv2CertificationModel;
42 import org.onap.oom.certservice.cmpv2client.validation.CmpCertificationValidator;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import java.io.IOException;
47 import java.security.KeyPair;
48 import java.security.Security;
49 import java.security.cert.CertificateParsingException;
50 import java.security.cert.X509Certificate;
51 import java.util.Collections;
52 import java.util.Date;
53 import java.util.Objects;
54 import java.util.Optional;
55
56 import static org.onap.oom.certservice.cmpv2client.impl.CmpResponseHelper.checkIfCmpResponseContainsError;
57 import static org.onap.oom.certservice.cmpv2client.impl.CmpResponseHelper.getCertFromByteArray;
58 import static org.onap.oom.certservice.cmpv2client.impl.CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore;
59
60 /**
61  * Implementation of the CmpClient Interface conforming to RFC4210 (Certificate Management Protocol
62  * (CMP)) and RFC4211 (Certificate Request Message Format (CRMF)) standards.
63  */
64 public class CmpClientImpl implements CmpClient {
65
66     private static final Logger LOG = LoggerFactory.getLogger(CmpClientImpl.class);
67     private final CloseableHttpClient httpClient;
68     private final CmpCertificationValidator validator;
69
70     public CmpClientImpl(CloseableHttpClient httpClient) {
71         this.httpClient = httpClient;
72         this.validator = new CmpCertificationValidator();
73     }
74
75     static {
76         Security.addProvider(new BouncyCastleProvider());
77     }
78
79     @Override
80     public Cmpv2CertificationModel executeInitializationRequest(
81             CsrModel csrModel,
82             Cmpv2Server server,
83             Date notBefore,
84             Date notAfter)
85             throws CmpClientException {
86
87         validator.validate(csrModel, server, httpClient, notBefore, notAfter);
88         final CreateCertRequest certRequest = getIakRvRequest(csrModel, server, notBefore, notAfter, PKIBody.TYPE_INIT_REQ);
89         return executeCmpRequest(csrModel, server, certRequest);
90     }
91
92     @Override
93     public Cmpv2CertificationModel executeInitializationRequest(CsrModel csrModel, Cmpv2Server server)
94             throws CmpClientException {
95         return executeInitializationRequest(csrModel, server, null, null);
96     }
97
98     @Override
99     public Cmpv2CertificationModel executeKeyUpdateRequest(CsrModel csrModel, Cmpv2Server cmpv2Server,
100         OldCertificateModel oldCertificateModel) throws CmpClientException {
101         validator.validate(csrModel, cmpv2Server, httpClient, null, null);
102
103         final PkiMessageProtection pkiMessageProtection = getSignatureProtection(oldCertificateModel);
104         final CreateCertRequest certRequest =
105             getCmpMessageBuilderWithCommonRequestValues(csrModel, cmpv2Server)
106                 .with(CreateCertRequest::setCmpRequestType, PKIBody.TYPE_KEY_UPDATE_REQ)
107                 .with(CreateCertRequest::setExtraCerts, getCMPCertificate(oldCertificateModel.getOldCertificate()))
108                 .with(CreateCertRequest::setProtection, pkiMessageProtection)
109                 .build();
110
111         return executeCmpRequest(csrModel, cmpv2Server, certRequest);
112     }
113
114     @Override
115     public Cmpv2CertificationModel executeCertificationRequest(CsrModel csrModel, Cmpv2Server cmpv2Server) throws CmpClientException {
116
117         validator.validate(csrModel, cmpv2Server, httpClient, null, null);
118         final CreateCertRequest certRequest = getIakRvRequest(csrModel, cmpv2Server, null, null, PKIBody.TYPE_CERT_REQ);
119         return executeCmpRequest(csrModel, cmpv2Server, certRequest);
120     }
121
122     private CreateCertRequest getIakRvRequest(
123         CsrModel csrModel,
124         Cmpv2Server server,
125         Date notBefore,
126         Date notAfter,
127         int requestType) {
128
129         final String iak = server.getAuthentication().getIak();
130         final PkiMessageProtection pkiMessageProtection = new PasswordBasedProtection(iak);
131         return getCmpMessageBuilderWithCommonRequestValues(csrModel, server)
132             .with(CreateCertRequest::setNotBefore, notBefore)
133             .with(CreateCertRequest::setNotAfter, notAfter)
134             .with(CreateCertRequest::setSenderKid, server.getAuthentication().getRv())
135             .with(CreateCertRequest::setCmpRequestType, requestType)
136             .with(CreateCertRequest::setProtection, pkiMessageProtection)
137             .build();
138     }
139
140     private Cmpv2CertificationModel executeCmpRequest(CsrModel csrModel, Cmpv2Server cmpv2Server,
141         CreateCertRequest certRequest) throws CmpClientException {
142         final PKIMessage pkiMessage = certRequest.generateCertReq();
143         Cmpv2HttpClient cmpv2HttpClient = new Cmpv2HttpClient(httpClient);
144         return retrieveCertificates(csrModel, cmpv2Server, pkiMessage, cmpv2HttpClient);
145     }
146
147     private CmpMessageBuilder<CreateCertRequest> getCmpMessageBuilderWithCommonRequestValues(CsrModel csrModel,
148         Cmpv2Server cmpv2Server) {
149         KeyPair keyPair = new KeyPair(csrModel.getPublicKey(), csrModel.getPrivateKey());
150         return CmpMessageBuilder.of(CreateCertRequest::new)
151             .with(CreateCertRequest::setIssuerDn, cmpv2Server.getIssuerDN())
152             .with(CreateCertRequest::setSubjectDn, csrModel.getSubjectData())
153             .with(CreateCertRequest::setSansArray, csrModel.getSans())
154             .with(CreateCertRequest::setSubjectKeyPair, keyPair);
155     }
156
157     private SignatureProtection getSignatureProtection(OldCertificateModel oldCertificateModel) {
158             return new SignatureProtection(oldCertificateModel.getOldPrivateKey());
159     }
160
161     private CMPCertificate[] getCMPCertificate(Certificate oldCertificate) {
162             CMPCertificate cert = new CMPCertificate(oldCertificate);
163             return new CMPCertificate[]{cert};
164     }
165
166     private Cmpv2CertificationModel retrieveCertificates(
167             CsrModel csrModel, Cmpv2Server server, PKIMessage pkiMessage, Cmpv2HttpClient cmpv2HttpClient)
168             throws CmpClientException {
169         final byte[] respBytes = cmpv2HttpClient.postRequest(pkiMessage, server.getUrl(), server.getCaName());
170         try {
171             final PKIMessage respPkiMessage = PKIMessage.getInstance(respBytes);
172             LOG.info("Received response from Server");
173             checkIfCmpResponseContainsError(respPkiMessage);
174             validator.checkCmpResponse(respPkiMessage, csrModel.getPublicKey(), server.getAuthentication().getIak());
175             return checkCmpCertRepMessage(respPkiMessage);
176         } catch (IllegalArgumentException iae) {
177             CmpClientException cmpClientException =
178                     new CmpClientException(
179                             "Error encountered while processing response from CA server ", iae);
180             LOG.error("Error encountered while processing response from CA server ", iae);
181             throw cmpClientException;
182         }
183     }
184
185     private Cmpv2CertificationModel checkCmpCertRepMessage(final PKIMessage respPkiMessage)
186         throws CmpClientException {
187         final PKIBody pkiBody = respPkiMessage.getBody();
188         if (Objects.nonNull(pkiBody) && pkiBody.getContent() instanceof CertRepMessage) {
189             final CertRepMessage certRepMessage = (CertRepMessage) pkiBody.getContent();
190             if (Objects.nonNull(certRepMessage)) {
191                 try {
192                     CertResponse certResponse = getCertificateResponseContainingNewCertificate(certRepMessage);
193                     validator.checkServerResponse(certResponse);
194                     return verifyReturnCertChainAndTrustStore(respPkiMessage, certRepMessage, certResponse);
195                 } catch (IOException | CertificateParsingException ex) {
196                     CmpClientException cmpClientException =
197                         new CmpClientException(
198                             "Exception occurred while retrieving Certificates from response", ex);
199                     LOG.error("Exception occurred while retrieving Certificates from response", ex);
200                     throw cmpClientException;
201                 }
202             } else {
203                 return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
204             }
205         }
206         return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
207     }
208
209     private Cmpv2CertificationModel verifyReturnCertChainAndTrustStore(
210         PKIMessage respPkiMessage, CertRepMessage certRepMessage, CertResponse certResponse)
211         throws CertificateParsingException, CmpClientException, IOException {
212         LOG.info("Verifying certificates returned as part of CertResponse.");
213         final CMPCertificate cmpCertificate =
214             certResponse.getCertifiedKeyPair().getCertOrEncCert().getCertificate();
215         final Optional<X509Certificate> leafCertificate =
216             getCertFromByteArray(cmpCertificate.getEncoded(), X509Certificate.class);
217         if (leafCertificate.isPresent()) {
218             return verifyAndReturnCertChainAndTrustSTore(
219                 respPkiMessage, certRepMessage, leafCertificate.get());
220         }
221         return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
222     }
223
224     private CertResponse getCertificateResponseContainingNewCertificate(
225         CertRepMessage certRepMessage) {
226         return certRepMessage.getResponse()[0];
227     }
228 }