null
for the default provider
* @param hasRSAdata true
if the sub-filter is adbe.pkcs7.sha1
* @throws InvalidKeyException on error
* @throws NoSuchProviderException on error
* @throws NoSuchAlgorithmException on error
*/
public PdfPKCS7(PrivateKey privKey, Certificate[] certChain,
String hashAlgorithm, String provider, ExternalDigest interfaceDigest, boolean hasRSAdata)
throws InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException {
this.provider = provider;
this.interfaceDigest = interfaceDigest;
// message digest
digestAlgorithmOid = DigestAlgorithms.getAllowedDigests(hashAlgorithm);
if (digestAlgorithmOid == null)
throw new NoSuchAlgorithmException(MessageLocalization.getComposedMessage("unknown.hash.algorithm.1", hashAlgorithm));
// Copy the certificates
signCert = (X509Certificate)certChain[0];
certs = new ArrayListnull
for the default provider
*/
@SuppressWarnings("unchecked")
public PdfPKCS7(byte[] contentsKey, byte[] certsKey, String provider) {
try {
this.provider = provider;
X509CertParser cr = new X509CertParser();
cr.engineInit(new ByteArrayInputStream(certsKey));
certs = cr.engineReadAll();
signCerts = certs;
signCert = (X509Certificate)certs.iterator().next();
crls = new ArrayListnull
for the default provider
*/
@SuppressWarnings({ "unchecked" })
public PdfPKCS7(byte[] contentsKey, PdfName filterSubtype, String provider) {
this.filterSubtype = filterSubtype;
isTsp = PdfName.ETSI_RFC3161.equals(filterSubtype);
isCades = PdfName.ETSI_CADES_DETACHED.equals(filterSubtype);
try {
this.provider = provider;
ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(contentsKey));
//
// Basic checks to make sure it's a PKCS#7 SignedData Object
//
ASN1Primitive pkcs;
try {
pkcs = din.readObject();
}
catch (IOException e) {
throw new IllegalArgumentException(MessageLocalization.getComposedMessage("can.t.decode.pkcs7signeddata.object"));
}
if (!(pkcs instanceof ASN1Sequence)) {
throw new IllegalArgumentException(MessageLocalization.getComposedMessage("not.a.valid.pkcs.7.object.not.a.sequence"));
}
ASN1Sequence signedData = (ASN1Sequence)pkcs;
ASN1ObjectIdentifier objId = (ASN1ObjectIdentifier)signedData.getObjectAt(0);
if (!objId.getId().equals(SecurityIDs.ID_PKCS7_SIGNED_DATA))
throw new IllegalArgumentException(MessageLocalization.getComposedMessage("not.a.valid.pkcs.7.object.not.signed.data"));
ASN1Sequence content = (ASN1Sequence)((ASN1TaggedObject)signedData.getObjectAt(1)).getObject();
// the positions that we care are:
// 0 - version
// 1 - digestAlgorithms
// 2 - possible ID_PKCS7_DATA
// (the certificates and crls are taken out by other means)
// last - signerInfos
// the version
version = ((ASN1Integer)content.getObjectAt(0)).getValue().intValue();
// the digestAlgorithms
digestalgos = new HashSetnull
if the digest
* is also null
. If the digest
is not null
* then it may be "RSA" or "DSA"
*/
public void setExternalDigest(byte digest[], byte RSAdata[], String digestEncryptionAlgorithm) {
externalDigest = digest;
externalRSAdata = RSAdata;
if (digestEncryptionAlgorithm != null) {
if (digestEncryptionAlgorithm.equals("RSA")) {
this.digestEncryptionAlgorithmOid = SecurityIDs.ID_RSA;
}
else if (digestEncryptionAlgorithm.equals("DSA")) {
this.digestEncryptionAlgorithmOid = SecurityIDs.ID_DSA;
}
else if (digestEncryptionAlgorithm.equals("ECDSA")) {
this.digestEncryptionAlgorithmOid = SecurityIDs.ID_ECDSA;
}
else
throw new ExceptionConverter(new NoSuchAlgorithmException(MessageLocalization.getComposedMessage("unknown.key.algorithm.1", digestEncryptionAlgorithm)));
}
}
// The signature is created internally
/** Class from the Java SDK that provides the functionality of a digital signature algorithm. */
private Signature sig;
/** The signed digest as calculated by this class (or extracted from an existing PDF) */
private byte[] digest;
/** The RSA data */
private byte[] RSAdata;
// Signing functionality.
/**
* Update the digest with the specified bytes.
* This method is used both for signing and verifying
* @param buf the data buffer
* @param off the offset in the data buffer
* @param len the data length
* @throws SignatureException on error
*/
public void update(byte[] buf, int off, int len) throws SignatureException {
if (RSAdata != null || digestAttr != null || isTsp)
messageDigest.update(buf, off, len);
else
sig.update(buf, off, len);
}
// adbe.x509.rsa_sha1 (PKCS#1)
/**
* Gets the bytes for the PKCS#1 object.
* @return a byte array
*/
public byte[] getEncodedPKCS1() {
try {
if (externalDigest != null)
digest = externalDigest;
else
digest = sig.sign();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream dout = new ASN1OutputStream(bOut);
dout.writeObject(new DEROctetString(digest));
dout.close();
return bOut.toByteArray();
}
catch (Exception e) {
throw new ExceptionConverter(e);
}
}
// other subfilters (PKCS#7)
/**
* Gets the bytes for the PKCS7SignedData object.
* @return the bytes for the PKCS7SignedData object
*/
public byte[] getEncodedPKCS7() {
return getEncodedPKCS7(null, null, null, null, null, CryptoStandard.CMS);
}
/**
* Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes
* in the signerInfo can also be set. If either of the parameters is null
, none will be used.
* @param secondDigest the digest in the authenticatedAttributes
* @param signingTime the signing time in the authenticatedAttributes
* @return the bytes for the PKCS7SignedData object
*/
public byte[] getEncodedPKCS7(byte secondDigest[], Calendar signingTime) {
return getEncodedPKCS7(secondDigest, signingTime, null, null, null, CryptoStandard.CMS);
}
/**
* Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes
* in the signerInfo can also be set, OR a time-stamp-authority client
* may be provided.
* @param secondDigest the digest in the authenticatedAttributes
* @param signingTime the signing time in the authenticatedAttributes
* @param tsaClient TSAClient - null or an optional time stamp authority client
* @return byte[] the bytes for the PKCS7SignedData object
* @since 2.1.6
*/
public byte[] getEncodedPKCS7(byte secondDigest[], Calendar signingTime, TSAClient tsaClient, byte[] ocsp, Collection* A simple example: *
*
* Calendar cal = Calendar.getInstance(); * PdfPKCS7 pk7 = new PdfPKCS7(key, chain, null, "SHA1", null, false); * MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); * byte buf[] = new byte[8192]; * int n; * InputStream inp = sap.getRangeStream(); * while ((n = inp.read(buf)) > 0) { * messageDigest.update(buf, 0, n); * } * byte hash[] = messageDigest.digest(); * byte sh[] = pk7.getAuthenticatedAttributeBytes(hash, cal); * pk7.update(sh, 0, sh.length); * byte sg[] = pk7.getEncodedPKCS7(hash, cal); ** @param secondDigest the content digest * @param signingTime the signing time * @return the byte array representation of the authenticatedAttributes ready to be signed */ public byte[] getAuthenticatedAttributeBytes(byte secondDigest[], Calendar signingTime, byte[] ocsp, Collection
true
if the signature checks out, false
otherwise
*/
public boolean verify() throws SignatureException {
if (verified)
return verifyResult;
if (isTsp) {
TimeStampTokenInfo info = timeStampToken.getTimeStampInfo();
MessageImprint imprint = info.toASN1Structure().getMessageImprint();
byte[] md = messageDigest.digest();
byte[] imphashed = imprint.getHashedMessage();
verifyResult = Arrays.equals(md, imphashed);
}
else {
if (sigAttr != null) {
final byte [] msgDigestBytes = messageDigest.digest();
boolean verifyRSAdata = true;
sig.update(sigAttr);
// Stefan Santesson fixed a bug, keeping the code backward compatible
boolean encContDigestCompare = false;
if (RSAdata != null) {
verifyRSAdata = Arrays.equals(msgDigestBytes, RSAdata);
encContDigest.update(RSAdata);
encContDigestCompare = Arrays.equals(encContDigest.digest(), digestAttr);
}
boolean absentEncContDigestCompare = Arrays.equals(msgDigestBytes, digestAttr);
boolean concludingDigestCompare = absentEncContDigestCompare || encContDigestCompare;
boolean sigVerify = sig.verify(digest);
verifyResult = concludingDigestCompare && sigVerify && verifyRSAdata;
}
else {
if (RSAdata != null)
sig.update(messageDigest.digest());
verifyResult = sig.verify(digest);
}
}
verified = true;
return verifyResult;
}
/**
* Checks if the timestamp refers to this document.
* @return true if it checks false otherwise
* @throws GeneralSecurityException on error
* @since 2.1.6
*/
public boolean verifyTimestampImprint() throws GeneralSecurityException {
if (timeStampToken == null)
return false;
TimeStampTokenInfo info = timeStampToken.getTimeStampInfo();
MessageImprint imprint = info.toASN1Structure().getMessageImprint();
String algOID = info.getMessageImprintAlgOID().getId();
byte[] md = new BouncyCastleDigest().getMessageDigest(DigestAlgorithms.getDigest(algOID)).digest(digest);
byte[] imphashed = imprint.getHashedMessage();
boolean res = Arrays.equals(md, imphashed);
return res;
}
// Certificates
/** All the X.509 certificates in no particular order. */
private Collection