Discussion:
PDF digital signature fails switching from BC 1.50 to 1.51
David Wall
2014-10-24 01:16:00 UTC
Permalink
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 again, so there's something
about 1.51 that breaks my current code.

The invalid signature complains that the "Document has been altered or
corrupted since it was signed".

Here's a link to an existing PDFs that show the issue:
http://open.esignforms.com/pdfboxlist/MyDocumentsGOOD.pdf (using BC
1.50 the signature is valid)
http://open.esignforms.com/pdfboxlist/MyDocumentsBAD.pdf (using BC 1.51
the signature is invalid)

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();
}
}
David Hook
2014-10-24 04:16:12 UTC
Permalink
That sounds a little odd...

If you generate a signature under 1.50 does it verify under 1.51? Can
you generate two detached signatures that show the problem?

Regards,

David
Post by David Wall
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 again, so there's something
about 1.51 that breaks my current code.
The invalid signature complains that the "Document has been altered or
corrupted since it was signed".
http://open.esignforms.com/pdfboxlist/MyDocumentsGOOD.pdf (using BC
1.50 the signature is valid)
http://open.esignforms.com/pdfboxlist/MyDocumentsBAD.pdf (using BC
1.51 the signature is invalid)
I am using Java 7.
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();
}
}
Continue reading on narkive:
Search results for 'PDF digital signature fails switching from BC 1.50 to 1.51' (Questions and Answers)
13
replies
Questions about Sweden, Germany, and Italy?
started 2006-04-23 11:31:47 UTC
homework help
Loading...