Bug 61182 - Invalid signature created for streamed xlsx file
Summary: Invalid signature created for streamed xlsx file
Alias: None
Product: POI
Classification: Unclassified
Component: OPC (show other bugs)
Version: 3.17-dev
Hardware: All All
: P2 major (vote)
Target Milestone: ---
Assignee: POI Developers List
Depends on:
Reported: 2017-06-13 10:36 UTC by asaf
Modified: 2017-07-25 22:43 UTC (History)
0 users

Patch for XML Signatures / Unix linebreaks (49.18 KB, patch)
2017-06-26 01:50 UTC, Andreas Beeker
Details | Diff
requested binary dump (5.74 KB, application/zip)
2017-07-14 12:04 UTC, Tim Allison

Note You need to log in before you can comment on or make changes to this bug.
Description asaf 2017-06-13 10:36:39 UTC
from here:

I am trying to create and add a valid regular cryptographic signature to a xlsx file i am creating. In addition, i am trying to do it in-memory. This seems to cause problems for me. This code creates the file but in windows excel states that the signature is invalid. note that i am sending an input stream containing the xlsx (in-memory - not in file system) file, and i am writing the pkg object to the output stream.

 private ByteArrayOutputStream signFile(PrivateKey key, X509Certificate x509Certificate, InputStream input) { //change to approve signed
    SignatureConfig signatureConfig = new SignatureConfig();
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    signatureConfig.setExecutionTime(new Date());
    ArrayList<X509Certificate> x509Certificates = new ArrayList<>(Collections.singletonList(x509Certificate));
    OPCPackage pkg = null;
    try {
        if (input instanceof ByteArrayInputStream)
        pkg = OPCPackage.open(input);
    } catch (Exception ex) {
        logger.error("failed to open package for file, exception:",ex);

    // adding the signature document to the package
    SignatureInfo si = new SignatureInfo();
    try {
    } catch (Exception ex) {
        logger.error("failed to confirm signature",ex);
    // optionally verify the generated signature
    boolean b = si.verifySignature();
    if (b==false){
        logger.error("signature verified result:" + b);

    try {
    } catch (Exception ex) {
        logger.error("failed to close package",ex);

    return stream;
in addition i have this test code which creates a file and uses OPCPackage.open(...) which works!! excel identifies the signature.

        SignatureConfig signatureConfig = new SignatureConfig();
        ArrayList<X509Certificate> x509Certificates = new ArrayList<>();

        OPCPackage pkg = OPCPackage.open(filePath, PackageAccess.READ_WRITE);

        // adding the signature document to the package
        SignatureInfo si = new SignatureInfo();
        // optionally verify the generated signature
        boolean b = si.verifySignature();
        // write the changes back to disc
Comment 1 Andreas Beeker 2017-06-26 01:50:24 UTC
Created attachment 35075 [details]
Patch for XML Signatures / Unix linebreaks

I'll apply the patch after the 3.17-beta1 is out.

Originally I've adapted/developed the XML signature code under a Win7 box, but now couldn't sign any documents anymore in an Ubuntu environment.
The reason was the indenting setting in StreamHelper.

For the actual bug entry, look at TestSignatureInfo on how to add a signature in-memory. I haven't changed the OPC code, which adds relations on the fly when saving, but rather ask the user to save the unsigned file first to a byte buffer before using OPCPackage to reload/sign/save it.
Comment 2 Andreas Beeker 2017-06-28 21:39:20 UTC
applied via r1800207
Comment 3 Tim Allison 2017-07-13 15:59:26 UTC
Testcase: bug61182 took 0.187 sec
expected:<[HDdvgXblLMiE6gZSoRSQUof6+aedrhK9i51we1n+4Q/ioqrQCeh5UkfQ8lD63nV4ZDbM4/pIVFi6VpMpN/HMnAUHeVdVUCVTgpn3Iz21Ymcd9/aerNov2BjHLhS8X3oUE+XTu2TbJLNmms0I9G4lfg6HWP9t7ZCXBXy6vyCMArc]=> but was:<[jVW6EPMywZ8jr4+I4alDosXzqrVuDG4wTdrr+la8QVbXfLm6HOh9AUFlo5yUZuWo/1gXrrkc34UTYNzuslyrOxKqadPOIRKUssJzdCh/hKeTxs/YtyWkpGHggrUjrF/vUUIeIXRHo+1DCAh6ptoicviH/I/Dtoa5NgkEHVuOHk8]=>
junit.framework.AssertionFailedError: expected:<[HDdvgXblLMiE6gZSoRSQUof6+aedrhK9i51we1n+4Q/ioqrQCeh5UkfQ8lD63nV4ZDbM4/pIVFi6VpMpN/HMnAUHeVdVUCVTgpn3Iz21Ymcd9/aerNov2BjHLhS8X3oUE+XTu2TbJLNmms0I9G4lfg6HWP9t7ZCXBXy6vyCMArc]=> but was:<[jVW6EPMywZ8jr4+I4alDosXzqrVuDG4wTdrr+la8QVbXfLm6HOh9AUFlo5yUZuWo/1gXrrkc34UTYNzuslyrOxKqadPOIRKUssJzdCh/hKeTxs/YtyWkpGHggrUjrF/vUUIeIXRHo+1DCAh6ptoicviH/I/Dtoa5NgkEHVuOHk8]=>
	at org.apache.poi.poifs.crypt.TestSignatureInfo.bug61182(TestSignatureInfo.java:191)

Hi Andi,
Is this user error on my part?  Something odd about my dev environment?

Windows 10, Java 8 131
Comment 4 Andreas Beeker 2017-07-14 09:59:22 UTC
I guess this is again a line ending problem - as I need to setup my windows environment first - could you write the ByteArrayOutputStream to a file, which is filled after pkg1.close()?
Comment 5 Tim Allison 2017-07-14 12:04:45 UTC
Created attachment 35140 [details]
requested binary dump

        OutputStream tmp = new FileOutputStream(new File("C:/data/testsig.bin"));
        IOUtils.copy(new ByteArrayInputStream(bos.toByteArray()), tmp);

Thank you, Andi!
Comment 6 Andreas Beeker 2017-07-25 10:53:09 UTC
The windows/linux files differ in their line-endings, due to org.apache.xmlbeans.impl.store.Saver._newLine being system dependent.

As the xml canonicalization handles the newlines as-is, this leads to different hashes.

Currently I think about 3 options:
a) change the _newLine static final via reflection
b) normalize the xmls to unix linebreaks on signing
c) add a switch in the junit test to check for windows/mac/linux hashes

As the files signed by a linux system worked in Libre/MS Office, I probably just go with c)
Comment 7 Andreas Beeker 2017-07-25 22:43:01 UTC
add hashes for other linebreaks via r1803011