Hi David,
Am 25.10.2014 um 21:10 schrieb David Wall:
Should anybody care, David at BC found the bug that managed to work for prior BC
versions, but no longer does under 1.51. We changed to this method in
CMSTypedDataInputStream to return 'in' instead of 'null' and it works under 1.50
as well as 1.51:
@Override
public Object getContent()
{
return in;
}
I've applied the fix to our codebase as well, see PDFBOX-2458 for further
details.
Thanks for the contribution!
BR
Andreas Lehmkühler
On 10/24/2014 3:06 PM, David Wall wrote:
I'm now getting an invalid digital signature that I created on PDFs we
generate (via wkhtmltopdf and PDFBox 1.8.7). It says "At least one signature
is invalid" but I previously could create them with valid signatures. This
occurred when going from BouncyCastle 1.50 to 1.51, and if I go back to 1.50,
it works fine.
The invalid signature complains that the "Document has been altered or
corrupted since it was signed".
Here's a link to an existing PDF that has an invalid signature:
http://open.esignforms.com/pdfboxlist/MyDocumentsGOOD.pdf (using BC 1.50)
http://open.esignforms.com/pdfboxlist/MyDocumentsBAD.pdf (using BC 1.51)
I am using Java 7.
Here are the relevant Java code:
boolean signPdf(File pdfFile, File signedPdfFile)
{
FileInputStream fis = null;
FileOutputStream fos = null;
PDDocument doc = null;
try
{
fis = new FileInputStream(pdfFile);
fos = new FileOutputStream(signedPdfFile);
int readCount;
byte[] buffer = new byte[8 * 1024];
while ((readCount = fis.read(buffer)) != -1)
{
fos.write(buffer, 0, readCount);
}
fis.close();
fis = new FileInputStream(signedPdfFile);
doc = PDDocument.load(pdfFile);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Open eSignForms Export PDF Integrity Lock");
signature.setLocation(Application.getInstance().getExternalContextPath());
signature.setReason("Used to ensure that an exported PDF has not
been tampered with since its generation by Open eSignForms deployment id: " +
Application.getInstance().getDeployId());
signature.setSignDate(Calendar.getInstance());
doc.addSignature(signature, this);
doc.saveIncremental(fis, fos);
return true;
}
catch( Exception e )
{
_logger.error("signPdf() - Failed to sign the PDF",e);
return false;
}
finally
{
if ( fis != null ) try { fis.close(); } catch( Exception e ) {}
if ( fos != null ) try { fos.close(); } catch( Exception e ) {}
if ( doc != null ) try { doc.close(); } catch( Exception e ) {}
}
}
@Override
public byte[] sign(InputStream is) throws SignatureException, IOException
{
Application app = Application.getInstance();
try
{
String provider = app.getPublicKeyGenerator().getProvider();
SignatureKey signatureKey = app.getSignatureKey();
X509Certificate cert = signatureKey.getX509Certificate();
Store certStore = new JcaCertStore(Arrays.asList(cert));
CMSTypedDataInputStream input = new CMSTypedDataInputStream(is);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha512Signer = new
JcaContentSignerBuilder(PublicKeyGenerator.SIGNATURE_ALGORITHM).setProvider(provider).build(signatureKey.getPrivateKey());
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
new
JcaDigestCalculatorProviderBuilder().setProvider(provider).build()).build(sha512Signer,
cert));
gen.addCertificates(certStore);
CMSSignedData signedData = gen.generate(input, false);
return signedData.getEncoded();
}
catch (Exception e)
{
_logger.error("sign() - Problem while preparing PDF signature",e);
return null;
}
}
class CMSTypedDataInputStream implements CMSTypedData
{
InputStream in;
public CMSTypedDataInputStream(InputStream is)
{
in = is;
}
@Override
public ASN1ObjectIdentifier getContentType()
{
return PKCSObjectIdentifiers.data;
}
@Override
public Object getContent()
{
return null;
}
@Override
public void write(OutputStream out) throws IOException, CMSException
{
byte[] buffer = new byte[8 * 1024];
int read;
while( (read = in.read(buffer)) != -1 )
{
out.write(buffer, 0, read);
}
in.close();
}
}