📄 sceprequestmessage.java
字号:
/************************************************************************* * * * EJBCA: 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;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.math.BigInteger;import java.security.GeneralSecurityException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.util.Collection;import java.util.Enumeration;import java.util.Iterator;import org.apache.log4j.Logger;import org.bouncycastle.asn1.ASN1InputStream;import org.bouncycastle.asn1.ASN1OctetString;import org.bouncycastle.asn1.ASN1Sequence;import org.bouncycastle.asn1.ASN1Set;import org.bouncycastle.asn1.DEREncodable;import org.bouncycastle.asn1.DERObject;import org.bouncycastle.asn1.DEROctetString;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.SignerInformation;import org.bouncycastle.cms.SignerInformationStore;import org.bouncycastle.jce.PKCS10CertificationRequest;import org.ejbca.util.Base64;import org.ejbca.util.CertTools;/** * Class to handle SCEP request messages sent to the CA. * TODO: don't forget extensions, e.g. KeyUsage requested by end entity * * @version $Id: ScepRequestMessage.java,v 1.7.2.1 2007/03/29 15:04:59 anatom Exp $ */public class ScepRequestMessage extends PKCS10RequestMessage implements IRequestMessage { /** * 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 requestors 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 = "BC"; /** IssuerAndSerialNUmber for CRL request */ private transient IssuerAndSerialNumber issuerAndSerno = null; /** preferred digest algorithm to use in replies, if applicable */ private transient String preferredDigestAlg = CMSSignedGenerator.DIGEST_MD5; private transient X509Certificate 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 { log.debug(">ScepRequestMessage"); this.scepmsg = msg; this.includeCACert = incCACert; init(); log.debug("<ScepRequestMessage"); } private void init() throws IOException { log.debug(">init"); try { CMSSignedData csd = new CMSSignedData(scepmsg); SignerInformationStore infoStore = csd.getSignerInfos(); Collection signers = infoStore.getSigners(); Iterator 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 entegrity of the PKIOperation message PKCS#7 /* If this would have been done using the newer CMS it would have made me so much happier... */ ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream(scepmsg)).readObject(); ContentInfo ci = new ContentInfo(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 = new SignedData((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... DEREncodable dercert = certs.getObjectAt(0); if (dercert != null) { // Requestors 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); log.debug("requestKeyInfo is SubjectDN: " + signercert.getSubjectDN().toString() + ", Serial=" + signercert.getSerialNumber().toString(16) + "; IssuerDN: "+ signercert.getIssuerDN().toString()); } catch (CertificateException e) { log.error("Error parsing requestKeyInfo : ", e); } } } } Enumeration sis = sd.getSignerInfos().getObjects(); if (sis.hasMoreElements()) { SignerInfo si = new SignerInfo((ASN1Sequence) sis.nextElement()); Enumeration attr = si.getAuthenticatedAttributes().getObjects(); while (attr.hasMoreElements()) { Attribute a = new Attribute((ASN1Sequence) attr.nextElement()); 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)); 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(); 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()); 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())) { DEROctetString content = (DEROctetString) ci.getContent(); log.debug("envelopedData is " + content.getOctets().length + " bytes."); ASN1Sequence seq1 = (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream(content.getOctets())).readObject(); envEncData = new ContentInfo(seq1); ctoid = envEncData.getContentType().getId(); if (ctoid.equals(CMSObjectIdentifiers.envelopedData.getId())) { envData = new EnvelopedData((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(); 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.debug("<init"); } // init private void decrypt() throws CMSException, NoSuchProviderException, GeneralSecurityException, IOException { log.debug(">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(); Collection c = recipients.getRecipients(); Iterator it = c.iterator(); byte[] decBytes = null; while (it.hasNext()) { RecipientInformation recipient = (RecipientInformation) it.next(); log.debug("Privatekey : " + privateKey.getAlgorithm()); decBytes = recipient.getContent(privateKey, jceProvider); break; } DERObject derobj = new ASN1InputStream(new ByteArrayInputStream(decBytes)).readObject(); if (messageType == ScepRequestMessage.SCEP_TYPE_PKCSREQ) { ASN1Sequence seq = (ASN1Sequence) derobj; pkcs10 = new PKCS10CertificationRequest(seq); log.debug("Successfully extracted PKCS10."); //log.debug("Successfully extracted PKCS10:"+new String(Base64.encode(pkcs10.getEncoded()))); } if (messageType == ScepRequestMessage.SCEP_TYPE_GETCRL) { issuerAndSerno = IssuerAndSerialNumber.getInstance(derobj); log.debug("Successfully extracted IssuerAndSerialNumber."); } log.debug("<decrypt"); } // decrypt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -