Added a catch and another workaround for the OpenJDK SHA2 AIOOBE bug
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1637001 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5f4a2a3b44
commit
1fcb0d7fd3
@ -32,6 +32,8 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -395,138 +397,149 @@ public class SignatureInfo implements SignatureConfigurable {
|
||||
@SuppressWarnings("unchecked")
|
||||
public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
|
||||
throws XMLSignatureException, MarshalException {
|
||||
signatureConfig.init(false);
|
||||
|
||||
// it's necessary to explicitly set the mdssi namespace, but the sign() method has no
|
||||
// normal way to interfere with, so we need to add the namespace under the hand ...
|
||||
EventTarget target = (EventTarget)document;
|
||||
EventListener creationListener = signatureConfig.getSignatureMarshalListener();
|
||||
if (creationListener != null) {
|
||||
if (creationListener instanceof SignatureMarshalListener) {
|
||||
((SignatureMarshalListener)creationListener).setEventTarget(target);
|
||||
}
|
||||
SignatureMarshalListener.setListener(target, creationListener, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signature context construction.
|
||||
*/
|
||||
XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);
|
||||
URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();
|
||||
if (null != uriDereferencer) {
|
||||
xmlSignContext.setURIDereferencer(uriDereferencer);
|
||||
}
|
||||
|
||||
for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
|
||||
xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());
|
||||
}
|
||||
xmlSignContext.setDefaultNamespacePrefix(""); // signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));
|
||||
|
||||
XMLSignatureFactory signatureFactory = signatureConfig.getSignatureFactory();
|
||||
|
||||
/*
|
||||
* Add ds:References that come from signing client local files.
|
||||
*/
|
||||
List<Reference> references = new ArrayList<Reference>();
|
||||
for (DigestInfo digestInfo : safe(digestInfos)) {
|
||||
byte[] documentDigestValue = digestInfo.digestValue;
|
||||
|
||||
String uri = new File(digestInfo.description).getName();
|
||||
Reference reference = SignatureFacet.newReference
|
||||
(uri, null, null, null, documentDigestValue, signatureConfig);
|
||||
references.add(reference);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke the signature facets.
|
||||
*/
|
||||
List<XMLObject> objects = new ArrayList<XMLObject>();
|
||||
for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
|
||||
LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());
|
||||
signatureFacet.preSign(document, references, objects);
|
||||
}
|
||||
|
||||
/*
|
||||
* ds:SignedInfo
|
||||
*/
|
||||
SignedInfo signedInfo;
|
||||
try {
|
||||
SignatureMethod signatureMethod = signatureFactory.newSignatureMethod
|
||||
(signatureConfig.getSignatureMethodUri(), null);
|
||||
CanonicalizationMethod canonicalizationMethod = signatureFactory
|
||||
.newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),
|
||||
(C14NMethodParameterSpec) null);
|
||||
signedInfo = signatureFactory.newSignedInfo(
|
||||
canonicalizationMethod, signatureMethod, references);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new XMLSignatureException(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* JSR105 ds:Signature creation
|
||||
*/
|
||||
String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";
|
||||
javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory
|
||||
.newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),
|
||||
signatureValueId);
|
||||
|
||||
/*
|
||||
* ds:Signature Marshalling.
|
||||
*/
|
||||
xmlSignature.sign(xmlSignContext);
|
||||
|
||||
/*
|
||||
* Completion of undigested ds:References in the ds:Manifests.
|
||||
*/
|
||||
for (XMLObject object : objects) {
|
||||
LOG.log(POILogger.DEBUG, "object java type: " + object.getClass().getName());
|
||||
List<XMLStructure> objectContentList = object.getContent();
|
||||
for (XMLStructure objectContent : objectContentList) {
|
||||
LOG.log(POILogger.DEBUG, "object content java type: " + objectContent.getClass().getName());
|
||||
if (!(objectContent instanceof Manifest)) continue;
|
||||
Manifest manifest = (Manifest) objectContent;
|
||||
List<Reference> manifestReferences = manifest.getReferences();
|
||||
for (Reference manifestReference : manifestReferences) {
|
||||
if (manifestReference.getDigestValue() != null) continue;
|
||||
|
||||
DOMReference manifestDOMReference = (DOMReference)manifestReference;
|
||||
manifestDOMReference.digest(xmlSignContext);
|
||||
signatureConfig.init(false);
|
||||
|
||||
// it's necessary to explicitly set the mdssi namespace, but the sign() method has no
|
||||
// normal way to interfere with, so we need to add the namespace under the hand ...
|
||||
EventTarget target = (EventTarget)document;
|
||||
EventListener creationListener = signatureConfig.getSignatureMarshalListener();
|
||||
if (creationListener != null) {
|
||||
if (creationListener instanceof SignatureMarshalListener) {
|
||||
((SignatureMarshalListener)creationListener).setEventTarget(target);
|
||||
}
|
||||
SignatureMarshalListener.setListener(target, creationListener, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signature context construction.
|
||||
*/
|
||||
XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);
|
||||
URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();
|
||||
if (null != uriDereferencer) {
|
||||
xmlSignContext.setURIDereferencer(uriDereferencer);
|
||||
}
|
||||
|
||||
for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
|
||||
xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());
|
||||
}
|
||||
xmlSignContext.setDefaultNamespacePrefix("");
|
||||
// signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));
|
||||
|
||||
// workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
|
||||
Provider bcProv = Security.getProvider("BC");
|
||||
if (bcProv != null) {
|
||||
xmlSignContext.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
|
||||
}
|
||||
|
||||
XMLSignatureFactory signatureFactory = signatureConfig.getSignatureFactory();
|
||||
|
||||
/*
|
||||
* Add ds:References that come from signing client local files.
|
||||
*/
|
||||
List<Reference> references = new ArrayList<Reference>();
|
||||
for (DigestInfo digestInfo : safe(digestInfos)) {
|
||||
byte[] documentDigestValue = digestInfo.digestValue;
|
||||
|
||||
String uri = new File(digestInfo.description).getName();
|
||||
Reference reference = SignatureFacet.newReference
|
||||
(uri, null, null, null, documentDigestValue, signatureConfig);
|
||||
references.add(reference);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke the signature facets.
|
||||
*/
|
||||
List<XMLObject> objects = new ArrayList<XMLObject>();
|
||||
for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
|
||||
LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());
|
||||
signatureFacet.preSign(document, references, objects);
|
||||
}
|
||||
|
||||
/*
|
||||
* ds:SignedInfo
|
||||
*/
|
||||
SignedInfo signedInfo;
|
||||
try {
|
||||
SignatureMethod signatureMethod = signatureFactory.newSignatureMethod
|
||||
(signatureConfig.getSignatureMethodUri(), null);
|
||||
CanonicalizationMethod canonicalizationMethod = signatureFactory
|
||||
.newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),
|
||||
(C14NMethodParameterSpec) null);
|
||||
signedInfo = signatureFactory.newSignedInfo(
|
||||
canonicalizationMethod, signatureMethod, references);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new XMLSignatureException(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* JSR105 ds:Signature creation
|
||||
*/
|
||||
String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";
|
||||
javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory
|
||||
.newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),
|
||||
signatureValueId);
|
||||
|
||||
/*
|
||||
* ds:Signature Marshalling.
|
||||
*/
|
||||
xmlSignature.sign(xmlSignContext);
|
||||
|
||||
/*
|
||||
* Completion of undigested ds:References in the ds:Manifests.
|
||||
*/
|
||||
for (XMLObject object : objects) {
|
||||
LOG.log(POILogger.DEBUG, "object java type: " + object.getClass().getName());
|
||||
List<XMLStructure> objectContentList = object.getContent();
|
||||
for (XMLStructure objectContent : objectContentList) {
|
||||
LOG.log(POILogger.DEBUG, "object content java type: " + objectContent.getClass().getName());
|
||||
if (!(objectContent instanceof Manifest)) continue;
|
||||
Manifest manifest = (Manifest) objectContent;
|
||||
List<Reference> manifestReferences = manifest.getReferences();
|
||||
for (Reference manifestReference : manifestReferences) {
|
||||
if (manifestReference.getDigestValue() != null) continue;
|
||||
|
||||
DOMReference manifestDOMReference = (DOMReference)manifestReference;
|
||||
manifestDOMReference.digest(xmlSignContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Completion of undigested ds:References.
|
||||
*/
|
||||
List<Reference> signedInfoReferences = signedInfo.getReferences();
|
||||
for (Reference signedInfoReference : signedInfoReferences) {
|
||||
DOMReference domReference = (DOMReference)signedInfoReference;
|
||||
|
||||
// ds:Reference with external digest value
|
||||
if (domReference.getDigestValue() != null) continue;
|
||||
|
||||
/*
|
||||
* Completion of undigested ds:References.
|
||||
*/
|
||||
List<Reference> signedInfoReferences = signedInfo.getReferences();
|
||||
for (Reference signedInfoReference : signedInfoReferences) {
|
||||
DOMReference domReference = (DOMReference)signedInfoReference;
|
||||
|
||||
// ds:Reference with external digest value
|
||||
if (domReference.getDigestValue() != null) continue;
|
||||
|
||||
domReference.digest(xmlSignContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculation of XML signature digest value.
|
||||
*/
|
||||
DOMSignedInfo domSignedInfo = (DOMSignedInfo)signedInfo;
|
||||
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
|
||||
domSignedInfo.canonicalize(xmlSignContext, dataStream);
|
||||
byte[] octets = dataStream.toByteArray();
|
||||
|
||||
/*
|
||||
* TODO: we could be using DigestOutputStream here to optimize memory
|
||||
* usage.
|
||||
*/
|
||||
|
||||
MessageDigest md = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());
|
||||
byte[] digestValue = md.digest(octets);
|
||||
|
||||
domReference.digest(xmlSignContext);
|
||||
|
||||
String description = signatureConfig.getSignatureDescription();
|
||||
return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new EncryptedDocumentException("\"your JVM is just too broken\" - check https://bugzilla.redhat.com/show_bug.cgi?id=1155012 if this applies to the stacktrace ...", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculation of XML signature digest value.
|
||||
*/
|
||||
DOMSignedInfo domSignedInfo = (DOMSignedInfo)signedInfo;
|
||||
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
|
||||
domSignedInfo.canonicalize(xmlSignContext, dataStream);
|
||||
byte[] octets = dataStream.toByteArray();
|
||||
|
||||
/*
|
||||
* TODO: we could be using DigestOutputStream here to optimize memory
|
||||
* usage.
|
||||
*/
|
||||
|
||||
MessageDigest md = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());
|
||||
byte[] digestValue = md.digest(octets);
|
||||
|
||||
|
||||
String description = signatureConfig.getSignatureDescription();
|
||||
return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,10 @@
|
||||
================================================================= */
|
||||
package org.apache.poi.poifs.crypt;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -47,6 +50,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackageAccess;
|
||||
@ -455,18 +459,29 @@ public class TestSignatureInfo {
|
||||
, HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160 };
|
||||
|
||||
for (HashAlgorithm ha : testAlgo) {
|
||||
signatureConfig.setDigestAlgo(ha);
|
||||
OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
|
||||
signatureConfig.setOpcPackage(pkg);
|
||||
|
||||
SignatureInfo si = new SignatureInfo();
|
||||
si.setSignatureConfig(signatureConfig);
|
||||
|
||||
si.confirmSignature();
|
||||
boolean b = si.verifySignature();
|
||||
pkg.close();
|
||||
|
||||
assertTrue(b);
|
||||
OPCPackage pkg = null;
|
||||
try {
|
||||
signatureConfig.setDigestAlgo(ha);
|
||||
pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
|
||||
signatureConfig.setOpcPackage(pkg);
|
||||
|
||||
SignatureInfo si = new SignatureInfo();
|
||||
si.setSignatureConfig(signatureConfig);
|
||||
|
||||
si.confirmSignature();
|
||||
boolean b = si.verifySignature();
|
||||
assertTrue(b);
|
||||
} catch (EncryptedDocumentException e) {
|
||||
// see http://apache-poi.1045710.n5.nabble.com/org-apache-poi-poifs-crypt-TestSignatureInfo-failing-on-trunk-on-Java-6-tp5717032.html
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof ArrayIndexOutOfBoundsException) {
|
||||
LOG.log(POILogger.ERROR, "ignoring AIOOBE - hopefully a SHA2 bug ...", e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
if (pkg != null) pkg.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user