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

Java tutorial

Introduction

Here is the source code for org.ejbca.core.protocol.cmp.CmpPbeVerifyer.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 java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Arrays;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers;
import org.bouncycastle.asn1.cmp.PBMParameter;
import org.bouncycastle.asn1.cmp.PKIHeader;
import org.bouncycastle.asn1.cmp.PKIMessage;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.ejbca.core.model.InternalEjbcaResources;

/**
 * Helper class to verify PBE of CMP messages, also extracts owf, mac Oids and iteration count.
 * @author tomas
 * @version $Id: CmpPbeVerifyer.java 19901 2014-09-30 14:29:38Z anatom $
 */
public class CmpPbeVerifyer {
    private static final Logger LOG = Logger.getLogger(CmpPbeVerifyer.class);
    /** Internal localization of logs and errors */
    private static final InternalEjbcaResources INTRES = InternalEjbcaResources.getInstance();

    private byte[] protectedBytes = null;
    private DERBitString protection = null;
    private AlgorithmIdentifier pAlg = null;
    private String errMsg = null;
    private String owfOid = null;
    private String macOid = null;
    private int iterationCount = 1024;
    private byte[] salt = null;
    private String lastUsedRaSecret = null;

    public CmpPbeVerifyer(final PKIMessage msg) {
        final PKIHeader head = msg.getHeader();
        protectedBytes = CmpMessageHelper.getProtectedBytes(msg);
        protection = msg.getProtection();
        pAlg = head.getProtectionAlg();
        final ASN1ObjectIdentifier algId = pAlg.getAlgorithm();
        if (!StringUtils.equals(algId.getId(), CMPObjectIdentifiers.passwordBasedMac.getId())) {
            final String errMsg = "Protection algorithm id expected '"
                    + CMPObjectIdentifiers.passwordBasedMac.getId() + "' (passwordBasedMac) but was '"
                    + algId.getId() + "'.";
            throw new IllegalArgumentException(errMsg);
        }
        final PBMParameter pp = PBMParameter.getInstance(pAlg.getParameters());
        iterationCount = pp.getIterationCount().getPositiveValue().intValue();
        final AlgorithmIdentifier owfAlg = pp.getOwf();
        // Normal OWF alg is 1.3.14.3.2.26 - SHA1
        owfOid = owfAlg.getAlgorithm().getId();
        final AlgorithmIdentifier macAlg = pp.getMac();
        // Normal mac alg is 1.3.6.1.5.5.8.1.2 - HMAC/SHA1
        macOid = macAlg.getAlgorithm().getId();
        if (LOG.isDebugEnabled()) {
            LOG.debug("Protection type is: " + algId.getId());
            LOG.debug("Iteration count is: " + iterationCount);
            LOG.debug("Owf type is: " + owfOid);
            LOG.debug("Mac type is: " + macOid);
        }
        salt = pp.getSalt().getOctets();
        //log.info("Salt: "+new String(salt));
    }

    public boolean verify(String raAuthenticationSecret)
            throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException {
        lastUsedRaSecret = raAuthenticationSecret;
        boolean ret = false;
        // Verify the PasswordBased protection of the message
        if (!pAlg.getAlgorithm().equals(CMPObjectIdentifiers.passwordBasedMac)) {
            errMsg = INTRES.getLocalizedMessage("cmp.errorunknownprotalg", pAlg.getAlgorithm().getId());
            LOG.error(errMsg);
            return ret;
        } else {
            if (iterationCount > 10000) {
                LOG.info("Received message with too many iterations in PBE protection: " + iterationCount);
                throw new InvalidKeyException("Iteration count can not exceed 10000");
            }
            byte[] raSecret = raAuthenticationSecret.getBytes();
            byte[] basekey = new byte[raSecret.length + salt.length];
            System.arraycopy(raSecret, 0, basekey, 0, raSecret.length);
            System.arraycopy(salt, 0, basekey, raSecret.length, salt.length);
            // Construct the base key according to rfc4210, section 5.1.3.1
            MessageDigest dig = MessageDigest.getInstance(owfOid, "BC");
            for (int i = 0; i < iterationCount; i++) {
                basekey = dig.digest(basekey);
                dig.reset();
            }
            // HMAC/SHA1 is normal 1.3.6.1.5.5.8.1.2 or 1.2.840.113549.2.7 
            Mac mac = Mac.getInstance(macOid, "BC");
            SecretKey key = new SecretKeySpec(basekey, macOid);
            mac.init(key);
            mac.reset();
            mac.update(protectedBytes, 0, protectedBytes.length);
            byte[] out = mac.doFinal();
            // My out should now be the same as the protection bits
            byte[] pb = protection.getBytes();
            ret = Arrays.equals(out, pb);
        }
        return ret;
    }

    public String getErrMsg() {
        return errMsg;
    }

    public String getMacOid() {
        return macOid;
    }

    public String getOwfOid() {
        return owfOid;
    }

    public int getIterationCount() {
        return iterationCount;
    }

    public String getLastUsedRaSecret() {
        return lastUsedRaSecret;
    }

}