another signature ubuntu jdk6 bug fix ... and offline/online handling

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1637283 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2014-11-07 01:16:21 +00:00
parent a6216f4383
commit 08c876f792
3 changed files with 186 additions and 160 deletions

View File

@ -57,6 +57,7 @@ import javax.xml.crypto.dsig.XMLSignContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.XMLValidateContext;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
@ -230,9 +231,25 @@ public class SignatureInfo implements SignatureConfigurable {
DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, doc);
domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", Boolean.TRUE);
domValidateContext.setURIDereferencer(signatureConfig.getUriDereferencer());
brokenJvmWorkaround(domValidateContext);
XMLSignatureFactory xmlSignatureFactory = signatureConfig.getSignatureFactory();
XMLSignature xmlSignature = xmlSignatureFactory.unmarshalXMLSignature(domValidateContext);
// TODO: replace with property when xml-sec patch is applied
for (Reference ref : (List<Reference>)xmlSignature.getSignedInfo().getReferences()) {
SignatureFacet.brokenJvmWorkaround(ref);
}
for (XMLObject xo : (List<XMLObject>)xmlSignature.getObjects()) {
for (XMLStructure xs : (List<XMLStructure>)xo.getContent()) {
if (xs instanceof Manifest) {
for (Reference ref : (List<Reference>)((Manifest)xs).getReferences()) {
SignatureFacet.brokenJvmWorkaround(ref);
}
}
}
}
boolean valid = xmlSignature.validate(domValidateContext);
if (valid) {
@ -241,8 +258,6 @@ public class SignatureInfo implements SignatureConfigurable {
}
return valid;
} catch (ArrayIndexOutOfBoundsException e) {
throw new JvmBrokenException(e);
} catch (Exception e) {
LOG.log(POILogger.ERROR, "error in marshalling and validating the signature", e);
return false;
@ -399,149 +414,141 @@ public class SignatureInfo implements SignatureConfigurable {
@SuppressWarnings("unchecked")
public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
throws XMLSignatureException, MarshalException {
try {
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);
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);
}
/*
* 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;
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);
String description = signatureConfig.getSignatureDescription();
return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
} catch (ArrayIndexOutOfBoundsException e) {
throw new JvmBrokenException(e);
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));
brokenJvmWorkaround(xmlSignContext);
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;
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);
String description = signatureConfig.getSignatureDescription();
return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
}
/**
@ -651,10 +658,20 @@ public class SignatureInfo implements SignatureConfigurable {
private static <T> List<T> safe(List<T> other) {
return other == null ? Collections.EMPTY_LIST : other;
}
private static class JvmBrokenException extends EncryptedDocumentException {
public JvmBrokenException(Throwable cause) {
super("\"your JVM is just too broken\" - check https://bugzilla.redhat.com/show_bug.cgi?id=1155012 if this applies to the stacktrace ...", cause);
}
private void brokenJvmWorkaround(XMLSignContext context) {
// workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
Provider bcProv = Security.getProvider("BC");
if (bcProv != null) {
context.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
}
}
private void brokenJvmWorkaround(XMLValidateContext context) {
// workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
Provider bcProv = Security.getProvider("BC");
if (bcProv != null) {
context.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
}
}
}

View File

@ -150,6 +150,16 @@ public abstract class SignatureFacet implements SignatureConfigurable {
reference = sigFac.newReference(uri, digestMethod, transforms, type, id, digestValue);
}
brokenJvmWorkaround(reference);
return reference;
}
// helper method ... will be removed soon
public static void brokenJvmWorkaround(Reference reference) {
DigestMethod digestMethod = reference.getDigestMethod();
String digestMethodUri = digestMethod.getAlgorithm();
// workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
// overwrite standard message digest, if a digest <> SHA1 is used
Provider bcProv = Security.getProvider("BC");
@ -166,7 +176,5 @@ public abstract class SignatureFacet implements SignatureConfigurable {
LOG.log(POILogger.WARN, "Can't overwrite message digest (workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012)", e);
}
}
return reference;
}
}

View File

@ -50,7 +50,6 @@ 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;
@ -299,7 +298,9 @@ public class TestSignatureInfo {
signatureConfig.addSignatureFacet(new XAdESSignatureFacet());
signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet());
boolean mockTsp = false;
// check for internet
Process p1 = Runtime.getRuntime().exec("ping www.google.com");
boolean mockTsp = (p1.waitFor() == 1);
// http://timestamping.edelweb.fr/service/tsp
// http://tsa.belgium.be/connect
// http://timestamp.comodoca.com/authenticode
@ -471,14 +472,14 @@ public class TestSignatureInfo {
si.confirmSignature();
boolean b = si.verifySignature();
assertTrue("Signature not correctly calculated for " + ha, 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;
}
// } 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();
}