bbca91b63a3ae457200474ba82f9f89171ef86dc
[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 static org.onap.oom.certservice.cmpv2client.impl.CmpResponseHelper.checkIfCmpResponseContainsError;
26 import static org.onap.oom.certservice.cmpv2client.impl.CmpResponseHelper.getCertFromByteArray;
27 import static org.onap.oom.certservice.cmpv2client.impl.CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore;
28
29 import java.io.IOException;
30 import java.security.KeyPair;
31 import java.security.Security;
32 import java.security.cert.CertificateParsingException;
33 import java.security.cert.X509Certificate;
34 import java.util.Collections;
35 import java.util.Date;
36 import java.util.Objects;
37 import java.util.Optional;
38 import org.apache.http.impl.client.CloseableHttpClient;
39 import org.bouncycastle.asn1.cmp.CMPCertificate;
40 import org.bouncycastle.asn1.cmp.CertRepMessage;
41 import org.bouncycastle.asn1.cmp.CertResponse;
42 import org.bouncycastle.asn1.cmp.PKIBody;
43 import org.bouncycastle.asn1.cmp.PKIMessage;
44 import org.bouncycastle.asn1.x509.Certificate;
45 import org.bouncycastle.jce.provider.BouncyCastleProvider;
46 import org.onap.oom.certservice.certification.configuration.model.Cmpv2Server;
47 import org.onap.oom.certservice.certification.model.CsrModel;
48 import org.onap.oom.certservice.certification.model.OldCertificateModel;
49 import org.onap.oom.certservice.cmpv2client.api.CmpClient;
50 import org.onap.oom.certservice.cmpv2client.exceptions.CmpClientException;
51 import org.onap.oom.certservice.cmpv2client.model.Cmpv2CertificationModel;
52 import org.onap.oom.certservice.cmpv2client.validation.CmpCertificationValidator;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * Implementation of the CmpClient Interface conforming to RFC4210 (Certificate Management Protocol
58  * (CMP)) and RFC4211 (Certificate Request Message Format (CRMF)) standards.
59  */
60 public class CmpClientImpl implements CmpClient {
61
62     private static final Logger LOG = LoggerFactory.getLogger(CmpClientImpl.class);
63     private final CloseableHttpClient httpClient;
64     private final CmpCertificationValidator validator;
65
66     public CmpClientImpl(CloseableHttpClient httpClient) {
67         this.httpClient = httpClient;
68         this.validator = new CmpCertificationValidator();
69     }
70
71     static {
72         Security.addProvider(new BouncyCastleProvider());
73     }
74
75     @Override
76     public Cmpv2CertificationModel executeInitializationRequest(
77             CsrModel csrModel,
78             Cmpv2Server server,
79             Date notBefore,
80             Date notAfter)
81             throws CmpClientException {
82
83         validator.validate(csrModel, server, httpClient, notBefore, notAfter);
84         final CreateCertRequest certRequest = getIakRvRequest(csrModel, server, notBefore, notAfter, PKIBody.TYPE_INIT_REQ);
85         return executeCmpRequest(csrModel, server, certRequest);
86     }
87
88     @Override
89     public Cmpv2CertificationModel executeInitializationRequest(CsrModel csrModel, Cmpv2Server server)
90             throws CmpClientException {
91         return executeInitializationRequest(csrModel, server, null, null);
92     }
93
94     @Override
95     public Cmpv2CertificationModel executeKeyUpdateRequest(CsrModel csrModel, Cmpv2Server cmpv2Server,
96         OldCertificateModel oldCertificateModel) throws CmpClientException {
97         validator.validate(csrModel, cmpv2Server, httpClient, null, null);
98
99         final PkiMessageProtection pkiMessageProtection = getSignatureProtection(oldCertificateModel);
100         final CreateCertRequest certRequest =
101             getCmpMessageBuilderWithCommonRequestValues(csrModel, cmpv2Server)
102                 .with(CreateCertRequest::setCmpRequestType, PKIBody.TYPE_KEY_UPDATE_REQ)
103                 .with(CreateCertRequest::setExtraCerts, getCMPCertificate(oldCertificateModel.getOldCertificate()))
104                 .with(CreateCertRequest::setProtection, pkiMessageProtection)
105                 .build();
106
107         return executeCmpRequest(csrModel, cmpv2Server, certRequest);
108     }
109
110     @Override
111     public Cmpv2CertificationModel executeCertificationRequest(CsrModel csrModel, Cmpv2Server cmpv2Server) throws CmpClientException {
112
113         validator.validate(csrModel, cmpv2Server, httpClient, null, null);
114         final CreateCertRequest certRequest = getIakRvRequest(csrModel, cmpv2Server, null, null, PKIBody.TYPE_CERT_REQ);
115         return executeCmpRequest(csrModel, cmpv2Server, certRequest);
116     }
117
118     private CreateCertRequest getIakRvRequest(
119         CsrModel csrModel,
120         Cmpv2Server server,
121         Date notBefore,
122         Date notAfter,
123         int requestType) {
124
125         final String iak = server.getAuthentication().getIak();
126         final PkiMessageProtection pkiMessageProtection = new PasswordBasedProtection(iak);
127         return getCmpMessageBuilderWithCommonRequestValues(csrModel, server)
128             .with(CreateCertRequest::setNotBefore, notBefore)
129             .with(CreateCertRequest::setNotAfter, notAfter)
130             .with(CreateCertRequest::setSenderKid, server.getAuthentication().getRv())
131             .with(CreateCertRequest::setCmpRequestType, requestType)
132             .with(CreateCertRequest::setProtection, pkiMessageProtection)
133             .build();
134     }
135
136     private Cmpv2CertificationModel executeCmpRequest(CsrModel csrModel, Cmpv2Server cmpv2Server,
137         CreateCertRequest certRequest) throws CmpClientException {
138         final PKIMessage pkiMessage = certRequest.generateCertReq();
139         Cmpv2HttpClient cmpv2HttpClient = new Cmpv2HttpClient(httpClient);
140         return retrieveCertificates(csrModel, cmpv2Server, pkiMessage, cmpv2HttpClient);
141     }
142
143     private CmpMessageBuilder<CreateCertRequest> getCmpMessageBuilderWithCommonRequestValues(CsrModel csrModel,
144         Cmpv2Server cmpv2Server) {
145         KeyPair keyPair = new KeyPair(csrModel.getPublicKey(), csrModel.getPrivateKey());
146         return CmpMessageBuilder.of(CreateCertRequest::new)
147             .with(CreateCertRequest::setIssuerDn, cmpv2Server.getIssuerDN())
148             .with(CreateCertRequest::setSubjectDn, csrModel.getSubjectData())
149             .with(CreateCertRequest::setSansArray, csrModel.getSans())
150             .with(CreateCertRequest::setSubjectKeyPair, keyPair);
151     }
152
153     private SignatureProtection getSignatureProtection(OldCertificateModel oldCertificateModel) {
154             return new SignatureProtection(oldCertificateModel.getOldPrivateKey());
155     }
156
157     private CMPCertificate[] getCMPCertificate(Certificate oldCertificate) {
158             CMPCertificate cert = new CMPCertificate(oldCertificate);
159             return new CMPCertificate[]{cert};
160     }
161
162     private Cmpv2CertificationModel retrieveCertificates(
163             CsrModel csrModel, Cmpv2Server server, PKIMessage pkiMessage, Cmpv2HttpClient cmpv2HttpClient)
164             throws CmpClientException {
165         final byte[] respBytes = cmpv2HttpClient.postRequest(pkiMessage, server.getUrl(), server.getCaName());
166         try {
167             final PKIMessage respPkiMessage = PKIMessage.getInstance(respBytes);
168             LOG.info("Received response from Server");
169             checkIfCmpResponseContainsError(respPkiMessage);
170             validator.checkCmpResponse(respPkiMessage, csrModel.getPublicKey(), server.getAuthentication().getIak());
171             return checkCmpCertRepMessage(respPkiMessage);
172         } catch (IllegalArgumentException iae) {
173             CmpClientException cmpClientException =
174                     new CmpClientException(
175                             "Error encountered while processing response from CA server ", iae);
176             LOG.error("Error encountered while processing response from CA server ", iae);
177             throw cmpClientException;
178         }
179     }
180
181     private Cmpv2CertificationModel checkCmpCertRepMessage(final PKIMessage respPkiMessage)
182         throws CmpClientException {
183         final PKIBody pkiBody = respPkiMessage.getBody();
184         if (Objects.nonNull(pkiBody) && pkiBody.getContent() instanceof CertRepMessage) {
185             final CertRepMessage certRepMessage = (CertRepMessage) pkiBody.getContent();
186             if (Objects.nonNull(certRepMessage)) {
187                 try {
188                     CertResponse certResponse = getCertificateResponseContainingNewCertificate(certRepMessage);
189                     validator.checkServerResponse(certResponse);
190                     return verifyReturnCertChainAndTrustStore(respPkiMessage, certRepMessage, certResponse);
191                 } catch (IOException | CertificateParsingException ex) {
192                     CmpClientException cmpClientException =
193                         new CmpClientException(
194                             "Exception occurred while retrieving Certificates from response", ex);
195                     LOG.error("Exception occurred while retrieving Certificates from response", ex);
196                     throw cmpClientException;
197                 }
198             } else {
199                 return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
200             }
201         }
202         return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
203     }
204
205     private Cmpv2CertificationModel verifyReturnCertChainAndTrustStore(
206         PKIMessage respPkiMessage, CertRepMessage certRepMessage, CertResponse certResponse)
207         throws CertificateParsingException, CmpClientException, IOException {
208         LOG.info("Verifying certificates returned as part of CertResponse.");
209         final CMPCertificate cmpCertificate =
210             certResponse.getCertifiedKeyPair().getCertOrEncCert().getCertificate();
211         final Optional<X509Certificate> leafCertificate =
212             getCertFromByteArray(cmpCertificate.getEncoded(), X509Certificate.class);
213         if (leafCertificate.isPresent()) {
214             return verifyAndReturnCertChainAndTrustSTore(
215                 respPkiMessage, certRepMessage, leafCertificate.get());
216         }
217         return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
218     }
219
220     private CertResponse getCertificateResponseContainingNewCertificate(
221         CertRepMessage certRepMessage) {
222         return certRepMessage.getResponse()[0];
223     }
224 }