org.ejbca.core.protocol.scep.ScepRequestMessage.java Source code

Java tutorial

Introduction

Here is the source code for org.ejbca.core.protocol.scep.ScepRequestMessage.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.scep;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.EnvelopedData;
import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
import org.bouncycastle.asn1.cms.KeyTransRecipientInfo;
import org.bouncycastle.asn1.cms.RecipientIdentifier;
import org.bouncycastle.asn1.cms.RecipientInfo;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.asn1.cms.SignerInfo;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedGenerator;
import org.bouncycastle.cms.RecipientInformation;
import org.bouncycastle.cms.RecipientInformationStore;
import org.bouncycastle.cms.SignerId;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.SignerInformationVerifier;
import org.bouncycastle.cms.SignerInformationVerifierProvider;
import org.bouncycastle.cms.jcajce.JcaSignerInfoVerifierBuilder;
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
import org.cesecore.certificates.certificate.request.PKCS10RequestMessage;
import org.cesecore.certificates.certificate.request.RequestMessage;
import org.cesecore.util.Base64;
import org.cesecore.util.CertTools;

/**
 * Class to handle SCEP request messages sent to the CA. 
 *
 * @version $Id: ScepRequestMessage.java 20960 2015-03-23 15:10:52Z mikekushner $
 */
public class ScepRequestMessage extends PKCS10RequestMessage implements RequestMessage {
    /**
     * 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 <a href=http://java.sun.com/products/jdk/1.1/docs/guide
     * /serialization/spec/version.doc.html> details. </a>
     *
     */
    static final long serialVersionUID = -235623330828902051L;

    private static Logger log = Logger.getLogger(ScepRequestMessage.class);

    public static final String id_Verisign = "2.16.840.1.113733";
    public static final String id_pki = id_Verisign + ".1";
    public static final String id_attributes = id_pki + ".9";
    public static final String id_messageType = id_attributes + ".2";
    public static final String id_pkiStatus = id_attributes + ".3";
    public static final String id_failInfo = id_attributes + ".4";
    public static final String id_senderNonce = id_attributes + ".5";
    public static final String id_recipientNonce = id_attributes + ".6";
    public static final String id_transId = id_attributes + ".7";
    public static final String id_extensionReq = id_attributes + ".8";

    /** Raw form of the Scep message */
    private byte[] scepmsg;

    /**
     * The messageType attribute specify the type of operation performed by the transaction. This
     * attribute is required in all PKI messages. Currently, the following message types are
     * defined: 
     * PKCSReq (19)  -- Permits use of PKCS#10 certificate request 
     * CertRep (3)   -- Response to certificate or CRL request 
     * GetCertInitial (20)  -- Certificate polling in manual enrollment 
     * GetCert (21)  -- Retrieve a certificate 
     * GetCRL  (22)  -- Retrieve a CRL
     */
    private int messageType = 0;
    public static int SCEP_TYPE_PKCSREQ = 19;
    public static int SCEP_TYPE_GETCERTINITIAL = 20; // Used when request is in pending state.
    public static int SCEP_TYPE_GETCRL = 22;
    public static int SCEP_TYPE_GETCERT = 21;

    /**
     * SenderNonce in a request is used as recipientNonce when the server sends back a reply to the
     * client. This is base64 encoded bytes
     */
    private String senderNonce = null;

    /** transaction id */
    private String transactionId = null;

    /** request key info, this is the requester's self-signed certificate used to identify the senders public key */
    private byte[] requestKeyInfo = null;

    /** Type of error */
    private int error = 0;

    /** Error text */
    private String errorText = null;

    /** Issuer DN the message is sent to (CAs Issuer DN), contained in the 
     * request as recipientInfo.issuerAndSerialNumber in EnvelopeData part */
    private transient String issuerDN = null;

    /** SerialNumber of the CA cert of the CA the message is sent to, contained in the 
     * request as recipientInfo.issuerAndSerialNumber in EnvelopeData part */
    private transient BigInteger serialNo = null;

    /** Signed data, the whole enchilada to to speak... */
    private transient SignedData sd = null;

    /** Enveloped data, carrying the 'beef' of the request */
    private transient EnvelopedData envData = null;

    /** Enveloped data, carrying the 'beef' of the request */
    private transient ContentInfo envEncData = null;

    /** Private key used for decryption. */
    private transient PrivateKey privateKey = null;
    /** JCE Provider used when decrypting with private key. Default provider is BC. */
    private transient String jceProvider = BouncyCastleProvider.PROVIDER_NAME;

    /** IssuerAndSerialNUmber for CRL request */
    private transient IssuerAndSerialNumber issuerAndSerno = null;

    /** preferred digest algorithm to use in replies, if applicable.
     *  Defaults to CMSSignedGenerator.DIGEST_MD5 for SCEP messages. If SCEP request is 
     * digested with SHA1 it is set to SHA1 though. This is only for backwards compatibility issues, as specified in a SCEP draft.
     * Modern request/responses will use SHA-1.
     */
    private transient String preferredDigestAlg = CMSSignedGenerator.DIGEST_MD5;

    private transient Certificate signercert;

    /**
     * Constructs a new SCEP/PKCS7 message handler object.
     *
     * @param msg The DER encoded PKCS7 request.
     * @param incCACert if the CA certificate should be included in the response or not
     *
     * @throws IOException if the request can not be parsed.
     */
    public ScepRequestMessage(byte[] msg, boolean incCACert) throws IOException {
        if (log.isTraceEnabled()) {
            log.trace(">ScepRequestMessage");
        }
        this.scepmsg = msg;
        this.includeCACert = incCACert;
        init();
        if (log.isTraceEnabled()) {
            log.trace("<ScepRequestMessage");
        }
    }

    /**
     * This method verifies the signature of the PKCS#7 wrapper of this message. 
     * 
     * @param publicKey the public key of the keypair that signed this message
     * @return true if signature verifies. 
     * @throws CMSException if the underlying byte array of this SCEP message couldn't be read
     * @throws OperatorCreationException if a signature verifier couldn't be constructed from the given public key
     */
    public boolean verifySignature(PublicKey publicKey) throws CMSException, OperatorCreationException {
        CMSSignedData cmsSignedData = new CMSSignedData(scepmsg);
        return cmsSignedData.verifySignatures(new ScepVerifierProvider(publicKey));
    }

    private void init() throws IOException {
        if (log.isTraceEnabled()) {
            log.trace(">init");
        }
        try {
            CMSSignedData csd = new CMSSignedData(scepmsg);
            SignerInformationStore infoStore = csd.getSignerInfos();
            @SuppressWarnings("unchecked")
            Collection<SignerInformation> signers = infoStore.getSigners();
            Iterator<SignerInformation> iter = signers.iterator();
            if (iter.hasNext()) {
                SignerInformation si = (SignerInformation) iter.next();
                preferredDigestAlg = si.getDigestAlgOID();
                log.debug("Set " + preferredDigestAlg + " as preferred digest algorithm for SCEP");
            }
        } catch (CMSException e) {
            // ignore, use default digest algo
            log.error("CMSException trying to get preferred digest algorithm: ", e);
        }
        // Parse and verify the integrity of the PKIOperation message PKCS#7
        /* If this would have been done using the newer CMS it would have made me so much happier... */
        ASN1InputStream seqAsn1InputStream = new ASN1InputStream(new ByteArrayInputStream(scepmsg));
        ASN1Sequence seq = null;
        try {
            seq = (ASN1Sequence) seqAsn1InputStream.readObject();
        } finally {
            seqAsn1InputStream.close();
        }
        ContentInfo ci = ContentInfo.getInstance(seq);
        String ctoid = ci.getContentType().getId();

        if (ctoid.equals(CMSObjectIdentifiers.signedData.getId())) {
            // This is SignedData so it is a pkcsCertReqSigned, pkcsGetCertInitialSigned, pkcsGetCertSigned, pkcsGetCRLSigned
            // (could also be pkcsRepSigned or certOnly, but we don't receive them on the server side
            // Try to find out what kind of message this is
            sd = SignedData.getInstance((ASN1Sequence) ci.getContent());
            // Get self signed cert to identify the senders public key
            ASN1Set certs = sd.getCertificates();
            if (certs.size() > 0) {
                // There should be only one...
                ASN1Encodable dercert = certs.getObjectAt(0);
                if (dercert != null) {
                    // Requester's self-signed certificate is requestKeyInfo
                    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
                    DEROutputStream dOut = new DEROutputStream(bOut);
                    dOut.writeObject(dercert);
                    if (bOut.size() > 0) {
                        requestKeyInfo = bOut.toByteArray();
                        //Create Certificate used for debugging
                        try {
                            signercert = CertTools.getCertfromByteArray(requestKeyInfo);
                            if (log.isDebugEnabled()) {
                                log.debug("requestKeyInfo is SubjectDN: " + CertTools.getSubjectDN(signercert)
                                        + ", Serial=" + CertTools.getSerialNumberAsString(signercert)
                                        + "; IssuerDN: " + CertTools.getIssuerDN(signercert).toString());
                            }
                        } catch (CertificateException e) {
                            log.error("Error parsing requestKeyInfo : ", e);
                        }

                    }
                }
            }

            Enumeration<?> sis = sd.getSignerInfos().getObjects();

            if (sis.hasMoreElements()) {
                SignerInfo si = SignerInfo.getInstance((ASN1Sequence) sis.nextElement());
                Enumeration<?> attr = si.getAuthenticatedAttributes().getObjects();

                while (attr.hasMoreElements()) {
                    Attribute a = Attribute.getInstance((ASN1Sequence) attr.nextElement());
                    if (log.isDebugEnabled()) {
                        log.debug("Found attribute: " + a.getAttrType().getId());
                    }
                    if (a.getAttrType().getId().equals(id_senderNonce)) {
                        Enumeration<?> values = a.getAttrValues().getObjects();
                        ASN1OctetString str = ASN1OctetString.getInstance(values.nextElement());
                        senderNonce = new String(Base64.encode(str.getOctets(), false));
                        if (log.isDebugEnabled()) {
                            log.debug("senderNonce = " + senderNonce);
                        }
                    }
                    if (a.getAttrType().getId().equals(id_transId)) {
                        Enumeration<?> values = a.getAttrValues().getObjects();
                        DERPrintableString str = DERPrintableString.getInstance(values.nextElement());
                        transactionId = str.getString();
                        if (log.isDebugEnabled()) {
                            log.debug("transactionId = " + transactionId);
                        }
                    }
                    if (a.getAttrType().getId().equals(id_messageType)) {
                        Enumeration<?> values = a.getAttrValues().getObjects();
                        DERPrintableString str = DERPrintableString.getInstance(values.nextElement());
                        messageType = Integer.parseInt(str.getString());
                        if (log.isDebugEnabled()) {
                            log.debug("messagetype = " + messageType);
                        }
                    }
                }
            }

            // If this is a PKCSReq
            if ((messageType == ScepRequestMessage.SCEP_TYPE_PKCSREQ)
                    || (messageType == ScepRequestMessage.SCEP_TYPE_GETCRL)
                    || (messageType == ScepRequestMessage.SCEP_TYPE_GETCERTINITIAL)) {
                // Extract the contents, which is an encrypted PKCS10 if messageType == 19
                // , and an encrypted issuer and subject if messageType == 20 (not extracted)
                // and an encrypted IssuerAndSerialNumber if messageType == 22
                ci = sd.getEncapContentInfo();
                ctoid = ci.getContentType().getId();

                if (ctoid.equals(CMSObjectIdentifiers.data.getId())) {
                    ASN1OctetString content = (ASN1OctetString) ci.getContent();
                    if (log.isDebugEnabled()) {
                        log.debug("envelopedData is " + content.getOctets().length + " bytes.");
                    }
                    ASN1InputStream seq1Asn1InputStream = new ASN1InputStream(
                            new ByteArrayInputStream(content.getOctets()));
                    ASN1Sequence seq1 = null;
                    try {
                        seq1 = (ASN1Sequence) seq1Asn1InputStream.readObject();
                    } finally {
                        seq1Asn1InputStream.close();
                    }
                    envEncData = ContentInfo.getInstance(seq1);
                    ctoid = envEncData.getContentType().getId();

                    if (ctoid.equals(CMSObjectIdentifiers.envelopedData.getId())) {
                        envData = EnvelopedData.getInstance((ASN1Sequence) envEncData.getContent());
                        ASN1Set recipientInfos = envData.getRecipientInfos();
                        Enumeration<?> e = recipientInfos.getObjects();
                        while (e.hasMoreElements()) {
                            RecipientInfo ri = RecipientInfo.getInstance(e.nextElement());
                            KeyTransRecipientInfo recipientInfo = KeyTransRecipientInfo.getInstance(ri.getInfo());
                            RecipientIdentifier rid = recipientInfo.getRecipientIdentifier();
                            IssuerAndSerialNumber iasn = IssuerAndSerialNumber.getInstance(rid.getId());
                            issuerDN = iasn.getName().toString();
                            serialNo = iasn.getSerialNumber().getValue();
                            if (log.isDebugEnabled()) {
                                log.debug("IssuerDN: " + issuerDN);
                                log.debug("SerialNumber: " + iasn.getSerialNumber().getValue().toString(16));
                            }
                        }
                    } else {
                        errorText = "EncapsulatedContentInfo does not contain PKCS7 envelopedData: ";
                        log.error(errorText + ctoid);
                        error = 2;
                    }
                } else {
                    errorText = "EncapsulatedContentInfo is not of type 'data': ";
                    log.error(errorText + ctoid);
                    error = 3;
                }
            } else {
                errorText = "This is not a certification request!";
                log.error(errorText);
                error = 4;
            }
        } else {
            errorText = "PKCSReq does not contain 'signedData': ";
            log.error(errorText + ctoid);
            error = 1;
        }

        log.trace("<init");
    } // init

    private void decrypt() throws CMSException, NoSuchProviderException, GeneralSecurityException, IOException {
        if (log.isTraceEnabled()) {
            log.trace(">decrypt");
        }
        // Now we are getting somewhere (pheew),
        // Now we just have to get the damn key...to decrypt the PKCS10
        if (privateKey == null) {
            errorText = "Need private key to decrypt!";
            error = 5;
            log.error(errorText);
            return;
        }

        if (envEncData == null) {
            errorText = "No enveloped data to decrypt!";
            error = 6;
            log.error(errorText);
            return;
        }

        CMSEnvelopedData ed = new CMSEnvelopedData(envEncData);
        RecipientInformationStore recipients = ed.getRecipientInfos();
        @SuppressWarnings("unchecked")
        Collection<RecipientInformation> c = recipients.getRecipients();
        Iterator<RecipientInformation> it = c.iterator();
        byte[] decBytes = null;

        while (it.hasNext()) {
            RecipientInformation recipient = (RecipientInformation) it.next();
            if (log.isDebugEnabled()) {
                log.debug("Privatekey : " + privateKey.getAlgorithm());
            }
            JceKeyTransEnvelopedRecipient rec = new JceKeyTransEnvelopedRecipient(privateKey);
            rec.setProvider(jceProvider); // Use the crypto token provides for asymmetric key operations
            rec.setContentProvider(BouncyCastleProvider.PROVIDER_NAME); // Use BC for the symmetric key operations
            decBytes = recipient.getContent(rec);
            break;
        }

        if (messageType == ScepRequestMessage.SCEP_TYPE_PKCSREQ) {
            pkcs10 = new JcaPKCS10CertificationRequest(decBytes);
            if (log.isDebugEnabled()) {
                log.debug("Successfully extracted PKCS10:" + new String(Base64.encode(pkcs10.getEncoded())));
            }
        }
        if (messageType == ScepRequestMessage.SCEP_TYPE_GETCRL) {
            ASN1InputStream derAsn1InputStream = new ASN1InputStream(new ByteArrayInputStream(decBytes));
            ASN1Primitive derobj = null;
            try {
                derobj = derAsn1InputStream.readObject();
            } finally {
                derAsn1InputStream.close();
            }
            issuerAndSerno = IssuerAndSerialNumber.getInstance(derobj);
            log.debug("Successfully extracted IssuerAndSerialNumber.");
        }
        if (log.isTraceEnabled()) {
            log.trace("<decrypt");
        }
    } // decrypt

    @Override
    public PublicKey getRequestPublicKey() {
        if (log.isTraceEnabled()) {
            log.trace(">getRequestPublicKey()");
        }
        PublicKey ret = null;
        try {
            if (envData == null) {
                init();
                decrypt();
            }
            ret = super.getRequestPublicKey();
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getRequestPublicKey()");
        }
        return ret;
    }

    @Override
    public String getRequestAltNames() {
        if (log.isTraceEnabled()) {
            log.trace(">getRequestAltNames()");
        }
        String ret = null;
        try {
            if (envData == null) {
                init();
                decrypt();
            }
            ret = super.getRequestAltNames();
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getRequestAltNames()");
        }
        return ret;
    }

    @Override
    public boolean verify() {
        if (log.isTraceEnabled()) {
            log.trace(">verify()");
        }
        boolean ret = false;
        try {
            if (pkcs10 == null) {
                init();
                decrypt();
            }
            ret = super.verify();
        } catch (IOException e) {
            log.error("PKCS7 not initialized!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<verify()");
        }
        return ret;
    }

    @Override
    public String getPassword() {
        if (log.isTraceEnabled()) {
            log.trace(">getPassword()");
        }
        String ret = null;
        try {
            if (pkcs10 == null) {
                init();
                decrypt();
            }
            ret = super.getPassword();
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getPassword()");
        }
        return ret;
    }

    @Override
    public String getUsername() {
        if (log.isTraceEnabled()) {
            log.trace(">getUsername()");
        }
        String ret = null;
        try {
            if (pkcs10 == null) {
                init();
                decrypt();
            }
            ret = super.getUsername();
            if (ret == null) {
                // For Cisco boxes they can sometimes send DN as SN instead of CN
                String name = CertTools.getPartFromDN(getRequestDN(), "SN");
                if (name == null) {
                    log.error("No SN in DN: " + getRequestDN());
                    return null;
                }
                // Special if the DN contains unstructuredAddress where it becomes: 
                // SN=1728668 + 1.2.840.113549.1.9.2=pix.primekey.se
                // We only want the SN and not the oid-part.
                int index = name.indexOf(' ');
                ret = name;
                if (index > 0) {
                    ret = name.substring(0, index);
                } else {
                    // Perhaps there is no space, only +
                    index = name.indexOf('+');
                    if (index > 0) {
                        ret = name.substring(0, index);
                    }
                }
            }
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getUsername(): " + ret);
        }
        return ret;
    }

    @Override
    public String getIssuerDN() {
        if (log.isTraceEnabled()) {
            log.trace(">getIssuerDN()");
        }
        String ret = null;
        try {
            if (envData == null) {
                init();
            }
            ret = issuerDN;
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        }
        if (log.isTraceEnabled()) {
            log.trace("<getIssuerDN(): " + ret);
        }
        return ret;
    }

    @Override
    public BigInteger getSerialNo() {
        if (log.isTraceEnabled()) {
            log.trace(">getSerialNo()");
        }
        // Use another method to do the decryption etc...
        getIssuerDN();
        return serialNo;
    }

    @Override
    public String getCRLIssuerDN() {
        if (log.isTraceEnabled()) {
            log.trace(">getCRLIssuerDN()");
        }
        String ret = null;
        try {
            if (issuerAndSerno == null) {
                init();
                decrypt();
            }
            ret = CertTools.stringToBCDNString(issuerAndSerno.getName().toString());
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getCRLIssuerDN(): " + ret);
        }
        return ret;
    }

    @Override
    public BigInteger getCRLSerialNo() {
        if (log.isTraceEnabled()) {
            log.trace(">getCRLSerialNo()");
        }
        BigInteger ret = null;
        try {
            if (issuerAndSerno == null) {
                init();
                decrypt();
            }
            ret = issuerAndSerno.getSerialNumber().getValue();
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getCRLSerialNo(): " + ret);
        }
        return ret;
    }

    @Override
    public String getRequestDN() {
        if (log.isTraceEnabled()) {
            log.trace(">getRequestDN()");
        }
        String ret = null;
        try {
            if (pkcs10 == null) {
                init();
                decrypt();
            }
            ret = super.getRequestDN();
        } catch (IOException e) {
            log.error("PKCS7 not inited!");
        } catch (GeneralSecurityException e) {
            log.error("Error in PKCS7:", e);
        } catch (CMSException e) {
            log.error("Error in PKCS7:", e);
        }
        if (log.isTraceEnabled()) {
            log.trace("<getRequestDN(): " + ret);
        }
        return ret;
    }

    @Override
    public boolean requireKeyInfo() {
        return true;
    }

    @Override
    public void setKeyInfo(Certificate cert, PrivateKey key, String provider) {
        // We don't need the public key 
        // this.cert = cert;
        this.privateKey = key;
        if (provider == null) {
            this.jceProvider = "BC";
        } else {
            this.jceProvider = provider;
        }
    }

    @Override
    public int getErrorNo() {
        return error;
    }

    @Override
    public String getErrorText() {
        return errorText;
    }

    @Override
    public String getSenderNonce() {
        return senderNonce;
    }

    @Override
    public String getTransactionId() {
        return transactionId;
    }

    @Override
    public byte[] getRequestKeyInfo() {
        return requestKeyInfo;
    }

    @Override
    public String getPreferredDigestAlg() {
        return preferredDigestAlg;
    }

    /** Returns the type of SCEP message it is
     * 
     * @return value as defined by SCEP_TYPE_PKCSREQ, SCEP_TYPE_GETCRL, SCEP_TYPE_GETCERT  
     */
    public int getMessageType() {
        return messageType;

    }

    /**
     * Method returning the certificate used to sign the SCEP_TYPE_PKCSREQ pkcs7 request.
     * 
     * @return The certificate used for signing or null if it doesn't exist or not been initialized.
     */
    public Certificate getSignerCert() {
        return signercert;
    }

    private static class ScepVerifierProvider implements SignerInformationVerifierProvider {

        private final SignerInformationVerifier signerInformationVerifier;

        public ScepVerifierProvider(PublicKey publicKey) throws OperatorCreationException {
            JcaDigestCalculatorProviderBuilder calculatorProviderBuilder = new JcaDigestCalculatorProviderBuilder()
                    .setProvider(BouncyCastleProvider.PROVIDER_NAME);
            JcaSignerInfoVerifierBuilder signerInfoVerifierBuilder = new JcaSignerInfoVerifierBuilder(
                    calculatorProviderBuilder.build()).setProvider(BouncyCastleProvider.PROVIDER_NAME);
            signerInformationVerifier = signerInfoVerifierBuilder.build(publicKey);
        }

        @Override
        public SignerInformationVerifier get(SignerId signerId) throws OperatorCreationException {
            return signerInformationVerifier;
        }

    }

}