/*************************************************************************
* *
* 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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers;
import org.bouncycastle.asn1.cmp.InfoTypeAndValue;
import org.bouncycastle.asn1.cmp.PKIBody;
import org.bouncycastle.asn1.cmp.PKIHeader;
import org.bouncycastle.asn1.cmp.PKIMessage;
import org.bouncycastle.asn1.crmf.AttributeTypeAndValue;
import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers;
import org.bouncycastle.asn1.crmf.CertReqMessages;
import org.bouncycastle.asn1.crmf.CertReqMsg;
import org.bouncycastle.asn1.crmf.CertRequest;
import org.bouncycastle.asn1.crmf.CertTemplate;
import org.bouncycastle.asn1.crmf.Controls;
import org.bouncycastle.asn1.crmf.OptionalValidity;
import org.bouncycastle.asn1.crmf.POPOSigningKey;
import org.bouncycastle.asn1.crmf.POPOSigningKeyInput;
import org.bouncycastle.asn1.crmf.ProofOfPossession;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.cms.CMSSignedGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.cesecore.util.CeSecoreNameStyle;
import org.cesecore.util.CertTools;
import org.ejbca.core.protocol.cmp.authentication.RegTokenPasswordExtractor;
/**
* Certificate request message (crmf) according to RFC4211.
* - Supported POPO:
* -- raVerified (null), i.e. no POPO verification is done, it should be configurable if the CA should allow this or require a real POPO
* -- Self signature, using the key in CertTemplate, or POPOSigningKeyInput (name and public key), option 2 and 3 in RFC4211, section "4.1. Signature Key POP"
*
* @version $Id: CrmfRequestMessage.java 26542 2017-09-14 10:36:30Z anatom $
*/
public class CrmfRequestMessage extends BaseCmpMessage implements ICrmfRequestMessage {
private static final Logger log = Logger.getLogger(CrmfRequestMessage.class);
/**
* Determines if a de-serialized file is compatible with this class.
*
* Maintainers must change this value if and only if the new version
* of this class is not compatible with old versions. See Sun docs
* for details.
*
*/
static final long serialVersionUID = 1002L;
public static final ASN1ObjectIdentifier id_regCtrl_protocolEncrKey = CRMFObjectIdentifiers.id_regCtrl.branch("6");
private int requestType = 0;
private int requestId = 0;
private String b64SenderNonce = null;
private String b64TransId = null;
/** Default CA DN */
private String defaultCADN = null;
private boolean allowRaVerifyPopo = false;
private String extractUsernameComponent = null;
/** manually set username */
private String username = null;
/** manually set password */
private String password = null;
/** manually set public and private key, if keys have been server generated */
private transient KeyPair serverGenKeyPair;
/** Because PKIMessage is not serializable we need to have the serializable bytes save as well, so
* we can restore the PKIMessage after serialization/deserialization. */
private byte[] pkimsgbytes = null;
private transient CertReqMsg req = null;
/** Because CertReqMsg is not serializable we may need to encode/decode bytes if the object is lost during deserialization. */
private CertReqMsg getReq() {
if (req == null) {
init();
}
return this.req;
}
/** preferred digest algorithm to use in replies, if applicable */
private String preferredDigestAlg = CMSSignedGenerator.DIGEST_SHA1;
public CrmfRequestMessage() { }
/**
*
* @param pkiMessage PKIMessage
* @param defaultCA possibility to enforce a certain CA, instead of taking the CA subject DN from the request, if set to null the CA subject DN is taken from the request
* @param allowRaVerifyPopo true if we allows the user/RA to specify the POP should not be verified
* @param extractUsernameComponent Defines which component from the DN should be used as username in EJBCA. Can be CN, UID or nothing. Null means that the username should have been pre-set, or that here it is the same as CN.
*/
public CrmfRequestMessage(final PKIMessage pkiMessage, final String defaultCADN, final boolean allowRaVerifyPopo, final String extractUsernameComponent) {
if (log.isTraceEnabled()) {
log.trace(">CrmfRequestMessage");
}
setPKIMessage(pkiMessage);
this.defaultCADN = defaultCADN;
this.allowRaVerifyPopo = allowRaVerifyPopo;
this.extractUsernameComponent = extractUsernameComponent;
init();
if (log.isTraceEnabled()) {
log.trace("