You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2020/03/18 21:06:09 UTC
svn commit: r1875392 - in /poi: site/src/documentation/content/xdocs/
site/src/documentation/content/xdocs/components/ trunk/ trunk/sonar/ooxml/
trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/
trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/...
Author: kiwiwings
Date: Wed Mar 18 21:06:09 2020
New Revision: 1875392
URL: http://svn.apache.org/viewvc?rev=1875392&view=rev
Log:
#63712 - upgrading xmlsec causes junit tests to fail
Modified:
poi/site/src/documentation/content/xdocs/changes.xml
poi/site/src/documentation/content/xdocs/components/index.xml
poi/site/src/documentation/content/xdocs/encryption.xml
poi/trunk/.classpath
poi/trunk/build.gradle
poi/trunk/build.xml
poi/trunk/sonar/ooxml/pom.xml
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalDefaultListener.java
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalListener.java
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
Modified: poi/site/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/changes.xml?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/changes.xml (original)
+++ poi/site/src/documentation/content/xdocs/changes.xml Wed Mar 18 21:06:09 2020
@@ -71,12 +71,16 @@
</section>
<release version="4.1.3" date="2020-05-??">
+ <summary>
+ <summary-item>Upgrade to XMLSec 2.1.5</summary-item>
+ </summary>
<actions>
<action type="add" fixes-bug="github-167" context="HSMF">HSMF enhancements - NamedIdChunk, MultiValueChunks, ByteChunkDeferred</action>
<action type="fix" context="SS_Common">Fix incorrect handling of format which should not produce any digit for zero</action>
<action type="fix" fixes-bug="58896,52834" context="SS_Common">Speed up auto-sizing of columns when the sheet contains merged regions</action>
<action type="fix" fixes-bug="64186" context="OPC">Decrease usage of ThreadLocals in XML Signature API</action>
<action type="fix" fixes-bug="64213" context="SS_Common">Picture.resize(double scale) scales width wrong for small pictures and when dx1 is set</action>
+ <action type="fix" fixes-bug="63712" context="OPC">upgrading xmlsec causes junit tests to fail</action>
</actions>
</release>
Modified: poi/site/src/documentation/content/xdocs/components/index.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/components/index.xml?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/components/index.xml (original)
+++ poi/site/src/documentation/content/xdocs/components/index.xml Wed Mar 18 21:06:09 2020
@@ -341,7 +341,7 @@
For signing:
<a href="https://search.maven.org/#artifactdetails|org.bouncycastle|bcpkix-jdk15on|1.64|jar">bcpkix-jdk15on</a>,
<a href="https://search.maven.org/#artifactdetails|org.bouncycastle|bcprov-jdk15on|1.64|jar">bcprov-jdk15on</a>,
- <a href="https://search.maven.org/#artifactdetails|org.apache.santuario|xmlsec|2.1.2|bundle">xmlsec</a>,
+ <a href="https://search.maven.org/#artifactdetails|org.apache.santuario|xmlsec|2.1.5|bundle">xmlsec</a>,
<a href="https://search.maven.org/#artifactdetails|org.slf4j|slf4j-api|1.7.30|jar">slf4j-api</a>
</td>
<td><a href="https://search.maven.org/#artifactdetails|org.apache.poi|ooxml-security|1.1|jar">ooxml-security-1.1.jar</a></td>
Modified: poi/site/src/documentation/content/xdocs/encryption.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/encryption.xml?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/encryption.xml (original)
+++ poi/site/src/documentation/content/xdocs/encryption.xml Wed Mar 18 21:06:09 2020
@@ -21,112 +21,115 @@
<document>
- <header>
- <title>Apache POI - Encryption support</title>
- <authors>
- <person id="maxcom" name="Maxim Valyanskiy" email="maxcom@apache.org"/>
- <person id="AB" name="Andreas Beeker" email="kiwiwings@apache.org"/>
- </authors>
- </header>
-
- <body>
- <section><title>Overview</title>
- <p>Apache POI contains support for reading few variants of encrypted office files: </p>
- <ul>
- <li>Binary formats (.xls, .ppt, .doc, ...)<br/>
- encryption is format-dependent and needs to be implemented per format differently.<br/>
- Use <a href="apidocs/dev/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.html">
- Biff8EncryptionKey</a>.<a href="apidocs/dev/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.html#setCurrentUserPassword(java.lang.String)">setCurrentUserPassword</a>(String password)
- to specify the decryption password before opening the file or (where applicable) before saving.
- Setting a null password before saving removes the password protection.<br/>
- The password is set in a thread local variable. Do not forget to reset it to null after text extraction.
- </li>
- <li>XML-based formats (.xlsx, .pptx, .docx, ...)<br/>
- use the same encryption logic over all formats. When encrypted, the zipped files will be
- stored within an OLE file in the EncryptedPackage stream.<br/>
- If you plan to use POI to actually generate encrypted documents, be aware not to use anything less than
- agile encryption, because <a href="https://eprint.iacr.org/2005/007.pdf">RC4 is not really secure</a> and
- <a href="https://blog.cryptographyengineering.com/2011/12/01/how-not-to-use-symmetric-encryption/">ECB chaining is problematic too</a>.
- Of course you'll need to make sure, that your clients can read the documents,
- i.e. the various free Excel, Powerpoint, Word viewers have limitations in the cipher or hashing parameters.<br/>
- If you want to use high encryption parameters, you need to install the "Java Cryptography Extension (JCE) Unlimited
- Strength Jurisdiction Policy Files" for your JRE version
- (Oracle <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html">JDK6</a>,
- <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html">JDK7</a>,
- <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html">JDK8</a>,
- IBM <a href="https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/sdkpolicyfiles.html">JDK8</a>).
- </li>
- </ul>
+ <header>
+ <title>Apache POI - Encryption support</title>
+ <authors>
+ <person id="maxcom" name="Maxim Valyanskiy" email="maxcom@apache.org"/>
+ <person id="AB" name="Andreas Beeker" email="kiwiwings@apache.org"/>
+ </authors>
+ </header>
+
+ <body>
+ <section>
+ <title>Overview</title>
+
+ <p>Apache POI contains support for reading few variants of encrypted office files: </p>
+ <ul>
+ <li>Binary formats (.xls, .ppt, .doc, ...)<br/>
+ encryption is format-dependent and needs to be implemented per format differently.<br/>
+ Use <a href="apidocs/dev/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.html">
+ Biff8EncryptionKey</a>.<a href="apidocs/dev/org/apache/poi/hssf/record/crypto/Biff8EncryptionKey.html#setCurrentUserPassword(java.lang.String)">setCurrentUserPassword</a>(String password)
+ to specify the decryption password before opening the file or (where applicable) before saving.
+ Setting a null password before saving removes the password protection.<br/>
+ The password is set in a thread local variable. Do not forget to reset it to null after text extraction.
+ </li>
+ <li>XML-based formats (.xlsx, .pptx, .docx, ...)<br/>
+ use the same encryption logic over all formats. When encrypted, the zipped files will be
+ stored within an OLE file in the EncryptedPackage stream.<br/>
+ If you plan to use POI to actually generate encrypted documents, be aware not to use anything less than
+ agile encryption, because <a href="https://eprint.iacr.org/2005/007.pdf">RC4 is not really secure</a> and
+ <a href="https://blog.cryptographyengineering.com/2011/12/01/how-not-to-use-symmetric-encryption/">ECB chaining is problematic too</a>.
+ Of course you'll need to make sure, that your clients can read the documents,
+ i.e. the various free Excel, Powerpoint, Word viewers have limitations in the cipher or hashing parameters.<br/>
+ If you want to use high encryption parameters, you need to install the "Java Cryptography Extension (JCE) Unlimited
+ Strength Jurisdiction Policy Files" for your JRE version
+ (Oracle <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html">JDK6</a>,
+ <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html">JDK7</a>,
+ <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html">JDK8</a>,
+ IBM <a href="https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/sdkpolicyfiles.html">JDK8</a>).
+ </li>
+ </ul>
- <p>Some "write-protected" files are encrypted with the built-in password "VelvetSweatshop", POI can read that files too.</p>
+ <p>Some "write-protected" files are encrypted with the built-in password "VelvetSweatshop", POI can read that files too.</p>
</section>
- <section><title>Supported feature matrix</title>
+ <section>
+ <title>Supported feature matrix</title>
- <table class="autosize POITable">
- <tr>
- <th>Encryption</th>
- <th>HSSF</th>
- <th>HSLF</th>
- <th>HWPF</th>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/dd949802(v=office.12).aspx">XOR obfuscation *)</a></td>
- <td class="feature-yes">Yes (Writing since 3.16)</td>
- <td class="feature-na">N/A</td>
- <td class="feature-no">No</td>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/dd909583(v=office.12).aspx">40-bit RC4 encryption</a></td>
- <td class="feature-yes">Yes (Writing since 3.16)</td>
- <td class="feature-na">N/A</td>
- <td class="feature-yes">Yes (since 3.17)</td>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/dd910113(v=office.12).aspx">Office Binary Document RC4 CryptoAPI Encryption</a></td>
- <td class="feature-yes">Yes (Since 3.16)</td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes (since 3.17)</td>
- </tr>
- <tr>
- <th/>
- <th>XSSF</th>
- <th>XSLF</th>
- <th>XWPF</th>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/dd907466(v=office.12).aspx">Office Binary Document RC4 Encryption **)</a></td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/dd906131(v=office.12).aspx">ECMA-376 Standard Encryption</a></td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/dd906131(v=office.12).aspx">ECMA-376 Agile Encryption</a></td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- </tr>
- <tr>
- <td><a href="https://msdn.microsoft.com/en-us/library/ms757845(v=vs.85).aspx">ECMA-376 XML Signature</a></td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- <td class="feature-yes">Yes</td>
- </tr>
- </table>
-
- <p>*) the xor encryption is flawed and works only for very small files - see <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=59857">#59857</a>.
- </p>
-
- <p>**) the <a href="https://msdn.microsoft.com/en-us/library/cc313071(v=office.12).aspx">MS-OFFCRYPTO</a>
- documentation only mentions the RC4 (without CryptoAPI) encryption as a "in place" encryption, but
- apparently there's also a container based method with that key generation logic.
- </p>
+ <table class="autosize POITable">
+ <tr>
+ <th>Encryption</th>
+ <th>HSSF</th>
+ <th>HSLF</th>
+ <th>HWPF</th>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/dd949802(v=office.12).aspx">XOR obfuscation *)</a></td>
+ <td class="feature-yes">Yes (Writing since 3.16)</td>
+ <td class="feature-na">N/A</td>
+ <td class="feature-no">No</td>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/dd909583(v=office.12).aspx">40-bit RC4 encryption</a></td>
+ <td class="feature-yes">Yes (Writing since 3.16)</td>
+ <td class="feature-na">N/A</td>
+ <td class="feature-yes">Yes (since 3.17)</td>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/dd910113(v=office.12).aspx">Office Binary Document RC4 CryptoAPI Encryption</a></td>
+ <td class="feature-yes">Yes (Since 3.16)</td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes (since 3.17)</td>
+ </tr>
+ <tr>
+ <th/>
+ <th>XSSF</th>
+ <th>XSLF</th>
+ <th>XWPF</th>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/dd907466(v=office.12).aspx">Office Binary Document RC4 Encryption **)</a></td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/dd906131(v=office.12).aspx">ECMA-376 Standard Encryption</a></td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/dd906131(v=office.12).aspx">ECMA-376 Agile Encryption</a></td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ </tr>
+ <tr>
+ <td><a href="https://msdn.microsoft.com/en-us/library/ms757845(v=vs.85).aspx">ECMA-376 XML Signature</a></td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ <td class="feature-yes">Yes</td>
+ </tr>
+ </table>
+
+ <p>*) the xor encryption is flawed and works only for very small files - see <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=59857">#59857</a>.
+ </p>
+
+ <p>**) the <a href="https://msdn.microsoft.com/en-us/library/cc313071(v=office.12).aspx">MS-OFFCRYPTO</a>
+ documentation only mentions the RC4 (without CryptoAPI) encryption as a "in place" encryption, but
+ apparently there's also a container based method with that key generation logic.
+ </p>
</section>
<section><title>Binary formats</title>
@@ -137,17 +140,17 @@
<section>
<title>XOR/RC4 decryption for xls</title>
- <source>
+ <source><![CDATA[
Biff8EncryptionKey.setCurrentUserPassword("pass");
POIFSFileSystem fs = new POIFSFileSystem(new File("file.xls"), true);
HSSFWorkbook hwb = new HSSFWorkbook(fs.getRoot(), true);
Biff8EncryptionKey.setCurrentUserPassword(null);
- </source>
+ ]]></source>
</section>
<section>
<title>RC4 CryptoApi support ppt - decryption</title>
- <source>
+ <source><![CDATA[
Biff8EncryptionKey.setCurrentUserPassword("pass");
POIFSFileSystem fs = new POIFSFileSystem(new File("file.ppt"), true);
HSLFSlideShow hss = new HSLFSlideShow(fs);
@@ -167,326 +170,360 @@
OutputStream os = new FileOutputStream("file_120bit.ppt");
hss.write(os);
os.close();
- </source>
+ ]]></source>
</section>
</section>
- <section><title>XML-based formats - Decryption</title>
- <p>XML-based formats are stored in OLE-package stream "EncryptedPackage". Use org.apache.poi.poifs.crypt.Decryptor
- to decode file:</p>
-
- <source>
-EncryptionInfo info = new EncryptionInfo(filesystem);
-Decryptor d = Decryptor.getInstance(info);
-
-try {
- if (!d.verifyPassword(password)) {
- throw new RuntimeException("Unable to process: document is encrypted");
- }
-
- InputStream dataStream = d.getDataStream(filesystem);
-
- // parse dataStream
-
-} catch (GeneralSecurityException ex) {
- throw new RuntimeException("Unable to process encrypted document", ex);
-}
- </source>
-
- <p>If you want to read file encrypted with build-in password, use Decryptor.DEFAULT_PASSWORD.</p>
- </section>
-
- <section><title>XML-based formats - Encryption</title>
- <p>Encrypting a file is similar to the above decryption process. Basically you'll need to choose between
- <a href="apidocs/dev/org/apache/poi/poifs/crypt/EncryptionMode.html">binaryRC4, standard and agile encryption</a>,
- the cryptoAPI mode is used internally and it's direct use would result in an incomplete file.
- Apart of the CipherMode, the EncryptionInfo class provides further parameters to specify the cipher and
- hashing algorithm to be used.</p>
- <source>
-try (POIFSFileSystem fs = new POIFSFileSystem()) {
- EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
- // EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha384, -1, -1, null);
-
- Encryptor enc = info.getEncryptor();
- enc.confirmPassword("foobaa");
-
- // Read in an existing OOXML file and write to encrypted output stream
- // don't forget to close the output stream otherwise the padding bytes aren't added
- try (OPCPackage opc = OPCPackage.open(new File("..."), PackageAccess.READ_WRITE);
- OutputStream os = enc.getDataStream(fs)) {
- opc.save(os);
- }
-
- // Write out the encrypted version
- try (FileOutputStream fos = new FileOutputStream("...")) {
- fs.writeFilesystem(fos);
- }
-}
- </source>
- </section>
-
- <section><title>XML-based formats - Signing (XML Signature)</title>
-
- <note>As of <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=64186">#64186</a> the configuration of the
- OPCPackage has changed, the examples below have been adopted and reflect the POI 4.1.3 API</note>
-
- <p>An Office document can be digital signed by a <a href="https://en.wikipedia.org/wiki/XML_Signature">XML Signature</a>
- to protect it from unauthorized modifications, i.e. modifications without having the original certificate.
- The current implementation is based on the <!--<a href="http://eid-applet.googlecode.com">eID Applet</a>-->
- <a href="https://github.com/e-Contract/eid-applet">eID Applet</a> which
- is dual-licensed to <!--<a href="https://code.google.com/p/eid-applet/source/browse/trunk/README.txt">ASF/POI</a>-->
- <a href="https://github.com/e-Contract/eid-applet/blob/master/README.md#7-license">Apache License 2.0 and LGPL v3.0</a>.
- Instead of using the internal <a href="http://www.jsourcecode.com/class.php?proj=jdk%5Copenjdk&jar=openjdk-6-b14&class=org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory">JDK API</a>
- this version is based on <a href="https://santuario.apache.org">Apache Santuario</a>.</p>
- <p>The classes have been tested against the following libraries, which need to be included additionally to the
- <a href="site:components">default dependencies</a>:</p>
- <ul>
- <li>BouncyCastle bcpkix and bcprov (tested against 1.64)</li>
- <li>Apache Santuario "xmlsec" (tested against 2.1.2)</li>
- <li>and slf4j-api (tested against 1.7.30)</li>
- </ul>
- <p>Depending on the <a href="apidocs/dev/org/apache/poi/poifs/crypt/dsig/SignatureConfig.html">configuration</a>
- and the activated <a href="apidocs/dev/org/apache/poi/poifs/crypt/dsig/facets/package-summary.html">facets</a>
- various <a href="https://en.wikipedia.org/wiki/XAdES">XAdES levels</a> are supported - the support for higher levels (XAdES-T+)
- depend on supporting services and although the code is adopted, the integration is not well tested ... please support us on
- integration (testing) with timestamp and revocation (OCSP) services.
- </p>
- <p>Further test examples can be found in the corresponding <a href="https://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java?view=markup">test class</a>.</p>
-
- <p>If you want to use a hash algorithm with 64 bytes (currently only applies to SHA512),
- <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=42061">a base64 "feature"</a> in xmlsec
- leads to line breaks in the digest values, which won't be accepted by Office. To workaround this, you
- need to set the following system property:<br/>
- <strong>-Dorg.apache.xml.security.ignoreLineBreaks=true</strong></p>
- </section>
-
- <section><title>Validating a signed office document</title>
-
- <source>
-OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ);
-SignatureConfig sic = new SignatureConfig();
-SignatureInfo si = new SignatureInfo();
-si.setOpcPackage(pkg);
-si.setSignatureConfig(sic);
-boolean isValid = si.verifySignature();
-...
- </source>
- </section>
-
- <section><title>Signing an office document</title>
-
- <section><title>Signing a file</title>
- <source>
-// loading the keystore - pkcs12 is used here, but of course jks & co are also valid
-// the keystore needs to contain a private key and it's certificate having a
-// 'digitalSignature' key usage
-char password[] = "test".toCharArray();
-File file = new File("test.pfx");
-KeyStore keystore = KeyStore.getInstance("PKCS12");
-FileInputStream fis = new FileInputStream(file);
-keystore.load(fis, password);
-fis.close();
-
-// extracting private key and certificate
-String alias = "xyz"; // alias of the keystore entry
-Key key = keystore.getKey(alias, password);
-X509Certificate x509 = (X509Certificate)keystore.getCertificate(alias);
-
-// filling the SignatureConfig entries (minimum fields, more options are available ...)
-SignatureConfig signatureConfig = new SignatureConfig();
-signatureConfig.setKey(keyPair.getPrivate());
-signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
-
-// adding the signature document to the package
-SignatureInfo si = new SignatureInfo();
-OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ_WRITE);
-si.setOpcPackage(pkg);
-si.setSignatureConfig(signatureConfig);
-si.confirmSignature();
-// optionally verify the generated signature
-boolean b = si.verifySignature();
-assert (b);
-// write the changes back to disc
-pkg.close();
- </source>
- </section>
-
- <section><title>Signing a stream - in-memory</title>
- <p>When saving a OOXML document, POI creates missing relations on the fly. Therefore calling the signing method before
- would result in an invalid signature. Instead of trying to fix all save invocations, the user is asked to save the stream
- before in a intermediate byte array (stream) and process this stream instead.</p>
-
- <source>
-// load the key and setup SignatureConfig ... - see "Signing a file"
-
-SignatureInfo si = new SignatureInfo();
-si.setSignatureConfig(signatureConfig);
-
-// populate sample object
-XSSFWorkbook wb = new XSSFWorkbook();
-wb.createSheet().createRow(1).createCell(1).setCellValue("Test");
-ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
-wb.write(bos);
-wb.close();
-
-// process the
-OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()));
-
-si.setOpcPackage(pkg);
-si.confirmSignature();
-bos.reset();
-pkg.save(bos);
-pkg.close();
-
-// bos now contains the signed ooxml document
- </source>
- </section>
- </section>
-
- <section><title>Encrypting temporary files created when unzipping an OOXML document</title>
- <p>For security-conscious environments where data at rest must be stored encrypted,
- the creation of plaintext temporary files is a grey area.</p>
-
- <p>The code example, written by PJ Fanning, modifies the behavior of SXSSFWorkbook
- to extract an OOXML spreadsheet zipped container and write the contents to disk using AES
- encryption.</p>
-
- <p>See <a href="https://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java?view=markup">SXSSFWorkbookWithCustomZipEntrySource.java</a>
- and other <a href="https://svn.apache.org/viewvc?view=revision&revision=1768744">files</a>
- that are needed for this example.</p>
- </section>
-
- <section><title>Debugging XML signature issues</title>
- <p>Finding the source of a XML signature problem can be sometimes a pain in the ... neck, because
- the hashing of the canonicalized form is more or less intransparent done in the background.</p>
-
- <!-- TODO: find original source -->
- <p>One of the tripping hazards are <a href="https://stackoverflow.com/questions/36063375">different
- linebreaks in Windows/Unix</a>, therefore use the non-indent form of the xmls.</p>
-
- <p>The next thing is to compare successful signed documents from Office vs. POIs generated signature,
- i.e. unzip both files and look for differences. Usually the package relations (*.rels) will be different,
- and the sig1.xml, core.xml and [Content_Types].xml due to different order of the references.</p>
-
- <p>The package relationsships (*.rels) will be specially handled, i.e. they will be filtered and only
- a subset will be processed - see <a href="https://www.ecma-international.org/activities/Office%20Open%20XML%20Formats/Draft%20ECMA-376%203rd%20edition,%20March%202011/Office%20Open%20XML%20Part%202%20-%20Open%20Packaging%20Conventions.pdf">13.2.4.24 Relationships Transform Algorithm</a>.</p>
-
- <p>To check the processed files in the canonicalized form, the below UnsyncBufferedOutputStream class needs
- to be injected/replaced. Put the .class file in separate directory and add the following JVM parameters:</p>
-
- <source>
--Djava.io.tmpdir=<em><custom temp directory></em>
--Xbootclasspath/p:<em><preload dir, which contains /org/apache/xml/security/utils/UnsyncBufferedOutputStream.class></em>
--Dorg.apache.poi.util.POILogger=org.apache.poi.util.CommonsLogger
--Djava.util.logging.config.file=<em><a dir containing ...></em>/logging.properties
- </source>
-
- <section><title>UnsyncBufferedOutputStream:</title>
- <source>
-package org.apache.xml.security.utils;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-public class UnsyncBufferedOutputStream extends OutputStream {
- static final int size = 8*1024;
- static int filecnt = 0;
-
- private int pointer = 0;
- private final OutputStream out;
- private final FileOutputStream out2;
-
- private final byte[] buf;
-
- public UnsyncBufferedOutputStream(OutputStream out) {
- buf = new byte[size];
- this.out = out;
- synchronized(UnsyncBufferedOutputStream.class) {
+ <section>
+ <title>XML-based formats - Decryption</title>
+
+ <p>XML-based formats are stored in OLE-package stream "EncryptedPackage". Use org.apache.poi.poifs.crypt.Decryptor
+ to decode file:</p>
+
+ <source><![CDATA[
+ EncryptionInfo info = new EncryptionInfo(filesystem);
+ Decryptor d = Decryptor.getInstance(info);
+
try {
- String tmpDir = System.getProperty("java.io.tmpdir");
- if (tmpDir == null) {
- tmpDir = "build";
+ if (!d.verifyPassword(password)) {
+ throw new RuntimeException("Unable to process: document is encrypted");
}
- File f = new File(tmpDir, "unsync-"+filecnt+".xml");
- out2 = new FileOutputStream(f);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- filecnt++;
+
+ InputStream dataStream = d.getDataStream(filesystem);
+
+ // parse dataStream
+
+ } catch (GeneralSecurityException ex) {
+ throw new RuntimeException("Unable to process encrypted document", ex);
}
- }
- }
+ ]]></source>
+
+ <p>If you want to read file encrypted with build-in password, use Decryptor.DEFAULT_PASSWORD.</p>
+ </section>
+
+ <section>
+ <title>XML-based formats - Encryption</title>
- public void write(byte[] arg0) throws IOException {
- write(arg0, 0, arg0.length);
- }
-
- public void write(byte[] arg0, int arg1, int len) throws IOException {
- int newLen = pointer+len;
- if (newLen > size) {
- flushBuffer();
- if (len > size) {
- out.write(arg0, arg1,len);
- out2.write(arg0, arg1,len);
- return;
+ <p>Encrypting a file is similar to the above decryption process. Basically you'll need to choose between
+ <a href="apidocs/dev/org/apache/poi/poifs/crypt/EncryptionMode.html">binaryRC4, standard and agile encryption</a>,
+ the cryptoAPI mode is used internally and it's direct use would result in an incomplete file.
+ Apart of the CipherMode, the EncryptionInfo class provides further parameters to specify the cipher and
+ hashing algorithm to be used.</p>
+ <source><![CDATA[
+ try (POIFSFileSystem fs = new POIFSFileSystem()) {
+ EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
+ // EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha384, -1, -1, null);
+
+ Encryptor enc = info.getEncryptor();
+ enc.confirmPassword("foobaa");
+
+ // Read in an existing OOXML file and write to encrypted output stream
+ // don't forget to close the output stream otherwise the padding bytes aren't added
+ try (OPCPackage opc = OPCPackage.open(new File("..."), PackageAccess.READ_WRITE);
+ OutputStream os = enc.getDataStream(fs)) {
+ opc.save(os);
+ }
+
+ // Write out the encrypted version
+ try (FileOutputStream fos = new FileOutputStream("...")) {
+ fs.writeFilesystem(fos);
+ }
}
- newLen = len;
- }
- System.arraycopy(arg0, arg1, buf, pointer, len);
- pointer = newLen;
- }
-
- private void flushBuffer() throws IOException {
- if (pointer > 0) {
- out.write(buf, 0, pointer);
- out2.write(buf, 0, pointer);
- }
- pointer = 0;
-
- }
-
- public void write(int arg0) throws IOException {
- if (pointer >= size) {
- flushBuffer();
- }
- buf[pointer++] = (byte)arg0;
-
- }
-
- public void flush() throws IOException {
- flushBuffer();
- out.flush();
- out2.flush();
- }
-
- public void close() throws IOException {
- flush();
- out.close();
- out2.close();
- }
-
-}
-</source>
-</section>
-
- <section><title>logging.properties</title>
- <source>
-handlers = org.slf4j.bridge.SLF4JBridgeHandler
-.level=ALL
-org.slf4j.bridge.SLF4JBridgeHandler.level=ALL
- </source>
- </section>
- </section>
- </body>
-
- <footer>
- <legal>
- Copyright (c) @year@ The Apache Software Foundation. All rights reserved.
- <br />
- Apache POI, POI, Apache, the Apache feather logo, and the Apache
- POI project logo are trademarks of The Apache Software Foundation.
- </legal>
- </footer>
+ ]]></source>
+ </section>
+
+ <section>
+ <title>XML-based formats - Signing (XML Signature)</title>
+
+ <note>As of <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=64186">#64186</a> the configuration of the
+ OPCPackage has changed, the examples below have been adopted and reflect the POI 4.1.3 API</note>
+
+ <p>An Office document can be digital signed by a <a href="https://en.wikipedia.org/wiki/XML_Signature">XML Signature</a>
+ to protect it from unauthorized modifications, i.e. modifications without having the original certificate.
+ The current implementation is based on the <!--<a href="http://eid-applet.googlecode.com">eID Applet</a>-->
+ <a href="https://github.com/e-Contract/eid-applet">eID Applet</a> which
+ is dual-licensed to <!--<a href="https://code.google.com/p/eid-applet/source/browse/trunk/README.txt">ASF/POI</a>-->
+ <a href="https://github.com/e-Contract/eid-applet/blob/master/README.md#7-license">Apache License 2.0 and LGPL v3.0</a>.
+ Instead of using the internal <a href="http://www.jsourcecode.com/class.php?proj=jdk%5Copenjdk&jar=openjdk-6-b14&class=org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory">JDK API</a>
+ this version is based on <a href="https://santuario.apache.org">Apache Santuario</a>.</p>
+ <p>The classes have been tested against the following libraries, which need to be included additionally to the
+ <a href="site:components">default dependencies</a>:</p>
+ <ul>
+ <li>BouncyCastle bcpkix and bcprov (tested against 1.64)</li>
+ <li>Apache Santuario "xmlsec" (tested against 2.1.5)</li>
+ <li>and slf4j-api (tested against 1.7.30)</li>
+ </ul>
+ <p>Depending on the <a href="apidocs/dev/org/apache/poi/poifs/crypt/dsig/SignatureConfig.html">configuration</a>
+ and the activated <a href="apidocs/dev/org/apache/poi/poifs/crypt/dsig/facets/package-summary.html">facets</a>
+ various <a href="https://en.wikipedia.org/wiki/XAdES">XAdES levels</a> are supported - the support for higher levels (XAdES-T+)
+ depend on supporting services and although the code is adopted, the integration is not well tested ... please support us on
+ integration (testing) with timestamp and revocation (OCSP) services.
+ </p>
+ <p>Further test examples can be found in the corresponding <a href="https://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java?view=markup">test class</a>.</p>
+
+ <p>If you want to use a hash algorithm with 64 bytes (currently only applies to SHA512),
+ <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=42061">a base64 "feature"</a> in xmlsec
+ leads to line breaks in the digest values, which won't be accepted by Office. To workaround this, you
+ need to set the following system property:<br/>
+ <strong>-Dorg.apache.xml.security.ignoreLineBreaks=true</strong></p>
+ </section>
+
+ <section>
+ <title>Validating a signed office document</title>
+
+ <source><![CDATA[
+ OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ);
+ SignatureConfig sic = new SignatureConfig();
+ SignatureInfo si = new SignatureInfo();
+ si.setOpcPackage(pkg);
+ si.setSignatureConfig(sic);
+ boolean isValid = si.verifySignature();
+ ...
+ ]]></source>
+ </section>
+
+ <section>
+ <title>Signing an office document</title>
+
+ <section>
+ <title>Signing a file</title>
+ <source><![CDATA[
+ // loading the keystore - pkcs12 is used here, but of course jks & co are also valid
+ // the keystore needs to contain a private key and it's certificate having a
+ // 'digitalSignature' key usage
+ char password[] = "test".toCharArray();
+ File file = new File("test.pfx");
+ KeyStore keystore = KeyStore.getInstance("PKCS12");
+ FileInputStream fis = new FileInputStream(file);
+ keystore.load(fis, password);
+ fis.close();
+
+ // extracting private key and certificate
+ String alias = "xyz"; // alias of the keystore entry
+ Key key = keystore.getKey(alias, password);
+ X509Certificate x509 = (X509Certificate)keystore.getCertificate(alias);
+
+ // filling the SignatureConfig entries (minimum fields, more options are available ...)
+ SignatureConfig signatureConfig = new SignatureConfig();
+ signatureConfig.setKey(keyPair.getPrivate());
+ signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
+
+ // adding the signature document to the package
+ SignatureInfo si = new SignatureInfo();
+ OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ_WRITE);
+ si.setOpcPackage(pkg);
+ si.setSignatureConfig(signatureConfig);
+ si.confirmSignature();
+ // optionally verify the generated signature
+ boolean b = si.verifySignature();
+ assert (b);
+ // write the changes back to disc
+ pkg.close();
+ ]]></source>
+ </section>
+
+ <section>
+ <title>Signing a stream - in-memory</title>
+
+ <p>When saving a OOXML document, POI creates missing relations on the fly. Therefore calling the signing method before
+ would result in an invalid signature. Instead of trying to fix all save invocations, the user is asked to save the stream
+ before in a intermediate byte array (stream) and process this stream instead.</p>
+
+ <source><![CDATA[
+ // load the key and setup SignatureConfig ... - see "Signing a file"
+
+ SignatureInfo si = new SignatureInfo();
+ si.setSignatureConfig(signatureConfig);
+
+ // populate sample object
+ XSSFWorkbook wb = new XSSFWorkbook();
+ wb.createSheet().createRow(1).createCell(1).setCellValue("Test");
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
+ wb.write(bos);
+ wb.close();
+
+ // process the
+ OPCPackage pkg = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()));
+
+ si.setOpcPackage(pkg);
+ si.confirmSignature();
+ bos.reset();
+ pkg.save(bos);
+ pkg.close();
+
+ // bos now contains the signed ooxml document
+ ]]></source>
+ </section>
+ </section>
+
+ <section>
+ <title>Encrypting temporary files created when unzipping an OOXML document</title>
+
+ <p>For security-conscious environments where data at rest must be stored encrypted,
+ the creation of plaintext temporary files is a grey area.</p>
+
+ <p>The code example, written by PJ Fanning, modifies the behavior of SXSSFWorkbook
+ to extract an OOXML spreadsheet zipped container and write the contents to disk using AES
+ encryption.</p>
+
+ <p>See <a href="https://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/SXSSFWorkbookWithCustomZipEntrySource.java?view=markup">SXSSFWorkbookWithCustomZipEntrySource.java</a>
+ and other <a href="https://svn.apache.org/viewvc?view=revision&revision=1768744">files</a>
+ that are needed for this example.</p>
+ </section>
+
+ <section>
+ <title>Debugging XML signature issues</title>
+ <p>Finding the source of a XML signature problem can be sometimes a pain in the ... neck, because
+ the hashing of the canonicalized form is more or less intransparent done in the background.</p>
+
+ <!-- TODO: find original source -->
+ <p>One of the tripping hazards are <a href="https://stackoverflow.com/questions/36063375">different
+ linebreaks in Windows/Unix</a>, therefore use the non-indent form of the xmls. Furthermore the
+ elements/anchestors containing namespace definitions and the used prefix might also differ.</p>
+
+ <p>The next thing is to compare successful signed documents from Office vs. POIs generated signature,
+ i.e. unzip both files and look for differences. Usually the package relations (*.rels) will be different,
+ and the sig1.xml, core.xml and [Content_Types].xml due to different order of the references.</p>
+
+ <p>The package relationsships (*.rels) will be specially handled, i.e. they will be filtered and only
+ a subset will be processed - see <a href="https://www.ecma-international.org/activities/Office%20Open%20XML%20Formats/Draft%20ECMA-376%203rd%20edition,%20March%202011/Office%20Open%20XML%20Part%202%20-%20Open%20Packaging%20Conventions.pdf">13.2.4.24 Relationships Transform Algorithm</a>.</p>
+
+ <p>POI can use <a href="https://commons.apache.org/proper/commons-logging/">commons logging</a>
+ and Santuario (XmlSec) uses <a href="http://www.slf4j.org/">SLF4J</a> for logging.
+ To get logging information and debug output ...:</p>
+
+ <ul>
+ <li>
+ add the following JVM parameters:
+ <source><![CDATA[
+ -Djava.io.tmpdir=<custom temp directory>
+ -Xbootclasspath/p:<preload dir, which contains /org/apache/xml/security/utils/UnsyncBufferedOutputStream.class>
+ -Dorg.apache.poi.util.POILogger=org.apache.poi.util.CommonsLogger
+ ]]></source>
+ </li>
+ <li>
+ replace commons-logging.jar with <a href="https://search.maven.org/artifact/org.slf4j/jcl-over-slf4j/1.7.30/jar">jcl-over-slf4j.jar</a>
+ </li>
+ <li>
+ beside log4j.jar, add <a href="https://search.maven.org/artifact/org.slf4j/slf4j-log4j12/1.7.30/jar">slf4j-log4j12.jar</a>
+ </li>
+ <li>
+ add a log4j.properties into the path with the following content:
+ <source><![CDATA[
+ log4j.rootLogger=ALL,FILE
+
+ # Define the file appender
+ log4j.appender.FILE=org.apache.log4j.FileAppender
+ log4j.appender.FILE.File=debug.log
+ log4j.appender.FILE.ImmediateFlush=true
+ log4j.appender.FILE.Threshold=debug
+ log4j.appender.FILE.Append=false
+ log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
+ log4j.appender.FILE.layout.conversionPattern=%-5p %c %x - %m%n
+ ]]></source>
+ </li>
+ <li>
+ To check the processed files in the canonicalized form, the below UnsyncBufferedOutputStream class needs
+ to be injected/replaced. Put the .class file in separate directory and add it to the JVM parameters (see above):
+
+ <source><![CDATA[
+ package org.apache.xml.security.utils;
+
+ import java.io.File;
+ import java.io.FileOutputStream;
+ import java.io.IOException;
+ import java.io.OutputStream;
+
+ public class UnsyncBufferedOutputStream extends OutputStream {
+ static final int size = 8*1024;
+ static int filecnt = 0;
+
+ private int pointer = 0;
+ private final OutputStream out;
+ private final FileOutputStream out2;
+
+ private final byte[] buf;
+
+ public UnsyncBufferedOutputStream(OutputStream out) {
+ buf = new byte[size];
+ this.out = out;
+ synchronized(UnsyncBufferedOutputStream.class) {
+ try {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir == null) {
+ tmpDir = "build";
+ }
+ File f = new File(tmpDir, "unsync-"+filecnt+".xml");
+ out2 = new FileOutputStream(f);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ filecnt++;
+ }
+ }
+ }
+
+ public void write(byte[] arg0) throws IOException {
+ write(arg0, 0, arg0.length);
+ }
+
+ public void write(byte[] arg0, int arg1, int len) throws IOException {
+ int newLen = pointer+len;
+ if (newLen > size) {
+ flushBuffer();
+ if (len > size) {
+ out.write(arg0, arg1,len);
+ out2.write(arg0, arg1,len);
+ return;
+ }
+ newLen = len;
+ }
+ System.arraycopy(arg0, arg1, buf, pointer, len);
+ pointer = newLen;
+ }
+
+ private void flushBuffer() throws IOException {
+ if (pointer > 0) {
+ out.write(buf, 0, pointer);
+ out2.write(buf, 0, pointer);
+ }
+ pointer = 0;
+
+ }
+
+ public void write(int arg0) throws IOException {
+ if (pointer >= size) {
+ flushBuffer();
+ }
+ buf[pointer++] = (byte)arg0;
+
+ }
+
+ public void flush() throws IOException {
+ flushBuffer();
+ out.flush();
+ out2.flush();
+ }
+
+ public void close() throws IOException {
+ flush();
+ out.close();
+ out2.close();
+ }
+
+ }
+ ]]></source>
+ </li>
+ </ul>
+ </section>
+ </body>
+
+ <footer>
+ <legal>
+ Copyright (c) @year@ The Apache Software Foundation. All rights reserved.
+ <br />
+ Apache POI, POI, Apache, the Apache feather logo, and the Apache
+ POI project logo are trademarks of The Apache Software Foundation.
+ </legal>
+ </footer>
</document>
Modified: poi/trunk/.classpath
URL: http://svn.apache.org/viewvc/poi/trunk/.classpath?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/.classpath (original)
+++ poi/trunk/.classpath Wed Mar 18 21:06:09 2020
@@ -33,7 +33,7 @@
<classpathentry kind="lib" path="ooxml-testlib/reflections.jar"/>
<classpathentry kind="lib" path="ooxml-testlib/guava.jar"/>
<classpathentry kind="lib" path="ooxml-testlib/javassist.jar"/>
- <classpathentry exported="true" kind="lib" path="compile-lib/xmlsec-2.1.2.jar"/>
+ <classpathentry exported="true" kind="lib" path="compile-lib/xmlsec-2.1.5.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.14.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-logging-1.2.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-collections4-4.4.jar"/>
Modified: poi/trunk/build.gradle
URL: http://svn.apache.org/viewvc/poi/trunk/build.gradle?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/build.gradle (original)
+++ poi/trunk/build.gradle Wed Mar 18 21:06:09 2020
@@ -241,7 +241,7 @@ project('ooxml') {
compile 'org.apache.commons:commons-collections4:4.4'
compile "org.apache.commons:commons-math3:${commonsMathVersion}"
compile "org.apache.commons:commons-compress:${commonsCompressVersion}"
- compile 'org.apache.santuario:xmlsec:2.1.2'
+ compile 'org.apache.santuario:xmlsec:2.1.5'
compile "org.bouncycastle:bcpkix-jdk15on:${bouncyCastleVersion}"
compile 'com.github.virtuald:curvesapi:1.06'
compile 'com.zaxxer:SparseBitSet:1.2'
Modified: poi/trunk/build.xml
URL: http://svn.apache.org/viewvc/poi/trunk/build.xml?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/build.xml (original)
+++ poi/trunk/build.xml Wed Mar 18 21:06:09 2020
@@ -223,8 +223,8 @@ under the License.
value="${repository.m2}/maven2/com/zaxxer/SparseBitSet/1.2/SparseBitSet-1.2.jar"/>
<!-- xml signature libs -->
- <property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.1.2.jar"/>
- <property name="dsig.xmlsec.url" value="${repository.m2}/maven2/org/apache/santuario/xmlsec/2.1.2/xmlsec-2.1.2.jar"/>
+ <property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.1.5.jar"/>
+ <property name="dsig.xmlsec.url" value="${repository.m2}/maven2/org/apache/santuario/xmlsec/2.1.5/xmlsec-2.1.5.jar"/>
<property name="dsig.bouncycastle-prov.jar" location="${compile.lib}/bcprov-ext-jdk15on-1.64.jar"/>
<property name="dsig.bouncycastle-prov.url" value="${repository.m2}/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.64/bcprov-ext-jdk15on-1.64.jar"/>
<property name="dsig.bouncycastle-pkix.jar" location="${compile.lib}/bcpkix-jdk15on-1.64.jar"/>
@@ -715,6 +715,10 @@ under the License.
<include name="xercesImpl-*.jar"/>
<include name="xmlsec-2.0*.jar"/>
<include name="xmlsec-2.1.0.jar"/>
+ <include name="xmlsec-2.1.1.jar"/>
+ <include name="xmlsec-2.1.2.jar"/>
+ <include name="xmlsec-2.1.3.jar"/>
+ <include name="xmlsec-2.1.4.jar"/>
<include name="bc*jdk15on-1.5*.jar"/>
<include name="bc*jdk15on-1.60*.jar"/>
<include name="bc*jdk15on-1.61*.jar"/>
Modified: poi/trunk/sonar/ooxml/pom.xml
URL: http://svn.apache.org/viewvc/poi/trunk/sonar/ooxml/pom.xml?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/sonar/ooxml/pom.xml (original)
+++ poi/trunk/sonar/ooxml/pom.xml Wed Mar 18 21:06:09 2020
@@ -84,7 +84,7 @@
</fileset>
</filesets>
</configuration>
- </plugin>
+ </plugin>
<!-- set jvm parameters for surefire plugin -->
@@ -147,7 +147,7 @@
<dependency>
<groupId>org.apache.santuario</groupId>
<artifactId>xmlsec</artifactId>
- <version>2.1.2</version>
+ <version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@@ -159,7 +159,7 @@
<artifactId>curvesapi</artifactId>
<version>1.06</version>
</dependency>
-
+
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Modified: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java Wed Mar 18 21:06:09 2020
@@ -153,7 +153,7 @@ import org.w3c.dom.events.MutationEvent;
* in the classpath:</p>
* <ul>
* <li>BouncyCastle bcpkix and bcprov (tested against 1.64)</li>
- * <li>Apache Santuario "xmlsec" (tested against 2.1.2)</li>
+ * <li>Apache Santuario "xmlsec" (tested against 2.1.5)</li>
* <li>and slf4j-api (tested against 1.7.30)</li>
* </ul>
*/
@@ -461,27 +461,22 @@ public class SignatureInfo {
return;
}
- EventTarget target = (EventTarget)document;
-
final EventListener[] el = { null };
- el[0] = (e) -> {
- if (!(e instanceof MutationEvent)) {
- return;
- }
+ final EventTarget eventTarget = (EventTarget)document;
+ final String eventType = "DOMSubtreeModified";
+ final boolean DONT_USE_CAPTURE = false;
- MutationEvent mutEvt = (MutationEvent) e;
- EventTarget et = mutEvt.getTarget();
- if (!(et instanceof Element)) {
- return;
+ el[0] = (e) -> {
+ if (e instanceof MutationEvent && e.getTarget() instanceof Document) {
+ eventTarget.removeEventListener(eventType, el[0], DONT_USE_CAPTURE);
+ sml.handleElement(this, document, eventTarget, el[0]);
+ eventTarget.addEventListener(eventType, el[0], DONT_USE_CAPTURE);
}
-
- sml.handleElement(this, (Element) et, target, el[0]);
};
- SignatureMarshalListener.setListener(target, el[0], true);
+ eventTarget.addEventListener(eventType, el[0], DONT_USE_CAPTURE);
}
-
/**
* Helper method for adding informations after the signing.
* Normally {@link #confirmSignature()} is sufficient to be used.
Modified: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalDefaultListener.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalDefaultListener.java?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalDefaultListener.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalDefaultListener.java Wed Mar 18 21:06:09 2020
@@ -17,47 +17,76 @@
package org.apache.poi.poifs.crypt.dsig;
-import static org.apache.poi.poifs.crypt.dsig.SignatureMarshalListener.setListener;
-import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.OO_DIGSIG_NS;
+import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_DIGSIG_NS;
import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_NS;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
/**
* This listener class is used, to modify the to be digested xml document,
* e.g. to register id attributes or set prefixes for registered namespaces
*/
public class SignatureMarshalDefaultListener implements SignatureMarshalListener {
+ private final Set<String> IGNORE_NS = new HashSet<>(Arrays.asList(null, XML_NS, XML_DIGSIG_NS));
+ private final String OBJECT_TAG = "Object";
+
@Override
- public void handleElement(SignatureInfo signatureInfo, Element el, EventTarget target, EventListener parentListener) {
- if (el.hasAttribute("Id")) {
- el.setIdAttribute("Id", true);
+ public void handleElement(SignatureInfo signatureInfo, Document doc, EventTarget target, EventListener parentListener) {
+ // see POI #63712 : because of Santuario change r1853805 in XmlSec 2.1.3,
+ // we have to deal with the whole document now
+
+ final DocumentTraversal traversal = (DocumentTraversal) doc;
+ final Map<String, String> prefixCfg = signatureInfo.getSignatureConfig().getNamespacePrefixes();
+
+ final Map<String, String> prefixUsed = new HashMap<>();
+
+ NodeList nl = doc.getElementsByTagName(OBJECT_TAG);
+ final int objLen = nl.getLength();
+ for (int i=0; i<objLen; i++) {
+ final Element objNode = (Element)nl.item(i);
+ getAllNamespaces(traversal, objNode, prefixCfg, prefixUsed);
+ prefixUsed.forEach((ns, prefix) -> objNode.setAttributeNS(XML_NS, "xmlns:"+prefix, ns));
}
+ }
- setListener(target, parentListener, false);
- if (OO_DIGSIG_NS.equals(el.getNamespaceURI())) {
- String parentNS = el.getParentNode().getNamespaceURI();
- if (!OO_DIGSIG_NS.equals(parentNS) && !el.hasAttributeNS(XML_NS, "mdssi")) {
- el.setAttributeNS(XML_NS, "xmlns:mdssi", OO_DIGSIG_NS);
+ private void getAllNamespaces(DocumentTraversal traversal, Element objNode, Map<String, String> prefixCfg, Map<String, String> prefixUsed) {
+ prefixUsed.clear();
+ final NodeIterator iter = traversal.createNodeIterator(objNode, NodeFilter.SHOW_ELEMENT, null, false);
+ try {
+ for (Element node; (node = (Element)iter.nextNode()) != null; ) {
+ setPrefix(node, prefixCfg, prefixUsed);
+ NamedNodeMap nnm = node.getAttributes();
+ final int nnmLen = nnm.getLength();
+ for (int j=0; j<nnmLen; j++) {
+ setPrefix(nnm.item(j), prefixCfg, prefixUsed);
+ }
}
+ } finally {
+ iter.detach();
}
- setPrefix(signatureInfo, el);
- setListener(target, parentListener, true);
}
- protected static void setPrefix(SignatureInfo signatureInfo, Node el) {
- String prefix = signatureInfo.getSignatureConfig().getNamespacePrefixes().get(el.getNamespaceURI());
- if (prefix != null && el.getPrefix() == null) {
- el.setPrefix(prefix);
- }
-
- NodeList nl = el.getChildNodes();
- for (int i=0; i<nl.getLength(); i++) {
- setPrefix(signatureInfo, nl.item(i));
+ private void setPrefix(Node node, Map<String,String> prefixCfg, Map<String,String> prefixUsed) {
+ String ns = node.getNamespaceURI();
+ String prefix = prefixCfg.get(ns);
+ if (!IGNORE_NS.contains(prefix)) {
+ node.setPrefix(prefix);
+ prefixUsed.put(ns, prefix);
}
}
}
Modified: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalListener.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalListener.java?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalListener.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureMarshalListener.java Wed Mar 18 21:06:09 2020
@@ -17,7 +17,7 @@
package org.apache.poi.poifs.crypt.dsig;
-import org.w3c.dom.Element;
+import org.w3c.dom.Document;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
@@ -26,16 +26,5 @@ import org.w3c.dom.events.EventTarget;
* e.g. to register id attributes or set prefixes for registered namespaces
*/
public interface SignatureMarshalListener {
- void handleElement(SignatureInfo signatureInfo, Element el, EventTarget target, EventListener parentListener);
-
- // helper method to keep it in one place
- static void setListener(EventTarget target, EventListener listener, boolean enabled) {
- final String type = "DOMSubtreeModified";
- final boolean DONT_USE_CAPTURE = false;
- if (enabled) {
- target.addEventListener(type, listener, DONT_USE_CAPTURE);
- } else {
- target.removeEventListener(type, listener, DONT_USE_CAPTURE);
- }
- }
+ void handleElement(SignatureInfo signatureInfo, Document doc, EventTarget target, EventListener parentListener);
}
\ No newline at end of file
Modified: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java?rev=1875392&r1=1875391&r2=1875392&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java Wed Mar 18 21:06:09 2020
@@ -31,8 +31,8 @@ import static org.apache.poi.poifs.crypt
import java.security.MessageDigest;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
-import java.util.Arrays;
import java.util.Calendar;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -74,7 +74,9 @@ import org.etsi.uri.x01903.v13.SignerRol
import org.w3.x2000.x09.xmldsig.DigestMethodType;
import org.w3.x2000.x09.xmldsig.X509IssuerSerialType;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* XAdES Signature Facet. Implements XAdES v1.4.1 which is compatible with XAdES
@@ -233,9 +235,15 @@ public class XAdESSignatureFacet impleme
private XMLObject addXadesObject(SignatureInfo signatureInfo, Document document, QualifyingPropertiesType qualifyingProperties) {
Node qualDocElSrc = qualifyingProperties.getDomNode();
- Node qualDocEl = document.importNode(qualDocElSrc, true);
- List<XMLStructure> xadesObjectContent = Arrays.asList(new DOMStructure(qualDocEl));
- return signatureInfo.getSignatureFactory().newXMLObject(xadesObjectContent, null, null, null);
+ Element qualDocEl = (Element)document.importNode(qualDocElSrc, true);
+
+ NodeList nl = qualDocEl.getElementsByTagNameNS(SignatureFacet.XADES_132_NS, "SignedProperties");
+ assert(nl.getLength() == 1);
+ ((Element)nl.item(0)).setIdAttribute("Id", true);
+
+ List<XMLStructure> xadesObjectContent = Collections.singletonList(new DOMStructure(qualDocEl));
+ XMLObject xo = signatureInfo.getSignatureFactory().newXMLObject(xadesObjectContent, null, null, null);
+ return xo;
}
private Reference addXadesReference(SignatureInfo signatureInfo) throws XMLSignatureException {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org