/************************************************************************* * * * 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("