org.ejbca.core.protocol.cmp.CrmfRARequestCustomSerialNoTest.java Source code

Java tutorial

Introduction

Here is the source code for org.ejbca.core.protocol.cmp.CrmfRARequestCustomSerialNoTest.java

Source

/*************************************************************************
 *                                                                       *
 *  EJBCA Community: The OpenSource Certificate Authority                *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/

package org.ejbca.core.protocol.cmp;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.cmp.PKIFailureInfo;
import org.bouncycastle.asn1.cmp.PKIMessage;
import org.bouncycastle.asn1.crmf.CertReqMessages;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.cesecore.certificates.ca.CAInfo;
import org.cesecore.certificates.ca.CaSessionRemote;
import org.cesecore.certificates.certificateprofile.CertificateProfile;
import org.cesecore.certificates.util.AlgorithmConstants;
import org.cesecore.configuration.GlobalConfigurationSessionRemote;
import org.cesecore.keys.util.KeyTools;
import org.cesecore.util.CertTools;
import org.cesecore.util.CryptoProviderTools;
import org.cesecore.util.EjbRemoteHelper;
import org.ejbca.config.CmpConfiguration;
import org.ejbca.core.model.ra.NotFoundException;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * @author tomas
 * @version $Id: CrmfRARequestCustomSerialNoTest.java 20003 2014-10-16 17:14:03Z mikekushner $
 */
public class CrmfRARequestCustomSerialNoTest extends CmpTestCase {

    final private static Logger log = Logger.getLogger(CrmfRARequestCustomSerialNoTest.class);

    final private static String PBEPASSWORD = "password";
    final private String issuerDN;
    final private int caid;
    final private X509Certificate cacert;
    final private CmpConfiguration cmpConfiguration;
    final private static String cmpAlias = "CmpCustomSerialNoTestAlias";

    final private CaSessionRemote caSession = EjbRemoteHelper.INSTANCE.getRemoteSession(CaSessionRemote.class);
    final private GlobalConfigurationSessionRemote globalConfigurationSession = EjbRemoteHelper.INSTANCE
            .getRemoteSession(GlobalConfigurationSessionRemote.class);

    @BeforeClass
    public static void beforeClass() throws Exception {
        CryptoProviderTools.installBCProvider();
    }

    public CrmfRARequestCustomSerialNoTest() throws Exception {
        this.cmpConfiguration = (CmpConfiguration) this.globalConfigurationSession
                .getCachedConfiguration(CmpConfiguration.CMP_CONFIGURATION_ID);

        // Try to use ManagementCA if it exists
        final CAInfo managementca;

        managementca = this.caSession.getCAInfo(ADMIN, "ManagementCA");

        if (managementca == null) {
            final Collection<Integer> caids;

            caids = this.caSession.getAuthorizedCaIds(ADMIN);

            final Iterator<Integer> iter = caids.iterator();
            int tmp = 0;
            while (iter.hasNext()) {
                tmp = iter.next().intValue();
            }
            this.caid = tmp;
        } else {
            this.caid = managementca.getCAId();
        }
        if (this.caid == 0) {
            assertTrue("No active CA! Must have at least one active CA to run tests!", false);
        }
        final CAInfo cainfo;

        cainfo = this.caSession.getCAInfo(ADMIN, this.caid);

        Collection<Certificate> certs = cainfo.getCertificateChain();
        if (certs.size() > 0) {
            Iterator<Certificate> certiter = certs.iterator();
            Certificate cert = certiter.next();
            String subject = CertTools.getSubjectDN(cert);
            if (StringUtils.equals(subject, cainfo.getSubjectDN())) {
                // Make sure we have a BC certificate
                try {
                    this.cacert = (X509Certificate) CertTools.getCertfromByteArray(cert.getEncoded());
                } catch (Exception e) {
                    throw new Error(e);
                }
            } else {
                this.cacert = null;
            }
        } else {
            log.error("NO CACERT for caid " + this.caid);
            this.cacert = null;
        }
        this.issuerDN = this.cacert != null ? this.cacert.getIssuerDN().getName()
                : "CN=ManagementCA,O=EJBCA Sample,C=SE";
    }

    @Override
    @Before
    public void setUp() throws Exception {
        super.setUp();

        // Configure CMP for this test
        this.cmpConfiguration.addAlias(cmpAlias);
        this.cmpConfiguration.setRAMode(cmpAlias, true);
        this.cmpConfiguration.setAllowRAVerifyPOPO(cmpAlias, true);
        this.cmpConfiguration.setResponseProtection(cmpAlias, "signature");
        this.cmpConfiguration.setRAEEProfile(cmpAlias, EEP_DN_OVERRIDE_NAME);
        this.cmpConfiguration.setRACertProfile(cmpAlias, CP_DN_OVERRIDE_NAME);
        this.cmpConfiguration.setRACAName(cmpAlias, "ManagementCA");
        this.cmpConfiguration.setRANameGenScheme(cmpAlias, "DN");
        this.cmpConfiguration.setRANameGenParams(cmpAlias, "CN");
        this.cmpConfiguration.setAllowRACustomSerno(cmpAlias, false);
        this.cmpConfiguration.setAuthenticationModule(cmpAlias,
                CmpConfiguration.AUTHMODULE_REG_TOKEN_PWD + ";" + CmpConfiguration.AUTHMODULE_HMAC);
        this.cmpConfiguration.setAuthenticationParameters(cmpAlias, "-;" + PBEPASSWORD);
        this.globalConfigurationSession.saveConfiguration(ADMIN, this.cmpConfiguration);
    }

    /**
     * @param userDN
     *            for new certificate.
     * @param keys
     *            key of the new certificate.
     * @param sFailMessage
     *            if !=null then EJBCA is expected to fail. The failure response
     *            message string is checked against this parameter.
     * @return If it is a certificate request that results in a successful certificate issuance, this certificate is returned
     * @throws Exception
     */
    private X509Certificate crmfHttpUserTest(X500Name userDN, KeyPair keys, String sFailMessage,
            BigInteger customCertSerno) throws Exception {

        X509Certificate ret = null;
        final byte[] nonce = CmpMessageHelper.createSenderNonce();
        final byte[] transid = CmpMessageHelper.createSenderNonce();
        final int reqId;
        {
            final PKIMessage one = genCertReq(this.issuerDN, userDN, keys, this.cacert, nonce, transid, true, null,
                    null, null, customCertSerno, null, null);
            final PKIMessage req = protectPKIMessage(one, false, PBEPASSWORD, 567);

            CertReqMessages ir = (CertReqMessages) req.getBody().getContent();
            reqId = ir.toCertReqMsgArray()[0].getCertReq().getCertReqId().getValue().intValue();
            assertNotNull(req);
            final ByteArrayOutputStream bao = new ByteArrayOutputStream();
            final DEROutputStream out = new DEROutputStream(bao);
            out.writeObject(req);
            final byte[] ba = bao.toByteArray();
            // Send request and receive response
            final byte[] resp = sendCmpHttp(ba, 200, cmpAlias);
            // do not check signing if we expect a failure (sFailMessage==null)
            checkCmpResponseGeneral(resp, this.issuerDN, userDN, this.cacert, nonce, transid, sFailMessage == null,
                    null, PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
            if (sFailMessage == null) {
                ret = checkCmpCertRepMessage(userDN, this.cacert, resp, reqId);
                // verify if custom cert serial number was used
                if (customCertSerno != null) {
                    assertTrue(ret.getSerialNumber().toString(16) + " is not same as expected "
                            + customCertSerno.toString(16), ret.getSerialNumber().equals(customCertSerno));
                }
            } else {
                checkCmpFailMessage(resp, sFailMessage, CmpPKIBodyConstants.ERRORMESSAGE, reqId,
                        PKIFailureInfo.badRequest, PKIFailureInfo.incorrectData);
            }
        }
        {
            // Send a confirm message to the CA
            final String hash = "foo123";
            final PKIMessage con = genCertConfirm(userDN, this.cacert, nonce, transid, hash, reqId);
            assertNotNull(con);
            PKIMessage confirm = protectPKIMessage(con, false, PBEPASSWORD, 567);
            final ByteArrayOutputStream bao = new ByteArrayOutputStream();
            final DEROutputStream out = new DEROutputStream(bao);
            out.writeObject(confirm);
            final byte[] ba = bao.toByteArray();
            // Send request and receive response
            final byte[] resp = sendCmpHttp(ba, 200, cmpAlias);
            checkCmpResponseGeneral(resp, this.issuerDN, userDN, this.cacert, nonce, transid, false, null,
                    PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
            checkCmpPKIConfirmMessage(userDN, this.cacert, resp);
        }
        return ret;
    }

    @Test
    public void test01CustomCertificateSerialNumber() throws Exception {
        final KeyPair key1 = KeyTools.genKeys("512", AlgorithmConstants.KEYALGORITHM_RSA);
        final String userName1 = "cmptest1";
        final X500Name userDN1 = new X500Name("C=SE,O=PrimeKey,CN=" + userName1);
        try {
            // check that several certificates could be created for one user and one key.
            long serno = RandomUtils.nextLong();
            BigInteger bint = BigInteger.valueOf(serno);
            // First it should fail because the CMP RA does not even look for, or parse, requested custom certificate serial numbers
            // Actually it does not fail here, but returns good answer
            X509Certificate cert = crmfHttpUserTest(userDN1, key1, null, null);
            assertFalse("SerialNumbers should not be equal when custom serialnumbers are not allowed.",
                    bint.equals(cert.getSerialNumber()));

            // Second it should fail when the certificate profile does not allow serial number override
            // crmfHttpUserTest checks the returned serno if bint parameter is not null
            this.cmpConfiguration.setAllowRACustomSerno(cmpAlias, true);
            this.globalConfigurationSession.saveConfiguration(ADMIN, this.cmpConfiguration);
            crmfHttpUserTest(userDN1, key1, "Used certificate profile ('" + this.cpDnOverrideId
                    + "') is not allowing certificate serial number override.", bint);

            // Third it should succeed and we should get our custom requested serialnumber
            this.cmpConfiguration.setAllowRACustomSerno(cmpAlias, true);
            this.globalConfigurationSession.saveConfiguration(ADMIN, this.cmpConfiguration);
            CertificateProfile cp = this.certProfileSession.getCertificateProfile(this.cpDnOverrideId);
            cp.setAllowCertSerialNumberOverride(true);
            // Now when the profile allows serial number override it should work
            this.certProfileSession.changeCertificateProfile(ADMIN, CP_DN_OVERRIDE_NAME, cp);
            crmfHttpUserTest(userDN1, key1, null, bint);
        } finally {
            try {
                this.endEntityManagementSession.deleteUser(ADMIN, userName1);
            } catch (NotFoundException e) {
                /* do nothing */}
        }
    }

    @Override
    @After
    public void tearDown() throws Exception {
        super.tearDown();
        this.cmpConfiguration.removeAlias(cmpAlias);
        this.globalConfigurationSession.saveConfiguration(ADMIN, this.cmpConfiguration);
    }

    @Override
    public String getRoleName() {
        return this.getClass().getSimpleName();
    }
}