PKCS7SignedDatapublic class PKCS7SignedData extends Object implements org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiersRepresents a PKCS#7 object - specifically the "Signed Data"
type.
How to use it? To verify a signature, do:
PKCS7SignedData pkcs7 = new PKCS7SignedData(der_bytes); // Create it
pkcs7.update(bytes, 0, bytes.length); // Update checksum
boolean verified = pkcs7.verify(); // Does it add up?
To sign, do this:
PKCS7SignedData pkcs7 = new PKCS7SignedData(privKey, certChain, "MD5");
pkcs7.update(bytes, 0, bytes.length); // Update checksum
pkcs7.sign(); // Create digest
bytes = pkcs7.getEncoded(); // Write it somewhere
This class is pretty close to obsolete, for a much better (and more complete)
implementation of PKCS7 have a look at the org.bouncycastle.cms package. |
Fields Summary |
---|
private int | version | private int | signerversion | private Set | digestalgos | private Collection | certs | private Collection | crls | private X509Certificate | signCert | private byte[] | digest | private String | digestAlgorithm | private String | digestEncryptionAlgorithm | private Signature | sig | private transient PrivateKey | privKey | private final String | ID_PKCS7_DATA | private final String | ID_PKCS7_SIGNED_DATA | private final String | ID_MD5 | private final String | ID_MD2 | private final String | ID_SHA1 | private final String | ID_RSA | private final String | ID_DSA |
Constructors Summary |
---|
public PKCS7SignedData(byte[] in)Read an existing PKCS#7 object from a DER encoded byte array using
the BC provider.
this(in, "BC");
| public PKCS7SignedData(byte[] in, String provider)Read an existing PKCS#7 object from a DER encoded byte array
ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(in));
//
// Basic checks to make sure it's a PKCS#7 SignedData Object
//
DERObject pkcs;
try
{
pkcs = din.readObject();
}
catch (IOException e)
{
throw new SecurityException("can't decode PKCS7SignedData object");
}
if (!(pkcs instanceof ASN1Sequence))
{
throw new SecurityException("Not a valid PKCS#7 object - not a sequence");
}
ContentInfo content = ContentInfo.getInstance(pkcs);
if (!content.getContentType().equals(signedData))
{
throw new SecurityException("Not a valid PKCS#7 signed-data object - wrong header " + content.getContentType().getId());
}
SignedData data = SignedData.getInstance(content.getContent());
certs = new ArrayList();
if (data.getCertificates() != null)
{
Enumeration ec = ASN1Set.getInstance(data.getCertificates()).getObjects();
while (ec.hasMoreElements())
{
certs.add(new X509CertificateObject(X509CertificateStructure.getInstance(ec.nextElement())));
}
}
crls = new ArrayList();
if (data.getCRLs() != null)
{
Enumeration ec = ASN1Set.getInstance(data.getCRLs()).getObjects();
while (ec.hasMoreElements())
{
crls.add(new X509CRLObject(CertificateList.getInstance(ec.nextElement())));
}
}
version = data.getVersion().getValue().intValue();
//
// Get the digest algorithm
//
digestalgos = new HashSet();
Enumeration e = data.getDigestAlgorithms().getObjects();
while (e.hasMoreElements())
{
ASN1Sequence s = (ASN1Sequence)e.nextElement();
DERObjectIdentifier o = (DERObjectIdentifier)s.getObjectAt(0);
digestalgos.add(o.getId());
}
//
// Get the SignerInfo
//
ASN1Set signerinfos = data.getSignerInfos();
if (signerinfos.size() != 1)
{
throw new SecurityException("This PKCS#7 object has multiple SignerInfos - only one is supported at this time");
}
SignerInfo signerInfo = SignerInfo.getInstance(signerinfos.getObjectAt(0));
signerversion = signerInfo.getVersion().getValue().intValue();
IssuerAndSerialNumber isAnds = signerInfo.getIssuerAndSerialNumber();
//
// Get the signing certificate
//
BigInteger serialNumber = isAnds.getCertificateSerialNumber().getValue();
X509Principal issuer = new X509Principal(isAnds.getName());
for (Iterator i = certs.iterator();i.hasNext();)
{
X509Certificate cert = (X509Certificate)i.next();
if (serialNumber.equals(cert.getSerialNumber())
&& issuer.equals(cert.getIssuerDN()))
{
signCert = cert;
break;
}
}
if (signCert == null)
{
throw new SecurityException("Can't find signing certificate with serial "+serialNumber.toString(16));
}
digestAlgorithm = signerInfo.getDigestAlgorithm().getObjectId().getId();
digest = signerInfo.getEncryptedDigest().getOctets();
digestEncryptionAlgorithm = signerInfo.getDigestEncryptionAlgorithm().getObjectId().getId();
sig = Signature.getInstance(getDigestAlgorithm(), provider);
sig.initVerify(signCert.getPublicKey());
| public PKCS7SignedData(PrivateKey privKey, Certificate[] certChain, String hashAlgorithm)Create a new PKCS#7 object from the specified key using the BC provider.
this(privKey, certChain, hashAlgorithm, "BC");
| public PKCS7SignedData(PrivateKey privKey, Certificate[] certChain, String hashAlgorithm, String provider)Create a new PKCS#7 object from the specified key.
this(privKey, certChain, null, hashAlgorithm, provider);
| public PKCS7SignedData(PrivateKey privKey, Certificate[] certChain, CRL[] crlList, String hashAlgorithm, String provider)Create a new PKCS#7 object from the specified key.
this.privKey = privKey;
if (hashAlgorithm.equals("MD5"))
{
digestAlgorithm = ID_MD5;
}
else if (hashAlgorithm.equals("MD2"))
{
digestAlgorithm = ID_MD2;
}
else if (hashAlgorithm.equals("SHA"))
{
digestAlgorithm = ID_SHA1;
}
else if (hashAlgorithm.equals("SHA1"))
{
digestAlgorithm = ID_SHA1;
}
else
{
throw new NoSuchAlgorithmException("Unknown Hash Algorithm "+hashAlgorithm);
}
version = signerversion = 1;
certs = new ArrayList();
crls = new ArrayList();
digestalgos = new HashSet();
digestalgos.add(digestAlgorithm);
//
// Copy in the certificates and crls used to sign the private key.
//
signCert = (X509Certificate)certChain[0];
for (int i = 0;i < certChain.length;i++)
{
certs.add(certChain[i]);
}
if (crlList != null)
{
for (int i = 0;i < crlList.length;i++)
{
crls.add(crlList[i]);
}
}
//
// Now we have private key, find out what the digestEncryptionAlgorithm is.
//
digestEncryptionAlgorithm = privKey.getAlgorithm();
if (digestEncryptionAlgorithm.equals("RSA"))
{
digestEncryptionAlgorithm = ID_RSA;
}
else if (digestEncryptionAlgorithm.equals("DSA"))
{
digestEncryptionAlgorithm = ID_DSA;
}
else
{
throw new NoSuchAlgorithmException("Unknown Key Algorithm "+digestEncryptionAlgorithm);
}
sig = Signature.getInstance(getDigestAlgorithm(), provider);
sig.initSign(privKey);
|
Methods Summary |
---|
public java.util.Collection | getCRLs()Get the X.509 certificate revocation lists associated with this PKCS#7 object
return crls;
| public java.security.cert.Certificate[] | getCertificates()Get the X.509 certificates associated with this PKCS#7 object
return (X509Certificate[])certs.toArray(new X509Certificate[certs.size()]);
| public java.lang.String | getDigestAlgorithm()Get the algorithm used to calculate the message digest
String da = digestAlgorithm;
String dea = digestEncryptionAlgorithm;
if (digestAlgorithm.equals(ID_MD5))
{
da = "MD5";
}
else if (digestAlgorithm.equals(ID_MD2))
{
da = "MD2";
}
else if (digestAlgorithm.equals(ID_SHA1))
{
da = "SHA1";
}
if (digestEncryptionAlgorithm.equals(ID_RSA))
{
dea = "RSA";
}
else if (digestEncryptionAlgorithm.equals(ID_DSA))
{
dea = "DSA";
}
return da + "with" + dea;
| public byte[] | getEncoded()return the bytes for the PKCS7SignedData object.
try
{
digest = sig.sign();
// Create the set of Hash algorithms. I've assumed this is the
// set of all hash agorithms used to created the digest in the
// "signerInfo" structure. I may be wrong.
//
ASN1EncodableVector v = new ASN1EncodableVector();
for (Iterator i = digestalgos.iterator(); i.hasNext();)
{
AlgorithmIdentifier a = new AlgorithmIdentifier(
new DERObjectIdentifier((String)i.next()),
null);
v.add(a);
}
DERSet algos = new DERSet(v);
// Create the contentInfo. Empty, I didn't implement this bit
//
DERSequence contentinfo = new DERSequence(
new DERObjectIdentifier(ID_PKCS7_DATA));
// Get all the certificates
//
v = new ASN1EncodableVector();
for (Iterator i = certs.iterator();i.hasNext();)
{
ASN1InputStream tempstream = new ASN1InputStream(new ByteArrayInputStream(((X509Certificate)i.next()).getEncoded()));
v.add(tempstream.readObject());
}
DERSet dercertificates = new DERSet(v);
// Create signerinfo structure.
//
ASN1EncodableVector signerinfo = new ASN1EncodableVector();
// Add the signerInfo version
//
signerinfo.add(new DERInteger(signerversion));
IssuerAndSerialNumber isAnds = new IssuerAndSerialNumber(
new X509Name((ASN1Sequence)getIssuer(signCert.getTBSCertificate())),
new DERInteger(signCert.getSerialNumber()));
signerinfo.add(isAnds);
// Add the digestAlgorithm
//
// BEGIN android-changed
signerinfo.add(new AlgorithmIdentifier(
new DERObjectIdentifier(digestAlgorithm),
DERNull.THE_ONE));
//
// Add the digestEncryptionAlgorithm
//
signerinfo.add(new AlgorithmIdentifier(
new DERObjectIdentifier(digestEncryptionAlgorithm),
DERNull.THE_ONE));
// END android-changed
//
// Add the digest
//
signerinfo.add(new DEROctetString(digest));
//
// Finally build the body out of all the components above
//
ASN1EncodableVector body = new ASN1EncodableVector();
body.add(new DERInteger(version));
body.add(algos);
body.add(contentinfo);
body.add(new DERTaggedObject(false, 0, dercertificates));
if (crls.size()>0)
{
v = new ASN1EncodableVector();
for (Iterator i = crls.iterator();i.hasNext();)
{
ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream(((X509CRL)i.next()).getEncoded()));
v.add(t.readObject());
}
DERSet dercrls = new DERSet(v);
body.add(new DERTaggedObject(false, 1, dercrls));
}
// Only allow one signerInfo
//
body.add(new DERSet(new DERSequence(signerinfo)));
// Now we have the body, wrap it in it's PKCS7Signed shell
// and return it
//
ASN1EncodableVector whole = new ASN1EncodableVector();
whole.add(new DERObjectIdentifier(ID_PKCS7_SIGNED_DATA));
whole.add(new DERTaggedObject(0, new DERSequence(body)));
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
DEROutputStream dout = new DEROutputStream(bOut);
dout.writeObject(new DERSequence(whole));
dout.close();
return bOut.toByteArray();
}
catch (Exception e)
{
throw new RuntimeException(e.toString());
}
| private DERObject | getIssuer(byte[] enc)Get the "issuer" from the TBSCertificate bytes that are passed in
try
{
ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(enc));
ASN1Sequence seq = (ASN1Sequence)in.readObject();
return (DERObject)seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 3 : 2);
}
catch (IOException e)
{
throw new Error("IOException reading from ByteArray: "+e);
}
| public java.security.cert.X509Certificate | getSigningCertificate()Get the X.509 certificate actually used to sign the digest.
return signCert;
| public int | getSigningInfoVersion()Get the version of the PKCS#7 "SignerInfo" object. Always 1
return signerversion;
| public int | getVersion()Get the version of the PKCS#7 object. Always 1
return version;
| public void | reset()Resets the PKCS7SignedData object to it's initial state, ready
to sign or verify a new buffer.
try
{
if (privKey==null)
{
sig.initVerify(signCert.getPublicKey());
}
else
{
sig.initSign(privKey);
}
}
catch (Exception e)
{
throw new RuntimeException(e.toString());
}
| public void | update(byte buf)Update the digest with the specified byte. This method is used both for signing and verifying
sig.update(buf);
| public void | update(byte[] buf, int off, int len)Update the digest with the specified bytes. This method is used both for signing and verifying
sig.update(buf, off, len);
| public boolean | verify()Verify the digest
return sig.verify(digest);
|
|