/*
* Copyright (C) 2019 Ericsson Software Technology AB. All rights reserved.
+ * Copyright (C) 2021 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.
package org.onap.oom.certservice.cmpv2client;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.MockitoAnnotations.initMocks;
import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
-import java.security.cert.X509Certificate;
+
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Base64.Decoder;
import java.util.Date;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
+import org.bouncycastle.asn1.ASN1GeneralizedTime;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.cmp.PKIBody;
+import org.bouncycastle.asn1.cmp.PKIHeader;
+import org.bouncycastle.asn1.cmp.PKIHeaderBuilder;
+import org.bouncycastle.asn1.cmp.PKIMessage;
+import org.bouncycastle.asn1.crmf.CertReqMessages;
+import org.bouncycastle.asn1.crmf.CertReqMsg;
+import org.bouncycastle.asn1.crmf.CertRequest;
+import org.bouncycastle.asn1.crmf.CertTemplateBuilder;
+import org.bouncycastle.asn1.crmf.ProofOfPossession;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
private Date notAfter;
private X500Name dn;
- @Mock
- X509Certificate cert;
@Mock
CloseableHttpClient httpClient;
private static KeyPair keyPair;
+ private final static Decoder BASE64_DECODER = Base64.getDecoder();
+
@BeforeEach
void setUp()
throws NoSuchProviderException, NoSuchAlgorithmException, IOException,
return new KeyPair(publicKey, privateKey);
}
+ @Test
+ void shouldReturnCorrectCmpCertificateForCorrectKeyUpdateResponse() throws CmpClientException, IOException {
+
+ // given
+ setCsrModelAndServerTestDefaultValues();
+ when(httpClient.execute(any())).thenReturn(httpResponse);
+ when(httpResponse.getEntity()).thenReturn(httpEntity);
+
+ doAnswer(
+ invocation -> {
+ OutputStream os = invocation.getArgument(0);
+ os.write(BASE64_DECODER.decode(ClientTestData.KUR_CORRECT_SERVER_RESPONSE_ENCODED.getBytes()));
+ return null;
+ })
+ .when(httpEntity)
+ .writeTo(any(OutputStream.class));
+ CmpClientImpl cmpClient = new CmpClientImpl(httpClient);
+
+ // when
+ Cmpv2CertificationModel cmpClientResult =
+ cmpClient.updateCertificate(csrModel, server, ClientTestData.TEST_CERTIFICATE_UPDATE_MODEL);
+
+ // then
+ assertNotNull(cmpClientResult);
+ assertThat(cmpClientResult.getCertificateChain()).isNotEmpty();
+ assertThat(cmpClientResult.getCertificateChain()).isNotEmpty();
+
+ }
+
+ @Test
+ void shouldReturnCorrectCmpCertificateForCorrectCertificationRequest() throws CmpClientException, IOException {
+
+ // given
+ setCsrModelAndServerTestDefaultValues();
+ when(httpClient.execute(any())).thenReturn(httpResponse);
+ when(httpResponse.getEntity()).thenReturn(httpEntity);
+
+ doAnswer(
+ invocation -> {
+ OutputStream os = invocation.getArgument(0);
+ os.write(BASE64_DECODER.decode(ClientTestData.CR_CORRECT_SERVER_RESPONSE_ENCODED.getBytes()));
+ return null;
+ })
+ .when(httpEntity)
+ .writeTo(any(OutputStream.class));
+ CmpClientImpl cmpClient = new CmpClientImpl(httpClient);
+
+ // when
+ Cmpv2CertificationModel cmpClientResult =
+ cmpClient.certificationRequest(csrModel, server);
+
+ // then
+ assertNotNull(cmpClientResult);
+ assertThat(cmpClientResult.getCertificateChain()).isNotEmpty();
+ assertThat(cmpClientResult.getCertificateChain()).isNotEmpty();
+
+ }
+
+ @Test
+ void shouldThrowCmpClientExceptionWhenCannotParseOldPrivateKey() {
+ setCsrModelAndServerTestDefaultValues();
+
+ CmpClientImpl cmpClient = new CmpClientImpl(httpClient);
+ assertThatExceptionOfType(CmpClientException.class)
+ .isThrownBy(() -> cmpClient.updateCertificate(csrModel, server, ClientTestData.TEST_CERTIFICATE_UPDATE_MODEL_WITH_WRONG_PRIVATE_KEY))
+ .withMessageContaining("Cannot parse old private key");
+
+ }
+
+
+ @Test
+ void shouldThrowCMPClientExceptionWhenCannotParseOldCertificate() {
+ setCsrModelAndServerTestDefaultValues();
+
+ CmpClientImpl cmpClient = new CmpClientImpl(httpClient);
+
+ // When // Then
+ assertThatExceptionOfType(CmpClientException.class)
+ .isThrownBy(() -> cmpClient.updateCertificate(csrModel, server, ClientTestData.TEST_CERTIFICATE_UPDATE_MODEL_WITH_WRONG_OLD_CERT))
+ .withMessageContaining("Cannot parse old certificate");
+ }
+
+
@Test
void shouldReturnValidPkiMessageWhenCreateCertificateRequestMessageMethodCalledWithValidCsr()
throws Exception {
() -> cmpClient.createCertificate(csrModel, server, notBefore, notAfter));
}
+
+ @Test
+ void shouldThrowExceptionWhenResponseNotContainProtectionAlgorithmField()
+ throws IOException, ParseException {
+
+ Date beforeDate = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse("2019/11/11 12:00:00");
+ Date afterDate = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse("2020/11/11 12:00:00");
+ setCsrModelAndServerValues(
+ "password",
+ "senderKID",
+ "http://127.0.0.1/ejbca/publicweb/cmp/cmp",
+ beforeDate,
+ afterDate);
+
+ when(httpClient.execute(any())).thenReturn(httpResponse);
+ when(httpResponse.getEntity()).thenReturn(httpEntity);
+
+ try (
+ BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(
+ preparePKIMessageWithoutProtectionAlgorithm().getEncoded()
+ ))) {
+
+ byte[] ba = IOUtils.toByteArray(bis);
+ doAnswer(
+ invocation -> {
+ OutputStream os = invocation.getArgument(0);
+ os.write(ba);
+ return null;
+ })
+ .when(httpEntity)
+ .writeTo(any(OutputStream.class));
+ }
+
+ CmpClientImpl cmpClient = new CmpClientImpl(httpClient);
+
+ assertThatExceptionOfType(CmpClientException.class)
+ .isThrownBy(() -> cmpClient.createCertificate(csrModel, server, notBefore, notAfter))
+ .withMessageContaining("CMP response does not contain Protection Algorithm field");
+
+ }
+
@Test
void shouldThrowIllegalArgumentExceptionWhencreateCertificateCalledWithInvalidCsr()
throws ParseException {
this.notBefore = notBefore;
this.notAfter = notAfter;
}
+
+ private void setCsrModelAndServerTestDefaultValues() {
+ csrModel = new CsrModel(null, dn, keyPair.getPrivate(), keyPair.getPublic(), new GeneralName[0]);
+
+ Authentication authentication = new Authentication();
+ authentication.setIak("mypassword");
+ authentication.setRv("senderKID");
+ server = new Cmpv2Server();
+ server.setAuthentication(authentication);
+ server.setUrl("http://127.0.0.1/ejbca/publicweb/cmp/cmp");
+ server.setIssuerDN(dn);
+ }
+
+ private PKIMessage preparePKIMessageWithoutProtectionAlgorithm() {
+
+ CertTemplateBuilder certTemplateBuilder = new CertTemplateBuilder();
+ X500Name issuerDN = getTestIssuerDN();
+
+ certTemplateBuilder.setIssuer(issuerDN);
+ certTemplateBuilder.setSerialNumber(new ASN1Integer(0L));
+
+ CertRequest certRequest = new CertRequest(4, certTemplateBuilder.build(), null);
+ CertReqMsg certReqMsg = new CertReqMsg(certRequest, new ProofOfPossession(), null);
+ CertReqMessages certReqMessages = new CertReqMessages(certReqMsg);
+
+ PKIHeaderBuilder pkiHeaderBuilder = new PKIHeaderBuilder(PKIHeader.CMP_2000, new GeneralName(issuerDN), new GeneralName(issuerDN));
+ pkiHeaderBuilder.setMessageTime(new ASN1GeneralizedTime(new Date()));
+ pkiHeaderBuilder.setProtectionAlg(null);
+
+ PKIBody pkiBody = new PKIBody(PKIBody.TYPE_INIT_REQ, certReqMessages);
+ return new PKIMessage(pkiHeaderBuilder.build(), pkiBody, new DERBitString("test".getBytes()));
+ }
+
+ private X500Name getTestIssuerDN() {
+ return new X500NameBuilder()
+ .addRDN(BCStyle.O, "Test_Organization")
+ .addRDN(BCStyle.UID, "Test_UID")
+ .addRDN(BCStyle.CN, "Test_CA")
+ .build();
+ }
+
}