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

Java tutorial

Introduction

Here is the source code for org.ejbca.core.protocol.cmp.CrmfRATcpRequestTest.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.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.KeyPair;
import java.security.cert.X509Certificate;

import javax.ejb.FinderException;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1InputStream;
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.bouncycastle.jce.X509KeyUsage;
import org.cesecore.CaTestUtils;
import org.cesecore.authorization.AuthorizationDeniedException;
import org.cesecore.certificates.ca.CA;
import org.cesecore.certificates.ca.CADoesntExistsException;
import org.cesecore.certificates.ca.CaSessionRemote;
import org.cesecore.certificates.certificateprofile.CertificateProfileConstants;
import org.cesecore.certificates.endentity.EndEntityConstants;
import org.cesecore.certificates.endentity.EndEntityTypes;
import org.cesecore.certificates.util.AlgorithmConstants;
import org.cesecore.configuration.GlobalConfigurationSessionRemote;
import org.cesecore.keys.token.CryptoTokenTestUtils;
import org.cesecore.keys.util.KeyTools;
import org.cesecore.util.Base64;
import org.cesecore.util.CryptoProviderTools;
import org.cesecore.util.EjbRemoteHelper;
import org.ejbca.config.CmpConfiguration;
import org.ejbca.core.EjbcaException;
import org.ejbca.core.ejb.ra.EndEntityExistsException;
import org.ejbca.core.model.SecConst;
import org.ejbca.core.model.approval.ApprovalException;
import org.ejbca.core.model.approval.WaitingForApprovalException;
import org.ejbca.core.model.ra.raadmin.UserDoesntFullfillEndEntityProfile;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * You need a CMP TCP listener configured on port 5587 to run this test.
 * (cmp.tcp.enabled=true, cmp.tcp.portno=5587)
 * 
 * 'ant clean; ant bootstrap' to deploy configuration changes.
 * 
 * @author tomas
 * @version $Id: CrmfRATcpRequestTest.java 19974 2014-10-09 15:19:06Z mikekushner $
 */
public class CrmfRATcpRequestTest extends CmpTestCase {

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

    private static final String CMP_USERNAME = "cmptest";
    private static final String PBEPASSWORD = "password";

    final private static X500Name userDN = new X500Name("CN=Some Common Name"); // we know what it is in this request...
    private static final String issuerDN = "CN=TestCA";
    final private KeyPair keys;
    final private int caid;
    final private X509Certificate cacert;
    final private CA testx509ca;
    final private CmpConfiguration cmpConfiguration;
    final private String cmpAlias = "tcp";

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

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

    public CrmfRATcpRequestTest() throws Exception {
        this.keys = KeyTools.genKeys("512", AlgorithmConstants.KEYALGORITHM_RSA);
        int keyusage = X509KeyUsage.digitalSignature + X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign;
        this.testx509ca = CaTestUtils.createTestX509CA(issuerDN, null, false, keyusage);
        this.caid = this.testx509ca.getCAId();
        this.cacert = (X509Certificate) this.testx509ca.getCACertificate();
        this.cmpConfiguration = (CmpConfiguration) this.globalConfigurationSession
                .getCachedConfiguration(CmpConfiguration.CMP_CONFIGURATION_ID);
    }

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

        this.caSession.addCA(ADMIN, this.testx509ca);

        this.configurationSession.backupConfiguration();

        // Configure CMP for this test
        if (this.cmpConfiguration.aliasExists(this.cmpAlias)) {
            this.cmpConfiguration.renameAlias(this.cmpAlias, "backupTcpAlias");
        }
        this.cmpConfiguration.addAlias(this.cmpAlias);
        this.cmpConfiguration.setRAMode(this.cmpAlias, true);
        this.cmpConfiguration.setAllowRAVerifyPOPO(this.cmpAlias, true);
        this.cmpConfiguration.setResponseProtection(this.cmpAlias, "signature");
        this.cmpConfiguration.setRAEEProfile(this.cmpAlias, EEP_DN_OVERRIDE_NAME);
        this.cmpConfiguration.setRACertProfile(this.cmpAlias, CP_DN_OVERRIDE_NAME);
        this.cmpConfiguration.setRACAName(this.cmpAlias, "TestCA");
        this.cmpConfiguration.setAuthenticationModule(this.cmpAlias,
                CmpConfiguration.AUTHMODULE_REG_TOKEN_PWD + ";" + CmpConfiguration.AUTHMODULE_HMAC);
        this.cmpConfiguration.setAuthenticationParameters(this.cmpAlias, "-;" + PBEPASSWORD);
        this.globalConfigurationSession.saveConfiguration(ADMIN, this.cmpConfiguration);
    }

    @Override
    @After
    public void tearDown() throws Exception {
        super.tearDown();

        this.cmpConfiguration.removeAlias(this.cmpAlias);
        if (this.cmpConfiguration.aliasExists("backupTcpAlias")) {
            this.cmpConfiguration.renameAlias("backupTcpAlias", this.cmpAlias);
        }
        this.globalConfigurationSession.saveConfiguration(ADMIN, this.cmpConfiguration);

        boolean cleanUpOk = true;
        if (!this.configurationSession.restoreConfiguration()) {
            cleanUpOk = false;
        }
        assertTrue("Unable to clean up properly.", cleanUpOk);

        CryptoTokenTestUtils.removeCryptoToken(null, this.testx509ca.getCAToken().getCryptoTokenId());
        this.caSession.removeCA(ADMIN, this.caid);
    }

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

    @Test
    public void test01CrmfUnknowUser() throws Exception {
        // A name that does not exis
        final X500Name dn = new X500Name("CN=abc123rry5774466, O=PrimeKey Solutions AB, C=SE");

        byte[] nonce = CmpMessageHelper.createSenderNonce();
        byte[] transid = CmpMessageHelper.createSenderNonce();

        PKIMessage one = genCertReq(issuerDN, dn, this.keys, this.cacert, nonce, transid, true, null, null, null,
                null, null, null);
        PKIMessage req = protectPKIMessage(one, false, PBEPASSWORD, 567);
        CertReqMessages ir = (CertReqMessages) req.getBody().getContent();
        int reqId = ir.toCertReqMsgArray()[0].getCertReq().getCertReqId().getValue().intValue();
        assertNotNull(req);
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        DEROutputStream out = new DEROutputStream(bao);
        out.writeObject(req);
        byte[] ba = bao.toByteArray();
        // Send request and receive response
        byte[] resp = sendCmpTcp(ba, 5);
        checkCmpResponseGeneral(resp, issuerDN, dn, this.cacert, nonce, transid, true, null,
                PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
        checkCmpCertRepMessage(dn, this.cacert, resp, reqId);
    }

    @Test
    public void test02CrmfOkUser() throws Exception {

        // Create a new good user
        final X500Name dn = new X500Name("C=SE,O=PrimeKey,CN=cmptest");
        createCmpUser(CMP_USERNAME, dn.toString());
        try {
            byte[] nonce = CmpMessageHelper.createSenderNonce();
            byte[] transid = CmpMessageHelper.createSenderNonce();

            PKIMessage one = genCertReq(issuerDN, dn, this.keys, this.cacert, nonce, transid, true, null, null,
                    null, null, null, null);
            PKIMessage req = protectPKIMessage(one, false, PBEPASSWORD, 567);

            CertReqMessages ir = (CertReqMessages) req.getBody().getContent();
            int reqId = ir.toCertReqMsgArray()[0].getCertReq().getCertReqId().getValue().intValue();
            assertNotNull(req);
            ByteArrayOutputStream bao = new ByteArrayOutputStream();
            DEROutputStream out = new DEROutputStream(bao);
            out.writeObject(req);
            byte[] ba = bao.toByteArray();
            // Send request and receive response
            byte[] resp = sendCmpTcp(ba, 5);
            checkCmpResponseGeneral(resp, issuerDN, dn, this.cacert, nonce, transid, true, null,
                    PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
            checkCmpCertRepMessage(dn, this.cacert, resp, reqId);

            // Send a confirm message to the CA
            String hash = "foo123";
            PKIMessage confirm = genCertConfirm(dn, this.cacert, nonce, transid, hash, reqId);
            assertNotNull(confirm);
            bao = new ByteArrayOutputStream();
            out = new DEROutputStream(bao);
            out.writeObject(confirm);
            ba = bao.toByteArray();
            // Send request and receive response
            resp = sendCmpTcp(ba, 5);
            checkCmpResponseGeneral(resp, issuerDN, dn, this.cacert, nonce, transid, false, null,
                    PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
            checkCmpPKIConfirmMessage(dn, this.cacert, resp);
        } finally {
            this.endEntityManagementSession.deleteUser(ADMIN, CMP_USERNAME);
        }
    }

    @Test
    public void test03BlueXCrmf() throws Exception {
        PKIMessage req = null;
        ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(bluexir));
        try {
            req = PKIMessage.getInstance(asn1InputStream.readObject());
        } finally {
            asn1InputStream.close();
        }
        byte[] resp = sendCmpTcp(bluexir, 5);
        assertNotNull(resp);
        byte[] senderNonce = req.getHeader().getSenderNonce().getOctets();
        byte[] transId = req.getHeader().getTransactionID().getOctets();
        CertReqMessages ir = (CertReqMessages) req.getBody().getContent();
        int reqId = ir.toCertReqMsgArray()[0].getCertReq().getCertReqId().getValue().intValue();
        checkCmpResponseGeneral(resp, issuerDN, userDN, this.cacert, senderNonce, transId, true, null,
                PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
        checkCmpCertRepMessage(userDN, this.cacert, resp, reqId);
    }

    @Test
    public void test04CrmfUnauthenticated() throws Exception {

        byte[] nonce = CmpMessageHelper.createSenderNonce();
        byte[] transid = CmpMessageHelper.createSenderNonce();

        PKIMessage req = genCertReq(issuerDN, userDN, this.keys, this.cacert, nonce, transid, true, null, null,
                null, null, null, null);

        assertNotNull(req);
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        DEROutputStream out = new DEROutputStream(bao);
        out.writeObject(req);
        byte[] ba = bao.toByteArray();
        // Send request and receive response
        byte[] resp = sendCmpTcp(ba, 5);
        checkCmpResponseGeneral(resp, issuerDN, userDN, this.cacert, nonce, transid, false, null,
                PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
        checkCmpPKIErrorMessage(resp, issuerDN, userDN, PKIFailureInfo.badMessageCheck,
                "PKI Message is not athenticated properly. No HMAC protection was found.");
    }

    @Test
    public void test05CrmfUnknownProtection() throws Exception {

        byte[] nonce = CmpMessageHelper.createSenderNonce();
        byte[] transid = CmpMessageHelper.createSenderNonce();

        PKIMessage one = genCertReq(issuerDN, userDN, this.keys, this.cacert, nonce, transid, true, null, null,
                null, null, null, null);
        PKIMessage req = protectPKIMessage(one, true, PBEPASSWORD, 567);

        assertNotNull(req);
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        DEROutputStream out = new DEROutputStream(bao);
        out.writeObject(req);
        byte[] ba = bao.toByteArray();
        // Send request and receive response
        byte[] resp = sendCmpTcp(ba, 5);
        checkCmpResponseGeneral(resp, issuerDN, userDN, this.cacert, nonce, transid, false, null,
                PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
        checkCmpPKIErrorMessage(resp, issuerDN, userDN, PKIFailureInfo.badMessageCheck,
                "Could not create CmpPbeVerifyer. Protection algorithm id expected '1.2.840.113533.7.66.13' (passwordBasedMac) but was '1.2.840.113533.7.66.13.7'.");
    }

    /**
     * Try a request with SubjectDN email and special characters.
     * 
     * @throws Exception
     */
    @Test
    public void test06DnEmail() throws Exception {
        try {
            final X500Name subjectDN = new X500Name("C=SE,CN=Gran Strmfrare,E=adam@eva.se");
            // createCmpUser("cmptest2", subjectDN);

            byte[] nonce = CmpMessageHelper.createSenderNonce();
            byte[] transid = CmpMessageHelper.createSenderNonce();

            PKIMessage one = genCertReq(issuerDN, subjectDN, null, this.keys, this.cacert, nonce, transid, true,
                    null, null, null, null, null, null);
            PKIMessage req = protectPKIMessage(one, false, PBEPASSWORD, 567);

            CertReqMessages ir = (CertReqMessages) req.getBody().getContent();
            int reqId = ir.toCertReqMsgArray()[0].getCertReq().getCertReqId().getValue().intValue();
            assertNotNull(req);
            ByteArrayOutputStream bao = new ByteArrayOutputStream();
            DEROutputStream out = new DEROutputStream(bao);
            out.writeObject(req);
            byte[] ba = bao.toByteArray();
            // Send request and receive response
            byte[] resp = sendCmpTcp(ba, 5);
            checkCmpResponseGeneral(resp, issuerDN, subjectDN, this.cacert, nonce, transid, true, null,
                    PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
            checkCmpCertRepMessage(subjectDN, this.cacert, resp, reqId);

            // Send a confirm message to the CA
            String hash = "foo123";
            PKIMessage confirm = genCertConfirm(subjectDN, this.cacert, nonce, transid, hash, reqId);
            assertNotNull(confirm);
            bao = new ByteArrayOutputStream();
            out = new DEROutputStream(bao);
            out.writeObject(confirm);
            ba = bao.toByteArray();
            // Send request and receive response
            resp = sendCmpTcp(ba, 5);
            checkCmpResponseGeneral(resp, issuerDN, subjectDN, this.cacert, nonce, transid, false, null,
                    PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
            checkCmpPKIConfirmMessage(subjectDN, this.cacert, resp);
        } finally {
            this.endEntityManagementSession.deleteUser(ADMIN, "Gran Strmfrare");
        }
    }

    //
    // Private helper methods
    //
    private void createCmpUser(String username, String dn)
            throws AuthorizationDeniedException, UserDoesntFullfillEndEntityProfile, ApprovalException,
            WaitingForApprovalException, EjbcaException, FinderException, CADoesntExistsException {
        // Make user that we know...
        boolean userExists = false;
        try {
            this.endEntityManagementSession.addUser(ADMIN, username, "foo123", dn, null, "cmptest@primekey.se",
                    false, SecConst.EMPTY_ENDENTITYPROFILE, CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER,
                    EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.TOKEN_SOFT_PEM, 0, this.caid);
            log.debug("created user: " + username + ", foo123, " + dn);
        } catch (EndEntityExistsException e) {
            userExists = true;
        }

        if (userExists) {
            log.debug("User " + username + " already exists.");
            this.endEntityManagementSession.setUserStatus(ADMIN, username, EndEntityConstants.STATUS_NEW);
            log.debug("Reset status to NEW");
        }
    }

    static byte[] bluexir = Base64.decode(("MIICIjCB1AIBAqQCMACkVjBUMQswCQYDVQQGEwJOTDEbMBkGA1UEChMSQS5FLlQu"
            + "IEV1cm9wZSBCLlYuMRQwEgYDVQQLEwtEZXZlbG9wbWVudDESMBAGA1UEAxMJVGVz"
            + "dCBDQSAxoT4wPAYJKoZIhvZ9B0INMC8EEAK/H7Do+55N724Kdvxm7NcwCQYFKw4D"
            + "AhoFAAICA+gwDAYIKwYBBQUIAQIFAKILBAlzc2xjbGllbnSkEgQQpFpBsonfhnW8"
            + "ia1otGchraUSBBAyzd3nkKAzcJqGFrDw0jkYoIIBLjCCASowggEmMIIBIAIBADCC"
            + "ARmkJqARGA8yMDA2MDkxOTE2MTEyNlqhERgPMjAwOTA2MTUxNjExMjZapR0wGzEZ"
            + "MBcGA1UEAwwQU29tZSBDb21tb24gTmFtZaaBoDANBgkqhkiG9w0BAQEFAAOBjgAw"
            + "gYoCgYEAuBgTGPgXrS3AIPN6iXO6LNf5GzAcb/WZhvebXMdxdrMo9+5hw/Le5St/"
            + "Sz4J93rxU95b2LMuHTg8U6njxC2lZarNExZTdEwnI37X6ep7lq1purq80zD9bFXj"
            + "ougRD5MHfhDUAQC+btOgEXkanoAo8St3cbtHoYUacAXN2Zs/RVcCBAABAAGpLTAr"
            + "BgNVHREEJDAioCAGCisGAQQBgjcUAgOgEgwQdXBuQGFldGV1cm9wZS5ubIAAoBcD"
            + "FQAy/vSoNUevcdUxXkCQx3fvxkjh6A==").getBytes());

}