Refactor CmpResponseHelper to support intermediate certificate
authorBartosz Gardziejewski <bartosz.gardziejewski@nokia.com>
Wed, 25 Mar 2020 13:08:49 +0000 (14:08 +0100)
committerZebek Bogumil <bogumil.zebek@nokia.com>
Fri, 27 Mar 2020 10:47:14 +0000 (11:47 +0100)
Issue-ID: AAF-1107
Signed-off-by: Bartosz Gardziejewski <bartosz.gardziejewski@nokia.com>
Change-Id: Ia2e2f9ba1fbcf0482121ffb5f451c408774481ba

certService/src/main/java/org/onap/aaf/certservice/certification/CertificationProvider.java
certService/src/main/java/org/onap/aaf/certservice/cmpv2client/api/CmpClient.java
certService/src/main/java/org/onap/aaf/certservice/cmpv2client/impl/CmpClientImpl.java
certService/src/main/java/org/onap/aaf/certservice/cmpv2client/impl/CmpResponseHelper.java
certService/src/main/java/org/onap/aaf/certservice/cmpv2client/model/Cmpv2CertificationModel.java [new file with mode: 0644]
certService/src/test/java/org/onap/aaf/certservice/certification/CertificationProviderTest.java
certService/src/test/java/org/onap/aaf/certservice/cmpv2client/Cmpv2ClientTest.java
certService/src/test/java/org/onap/aaf/certservice/cmpv2client/impl/CmpResponseHelperTest.java [new file with mode: 0644]

index 4435aa7..2478cc5 100644 (file)
@@ -28,6 +28,7 @@ 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.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -53,9 +54,9 @@ public class CertificationProvider {
 
     public CertificationModel signCsr(CsrModel csrModel, Cmpv2Server server)
             throws CmpClientException {
-        List<List<X509Certificate>> certificates = cmpClient.createCertificate(csrModel, server);
-        return new CertificationModel(convertFromX509CertificateListToPemList(certificates.get(0)),
-                convertFromX509CertificateListToPemList(certificates.get(1)));
+        Cmpv2CertificationModel certificates = cmpClient.createCertificate(csrModel, server);
+        return new CertificationModel(convertFromX509CertificateListToPemList(certificates.getCertificateChain()),
+                convertFromX509CertificateListToPemList(certificates.getTrustedCertificates()));
     }
 
     private static List<String> convertFromX509CertificateListToPemList(List<X509Certificate> certificates) {
index 6ff1bf6..cccb744 100644 (file)
 
 package org.onap.aaf.certservice.cmpv2client.api;
 
-import java.security.cert.X509Certificate;
 import java.util.Date;
-import java.util.List;
 
 import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server;
 import org.onap.aaf.certservice.certification.model.CsrModel;
 import org.onap.aaf.certservice.cmpv2client.exceptions.CmpClientException;
+import org.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
 
 /**
  * This class represent CmpV2Client Interface for obtaining X.509 Digital Certificates in a Public
@@ -47,10 +46,10 @@ public interface CmpClient {
    *                  before this date.
    * @param notAfter  An optional validity to set in the created certificate, Certificate not valid
    *                  after this date.
-   * @return {@link X509Certificate} The newly created Certificate.
+   * @return model for certification containing certificate chain and trusted certificates
    * @throws CmpClientException if client error occurs.
    */
-  List<List<X509Certificate>> createCertificate(
+  Cmpv2CertificationModel createCertificate(
       CsrModel csrModel,
       Cmpv2Server server,
       Date notBefore,
@@ -65,10 +64,10 @@ public interface CmpClient {
    *
    * @param csrModel  Certificate Signing Request Model. Must not be {@code null}.
    * @param server    CMPv2 server. Must not be {@code null}.
-   * @return {@link X509Certificate} The newly created Certificate.
+   * @return model for certification containing certificate chain and trusted certificates
    * @throws CmpClientException if client error occurs.
    */
-  List<List<X509Certificate>> createCertificate(
+  Cmpv2CertificationModel createCertificate(
       CsrModel csrModel,
       Cmpv2Server server)
       throws CmpClientException;
index 28731f2..8799113 100644 (file)
@@ -24,7 +24,7 @@ import java.security.KeyPair;
 import java.security.PublicKey;
 
 import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseHelper.checkIfCmpResponseContainsError;
-import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseHelper.getCertfromByteArray;
+import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseHelper.getCertFromByteArray;
 import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore;
 import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseValidationHelper.checkImplicitConfirm;
 import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseValidationHelper.verifyPasswordBasedProtection;
@@ -33,10 +33,8 @@ import static org.onap.aaf.certservice.cmpv2client.impl.CmpResponseValidationHel
 import java.io.IOException;
 import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
-import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 
@@ -53,6 +51,7 @@ import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server;
 import org.onap.aaf.certservice.certification.model.CsrModel;
 import org.onap.aaf.certservice.cmpv2client.exceptions.CmpClientException;
 import org.onap.aaf.certservice.cmpv2client.api.CmpClient;
+import org.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,7 +72,7 @@ public class CmpClientImpl implements CmpClient {
     }
 
     @Override
-    public List<List<X509Certificate>> createCertificate(
+    public Cmpv2CertificationModel createCertificate(
             CsrModel csrModel,
             Cmpv2Server server,
             Date notBefore,
@@ -101,7 +100,7 @@ public class CmpClientImpl implements CmpClient {
     }
 
     @Override
-    public List<List<X509Certificate>> createCertificate(CsrModel csrModel, Cmpv2Server server)
+    public Cmpv2CertificationModel createCertificate(CsrModel csrModel, Cmpv2Server server)
             throws CmpClientException {
         return createCertificate(csrModel, server, null, null);
     }
@@ -145,7 +144,7 @@ public class CmpClientImpl implements CmpClient {
         }
     }
 
-    private List<List<X509Certificate>> checkCmpCertRepMessage(final PKIMessage respPkiMessage)
+    private Cmpv2CertificationModel checkCmpCertRepMessage(final PKIMessage respPkiMessage)
             throws CmpClientException {
         final PKIBody pkiBody = respPkiMessage.getBody();
         if (Objects.nonNull(pkiBody) && pkiBody.getContent() instanceof CertRepMessage) {
@@ -163,25 +162,25 @@ public class CmpClientImpl implements CmpClient {
                     throw cmpClientException;
                 }
             } else {
-                return new ArrayList<>(Collections.emptyList());
+                return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
             }
         }
-        return new ArrayList<>(Collections.emptyList());
+        return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
     }
 
-    private List<List<X509Certificate>> verifyReturnCertChainAndTrustStore(
+    private Cmpv2CertificationModel verifyReturnCertChainAndTrustStore(
             PKIMessage respPkiMessage, CertRepMessage certRepMessage, CertResponse certResponse)
             throws CertificateParsingException, CmpClientException, IOException {
         LOG.info("Verifying certificates returned as part of CertResponse.");
         final CMPCertificate cmpCertificate =
                 certResponse.getCertifiedKeyPair().getCertOrEncCert().getCertificate();
         final Optional<X509Certificate> leafCertificate =
-                getCertfromByteArray(cmpCertificate.getEncoded(), X509Certificate.class);
+                getCertFromByteArray(cmpCertificate.getEncoded(), X509Certificate.class);
         if (leafCertificate.isPresent()) {
             return verifyAndReturnCertChainAndTrustSTore(
                     respPkiMessage, certRepMessage, leafCertificate.get());
         }
-        return Collections.emptyList();
+        return new Cmpv2CertificationModel(Collections.emptyList(), Collections.emptyList());
     }
 
     private CertResponse getCertificateResponseContainingNewCertificate(
@@ -192,8 +191,8 @@ public class CmpClientImpl implements CmpClient {
     /**
      * Validate inputs for Certificate Creation.
      *
-     * @param csrModel        Certificate Signing Request model. Must not be {@code null}.
-     * @param server          CMPv2 Server. Must not be {@code null}.
+     * @param csrModel Certificate Signing Request model. Must not be {@code null}.
+     * @param server   CMPv2 Server. Must not be {@code null}.
      * @throws IllegalArgumentException if Before Date is set after the After Date.
      */
     private static void validate(
@@ -222,7 +221,7 @@ public class CmpClientImpl implements CmpClient {
         }
     }
 
-    private List<List<X509Certificate>> retrieveCertificates(
+    private Cmpv2CertificationModel retrieveCertificates(
             CsrModel csrModel, Cmpv2Server server, PKIMessage pkiMessage, Cmpv2HttpClient cmpv2HttpClient)
             throws CmpClientException {
         final byte[] respBytes = cmpv2HttpClient.postRequest(pkiMessage, server.getUrl(), server.getCaName());
index b2a7b29..3cb0b0c 100644 (file)
@@ -40,7 +40,9 @@ import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 
@@ -49,9 +51,11 @@ import org.bouncycastle.asn1.cmp.CertRepMessage;
 import org.bouncycastle.asn1.cmp.ErrorMsgContent;
 import org.bouncycastle.asn1.cmp.PKIBody;
 import org.bouncycastle.asn1.cmp.PKIMessage;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.onap.aaf.certservice.cmpv2client.exceptions.CmpClientException;
 import org.onap.aaf.certservice.cmpv2client.exceptions.PkiErrorException;
+import org.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,7 +66,7 @@ public final class CmpResponseHelper {
     private CmpResponseHelper() {
     }
 
-    public static void checkIfCmpResponseContainsError(PKIMessage respPkiMessage)
+    static void checkIfCmpResponseContainsError(PKIMessage respPkiMessage)
             throws CmpClientException {
         if (respPkiMessage.getBody().getType() == PKIBody.TYPE_ERROR) {
             final ErrorMsgContent errorMsgContent =
@@ -77,54 +81,91 @@ public final class CmpResponseHelper {
         }
     }
 
+
     /**
-     * @param cert       byte array that contains certificate
-     * @param returnType the type of Certificate to be returned, for example X509Certificate.class.
-     *                   Certificate.class can be used if certificate type is unknown.
-     * @throws CertificateParsingException if the byte array does not contain a proper certificate.
+     * Puts together certChain and Trust store and verifies the certChain
+     *
+     * @param respPkiMessage  PKIMessage that may contain extra certs used for certchain
+     * @param certRepMessage  CertRepMessage that should contain rootCA for certchain
+     * @param leafCertificate certificate returned from our original Cert Request
+     * @return model for certification containing certificate chain and trusted certificates
+     * @throws CertificateParsingException thrown if error occurs while parsing certificate
+     * @throws IOException                 thrown if IOException occurs while parsing certificate
+     * @throws CmpClientException          thrown if error occurs during the verification of the certChain
      */
-    public static <T extends Certificate> Optional<X509Certificate> getCertfromByteArray(
-            byte[] cert, Class<T> returnType) throws CertificateParsingException, CmpClientException {
-        LOG.debug("Retrieving certificate of type {} from byte array.", returnType);
-        return getCertfromByteArray(cert, BouncyCastleProvider.PROVIDER_NAME, returnType);
+    static Cmpv2CertificationModel verifyAndReturnCertChainAndTrustSTore(
+            PKIMessage respPkiMessage, CertRepMessage certRepMessage, X509Certificate leafCertificate)
+            throws CertificateParsingException, IOException, CmpClientException {
+        Map<X500Name, X509Certificate> certificates = mapAllCertificates(respPkiMessage, certRepMessage);
+        return extractCertificationModel(certificates, leafCertificate);
     }
 
-    /**
-     * @param cert       byte array that contains certificate
-     * @param provider   provider used to generate certificate from bytes
-     * @param returnType the type of Certificate to be returned, for example X509Certificate.class.
-     *                   Certificate.class can be used if certificate type is unknown.
-     * @throws CertificateParsingException if the byte array does not contain a proper certificate.
-     */
-    public static <T extends Certificate> Optional<X509Certificate> getCertfromByteArray(
-            byte[] cert, String provider, Class<T> returnType)
-            throws CertificateParsingException, CmpClientException {
-        String prov = provider;
-        if (provider == null) {
-            prov = BouncyCastleProvider.PROVIDER_NAME;
-        }
+    private static Map<X500Name, X509Certificate> mapAllCertificates(
+            PKIMessage respPkiMessage, CertRepMessage certRepMessage
+    )
+            throws IOException, CertificateParsingException, CmpClientException {
 
-        if (returnType.equals(X509Certificate.class)) {
-            return parseX509Certificate(prov, cert);
+        Map<X500Name, X509Certificate> certificates = new HashMap<>();
+
+        CMPCertificate[] extraCerts = respPkiMessage.getExtraCerts();
+        certificates.putAll(mapCertificates(extraCerts));
+
+        CMPCertificate[] caPubsCerts = certRepMessage.getCaPubs();
+        certificates.putAll(mapCertificates(caPubsCerts));
+
+        return certificates;
+    }
+
+    private static Map<X500Name, X509Certificate> mapCertificates(
+            CMPCertificate[] cmpCertificates)
+            throws CertificateParsingException, CmpClientException, IOException {
+
+        Map<X500Name, X509Certificate> certificates = new HashMap<>();
+        if (cmpCertificates != null) {
+            for (CMPCertificate certificate : cmpCertificates) {
+                getCertFromByteArray(certificate.getEncoded(), X509Certificate.class)
+                        .ifPresent(x509Certificate ->
+                                certificates.put(extractSubjectDn(x509Certificate), x509Certificate)
+                        );
+            }
         }
-        return Optional.empty();
+
+        return certificates;
     }
 
-    /**
-     * Check the certificate with CA certificate.
-     *
-     * @param caCertChain Collection of X509Certificates. May not be null, an empty list or a
-     *                    Collection with null entries.
-     * @throws CmpClientException if verification failed
-     */
-    public static void verify(List<X509Certificate> caCertChain) throws CmpClientException {
-        int iterator = 1;
-        while (iterator < caCertChain.size()) {
-            verify(caCertChain.get(iterator - 1), caCertChain.get(iterator), null);
-            iterator += 1;
+    private static Cmpv2CertificationModel extractCertificationModel(
+            Map<X500Name, X509Certificate> certificates, X509Certificate leafCertificate
+    )
+            throws CmpClientException {
+        List<X509Certificate> certificateChain = new ArrayList<>();
+        X509Certificate previousCertificateInChain;
+        X509Certificate nextCertificateInChain = leafCertificate;
+        do {
+            certificateChain.add(nextCertificateInChain);
+            certificates.remove(extractSubjectDn(nextCertificateInChain));
+            previousCertificateInChain = nextCertificateInChain;
+            nextCertificateInChain = certificates.get(extractIssuerDn(nextCertificateInChain));
+            verify(previousCertificateInChain, nextCertificateInChain, null);
         }
+        while (!isSelfSign(nextCertificateInChain));
+        List<X509Certificate> trustedCertificates = new ArrayList<>(certificates.values());
+
+        return new Cmpv2CertificationModel(certificateChain, trustedCertificates);
+    }
+
+    private static boolean isSelfSign(X509Certificate certificate) {
+        return extractIssuerDn(certificate).equals(extractSubjectDn(certificate));
+    }
+
+    private static X500Name extractIssuerDn(X509Certificate x509Certificate) {
+        return X500Name.getInstance(x509Certificate.getIssuerDN());
+    }
+
+    private static X500Name extractSubjectDn(X509Certificate x509Certificate) {
+        return X500Name.getInstance(x509Certificate.getSubjectDN());
     }
 
+
     /**
      * Check the certificate with CA certificate.
      *
@@ -136,7 +177,7 @@ public final class CmpResponseHelper {
      *                             path validation
      * @throws CmpClientException if certificate could not be validated
      */
-    public static void verify(
+    private static void verify(
             X509Certificate certificate,
             X509Certificate caCertChain,
             Date date,
@@ -179,13 +220,17 @@ public final class CmpResponseHelper {
         }
     }
 
-    public static void verifyCertificates(
+    private static void verifyCertificates(
             X509Certificate certificate,
             X509Certificate caCertChain,
             Date date,
             PKIXCertPathChecker[] pkixCertPathCheckers)
             throws CertificateException, NoSuchProviderException, InvalidAlgorithmParameterException,
             NoSuchAlgorithmException, CertPathValidatorException {
+        if (caCertChain == null) {
+            final String noRootCaCertificateMessage = "Server response does not contain proper root CA certificate";
+            throw new CertificateException(noRootCaCertificateMessage);
+        }
         LOG.debug(
                 "Verifying certificate {} as part of cert chain with certificate {}",
                 certificate.getSubjectDN().getName(),
@@ -200,7 +245,7 @@ public final class CmpResponseHelper {
         }
     }
 
-    public static PKIXParameters getPkixParameters(
+    private static PKIXParameters getPkixParameters(
             X509Certificate caCertChain, Date date, PKIXCertPathChecker[] pkixCertPathCheckers)
             throws InvalidAlgorithmParameterException {
         TrustAnchor anchor = new TrustAnchor(caCertChain, null);
@@ -213,7 +258,7 @@ public final class CmpResponseHelper {
         return params;
     }
 
-    public static CertPath getCertPath(X509Certificate certificate)
+    private static CertPath getCertPath(X509Certificate certificate)
             throws CertificateException, NoSuchProviderException {
         ArrayList<X509Certificate> certlist = new ArrayList<>();
         certlist.add(certificate);
@@ -221,34 +266,6 @@ public final class CmpResponseHelper {
                 .generateCertPath(certlist);
     }
 
-    /**
-     * Parse a X509Certificate from an array of bytes
-     *
-     * @param provider a provider name
-     * @param cert     a byte array containing an encoded certificate
-     * @return a decoded X509Certificate
-     * @throws CertificateParsingException if the byte array wasn't valid, or contained a certificate
-     *                                     other than an X509 Certificate.
-     */
-    public static Optional<X509Certificate> parseX509Certificate(String provider, byte[] cert)
-            throws CertificateParsingException, CmpClientException {
-        LOG.debug("Parsing X509Certificate from bytes with provider {}", provider);
-        final CertificateFactory cf = getCertificateFactory(provider);
-        X509Certificate result;
-        try {
-            result =
-                    (X509Certificate)
-                            Objects.requireNonNull(cf).generateCertificate(new ByteArrayInputStream(cert));
-        } catch (CertificateException ce) {
-            throw new CertificateParsingException("Could not parse byte array as X509Certificate ", ce);
-        }
-        if (result != null) {
-            return Optional.of(result);
-        } else {
-            throw new CertificateParsingException("Could not parse byte array as X509Certificate.");
-        }
-    }
-
     /**
      * Returns a CertificateFactory that can be used to create certificates from byte arrays and such.
      *
@@ -256,7 +273,7 @@ public final class CmpResponseHelper {
      *                 null is passed.
      * @return CertificateFactory for creating certificate
      */
-    public static CertificateFactory getCertificateFactory(final String provider)
+    private static CertificateFactory getCertificateFactory(final String provider)
             throws CmpClientException {
         LOG.debug("Creating certificate Factory to generate certificate using provider {}", provider);
         final String prov;
@@ -275,99 +292,44 @@ public final class CmpResponseHelper {
     }
 
     /**
-     * puts together certChain and Trust store and verifies the certChain
-     *
-     * @param respPkiMessage  PKIMessage that may contain extra certs used for certchain
-     * @param certRepMessage  CertRepMessage that should contain rootCA for certchain
-     * @param leafCertificate certificate returned from our original Cert Request
-     * @return list of two lists, CertChain and TrustStore
-     * @throws CertificateParsingException thrown if error occurs while parsing certificate
-     * @throws IOException                 thrown if IOException occurs while parsing certificate
-     * @throws CmpClientException          thrown if error occurs during the verification of the certChain
+     * @param cert       byte array that contains certificate
+     * @param returnType the type of Certificate to be returned, for example X509Certificate.class.
+     *                   Certificate.class can be used if certificate type is unknown.
+     * @throws CertificateParsingException if the byte array does not contain a proper certificate.
      */
-    public static List<List<X509Certificate>> verifyAndReturnCertChainAndTrustSTore(
-            PKIMessage respPkiMessage, CertRepMessage certRepMessage, X509Certificate leafCertificate)
-            throws CertificateParsingException, IOException, CmpClientException {
-        List<X509Certificate> certChain =
-                addExtraCertsToChain(respPkiMessage, certRepMessage, leafCertificate);
-        List<String> certNames = getNamesOfCerts(certChain);
-        LOG.debug("Verifying the following certificates in the cert chain: {}", certNames);
-        verify(certChain);
-        ArrayList<X509Certificate> trustStore = new ArrayList<>();
-        final int rootCaIndex = certChain.size() - 1;
-        trustStore.add(certChain.get(rootCaIndex));
-        certChain.remove(rootCaIndex);
-        List<List<X509Certificate>> listOfArray = new ArrayList<>();
-        listOfArray.add(certChain);
-        listOfArray.add(trustStore);
-        return listOfArray;
-    }
+    static <T extends Certificate> Optional<X509Certificate> getCertFromByteArray(
+            byte[] cert, Class<T> returnType) throws CertificateParsingException, CmpClientException {
+        LOG.debug("Retrieving certificate of type {} from byte array.", returnType);
+        String prov = BouncyCastleProvider.PROVIDER_NAME;
 
-    public static List<String> getNamesOfCerts(List<X509Certificate> certChain) {
-        List<String> certNames = new ArrayList<>();
-        certChain.forEach(cert -> certNames.add(cert.getSubjectDN().getName()));
-        return certNames;
+        if (returnType.equals(X509Certificate.class)) {
+            return parseX509Certificate(prov, cert);
+        } else {
+            LOG.debug("Certificate of type {} was skipped, because type of certificate is not 'X509Certificate'.", returnType);
+            return Optional.empty();
+        }
     }
 
+
     /**
-     * checks whether PKIMessage contains extracerts to create certchain, if not creates from caPubs
+     * Parse a X509Certificate from an array of bytes
      *
-     * @param respPkiMessage PKIMessage that may contain extra certs used for certchain
-     * @param certRepMessage CertRepMessage that should contain rootCA for certchain
-     * @param leafCert       certificate at top of certChain.
-     * @throws CertificateParsingException thrown if error occurs while parsing certificate
-     * @throws IOException                 thrown if IOException occurs while parsing certificate
-     * @throws CmpClientException          thrown if there are errors creating CertificateFactory
+     * @param provider a provider name
+     * @param cert     a byte array containing an encoded certificate
+     * @return a decoded X509Certificate
+     * @throws CertificateParsingException if the byte array wasn't valid, or contained a certificate
+     *                                     other than an X509 Certificate.
      */
-    public static List<X509Certificate> addExtraCertsToChain(
-            PKIMessage respPkiMessage, CertRepMessage certRepMessage, X509Certificate leafCert)
-            throws CertificateParsingException, IOException, CmpClientException {
-        List<X509Certificate> certChain = new ArrayList<>();
-        certChain.add(leafCert);
-        if (respPkiMessage.getExtraCerts() != null) {
-            final CMPCertificate[] extraCerts = respPkiMessage.getExtraCerts();
-            for (CMPCertificate cmpCert : extraCerts) {
-                Optional<X509Certificate> cert =
-                        getCertfromByteArray(cmpCert.getEncoded(), X509Certificate.class);
-                certChain =
-                        ifCertPresent(
-                                certChain,
-                                cert,
-                                "Adding certificate from extra certs {} to cert chain",
-                                "Couldn't add certificate from extra certs, certificate wasn't an X509Certificate");
-                return certChain;
-            }
-        } else {
-            final CMPCertificate respCmpCaCert = getRootCa(certRepMessage);
-            Optional<X509Certificate> cert =
-                    getCertfromByteArray(respCmpCaCert.getEncoded(), X509Certificate.class);
-            certChain =
-                    ifCertPresent(
-                            certChain,
-                            cert,
-                            "Adding certificate from CaPubs {} to TrustStore",
-                            "Couldn't add certificate from CaPubs, certificate wasn't an X509Certificate");
-            return certChain;
-        }
-        return Collections.emptyList();
-    }
-
-    public static List<X509Certificate> ifCertPresent(
-            List<X509Certificate> certChain,
-            Optional<X509Certificate> cert,
-            String certPresentString,
-            String certUnavailableString) {
-        if (cert.isPresent()) {
-            LOG.debug(certPresentString, cert.get().getSubjectDN().getName());
-            certChain.add(cert.get());
-            return certChain;
-        } else {
-            LOG.debug(certUnavailableString);
-            return certChain;
+    private static Optional<X509Certificate> parseX509Certificate(String provider, byte[] cert)
+            throws CertificateParsingException, CmpClientException {
+        LOG.debug("Parsing X509Certificate from bytes with provider {}", provider);
+        final CertificateFactory cf = getCertificateFactory(provider);
+        X509Certificate result;
+        try {
+            result = (X509Certificate) Objects.requireNonNull(cf).generateCertificate(new ByteArrayInputStream(cert));
+            return Optional.ofNullable(result);
+        } catch (CertificateException ce) {
+            throw new CertificateParsingException("Could not parse byte array as X509Certificate ", ce);
         }
     }
-
-    private static CMPCertificate getRootCa(CertRepMessage certRepMessage) {
-        return certRepMessage.getCaPubs()[0];
-    }
 }
diff --git a/certService/src/main/java/org/onap/aaf/certservice/cmpv2client/model/Cmpv2CertificationModel.java b/certService/src/main/java/org/onap/aaf/certservice/cmpv2client/model/Cmpv2CertificationModel.java
new file mode 100644 (file)
index 0000000..5d48b97
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.aaf.certservice.cmpv2client.model;
+
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.List;
+
+public class Cmpv2CertificationModel {
+
+    private final List<X509Certificate> certificateChain;
+    private final List<X509Certificate> trustedCertificates;
+
+    public Cmpv2CertificationModel(List<X509Certificate> certificateChain, List<X509Certificate> trustedCertificates) {
+        this.certificateChain = certificateChain;
+        this.trustedCertificates = trustedCertificates;
+    }
+
+    public List<X509Certificate> getCertificateChain() {
+        return Collections.unmodifiableList(certificateChain);
+    }
+
+    public List<X509Certificate> getTrustedCertificates() {
+        return Collections.unmodifiableList(trustedCertificates);
+    }
+}
index cf3c723..a590c5e 100644 (file)
@@ -31,6 +31,7 @@ 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.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -38,9 +39,7 @@ import java.nio.charset.StandardCharsets;
 import java.security.NoSuchProviderException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 import java.util.Objects;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -115,14 +114,15 @@ class CertificationProviderTest {
         assertThat(exception.getMessage()).isEqualTo(expectedErrorMessage);
     }
 
-    private List<List<X509Certificate>> createCorrectClientResponse()
+    private Cmpv2CertificationModel createCorrectClientResponse()
             throws CertificateException, NoSuchProviderException {
         InputStream certificateChain = getClass().getClassLoader().getResourceAsStream("certificateChain.first");
         InputStream trustedCertificate = getClass().getClassLoader().getResourceAsStream("trustedCertificates.first");
         X509Certificate x509Certificate = new CertificateFactoryProvider().generateCertificate(certificateChain);
         X509Certificate x509TrustedCertificate =
                 new CertificateFactoryProvider().generateCertificate(trustedCertificate);
-        return Arrays.asList(Collections.singletonList(x509Certificate),
+        return new Cmpv2CertificationModel(
+                Collections.singletonList(x509Certificate),
                 Collections.singletonList(x509TrustedCertificate));
     }
 
index 06eeecc..05bda54 100644 (file)
@@ -62,6 +62,7 @@ import org.onap.aaf.certservice.certification.configuration.model.Cmpv2Server;
 import org.onap.aaf.certservice.certification.model.CsrModel;
 import org.onap.aaf.certservice.cmpv2client.exceptions.CmpClientException;
 import org.onap.aaf.certservice.cmpv2client.impl.CmpClientImpl;
+import org.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
 
 class Cmpv2ClientTest {
 
@@ -152,7 +153,7 @@ class Cmpv2ClientTest {
         }
         CmpClientImpl cmpClient = spy(new CmpClientImpl(httpClient));
         // when
-        List<List<X509Certificate>> cmpClientResult =
+        Cmpv2CertificationModel cmpClientResult =
                 cmpClient.createCertificate(csrModel, server, notBefore, notAfter);
         // then
         assertNotNull(cmpClientResult);
diff --git a/certService/src/test/java/org/onap/aaf/certservice/cmpv2client/impl/CmpResponseHelperTest.java b/certService/src/test/java/org/onap/aaf/certservice/cmpv2client/impl/CmpResponseHelperTest.java
new file mode 100644 (file)
index 0000000..c41d636
--- /dev/null
@@ -0,0 +1,609 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.aaf.certservice.cmpv2client.impl;
+
+import org.bouncycastle.asn1.cmp.CMPCertificate;
+import org.bouncycastle.asn1.cmp.CertRepMessage;
+import org.bouncycastle.asn1.cmp.PKIMessage;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.onap.aaf.certservice.cmpv2client.exceptions.CmpClientException;
+import org.onap.aaf.certservice.cmpv2client.model.Cmpv2CertificationModel;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class CmpResponseHelperTest {
+
+
+    private static final String EXPECTED_ERROR_MESSAGE = "Something was wrong with the supplied certificate";
+
+    private static final String TEST_1LAYER_ENTITY_CERT = ""
+            + "-----BEGIN CERTIFICATE-----\n"
+            + "MIIEqDCCAxCgAwIBAgIUFioEkVJsxfZGGDMEyCA8Rin3uhQwDQYJKoZIhvcNAQEL\n"
+            + "BQAwYTEjMCEGCgmSJomT8ixkAQEME2MtMDM1ZDk4NTAwYzhiN2JiMjIxFTATBgNV\n"
+            + "BAMMDE1hbmFnZW1lbnRDQTEjMCEGA1UECgwaRUpCQ0EgQ29udGFpbmVyIFF1aWNr\n"
+            + "c3RhcnQwHhcNMjAwMzI0MTEzNTU0WhcNMjIwMzI0MTEzNTU0WjCBljEgMB4GCSqG\n"
+            + "SIb3DQEJARYRQ29tbW9uTmFtZUBjbi5jb20xDjAMBgNVBAMMBUNsMTIzMQ0wCwYD\n"
+            + "VQQLDARPTkFQMRkwFwYDVQQKDBBMaW51eC1Gb3VuZGF0aW9uMRYwFAYDVQQHDA1T\n"
+            + "YW4tRnJhbmNpc2NvMRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzCC\n"
+            + "ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL94FcmRn/g9Y9ZrEL+jKiud\n"
+            + "xzDdtVLoF0ijZOGG0rnzyimzzwOjd8LA0jiZlYtpoDef95bbMeZJMKzE3bA8EMFp\n"
+            + "hynqUHs/KdsLBV+o3J6EzlpYHrwypX7kOriw9o4dmPAxvJHXTu3HC2SejJjHHArk\n"
+            + "FyahEJ03ypvCJx3iPvGXkLI9tZetobiVXslBJd5t0hQj+JQxzAlTwS0fV+xMowFT\n"
+            + "css2IlGXfQgd88cdhXBVOE0//qln1ko3G3KeH58iIWLqh9KG660SCeoTCop7bO1N\n"
+            + "abVrcXlgdE06hAvzTj3FoBxqO5KEWDPo2Dr11qRdq8bLP2T0EbTzAw4DPUwE+H8C\n"
+            + "AwEAAaOBoTCBnjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFDPaBc+EX/hCLe5c\n"
+            + "d+oZIxcQZ1tHMB8GA1UdEQQYMBaCBUNsMTIzgg10ZXN0Lm9uYXAub3JnMB0GA1Ud\n"
+            + "JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAdBgNVHQ4EFgQU4dP1HuV9O+sHInl+\n"
+            + "WuvdDJ63lp8wDgYDVR0PAQH/BAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBgQBWTF8C\n"
+            + "sH0ir4bj7rTlJMf5o7apkXFeQ/c7+zXnSLCfXqwM6ad0EDh3FixfTC8IpW5CaENt\n"
+            + "zTR7IGJr06ccwLgsigR7FxJKnEkxJiBxzkE3zFOEel3KAnV2b7KvOP7cJAzsCdcS\n"
+            + "iZU475XHOw4Ox3k8fHzhTJJa0Tzw5EjQ3GO99HTiUClGrjJuYDLfen1q7IQSNuTY\n"
+            + "FzxJZjyqzi34pkKeCNSPRj8Z8Q5aZiWqlmzSJmZRT83xzzeW/pQ1JwvIrWwrbEjR\n"
+            + "FPXBlUa1n2HztkDgeBQfRyMAj5ixFV+s1Jj+cEYl3pjbugnuHfgBdSJokXFGBo6N\n"
+            + "8PTd1CnMGWcWiMyhbTwNm2UiSr5KhQbjABjiUzDp4C7jFhIzmu/4/tm2uA+y0xPN\n"
+            + "342uEZC0ZSZmpCIbQMhPaBNjSHeHj8NaLHjnt5jppLkMxScayRqMvSW07eNew2+k\n"
+            + "VYJD6z6gfy4y+Y5MSLfvddq1JdPDU86TFprtD1ydcUBS5tduYQG2+1bLgpE="
+            + "\n-----END CERTIFICATE-----\n";
+
+    private static final String TEST_1LAYER_CA_CERT = ""
+            + "-----BEGIN CERTIFICATE-----\n"
+            + "MIIEszCCAxugAwIBAgIUEhkh+zJtXZN3K3kzQYcbp2smyIkwDQYJKoZIhvcNAQEL\n"
+            + "BQAwYTEjMCEGCgmSJomT8ixkAQEME2MtMDM1ZDk4NTAwYzhiN2JiMjIxFTATBgNV\n"
+            + "BAMMDE1hbmFnZW1lbnRDQTEjMCEGA1UECgwaRUpCQ0EgQ29udGFpbmVyIFF1aWNr\n"
+            + "c3RhcnQwHhcNMjAwMzI0MTAyODQyWhcNMzAwMzI0MTAyODQyWjBhMSMwIQYKCZIm\n"
+            + "iZPyLGQBAQwTYy0wMzVkOTg1MDBjOGI3YmIyMjEVMBMGA1UEAwwMTWFuYWdlbWVu\n"
+            + "dENBMSMwIQYDVQQKDBpFSkJDQSBDb250YWluZXIgUXVpY2tzdGFydDCCAaIwDQYJ\n"
+            + "KoZIhvcNAQEBBQADggGPADCCAYoCggGBAJyKZyKIRyW6cbga/I1YFJGCEEgs9JVU\n"
+            + "sV7MD5/yF4SIkJlZqFjJ9kfw8D5thg68zAx2vEWIpNTMroqb1eptIn/XsFoyM//6\n"
+            + "HzKrY3UUYWHx9sQMDZPenTL8LTRx+4szSen7rzrozH2pJat7kfX4EODEtQ6q7RQ2\n"
+            + "hmXoo7heeSgiHoeHsPGZixPGzcB27WBaY00Z/sP/n+f0CFaE04MKLw8WeQmq/RkC\n"
+            + "pj628+eBK0lGtEmUcT7z4CBy4x3hbhn9XHOb0+RlDk7rqFbsc09vHoZK2BfQ/r6e\n"
+            + "HguZjBQ5Ebqf6PiLF3HqkSW73toIdIy/olvQ2dLbOEyI4OnlObc+8xs/1AC7l9xX\n"
+            + "FkXY+NBv24KG1C2POXx14+ufHhWY0k2nIRUUlkUIJ7WGMWbuiNUXc1wSE1VrmY/c\n"
+            + "iXlhsJERqFc6bL/STlhOGuwmkdAD1/K8WS+o/QmIIX6cXlOR0U9bHMbD40F9fur6\n"
+            + "PV8wSKcQQNd0VHRLhmFwo4kkhZpDpuUp4QIDAQABo2MwYTAPBgNVHRMBAf8EBTAD\n"
+            + "AQH/MB8GA1UdIwQYMBaAFDPaBc+EX/hCLe5cd+oZIxcQZ1tHMB0GA1UdDgQWBBQz\n"
+            + "2gXPhF/4Qi3uXHfqGSMXEGdbRzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL\n"
+            + "BQADggGBAFGsyu5nWycdk8iva+uY98QnPQe/M6uaUGUis0vGn9UYxoz5ddtpF3Z+\n"
+            + "MsHgbS51BH9iRYn4ZkQoRoukIjt1iO86d6sgpUS5AStCXsylL4DwAY5G/K5i/Qw5\n"
+            + "x0lP/tRYwqh2tUhmnx1xZLOWbRFZ63A0YHdguj3CqaXQ/cxafYZe0zcNhX3iH3gf\n"
+            + "5kHH8E682RT0x4ibb1JtPioQ48+pweyfMlOJkJ7WmZEfiVQitQSSNOnw1hRORiUz\n"
+            + "oFb0MlYHqe/9lIb9nmzD8QQ9q0H8J6RBCFsntx/Z6oUM8GHr80zAvNjqFfR14lOo\n"
+            + "jp05w2mr7wxIHFpM6h1HGY1QaeGp6W/fi+N7+gSL3nu1LzXVCYNCTcGkBDeasovB\n"
+            + "ma70KHGO4ZyRcEMKFCxxE8y4GZnw/EhMhDDevXAVsHEzr6XsBCJkC8e2l3iW5IKH\n"
+            + "4N/f/k06d4kS5pL290dJ450zx/mBxYGJm+pPHZfDszqVeKn1m1ZhGT80150OePGQ\n"
+            + "Cc2ir84HwQ=="
+            + "\n-----END CERTIFICATE-----\n";
+
+    private static final String TEST_2LAYER_ENTITY_CERT = ""
+            + "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDjDCCAnSgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwgYQxCzAJBgNVBAYTAlVT\n"
+            + "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4tRnJhbmNpc2NvMRkw\n"
+            + "FwYDVQQKDBBMaW51eC1Gb3VuZGF0aW9uMQ0wCwYDVQQLDARPTkFQMR4wHAYDVQQD\n"
+            + "DBVpbnRlcm1lZGlhdGUub25hcC5vcmcwHhcNMjAwMjEyMDk1MTI2WhcNMjIxMTA4\n"
+            + "MDk1MTI2WjB7MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG\n"
+            + "A1UEBwwNU2FuLUZyYW5jaXNjbzEZMBcGA1UECgwQTGludXgtRm91bmRhdGlvbjEN\n"
+            + "MAsGA1UECwwET05BUDEVMBMGA1UEAwwMdmlkLm9uYXAub3JnMIIBIjANBgkqhkiG\n"
+            + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+GIRzJzUOh0gtc+wzFJEdTnn+q5F10L0Yhr\n"
+            + "G1xKdjPieHIFGsoiXwcuCU8arNSqlz7ocx62KQRkcA8y6edlOAsYtdOEJvqEI9vc\n"
+            + "eyTB/HYsbzw3URPGch4AmibrQkKU9QvGwouHtHn4R2Ft2Y0tfEqv9hxj9v4njq4A\n"
+            + "EiDLAFLl5FmVyCZu/MtKngSgu1smcaFKTYySPMxytgJZexoa/ALZyyE0gRhsvwHm\n"
+            + "NLGCPt1bmE/PEGZybsCqliyTO0S56ncD55The7+D/UDS4kE1Wg0svlWon/YsE6QW\n"
+            + "B3oeJDX7Kr8ebDTIAErevIAD7Sm4ee5se2zxYrsYlj0MzHZtvwIDAQABoxAwDjAM\n"
+            + "BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCvQ1pTvjON6vSlcJRKSY4r\n"
+            + "8q7L4/9ZaVXWJAjzEYJtPIqsgGiPWz0vGfgklowU6tZxp9zRZFXfMil+mPQSe+yo\n"
+            + "ULrZSQ/z48YHPueE/BNO/nT4aaVBEhPLR5aVwC7uQVX8H+m1V1UGT8lk9vdI9rej\n"
+            + "CI9l524sLCpdE4dFXiWK2XHEZ0Vfylk221u3IYEogVVA+UMX7BFPSsOnI2vtYK/i\n"
+            + "lwZtlri8LtTusNe4oiTkYyq+RSyDhtAswg8ANgvfHolhCHoLFj6w1IkG88UCmbwN\n"
+            + "d7BoGMy06y5MJxyXEZG0vR7eNeLey0TIh+rAszAFPsIQvrOHW+HuA+WLQAj1mhnm\n"
+            + "-----END CERTIFICATE-----";
+
+    private static final String TEST_2LAYER_INTERMEDIATE_CERT = ""
+            + "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDqTCCApGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVT\n"
+            + "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4tRnJhbmNpc2NvMRkw\n"
+            + "FwYDVQQKDBBMaW51eC1Gb3VuZGF0aW9uMQ0wCwYDVQQLDARPTkFQMREwDwYDVQQD\n"
+            + "DAhvbmFwLm9yZzEeMBwGCSqGSIb3DQEJARYPdGVzdGVyQG9uYXAub3JnMB4XDTIw\n"
+            + "MDIxMjA5NDAxMloXDTIyMTEwODA5NDAxMlowgYQxCzAJBgNVBAYTAlVTMRMwEQYD\n"
+            + "VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4tRnJhbmNpc2NvMRkwFwYDVQQK\n"
+            + "DBBMaW51eC1Gb3VuZGF0aW9uMQ0wCwYDVQQLDARPTkFQMR4wHAYDVQQDDBVpbnRl\n"
+            + "cm1lZGlhdGUub25hcC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\n"
+            + "AQC1oOYMZ6G+2DGDAizYnzdCNiogivlht1s4oqgem7fM1XFPxD2p31ATIibOdqr/\n"
+            + "gv1qemO9Q4r1xn6w1Ufq7T1K7PjnMzdSeTqZefurE2JM/HHx2QvW4TjMlz2ILgaD\n"
+            + "L1LN60kmMQSOi5VxKJpsrCQxbOsxhvefd212gny5AZMcjJe23kUd9OxUrtvpdLEv\n"
+            + "wI3vFEvT7oRUnEUg/XNz7qeg33vf1C39yMR+6O4s6oevgsEebVKjb+yOoS6zzGtz\n"
+            + "72wZjm07C54ZlO+4Uy+QAlMjRiU3mgWkKbkOy+4CvwehjhpTikdBs2DX39ZLGHhn\n"
+            + "L/0a2NYtGulp9XEqmTvRoI+PAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n"
+            + "hvcNAQELBQADggEBADcitdJ6YswiV8jAD9GK0gf3+zqcGegt4kt+79JXlXYbb1sY\n"
+            + "q3o6prcB7nSUoClgF2xUPCslFGpM0Er9FCSFElQM/ru0l/KVmJS6kSpwEHvsYIH3\n"
+            + "q5anta+Pyk8JSQWAAw+qrind0uBQMnhR8Tn13tgV+Kjvg/xlH/nZIEdN5YtLB1cA\n"
+            + "beVsZRyRfVL9DeZU8s/MZ5wC3kgcEp5A4m5lg7HyBxBdqhzFcDr6xiy6OGqW8Yep\n"
+            + "xrwfc8Fw8a/lOv4U+tBeGNKPQDYaL9hh+oM+qMkNXsHXDqdJsuEGJtU4i3Wcwzoc\n"
+            + "XGN5NWV//4bP+NFmwgcn7AYCdRvz04A8GU/0Cwg=\n"
+            + "-----END CERTIFICATE-----";
+
+    private static final String TEST_2LAYER_CA_CERT = ""
+            + "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDtzCCAp8CFAwqQddh4/iyGfP8UZ3dpXlxfAN8MA0GCSqGSIb3DQEBCwUAMIGX\n"
+            + "MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu\n"
+            + "LUZyYW5jaXNjbzEZMBcGA1UECgwQTGludXgtRm91bmRhdGlvbjENMAsGA1UECwwE\n"
+            + "T05BUDERMA8GA1UEAwwIb25hcC5vcmcxHjAcBgkqhkiG9w0BCQEWD3Rlc3RlckBv\n"
+            + "bmFwLm9yZzAeFw0yMDAyMTIwOTM0MjdaFw0yMTAyMTEwOTM0MjdaMIGXMQswCQYD\n"
+            + "VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuLUZyYW5j\n"
+            + "aXNjbzEZMBcGA1UECgwQTGludXgtRm91bmRhdGlvbjENMAsGA1UECwwET05BUDER\n"
+            + "MA8GA1UEAwwIb25hcC5vcmcxHjAcBgkqhkiG9w0BCQEWD3Rlc3RlckBvbmFwLm9y\n"
+            + "ZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMCFrnO7/eT6V+7XkPPd\n"
+            + "eiL/6xXreuegvit/1/jTVjG+3AOVcmTn2WXwXXRcQLvkWQfJVPoltsY8E3FqFRti\n"
+            + "797XjY6cdQJFVDyzNU0+Fb4vJL9FK5wSvnS6EFjBEn3JvXRlENorDCs/mfjkjJoa\n"
+            + "Dl74gXQEJYcg4nsTeNIj7cm3Q7VK3mZt1t7LSJJ+czxv69UJDuNJpmQ/2WOKyLZA\n"
+            + "gTtBJ+Hyol45/OLsrqwq1dAn9ZRWIFPvRt/XQYH9bI/6MtqSreRVUrdYCiTe/XpP\n"
+            + "B/OM6NEi2+p5QLi3Yi70CEbqP3HqUVbkzF+r7bwIb6M5/HxfqzLmGwLvD+6rYnUn\n"
+            + "Bm8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAhXoO65DXth2X/zFRNsCNpLwmDy7r\n"
+            + "PxT9ZAIZAzSxx3/aCYiuTrKP1JnqjkO+F2IbikrI4n6sKO49SKnRf9SWTFhd+5dX\n"
+            + "vxq5y7MaqxHAY9J7+Qzq33+COVFQnaF7ddel2NbyUVb2b9ZINNsaZkkPXui6DtQ7\n"
+            + "/Fb/1tmAGWd3hMp75G2thBSzs816JMKKa9WD+4VGATEs6OSll4sv2fOZEn+0mAD3\n"
+            + "9q9c+WtLGIudOwcHwzPb2njtNntQSCK/tVOqbY+vzhMY3JW+p9oSrLDSdGC+pAKK\n"
+            + "m/wB+2VPIYcsPMtIhHC4tgoSaiCqjXYptaOh4b8ye8CPBUCpX/AYYkN0Ow==\n"
+            + "-----END CERTIFICATE-----";
+
+
+    @BeforeAll
+    static void setUpSecurity() {
+        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+    }
+
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertInCaPubsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        PKIMessage respPkiMessage = mockExtraCerts(null);
+
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {caCmpCertificate};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityCertificate(certs, TEST_1LAYER_ENTITY_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(certs, caCmpCertificate);
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertInExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] extraCmpCertificates = {caCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CertRepMessage certRepMessage = mockCaPubs(null);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityCertificate(certs, TEST_1LAYER_ENTITY_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(certs, caCmpCertificate);
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertInExtraCertsAndExtraTrustAnchorInCaPubsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] extraCmpCertificates = {caCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CMPCertificate extraTrustAnchor = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {extraTrustAnchor};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityCertificate(certs, TEST_1LAYER_ENTITY_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate, extraTrustAnchor
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertInExtraCertsAndExtraTrustAnchorInExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate trustedCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] extraCmpCertificates = {caCmpCertificate, trustedCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CertRepMessage certRepMessage = mockCaPubs(null);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityCertificate(certs, TEST_1LAYER_ENTITY_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate, trustedCmpCertificate
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertAndIntermediateCertInExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate intermediateCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_INTERMEDIATE_CERT);
+        CMPCertificate[] extraCmpCertificates = {caCmpCertificate, intermediateCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CertRepMessage certRepMessage = mockCaPubs(null);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityAndIntermediateCertificate(certs, TEST_2LAYER_ENTITY_CERT, TEST_2LAYER_INTERMEDIATE_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertAndIntermediateCertInCmpCertificatesAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        PKIMessage respPkiMessage = mockExtraCerts(null);
+
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate intermediateCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_INTERMEDIATE_CERT);
+        CMPCertificate[] cmpCertificates = {caCmpCertificate, intermediateCmpCertificate};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityAndIntermediateCertificate(certs, TEST_2LAYER_ENTITY_CERT, TEST_2LAYER_INTERMEDIATE_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertInCaPubsAndIntermediateCertInExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate intermediateCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_INTERMEDIATE_CERT);
+        CMPCertificate[] extraCmpCertificates = {intermediateCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {caCmpCertificate};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityAndIntermediateCertificate(certs, TEST_2LAYER_ENTITY_CERT, TEST_2LAYER_INTERMEDIATE_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertInCaPubsAndExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] extraCmpCertificates = {caCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+        CMPCertificate[] cmpCertificates = {mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT)};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityCertificate(certs, TEST_1LAYER_ENTITY_CERT);
+        assertThatRootCaAndTrustedCaAreInSecondList(certs, mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT));
+
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertAndIntermediateCertInExtraCertsAndIntermediateCertInCaPubsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate intermediateCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_INTERMEDIATE_CERT);
+        CMPCertificate[] extraCmpCertificates = {caCmpCertificate, intermediateCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+        CMPCertificate[] cmpCertificates = {intermediateCmpCertificate};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityAndIntermediateCertificate(certs, TEST_2LAYER_ENTITY_CERT, TEST_2LAYER_INTERMEDIATE_CERT);
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertAndExtraTrustAnchorInCaPubsAndIntermediateCertInExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate intermediateCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_INTERMEDIATE_CERT);
+        CMPCertificate[] extraCmpCertificates = {intermediateCmpCertificate};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate extraTrustAnchor = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {caCmpCertificate, extraTrustAnchor};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityAndIntermediateCertificate(certs, TEST_2LAYER_ENTITY_CERT, TEST_2LAYER_INTERMEDIATE_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate, extraTrustAnchor
+        );
+    }
+
+    @Test
+    void returnListOfCertificationWhenGivenCaCertAndFirstExtraTrustAnchorInCaPubsAndIntermediateCertAndSecondExtraTrustAnchorInExtraCertsAndEntityCertInLeafCertificate()
+            throws CertificateException, CmpClientException, IOException, NoSuchProviderException {
+        //  given
+        CMPCertificate intermediateCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_INTERMEDIATE_CERT);
+        CMPCertificate extraTrustAnchor01 = mockCmpCertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+        CMPCertificate[] extraCmpCertificates = {intermediateCmpCertificate, extraTrustAnchor01};
+        PKIMessage respPkiMessage = mockExtraCerts(extraCmpCertificates);
+
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate extraTrustAnchor02 = mockCmpCertificateFromPem(TEST_1LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {caCmpCertificate, extraTrustAnchor02};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Cmpv2CertificationModel certs = CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                respPkiMessage, certRepMessage, leafCertificate);
+
+        // then
+        assertThatChainContainsEntityAndIntermediateCertificate(certs, TEST_2LAYER_ENTITY_CERT, TEST_2LAYER_INTERMEDIATE_CERT);
+
+        assertThatRootCaAndTrustedCaAreInSecondList(
+                certs,
+                caCmpCertificate, extraTrustAnchor01, extraTrustAnchor02
+        );
+    }
+
+    @Test
+    void throwsExceptionWhenNoCaCertForEntityCertIsGivenAndOnlyExtraTrustAnchorIsReturned()
+            throws CertificateException, IOException, NoSuchProviderException {
+        //  given
+
+        PKIMessage respPkiMessage = mockExtraCerts(null);
+
+        CMPCertificate trustedCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {trustedCmpCertificate};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Exception exception = assertThrows(
+                CmpClientException.class,
+                () -> CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                        respPkiMessage, certRepMessage, leafCertificate
+                )
+        );
+
+        String actualMessage = exception.getMessage();
+
+        // then
+        assertThat(actualMessage).isEqualTo(EXPECTED_ERROR_MESSAGE);
+    }
+
+    @Test
+    void throwsExceptionWhenBothExtraCertsAndCaPubsAreEmpty()
+            throws CertificateException, IOException, NoSuchProviderException {
+        //  given
+
+        PKIMessage respPkiMessage = mockExtraCerts(null);
+        CertRepMessage certRepMessage = mockCaPubs(null);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_1LAYER_ENTITY_CERT);
+
+        //  when
+        Exception exception = assertThrows(
+                CmpClientException.class,
+                () -> CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                        respPkiMessage, certRepMessage, leafCertificate
+                )
+        );
+
+        String actualMessage = exception.getMessage();
+
+        // then
+        assertThat(actualMessage).isEqualTo(EXPECTED_ERROR_MESSAGE);
+    }
+
+    @Test
+    void throwsExceptionWhenNoIntermediateCertForEntityCertIsGiven()
+            throws CertificateException, IOException, NoSuchProviderException {
+        //  given
+
+        PKIMessage respPkiMessage = mockExtraCerts(null);
+
+        CMPCertificate caCmpCertificate = mockCmpCertificateFromPem(TEST_2LAYER_CA_CERT);
+        CMPCertificate[] cmpCertificates = {caCmpCertificate};
+        CertRepMessage certRepMessage = mockCaPubs(cmpCertificates);
+
+        X509Certificate leafCertificate = getX509CertificateFromPem(TEST_2LAYER_ENTITY_CERT);
+
+        //  when
+        Exception exception = assertThrows(
+                CmpClientException.class,
+                () -> CmpResponseHelper.verifyAndReturnCertChainAndTrustSTore(
+                        respPkiMessage, certRepMessage, leafCertificate
+                )
+        );
+
+        String actualMessage = exception.getMessage();
+
+        // then
+        assertThat(actualMessage).isEqualTo(EXPECTED_ERROR_MESSAGE);
+    }
+
+
+    private void assertThatRootCaAndTrustedCaAreInSecondList(
+            Cmpv2CertificationModel certs, CMPCertificate... rootAndTrustedCerts
+    ) throws IOException {
+        assertThat(certs.getTrustedCertificates().size()).isEqualTo(rootAndTrustedCerts.length);
+        for (CMPCertificate certificate : rootAndTrustedCerts) {
+            assertThat(certs.getTrustedCertificates())
+                    .extracting(Certificate::getEncoded)
+                    .contains(certificate.getEncoded());
+        }
+    }
+
+    private void assertThatChainContainsEntityCertificate(
+            Cmpv2CertificationModel certs, String entityCertificate
+    ) throws CertificateEncodingException, IOException {
+        assertThat(certs.getCertificateChain().size()).isEqualTo(1);
+        assertThat(certs.getCertificateChain().get(0).getEncoded()).isEqualTo(createPemObject(entityCertificate).getContent());
+    }
+
+    private void assertThatChainContainsEntityAndIntermediateCertificate(
+            Cmpv2CertificationModel certs, String entityCertificate, String intermediateCertificate
+    ) throws CertificateEncodingException, IOException {
+        assertThat(certs.getCertificateChain().size()).isEqualTo(2);
+        assertThat(certs.getCertificateChain().get(0).getEncoded()).isEqualTo(createPemObject(entityCertificate).getContent());
+        assertThat(certs.getCertificateChain().get(1).getEncoded()).isEqualTo(createPemObject(intermediateCertificate).getContent());
+    }
+
+    private X509Certificate getX509CertificateFromPem(String pem) throws CertificateException, NoSuchProviderException, IOException {
+        return (X509Certificate)
+                CertificateFactory.getInstance("X.509", "BC").generateCertificate(
+                        new ByteArrayInputStream(createPemObject(pem).getContent())
+                );
+    }
+
+    private PKIMessage mockExtraCerts(CMPCertificate[] cmpCertificates) {
+        PKIMessage respPkiMessage = mock(PKIMessage.class);
+        when(respPkiMessage.getExtraCerts()).thenReturn(cmpCertificates);
+        return respPkiMessage;
+    }
+
+    private CertRepMessage mockCaPubs(CMPCertificate[] cmpCertificates) {
+        CertRepMessage certRepMessage = mock(CertRepMessage.class);
+        when(certRepMessage.getCaPubs()).thenReturn(cmpCertificates);
+        return certRepMessage;
+    }
+
+    private CMPCertificate mockCmpCertificateFromPem(String pem) throws IOException {
+        return mockCmpCertificate(createPemObject(pem).getContent());
+    }
+
+    private CMPCertificate mockCmpCertificate(byte[] encodedCertificate) throws IOException {
+        CMPCertificate cmpCertificate01 = mock(CMPCertificate.class);
+        when(cmpCertificate01.getEncoded()).thenReturn(encodedCertificate);
+        return cmpCertificate01;
+    }
+
+    private PemObject createPemObject(String pem) throws IOException {
+        try (StringReader stringReader = new StringReader(pem);
+             PemReader pemReader = new PemReader(stringReader)) {
+            return pemReader.readPemObject();
+        }
+    }
+}