[OOM-CERT-SERVICE] Add Certification Request functionality
[oom/platform/cert-service.git] / certService / src / test / java / org / onap / oom / certservice / cmpv2client / Cmpv2ClientTest.java
index 6a5a37f..de0a100 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * 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.
@@ -16,6 +17,8 @@
 
 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;
@@ -24,6 +27,7 @@ import static org.mockito.Mockito.when;
 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;
@@ -35,18 +39,32 @@ import java.security.NoSuchProviderException;
 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;
@@ -76,8 +94,6 @@ class Cmpv2ClientTest {
     private Date notAfter;
     private X500Name dn;
 
-    @Mock
-    X509Certificate cert;
 
     @Mock
     CloseableHttpClient httpClient;
@@ -90,6 +106,8 @@ class Cmpv2ClientTest {
 
     private static KeyPair keyPair;
 
+    private final static Decoder BASE64_DECODER = Base64.getDecoder();
+
     @BeforeEach
     void setUp()
             throws NoSuchProviderException, NoSuchAlgorithmException, IOException,
@@ -122,6 +140,89 @@ class Cmpv2ClientTest {
         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 {
@@ -233,6 +334,47 @@ class Cmpv2ClientTest {
                 () -> 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 {
@@ -285,4 +427,45 @@ class Cmpv2ClientTest {
         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();
+    }
+
 }