reorganization, xmlsignatureservice is now in signatureinfo

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1626107 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2014-09-18 23:47:41 +00:00
parent 9fec16c622
commit 1fd5289bf6
13 changed files with 496 additions and 709 deletions

View File

@ -24,48 +24,88 @@
package org.apache.poi.poifs.crypt.dsig; package org.apache.poi.poifs.crypt.dsig;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.security.InvalidAlgorithmParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.NoSuchProviderException;
import java.security.Provider; import java.security.Provider;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.xml.crypto.MarshalException; import javax.xml.crypto.MarshalException;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Manifest;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignContext;
import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.apache.jcp.xml.dsig.internal.dom.DOMReference;
import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageNamespaces;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.poifs.crypt.ChainingMode; import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm; import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService; import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService;
import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo;
import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.DocumentHelper;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.xml.security.Init; import org.apache.xml.security.Init;
import org.apache.xmlbeans.XmlCursor; import org.apache.xml.security.utils.Base64;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions;
import org.w3.x2000.x09.xmldsig.SignatureDocument;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.events.MutationEvent;
import org.xml.sax.SAXException;
public class SignatureInfo { public class SignatureInfo {
@ -104,12 +144,16 @@ public class SignatureInfo {
private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class); private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);
private static boolean isInitialized = false; private static boolean isInitialized = false;
private final OPCPackage pkg; private SignatureInfoConfig signatureConfig;
public SignatureInfo(OPCPackage pkg) { public SignatureInfoConfig getSignatureConfig() {
this.pkg = pkg; return signatureConfig;
} }
public void setSignatureConfig(SignatureInfoConfig signatureConfig) {
this.signatureConfig = signatureConfig;
}
public boolean verifySignature() { public boolean verifySignature() {
initXmlProvider(); initXmlProvider();
// http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html // http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
@ -117,40 +161,27 @@ public class SignatureInfo {
return getSignersAndValidate(signers, true); return getSignersAndValidate(signers, true);
} }
public void confirmSignature(PrivateKey key, X509Certificate x509) public void confirmSignature()
throws NoSuchAlgorithmException, IOException, MarshalException, ParserConfigurationException, XmlException { throws NoSuchAlgorithmException, IOException, MarshalException, ParserConfigurationException, XmlException, InvalidAlgorithmParameterException, NoSuchProviderException, XMLSignatureException, TransformerFactoryConfigurationError, TransformerException, SAXException, URISyntaxException {
confirmSignature(key, x509, HashAlgorithm.sha1);
}
public void confirmSignature(PrivateKey key, X509Certificate x509, HashAlgorithm hashAlgo)
throws NoSuchAlgorithmException, IOException, MarshalException, ParserConfigurationException, XmlException {
SignatureInfoConfig signatureConfig = new SignatureInfoConfig();
signatureConfig.setOpcPackage(pkg);
signatureConfig.setDigestAlgo(hashAlgo);
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
signatureConfig.setKey(key);
signatureConfig.addDefaultFacets();
XmlSignatureService signatureService = new XmlSignatureService(signatureConfig);
Document document = DocumentHelper.createDocument(); Document document = DocumentHelper.createDocument();
// operate // operate
DigestInfo digestInfo = signatureService.preSign(document, null); DigestInfo digestInfo = preSign(document, null);
// setup: key material, signature value // setup: key material, signature value
byte[] signatureValue = signDigest(key, hashAlgo, digestInfo.digestValue); byte[] signatureValue = signDigest(digestInfo.digestValue);
// operate: postSign // operate: postSign
signatureService.postSign(document, signatureValue); postSign(document, signatureValue);
} }
public static byte[] signDigest(PrivateKey key, HashAlgorithm hashAlgo, byte digest[]) { public byte[] signDigest(byte digest[]) {
Cipher cipher = CryptoFunctions.getCipher(key, CipherAlgorithm.rsa Cipher cipher = CryptoFunctions.getCipher(signatureConfig.getKey(), CipherAlgorithm.rsa
, ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding"); , ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
try { try {
ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream(); ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();
digestInfoValueBuf.write(getHashMagic(hashAlgo)); digestInfoValueBuf.write(getHashMagic());
digestInfoValueBuf.write(digest); digestInfoValueBuf.write(digest);
byte[] digestInfoValue = digestInfoValueBuf.toByteArray(); byte[] digestInfoValue = digestInfoValueBuf.toByteArray();
byte[] signatureValue = cipher.doFinal(digestInfoValue); byte[] signatureValue = cipher.doFinal(digestInfoValue);
@ -175,15 +206,12 @@ public class SignatureInfo {
allValid = false; allValid = false;
} }
SignatureInfoConfig signatureConfig = new SignatureInfoConfig();
signatureConfig.setOpcPackage(pkg);
for (PackagePart signaturePart : signatureParts) { for (PackagePart signaturePart : signatureParts) {
KeyInfoKeySelector keySelector = new KeyInfoKeySelector(); KeyInfoKeySelector keySelector = new KeyInfoKeySelector();
try { try {
Document doc = DocumentHelper.readDocument(signaturePart.getInputStream()); Document doc = DocumentHelper.readDocument(signaturePart.getInputStream());
XmlSignatureService.registerIds(doc); registerIds(doc);
DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, doc); DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, doc);
domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", Boolean.TRUE); domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", Boolean.TRUE);
@ -209,6 +237,7 @@ public class SignatureInfo {
protected List<PackagePart> getSignatureParts(boolean onlyFirst) { protected List<PackagePart> getSignatureParts(boolean onlyFirst) {
List<PackagePart> packageParts = new ArrayList<PackagePart>(); List<PackagePart> packageParts = new ArrayList<PackagePart>();
OPCPackage pkg = signatureConfig.getOpcPackage();
PackageRelationshipCollection sigOrigRels = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN); PackageRelationshipCollection sigOrigRels = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
for (PackageRelationship rel : sigOrigRels) { for (PackageRelationship rel : sigOrigRels) {
@ -260,31 +289,6 @@ public class SignatureInfo {
throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!"); throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!");
} }
public static void insertXChild(XmlObject root, XmlObject child) {
XmlCursor rootCursor = root.newCursor();
insertXChild(rootCursor, child);
rootCursor.dispose();
}
public static void insertXChild(XmlCursor rootCursor, XmlObject child) {
rootCursor.toEndToken();
XmlCursor childCursor = child.newCursor();
childCursor.toNextToken();
childCursor.moveXml(rootCursor);
childCursor.dispose();
}
// public static void setPrefix(XmlObject xobj, String ns, String prefix) {
// XmlCursor cur;
// for (cur = xobj.newCursor(); cur.hasNextToken(); cur.toNextToken()) {
// if (cur.isStart()) {
// Element el = (Element)cur.getDomNode();
// if (ns.equals(el.getNamespaceURI())) el.setPrefix(prefix);
// }
// }
// cur.dispose();
// }
public static void setPrefix(Node el, String ns, String prefix) { public static void setPrefix(Node el, String ns, String prefix) {
if (ns.equals(el.getNamespaceURI())) el.setPrefix(prefix); if (ns.equals(el.getNamespaceURI())) el.setPrefix(prefix);
NodeList nl = el.getChildNodes(); NodeList nl = el.getChildNodes();
@ -293,8 +297,8 @@ public class SignatureInfo {
} }
} }
protected static byte[] getHashMagic(HashAlgorithm hashAlgo) { protected byte[] getHashMagic() {
switch (hashAlgo) { switch (signatureConfig.getDigestAlgo()) {
case sha1: return SHA1_DIGEST_INFO_PREFIX; case sha1: return SHA1_DIGEST_INFO_PREFIX;
// sha224: return SHA224_DIGEST_INFO_PREFIX; // sha224: return SHA224_DIGEST_INFO_PREFIX;
case sha256: return SHA256_DIGEST_INFO_PREFIX; case sha256: return SHA256_DIGEST_INFO_PREFIX;
@ -303,9 +307,22 @@ public class SignatureInfo {
case ripemd128: return RIPEMD128_DIGEST_INFO_PREFIX; case ripemd128: return RIPEMD128_DIGEST_INFO_PREFIX;
case ripemd160: return RIPEMD160_DIGEST_INFO_PREFIX; case ripemd160: return RIPEMD160_DIGEST_INFO_PREFIX;
// case ripemd256: return RIPEMD256_DIGEST_INFO_PREFIX; // case ripemd256: return RIPEMD256_DIGEST_INFO_PREFIX;
default: throw new EncryptedDocumentException("Hash algorithm "+hashAlgo+" not supported for signing."); default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");
} }
} }
protected String getSignatureMethod() {
switch (signatureConfig.getDigestAlgo()) {
case sha1: return ALGO_ID_SIGNATURE_RSA_SHA1;
case sha256: return ALGO_ID_SIGNATURE_RSA_SHA256;
case sha384: return ALGO_ID_SIGNATURE_RSA_SHA384;
case sha512: return ALGO_ID_SIGNATURE_RSA_SHA512;
case ripemd160: return ALGO_ID_MAC_HMAC_RIPEMD160;
default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");
}
}
public static synchronized void initXmlProvider() { public static synchronized void initXmlProvider() {
if (isInitialized) return; if (isInitialized) return;
@ -319,4 +336,281 @@ public class SignatureInfo {
throw new RuntimeException("Xml & BouncyCastle-Provider initialization failed", e); throw new RuntimeException("Xml & BouncyCastle-Provider initialization failed", e);
} }
} }
@SuppressWarnings("unchecked")
public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
throws ParserConfigurationException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, MarshalException,
javax.xml.crypto.dsig.XMLSignatureException,
TransformerFactoryConfigurationError, TransformerException,
IOException, SAXException, NoSuchProviderException, XmlException, URISyntaxException {
SignatureInfo.initXmlProvider();
// 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 ...
final EventTarget et = (EventTarget)document;
EventListener myModificationListener = new EventListener() {
@Override
public void handleEvent(Event e) {
if (e instanceof MutationEvent) {
MutationEvent mutEvt = (MutationEvent)e;
if (mutEvt.getTarget() instanceof Element) {
Element el = (Element)mutEvt.getTarget();
if ("idPackageObject".equals(el.getAttribute("Id"))) {
et.removeEventListener("DOMSubtreeModified", this, false);
el.setAttributeNS(XmlNS, "xmlns:mdssi", PackageNamespaces.DIGITAL_SIGNATURE);
}
}
}
}
};
et.addEventListener("DOMSubtreeModified", myModificationListener, false);
/*
* Signature context construction.
*/
XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);
URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();
if (null != uriDereferencer) {
xmlSignContext.setURIDereferencer(uriDereferencer);
}
xmlSignContext.putNamespacePrefix(
"http://schemas.openxmlformats.org/package/2006/digital-signature",
"mdssi");
String sigNsPrefix = signatureConfig.getSignatureNamespacePrefix();
if (sigNsPrefix != null) {
/*
* OOo doesn't like ds namespaces so per default prefixing is off.
*/
xmlSignContext.putNamespacePrefix(XmlDSigNS, sigNsPrefix);
}
XMLSignatureFactory signatureFactory = SignatureInfo.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;
DigestMethod digestMethod = signatureFactory.newDigestMethod(
digestInfo.hashAlgo.xmlSignUri, null);
String uri = new File(digestInfo.description).getName();
Reference reference = signatureFactory.newReference
(uri, digestMethod, null, null, null, documentDigestValue);
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, signatureFactory, references, objects);
}
/*
* ds:SignedInfo
*/
SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(), null);
CanonicalizationMethod canonicalizationMethod = signatureFactory
.newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),
(C14NMethodParameterSpec) null);
SignedInfo signedInfo = signatureFactory.newSignedInfo(
canonicalizationMethod, signatureMethod, references);
/*
* 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.
*/
xmlSignContext.setDefaultNamespacePrefix(signatureConfig.getSignatureNamespacePrefix());
// xmlSignContext.putNamespacePrefix(PackageNamespaces.DIGITAL_SIGNATURE, "mdssi");
xmlSignature.sign(xmlSignContext);
registerIds(document);
/*
* 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 jcaMessageDigest = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());
byte[] digestValue = jcaMessageDigest.digest(octets);
String description = signatureConfig.getSignatureDescription();
return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
}
public void postSign(Document document, byte[] signatureValue)
throws IOException, MarshalException, ParserConfigurationException, XmlException {
LOG.log(POILogger.DEBUG, "postSign");
SignatureInfo.initXmlProvider();
/*
* Check ds:Signature node.
*/
String signatureId = signatureConfig.getPackageSignatureId();
if (!signatureId.equals(document.getDocumentElement().getAttribute("Id"))) {
throw new RuntimeException("ds:Signature not found for @Id: " + signatureId);
}
/*
* Insert signature value into the ds:SignatureValue element
*/
NodeList sigValNl = document.getElementsByTagNameNS(XmlDSigNS, "SignatureValue");
if (sigValNl.getLength() != 1) {
throw new RuntimeException("preSign has to be called before postSign");
}
sigValNl.item(0).setTextContent(Base64.encode(signatureValue));
/*
* Allow signature facets to inject their own stuff.
*/
for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
signatureFacet.postSign(document, signatureConfig.getSigningCertificateChain());
}
registerIds(document);
writeDocument(document);
}
protected void writeDocument(Document document) throws IOException, XmlException {
XmlOptions xo = new XmlOptions();
Map<String,String> namespaceMap = new HashMap<String,String>();
for (SignatureFacet sf : signatureConfig.getSignatureFacets()) {
Map<String,String> sfm = sf.getNamespacePrefixMapping();
if (sfm != null) {
namespaceMap.putAll(sfm);
}
}
xo.setSaveSuggestedPrefixes(namespaceMap);
xo.setUseDefaultNamespace();
LOG.log(POILogger.DEBUG, "output signed Office OpenXML document");
/*
* Copy the original OOXML content to the signed OOXML package. During
* copying some files need to changed.
*/
OPCPackage pkg = signatureConfig.getOpcPackage();
PackagePartName sigPartName, sigsPartName;
try {
// <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
sigPartName = PackagingURIHelper.createPartName("/_xmlsignatures/sig1.xml");
// <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/>
sigsPartName = PackagingURIHelper.createPartName("/_xmlsignatures/origin.sigs");
} catch (InvalidFormatException e) {
throw new IOException(e);
}
String sigContentType = "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml";
PackagePart sigPart = pkg.getPart(sigPartName);
if (sigPart == null) {
sigPart = pkg.createPart(sigPartName, sigContentType);
}
OutputStream os = sigPart.getOutputStream();
SignatureDocument sigDoc = SignatureDocument.Factory.parse(document);
sigDoc.save(os, xo);
os.close();
String sigsContentType = "application/vnd.openxmlformats-package.digital-signature-origin";
PackagePart sigsPart = pkg.getPart(sigsPartName);
if (sigsPart == null) {
// touch empty marker file
sigsPart = pkg.createPart(sigsPartName, sigsContentType);
}
PackageRelationshipCollection relCol = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
for (PackageRelationship pr : relCol) {
pkg.removeRelationship(pr.getId());
}
pkg.addRelationship(sigsPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
sigsPart.addRelationship(sigPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE);
}
/**
* the resulting document needs to be tweaked before it can be digested -
* this applies to the verification and signing step
*
* @param doc
*/
private static void registerIds(Document doc) {
NodeList nl = doc.getElementsByTagNameNS(XmlDSigNS, "Object");
registerIdAttribute(nl);
nl = doc.getElementsByTagNameNS("http://uri.etsi.org/01903/v1.3.2#", "SignedProperties");
registerIdAttribute(nl);
}
public static void registerIdAttribute(NodeList nl) {
for (int i=0; i<nl.getLength(); i++) {
Element el = (Element)nl.item(i);
if (el.hasAttribute("Id")) {
el.setIdAttribute("Id", true);
}
}
}
@SuppressWarnings("unchecked")
public static <T> List<T> safe(List<T> other) {
return other == null ? Collections.EMPTY_LIST : other;
}
} }

View File

@ -22,8 +22,10 @@ import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID;
import javax.xml.crypto.URIDereferencer; import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.HashAlgorithm;
@ -31,8 +33,8 @@ import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet; import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
import org.apache.poi.poifs.crypt.dsig.facets.Office2010SignatureFacet; import org.apache.poi.poifs.crypt.dsig.facets.Office2010SignatureFacet;
import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet; import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
import org.apache.poi.poifs.crypt.dsig.facets.SignaturePolicyService;
import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet; import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
import org.apache.poi.poifs.crypt.dsig.services.SignaturePolicyService;
import org.apache.poi.poifs.crypt.dsig.spi.AddressDTO; import org.apache.poi.poifs.crypt.dsig.spi.AddressDTO;
import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO; import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO;
@ -48,7 +50,21 @@ public class SignatureInfoConfig {
private AddressDTO address; private AddressDTO address;
private byte[] photo; private byte[] photo;
private SignaturePolicyService signaturePolicyService; private SignaturePolicyService signaturePolicyService;
private URIDereferencer uriDereferencer; private URIDereferencer uriDereferencer;
private String signatureNamespacePrefix;
private String canonicalizationMethod = CanonicalizationMethod.INCLUSIVE;
/**
* The signature Id attribute value used to create the XML signature. A
* <code>null</code> value will trigger an automatically generated signature Id.
*/
private String packageSignatureId = "idPackageSignature";
/**
* Gives back the human-readable description of what the citizen will be
* signing. The default value is "Office OpenXML Document".
*/
private String signatureDescription = "Office OpenXML Document";
public SignatureInfoConfig() { public SignatureInfoConfig() {
OOXMLURIDereferencer uriDereferencer = new OOXMLURIDereferencer(); OOXMLURIDereferencer uriDereferencer = new OOXMLURIDereferencer();
@ -148,8 +164,7 @@ public class SignatureInfoConfig {
public SignaturePolicyService getSignaturePolicyService() { public SignaturePolicyService getSignaturePolicyService() {
return signaturePolicyService; return signaturePolicyService;
} }
public void setSignaturePolicyService( public void setSignaturePolicyService(SignaturePolicyService signaturePolicyService) {
SignaturePolicyService signaturePolicyService) {
this.signaturePolicyService = signaturePolicyService; this.signaturePolicyService = signaturePolicyService;
} }
public URIDereferencer getUriDereferencer() { public URIDereferencer getUriDereferencer() {
@ -158,6 +173,30 @@ public class SignatureInfoConfig {
public void setUriDereferencer(URIDereferencer uriDereferencer) { public void setUriDereferencer(URIDereferencer uriDereferencer) {
this.uriDereferencer = uriDereferencer; this.uriDereferencer = uriDereferencer;
} }
public String getSignatureDescription() {
return signatureDescription;
}
public void setSignatureDescription(String signatureDescription) {
this.signatureDescription = signatureDescription;
}
public String getSignatureNamespacePrefix() {
return signatureNamespacePrefix;
}
public void setSignatureNamespacePrefix(String signatureNamespacePrefix) {
this.signatureNamespacePrefix = signatureNamespacePrefix;
}
public String getCanonicalizationMethod() {
return canonicalizationMethod;
}
public void setCanonicalizationMethod(String canonicalizationMethod) {
this.canonicalizationMethod = canonicalizationMethod;
}
public String getPackageSignatureId() {
return packageSignatureId;
}
public void setPackageSignatureId(String packageSignatureId) {
this.packageSignatureId = (packageSignatureId != null)
? packageSignatureId
: "xmldsig-" + UUID.randomUUID();
}
} }

View File

@ -15,7 +15,7 @@ import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.spec.TransformParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig;
import org.w3c.dom.Document; import org.w3c.dom.Document;
/** /**
@ -26,24 +26,10 @@ import org.w3c.dom.Document;
*/ */
public class EnvelopedSignatureFacet implements SignatureFacet { public class EnvelopedSignatureFacet implements SignatureFacet {
private final HashAlgorithm hashAlgo; private SignatureInfoConfig signatureConfig;
/** public EnvelopedSignatureFacet(SignatureInfoConfig signatureConfig) {
* Default constructor. Digest algorithm will be SHA-1. this.signatureConfig = signatureConfig;
*/
public EnvelopedSignatureFacet() {
this(HashAlgorithm.sha1);
}
/**
* Main constructor.
*
* @param hashAlgo
* the digest algorithm to be used within the ds:Reference
* element. Possible values: "SHA-1", "SHA-256, or "SHA-512".
*/
public EnvelopedSignatureFacet(HashAlgorithm hashAlgo) {
this.hashAlgo = hashAlgo;
} }
@Override @Override
@ -52,14 +38,12 @@ public class EnvelopedSignatureFacet implements SignatureFacet {
} }
@Override @Override
public void preSign(Document document, public void preSign(Document document
XMLSignatureFactory signatureFactory, , XMLSignatureFactory signatureFactory
String signatureId, , List<Reference> references
List<X509Certificate> signingCertificateChain, , List<XMLObject> objects)
List<Reference> references, List<XMLObject> objects) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod(
this.hashAlgo.xmlSignUri, null);
List<Transform> transforms = new ArrayList<Transform>(); List<Transform> transforms = new ArrayList<Transform>();
Transform envelopedTransform = signatureFactory Transform envelopedTransform = signatureFactory

View File

@ -173,12 +173,11 @@ public class KeyInfoSignatureFacet implements SignatureFacet {
} }
@Override @Override
public void preSign(Document document, public void preSign(
XMLSignatureFactory signatureFactory, Document document
String signatureId, , XMLSignatureFactory signatureFactory
List<X509Certificate> signingCertificateChain, , List<Reference> references
List<Reference> references, , List<XMLObject> objects
List<XMLObject> objects
) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
// empty // empty
} }

View File

@ -104,20 +104,20 @@ public class OOXMLSignatureFacet implements SignatureFacet {
} }
@Override @Override
public void preSign(Document document, public void preSign(
XMLSignatureFactory signatureFactory, Document document
String signatureId, , XMLSignatureFactory signatureFactory
List<X509Certificate> signingCertificateChain, , List<Reference> references
List<Reference> references, List<XMLObject> objects) , List<XMLObject> objects)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException, URISyntaxException, XmlException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException, URISyntaxException, XmlException {
LOG.log(POILogger.DEBUG, "pre sign"); LOG.log(POILogger.DEBUG, "pre sign");
addManifestObject(document, signatureFactory, signatureId, references, objects); addManifestObject(document, signatureFactory, references, objects);
addSignatureInfo(document, signatureFactory, signatureId, references, objects); addSignatureInfo(document, signatureFactory, references, objects);
} }
private void addManifestObject(Document document, private void addManifestObject(Document document,
XMLSignatureFactory signatureFactory, XMLSignatureFactory signatureFactory,
String signatureId, List<Reference> references, List<Reference> references,
List<XMLObject> objects) throws NoSuchAlgorithmException, List<XMLObject> objects) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException, IOException, URISyntaxException, XmlException { InvalidAlgorithmParameterException, IOException, URISyntaxException, XmlException {
@ -129,7 +129,7 @@ public class OOXMLSignatureFacet implements SignatureFacet {
List<XMLStructure> objectContent = new ArrayList<XMLStructure>(); List<XMLStructure> objectContent = new ArrayList<XMLStructure>();
objectContent.add(manifest); objectContent.add(manifest);
addSignatureTime(document, signatureFactory, signatureId, objectContent); addSignatureTime(document, signatureFactory, objectContent);
XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null); XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null);
objects.add(xo); objects.add(xo);
@ -225,7 +225,6 @@ public class OOXMLSignatureFacet implements SignatureFacet {
private void addSignatureTime(Document document, private void addSignatureTime(Document document,
XMLSignatureFactory signatureFactory, XMLSignatureFactory signatureFactory,
String signatureId,
List<XMLStructure> objectContent) { List<XMLStructure> objectContent) {
/* /*
* SignatureTime * SignatureTime
@ -247,7 +246,7 @@ public class OOXMLSignatureFacet implements SignatureFacet {
List<XMLStructure> signatureTimeContent = new ArrayList<XMLStructure>(); List<XMLStructure> signatureTimeContent = new ArrayList<XMLStructure>();
signatureTimeContent.add(new DOMStructure(n)); signatureTimeContent.add(new DOMStructure(n));
SignatureProperty signatureTimeSignatureProperty = signatureFactory SignatureProperty signatureTimeSignatureProperty = signatureFactory
.newSignatureProperty(signatureTimeContent, "#" + signatureId, .newSignatureProperty(signatureTimeContent, "#" + signatureConfig.getPackageSignatureId(),
"idSignatureTime"); "idSignatureTime");
List<SignatureProperty> signaturePropertyContent = new ArrayList<SignatureProperty>(); List<SignatureProperty> signaturePropertyContent = new ArrayList<SignatureProperty>();
signaturePropertyContent.add(signatureTimeSignatureProperty); signaturePropertyContent.add(signatureTimeSignatureProperty);
@ -258,10 +257,10 @@ public class OOXMLSignatureFacet implements SignatureFacet {
} }
private void addSignatureInfo(Document document, private void addSignatureInfo(Document document,
XMLSignatureFactory signatureFactory, XMLSignatureFactory signatureFactory,
String signatureId, List<Reference> references, List<Reference> references,
List<XMLObject> objects) throws NoSuchAlgorithmException, List<XMLObject> objects)
InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
List<XMLStructure> objectContent = new ArrayList<XMLStructure>(); List<XMLStructure> objectContent = new ArrayList<XMLStructure>();
SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance(); SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance();
@ -273,7 +272,7 @@ public class OOXMLSignatureFacet implements SignatureFacet {
List<XMLStructure> signatureInfoContent = new ArrayList<XMLStructure>(); List<XMLStructure> signatureInfoContent = new ArrayList<XMLStructure>();
signatureInfoContent.add(new DOMStructure(n)); signatureInfoContent.add(new DOMStructure(n));
SignatureProperty signatureInfoSignatureProperty = signatureFactory SignatureProperty signatureInfoSignatureProperty = signatureFactory
.newSignatureProperty(signatureInfoContent, "#" + signatureId, .newSignatureProperty(signatureInfoContent, "#" + signatureConfig.getPackageSignatureId(),
"idOfficeV1Details"); "idOfficeV1Details");
List<SignatureProperty> signaturePropertyContent = new ArrayList<SignatureProperty>(); List<SignatureProperty> signaturePropertyContent = new ArrayList<SignatureProperty>();

View File

@ -54,12 +54,11 @@ import org.w3c.dom.NodeList;
public class Office2010SignatureFacet implements SignatureFacet { public class Office2010SignatureFacet implements SignatureFacet {
@Override @Override
public void preSign(Document document, public void preSign(
XMLSignatureFactory signatureFactory, Document document
String signatureId, , XMLSignatureFactory signatureFactory
List<X509Certificate> signingCertificateChain, , List<Reference> references
List<Reference> references, , List<XMLObject> objects
List<XMLObject> objects
) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
} }

View File

@ -66,8 +66,6 @@ public interface SignatureFacet {
void preSign( void preSign(
Document document Document document
, XMLSignatureFactory signatureFactory , XMLSignatureFactory signatureFactory
, String signatureId
, List<X509Certificate> signingCertificateChain
, List<Reference> references , List<Reference> references
, List<XMLObject> objects , List<XMLObject> objects
) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException, URISyntaxException, XmlException; ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, IOException, URISyntaxException, XmlException;

View File

@ -53,9 +53,11 @@ import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.crypt.dsig.SignatureInfo; import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig;
import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService; import org.apache.poi.poifs.crypt.dsig.services.SignaturePolicyService;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlString; import org.apache.xmlbeans.XmlString;
import org.etsi.uri.x01903.v13.AnyType; import org.etsi.uri.x01903.v13.AnyType;
import org.etsi.uri.x01903.v13.CertIDListType; import org.etsi.uri.x01903.v13.CertIDListType;
@ -134,8 +136,6 @@ public class XAdESSignatureFacet implements SignatureFacet {
@Override @Override
public void preSign(Document document, public void preSign(Document document,
XMLSignatureFactory signatureFactory, XMLSignatureFactory signatureFactory,
String signatureId,
List<X509Certificate> signingCertificateChain,
List<Reference> references, List<XMLObject> objects) List<Reference> references, List<XMLObject> objects)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
LOG.log(POILogger.DEBUG, "preSign"); LOG.log(POILogger.DEBUG, "preSign");
@ -143,13 +143,13 @@ public class XAdESSignatureFacet implements SignatureFacet {
// QualifyingProperties // QualifyingProperties
QualifyingPropertiesDocument qualDoc = QualifyingPropertiesDocument.Factory.newInstance(); QualifyingPropertiesDocument qualDoc = QualifyingPropertiesDocument.Factory.newInstance();
QualifyingPropertiesType qualifyingProperties = qualDoc.addNewQualifyingProperties(); QualifyingPropertiesType qualifyingProperties = qualDoc.addNewQualifyingProperties();
qualifyingProperties.setTarget("#" + signatureId); qualifyingProperties.setTarget("#" + signatureConfig.getPackageSignatureId());
// SignedProperties // SignedProperties
SignedPropertiesType signedProperties = qualifyingProperties.addNewSignedProperties(); SignedPropertiesType signedProperties = qualifyingProperties.addNewSignedProperties();
String signedPropertiesId = this.idSignedProperties; String signedPropertiesId = this.idSignedProperties;
if (this.idSignedProperties == null) { if (this.idSignedProperties == null) {
signedPropertiesId = signatureId + "-xades"; signedPropertiesId = signatureConfig.getPackageSignatureId() + "-xades";
} }
signedProperties.setId(signedPropertiesId); signedProperties.setId(signedPropertiesId);
@ -164,13 +164,13 @@ public class XAdESSignatureFacet implements SignatureFacet {
signedSignatureProperties.setSigningTime(xmlGregorianCalendar); signedSignatureProperties.setSigningTime(xmlGregorianCalendar);
// SigningCertificate // SigningCertificate
if (null == signingCertificateChain if (signatureConfig.getSigningCertificateChain() == null
|| signingCertificateChain.isEmpty()) { || signatureConfig.getSigningCertificateChain().isEmpty()) {
throw new RuntimeException("no signing certificate chain available"); throw new RuntimeException("no signing certificate chain available");
} }
CertIDListType signingCertificates = signedSignatureProperties.addNewSigningCertificate(); CertIDListType signingCertificates = signedSignatureProperties.addNewSigningCertificate();
CertIDType certId = signingCertificates.addNewCert(); CertIDType certId = signingCertificates.addNewCert();
X509Certificate signingCertificate = signingCertificateChain.get(0); X509Certificate signingCertificate = signatureConfig.getSigningCertificateChain().get(0);
setCertID(certId, signingCertificate, this.signatureConfig.getDigestAlgo(), this.issuerNameNoReverseOrder); setCertID(certId, signingCertificate, this.signatureConfig.getDigestAlgo(), this.issuerNameNoReverseOrder);
// ClaimedRole // ClaimedRole
@ -181,7 +181,7 @@ public class XAdESSignatureFacet implements SignatureFacet {
AnyType claimedRole = claimedRolesList.addNewClaimedRole(); AnyType claimedRole = claimedRolesList.addNewClaimedRole();
XmlString roleString = XmlString.Factory.newInstance(); XmlString roleString = XmlString.Factory.newInstance();
roleString.setStringValue(this.role); roleString.setStringValue(this.role);
SignatureInfo.insertXChild(claimedRole, roleString); insertXChild(claimedRole, roleString);
} }
// XAdES-EPES // XAdES-EPES
@ -208,7 +208,7 @@ public class XAdESSignatureFacet implements SignatureFacet {
AnyType sigPolicyQualifier = sigPolicyQualifiers.addNewSigPolicyQualifier(); AnyType sigPolicyQualifier = sigPolicyQualifiers.addNewSigPolicyQualifier();
XmlString spUriElement = XmlString.Factory.newInstance(); XmlString spUriElement = XmlString.Factory.newInstance();
spUriElement.setStringValue(signaturePolicyDownloadUrl); spUriElement.setStringValue(signaturePolicyDownloadUrl);
SignatureInfo.insertXChild(sigPolicyQualifier, spUriElement); insertXChild(sigPolicyQualifier, spUriElement);
} }
} else if (this.signaturePolicyImplied) { } else if (this.signaturePolicyImplied) {
SignaturePolicyIdentifierType signaturePolicyIdentifier = SignaturePolicyIdentifierType signaturePolicyIdentifier =
@ -238,7 +238,7 @@ public class XAdESSignatureFacet implements SignatureFacet {
// add XAdES ds:Object // add XAdES ds:Object
List<XMLStructure> xadesObjectContent = new ArrayList<XMLStructure>(); List<XMLStructure> xadesObjectContent = new ArrayList<XMLStructure>();
Element qualDocEl = (Element)document.importNode(qualifyingProperties.getDomNode(), true); Element qualDocEl = (Element)document.importNode(qualifyingProperties.getDomNode(), true);
XmlSignatureService.registerIdAttribute(qualDocEl.getElementsByTagName("SignedProperties")); SignatureInfo.registerIdAttribute(qualDocEl.getElementsByTagName("SignedProperties"));
qualDocEl.setAttributeNS(XmlNS, "xmlns:xd", "http://uri.etsi.org/01903/v1.3.2#"); qualDocEl.setAttributeNS(XmlNS, "xmlns:xd", "http://uri.etsi.org/01903/v1.3.2#");
setPrefix(qualDocEl, "http://uri.etsi.org/01903/v1.3.2#", "xd"); setPrefix(qualDocEl, "http://uri.etsi.org/01903/v1.3.2#", "xd");
xadesObjectContent.add(new DOMStructure(qualDocEl)); xadesObjectContent.add(new DOMStructure(qualDocEl));
@ -376,4 +376,14 @@ public class XAdESSignatureFacet implements SignatureFacet {
return map; return map;
} }
protected static void insertXChild(XmlObject root, XmlObject child) {
XmlCursor rootCursor = root.newCursor();
rootCursor.toEndToken();
XmlCursor childCursor = child.newCursor();
childCursor.toNextToken();
childCursor.moveXml(rootCursor);
childCursor.dispose();
rootCursor.dispose();
}
} }

View File

@ -25,6 +25,7 @@
package org.apache.poi.poifs.crypt.dsig.facets; package org.apache.poi.poifs.crypt.dsig.facets;
import static org.apache.poi.poifs.crypt.dsig.SignatureInfo.XmlDSigNS; import static org.apache.poi.poifs.crypt.dsig.SignatureInfo.XmlDSigNS;
import static org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet.insertXChild;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -50,7 +51,6 @@ import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.XMLSignatureFactory;
import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
import org.apache.poi.poifs.crypt.dsig.services.RevocationData; import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService; import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService; import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
@ -221,7 +221,7 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
// xadesv141::TimeStampValidationData // xadesv141::TimeStampValidationData
if (tsaRevocationDataXadesT.hasRevocationDataEntries()) { if (tsaRevocationDataXadesT.hasRevocationDataEntries()) {
ValidationDataType validationData = createValidationData(tsaRevocationDataXadesT); ValidationDataType validationData = createValidationData(tsaRevocationDataXadesT);
SignatureInfo.insertXChild(unsignedSigProps, validationData); insertXChild(unsignedSigProps, validationData);
} }
if (null == this.revocationDataService) { if (null == this.revocationDataService) {
@ -334,7 +334,7 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
this.c14nAlgoId, this.timeStampService); this.c14nAlgoId, this.timeStampService);
if (tsaRevocationDataXadesX1.hasRevocationDataEntries()) { if (tsaRevocationDataXadesX1.hasRevocationDataEntries()) {
ValidationDataType timeStampXadesX1ValidationData = createValidationData(tsaRevocationDataXadesX1); ValidationDataType timeStampXadesX1ValidationData = createValidationData(tsaRevocationDataXadesX1);
SignatureInfo.insertXChild(unsignedSigProps, timeStampXadesX1ValidationData); insertXChild(unsignedSigProps, timeStampXadesX1ValidationData);
} }
// marshal XAdES-X // marshal XAdES-X
@ -381,8 +381,6 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
@Override @Override
public void preSign(Document document, public void preSign(Document document,
XMLSignatureFactory signatureFactory, XMLSignatureFactory signatureFactory,
String signatureId,
List<X509Certificate> signingCertificateChain,
List<Reference> references, List<XMLObject> objects) List<Reference> references, List<XMLObject> objects)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
// nothing to do here // nothing to do here

View File

@ -22,7 +22,7 @@
Copyright (C) 2008-2014 FedICT. Copyright (C) 2008-2014 FedICT.
================================================================= */ ================================================================= */
package org.apache.poi.poifs.crypt.dsig.facets; package org.apache.poi.poifs.crypt.dsig.services;
/** /**
* Interface for the signature policy service. * Interface for the signature policy service.

View File

@ -1,68 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
/* ====================================================================
This product contains an ASLv2 licensed version of the OOXML signer
package from the eID Applet project
http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
Copyright (C) 2008-2014 FedICT.
================================================================= */
package org.apache.poi.poifs.crypt.dsig.services;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.xml.crypto.MarshalException;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo;
import org.apache.xmlbeans.XmlException;
import org.w3c.dom.Document;
/**
* Interface for signature service component.
*
* @author Frank Cornelis
*
*/
public interface SignatureService {
/**
* Pre-sign callback method. Depending on the configuration some parameters
* are passed. The returned value will be signed by the eID Applet.
*
* @param digestInfos
* the optional list of digest infos.
* @return the digest to be signed.
* @throws NoSuchAlgorithmException
*/
DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
throws NoSuchAlgorithmException;
/**
* Post-sign callback method. Received the signature value. Depending on the
* configuration the signing certificate chain is also obtained.
*
* @param signatureValue
* @param signingCertificateChain
* the optional chain of signing certificates.
*/
void postSign(Document document, byte[] signatureValue)
throws IOException, MarshalException, ParserConfigurationException, XmlException;
}

View File

@ -1,481 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
/* ====================================================================
This product contains an ASLv2 licensed version of the OOXML signer
package from the eID Applet project
http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
Copyright (C) 2008-2014 FedICT.
================================================================= */
package org.apache.poi.poifs.crypt.dsig.services;
import static org.apache.poi.poifs.crypt.dsig.SignatureInfo.XmlDSigNS;
import static org.apache.poi.poifs.crypt.dsig.SignatureInfo.XmlNS;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.security.InvalidAlgorithmParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Manifest;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignContext;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.apache.jcp.xml.dsig.internal.dom.DOMReference;
import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageNamespaces;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig;
import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.Base64;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.w3.x2000.x09.xmldsig.SignatureDocument;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.events.MutationEvent;
import org.xml.sax.SAXException;
/**
* Abstract base class for an XML Signature Service implementation.
*/
public class XmlSignatureService implements SignatureService {
private static final POILogger LOG = POILogFactory.getLogger(XmlSignatureService.class);
protected SignatureInfoConfig signatureConfig;
private String signatureNamespacePrefix;
private String signatureId = "idPackageSignature";
/**
* Main constructor.
*/
public XmlSignatureService(SignatureInfoConfig signatureConfig) {
this.signatureNamespacePrefix = null;
this.signatureConfig = signatureConfig;
}
public SignatureInfoConfig getSignatureConfig() {
return signatureConfig;
}
/**
* Sets the signature Id attribute value used to create the XML signature. A
* <code>null</code> value will trigger an automatically generated signature
* Id.
*
* @param signatureId
*/
protected void setSignatureId(String signatureId) {
this.signatureId = signatureId;
}
/**
* Sets the XML Signature namespace prefix to be used for signature
* creation. A <code>null</code> value will omit the prefixing.
*
* @param signatureNamespacePrefix
*/
protected void setSignatureNamespacePrefix(String signatureNamespacePrefix) {
this.signatureNamespacePrefix = signatureNamespacePrefix;
}
/**
* Gives back the human-readable description of what the citizen will be
* signing. The default value is "XML Document". Override this method to
* provide the citizen with another description.
*
* @return
*/
protected String getSignatureDescription() {
return "Office OpenXML Document";
}
/**
* Gives back the output stream to which to write the signed XML document.
*
* @return
*/
// protected abstract OutputStream getSignedDocumentOutputStream();
@Override
public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
throws NoSuchAlgorithmException {
SignatureInfo.initXmlProvider();
LOG.log(POILogger.DEBUG, "preSign");
HashAlgorithm hashAlgo = this.signatureConfig.getDigestAlgo();
byte[] digestValue;
try {
digestValue = getXmlSignatureDigestValue(document, digestInfos);
} catch (Exception e) {
throw new RuntimeException("XML signature error: " + e.getMessage(), e);
}
String description = getSignatureDescription();
return new DigestInfo(digestValue, hashAlgo, description);
}
@Override
public void postSign(Document document, byte[] signatureValue)
throws IOException, MarshalException, ParserConfigurationException, XmlException {
LOG.log(POILogger.DEBUG, "postSign");
SignatureInfo.initXmlProvider();
/*
* Check ds:Signature node.
*/
if (!signatureId.equals(document.getDocumentElement().getAttribute("Id"))) {
throw new RuntimeException("ds:Signature not found for @Id: " + signatureId);
}
/*
* Insert signature value into the ds:SignatureValue element
*/
NodeList sigValNl = document.getElementsByTagNameNS(XmlDSigNS, "SignatureValue");
if (sigValNl.getLength() != 1) {
throw new RuntimeException("preSign has to be called before postSign");
}
sigValNl.item(0).setTextContent(Base64.encode(signatureValue));
/*
* Allow signature facets to inject their own stuff.
*/
for (SignatureFacet signatureFacet : this.signatureConfig.getSignatureFacets()) {
signatureFacet.postSign(document, this.signatureConfig.getSigningCertificateChain());
}
registerIds(document);
writeDocument(document);
}
@SuppressWarnings("unchecked")
private byte[] getXmlSignatureDigestValue(Document document, List<DigestInfo> digestInfos)
throws ParserConfigurationException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, MarshalException,
javax.xml.crypto.dsig.XMLSignatureException,
TransformerFactoryConfigurationError, TransformerException,
IOException, SAXException, NoSuchProviderException, XmlException, URISyntaxException {
// 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 ...
final EventTarget et = (EventTarget)document;
EventListener myModificationListener = new EventListener() {
@Override
public void handleEvent(Event e) {
if (e instanceof MutationEvent) {
MutationEvent mutEvt = (MutationEvent)e;
if (mutEvt.getTarget() instanceof Element) {
Element el = (Element)mutEvt.getTarget();
if ("idPackageObject".equals(el.getAttribute("Id"))) {
et.removeEventListener("DOMSubtreeModified", this, false);
el.setAttributeNS(XmlNS, "xmlns:mdssi", PackageNamespaces.DIGITAL_SIGNATURE);
}
}
}
}
};
et.addEventListener("DOMSubtreeModified", myModificationListener, false);
/*
* Signature context construction.
*/
XMLSignContext xmlSignContext = new DOMSignContext(this.signatureConfig.getKey(), document);
URIDereferencer uriDereferencer = this.signatureConfig.getUriDereferencer();
if (null != uriDereferencer) {
xmlSignContext.setURIDereferencer(uriDereferencer);
}
xmlSignContext.putNamespacePrefix(
"http://schemas.openxmlformats.org/package/2006/digital-signature",
"mdssi");
if (this.signatureNamespacePrefix != null) {
/*
* OOo doesn't like ds namespaces so per default prefixing is off.
*/
xmlSignContext.putNamespacePrefix(XmlDSigNS, this.signatureNamespacePrefix);
}
XMLSignatureFactory signatureFactory = SignatureInfo.getSignatureFactory();
/*
* Add ds:References that come from signing client local files.
*/
List<Reference> references = new ArrayList<Reference>();
addDigestInfosAsReferences(digestInfos, signatureFactory, references);
/*
* Invoke the signature facets.
*/
String localSignatureId = this.signatureId;
if (localSignatureId == null) {
localSignatureId = "xmldsig-" + UUID.randomUUID().toString();
}
List<XMLObject> objects = new ArrayList<XMLObject>();
for (SignatureFacet signatureFacet : this.signatureConfig.getSignatureFacets()) {
LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());
signatureFacet.preSign(document, signatureFactory, localSignatureId, this.signatureConfig.getSigningCertificateChain(), references, objects);
}
/*
* ds:SignedInfo
*/
SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(this.signatureConfig.getDigestAlgo()), null);
CanonicalizationMethod canonicalizationMethod = signatureFactory
.newCanonicalizationMethod(getCanonicalizationMethod(),
(C14NMethodParameterSpec) null);
SignedInfo signedInfo = signatureFactory.newSignedInfo(
canonicalizationMethod, signatureMethod, references);
/*
* JSR105 ds:Signature creation
*/
String signatureValueId = localSignatureId + "-signature-value";
javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory
.newXMLSignature(signedInfo, null, objects, localSignatureId,
signatureValueId);
/*
* ds:Signature Marshalling.
*/
xmlSignContext.setDefaultNamespacePrefix(this.signatureNamespacePrefix);
// xmlSignContext.putNamespacePrefix(PackageNamespaces.DIGITAL_SIGNATURE, "mdssi");
xmlSignature.sign(xmlSignContext);
registerIds(document);
/*
* 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 jcaMessageDigest = CryptoFunctions.getMessageDigest(this.signatureConfig.getDigestAlgo());
byte[] digestValue = jcaMessageDigest.digest(octets);
return digestValue;
}
/**
* the resulting document needs to be tweaked before it can be digested -
* this applies to the verification and signing step
*
* @param doc
*/
public static void registerIds(Document doc) {
NodeList nl = doc.getElementsByTagNameNS(XmlDSigNS, "Object");
registerIdAttribute(nl);
nl = doc.getElementsByTagNameNS("http://uri.etsi.org/01903/v1.3.2#", "SignedProperties");
registerIdAttribute(nl);
}
public static void registerIdAttribute(NodeList nl) {
for (int i=0; i<nl.getLength(); i++) {
Element el = (Element)nl.item(i);
if (el.hasAttribute("Id")) {
el.setIdAttribute("Id", true);
}
}
}
private void addDigestInfosAsReferences(List<DigestInfo> digestInfos, XMLSignatureFactory signatureFactory, List<Reference> references)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, MalformedURLException {
for (DigestInfo digestInfo : safe(digestInfos)) {
byte[] documentDigestValue = digestInfo.digestValue;
DigestMethod digestMethod = signatureFactory.newDigestMethod(
digestInfo.hashAlgo.xmlSignUri, null);
String uri = new File(digestInfo.description).getName();
Reference reference = signatureFactory.newReference(uri,
digestMethod, null, null, null, documentDigestValue);
references.add(reference);
}
}
private String getSignatureMethod(HashAlgorithm hashAlgo) {
if (null == hashAlgo) {
throw new RuntimeException("digest algo is null");
}
switch (hashAlgo) {
case sha1: return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
case sha256: return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;
case sha384: return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;
case sha512: return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;
case ripemd160: return XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;
default: break;
}
throw new RuntimeException("unsupported sign algo: " + hashAlgo);
}
protected String getCanonicalizationMethod() {
return CanonicalizationMethod.INCLUSIVE;
}
protected void writeDocument(Document document) throws IOException, XmlException {
XmlOptions xo = new XmlOptions();
Map<String,String> namespaceMap = new HashMap<String,String>();
for (SignatureFacet sf : this.signatureConfig.getSignatureFacets()) {
Map<String,String> sfm = sf.getNamespacePrefixMapping();
if (sfm != null) {
namespaceMap.putAll(sfm);
}
}
xo.setSaveSuggestedPrefixes(namespaceMap);
xo.setUseDefaultNamespace();
LOG.log(POILogger.DEBUG, "output signed Office OpenXML document");
/*
* Copy the original OOXML content to the signed OOXML package. During
* copying some files need to changed.
*/
OPCPackage pkg = this.signatureConfig.getOpcPackage();
PackagePartName sigPartName, sigsPartName;
try {
// <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
sigPartName = PackagingURIHelper.createPartName("/_xmlsignatures/sig1.xml");
// <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/>
sigsPartName = PackagingURIHelper.createPartName("/_xmlsignatures/origin.sigs");
} catch (InvalidFormatException e) {
throw new IOException(e);
}
String sigContentType = "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml";
PackagePart sigPart = pkg.getPart(sigPartName);
if (sigPart == null) {
sigPart = pkg.createPart(sigPartName, sigContentType);
}
OutputStream os = sigPart.getOutputStream();
SignatureDocument sigDoc = SignatureDocument.Factory.parse(document);
sigDoc.save(os, xo);
os.close();
String sigsContentType = "application/vnd.openxmlformats-package.digital-signature-origin";
PackagePart sigsPart = pkg.getPart(sigsPartName);
if (sigsPart == null) {
// touch empty marker file
sigsPart = pkg.createPart(sigsPartName, sigsContentType);
}
PackageRelationshipCollection relCol = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
for (PackageRelationship pr : relCol) {
pkg.removeRelationship(pr.getId());
}
pkg.addRelationship(sigsPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
sigsPart.addRelationship(sigPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE);
}
@SuppressWarnings("unchecked")
public static <T> List<T> safe(List<T> other) {
return other == null ? Collections.EMPTY_LIST : other;
}
}

View File

@ -67,7 +67,6 @@ import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
import org.apache.poi.poifs.crypt.dsig.services.TSPTimeStampService; import org.apache.poi.poifs.crypt.dsig.services.TSPTimeStampService;
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService; import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator; import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService;
import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo;
import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.DocumentHelper;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
@ -120,7 +119,10 @@ public class TestSignatureInfo {
for (String testFile : testFiles) { for (String testFile : testFiles) {
OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ); OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ);
SignatureInfo si = new SignatureInfo(pkg); SignatureInfoConfig sic = new SignatureInfoConfig();
sic.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(sic);
List<X509Certificate> result = si.getSigners(); List<X509Certificate> result = si.getSigners();
pkg.revert(); pkg.revert();
pkg.close(); pkg.close();
@ -146,7 +148,10 @@ public class TestSignatureInfo {
for (String testFile : testFiles) { for (String testFile : testFiles) {
OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ); OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ);
SignatureInfo si = new SignatureInfo(pkg); SignatureInfoConfig sic = new SignatureInfoConfig();
sic.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(sic);
List<X509Certificate> result = si.getSigners(); List<X509Certificate> result = si.getSigners();
assertNotNull(result); assertNotNull(result);
@ -164,7 +169,10 @@ public class TestSignatureInfo {
public void getMultiSigners() throws Exception { public void getMultiSigners() throws Exception {
String testFile = "hello-world-signed-twice.docx"; String testFile = "hello-world-signed-twice.docx";
OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ); OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ);
SignatureInfo si = new SignatureInfo(pkg); SignatureInfoConfig sic = new SignatureInfoConfig();
sic.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(sic);
List<X509Certificate> result = si.getSigners(); List<X509Certificate> result = si.getSigners();
assertNotNull(result); assertNotNull(result);
@ -189,12 +197,18 @@ public class TestSignatureInfo {
@Test @Test
public void testSignSpreadsheetWithSignatureInfo() throws Exception { public void testSignSpreadsheetWithSignatureInfo() throws Exception {
initKeyPair("Test", "CN=Test");
String testFile = "hello-world-unsigned.xlsx"; String testFile = "hello-world-unsigned.xlsx";
OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE); OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
SignatureInfo si = new SignatureInfo(pkg); SignatureInfoConfig sic = new SignatureInfoConfig();
initKeyPair("Test", "CN=Test"); sic.setOpcPackage(pkg);
sic.setKey(keyPair.getPrivate());
sic.setSigningCertificateChain(Collections.singletonList(x509));
sic.addDefaultFacets();
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(sic);
// hash > sha1 doesn't work in excel viewer ... // hash > sha1 doesn't work in excel viewer ...
si.confirmSignature(keyPair.getPrivate(), x509, HashAlgorithm.sha1); si.confirmSignature();
List<X509Certificate> signer = si.getSigners(); List<X509Certificate> signer = si.getSigners();
assertEquals(1, signer.size()); assertEquals(1, signer.size());
pkg.close(); pkg.close();
@ -223,7 +237,7 @@ public class TestSignatureInfo {
certificateChain.add(x509); certificateChain.add(x509);
signatureConfig.setSigningCertificateChain(certificateChain); signatureConfig.setSigningCertificateChain(certificateChain);
signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet()); signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet(signatureConfig));
signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet(true, false, false)); signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet(true, false, false));
signatureConfig.addSignatureFacet(new XAdESSignatureFacet(signatureConfig)); signatureConfig.addSignatureFacet(new XAdESSignatureFacet(signatureConfig));
@ -274,12 +288,13 @@ public class TestSignatureInfo {
XAdESXLSignatureFacet xadesXLSignatureFacet = new XAdESXLSignatureFacet( XAdESXLSignatureFacet xadesXLSignatureFacet = new XAdESXLSignatureFacet(
timeStampService, revocationDataService); timeStampService, revocationDataService);
XmlSignatureService testedInstance = new XmlSignatureService(signatureConfig); SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
Document document = DocumentHelper.createDocument(); Document document = DocumentHelper.createDocument();
// operate // operate
DigestInfo digestInfo = testedInstance.preSign(document, null); DigestInfo digestInfo = si.preSign(document, null);
// verify // verify
assertNotNull(digestInfo); assertNotNull(digestInfo);
@ -297,10 +312,10 @@ public class TestSignatureInfo {
assertNotNull(certDigest.getDigestValue()); assertNotNull(certDigest.getDigestValue());
// Sign the received XML signature digest value. // Sign the received XML signature digest value.
byte[] signatureValue = SignatureInfo.signDigest(keyPair.getPrivate(), HashAlgorithm.sha1, digestInfo.digestValue); byte[] signatureValue = si.signDigest(digestInfo.digestValue);
// Operate: postSign // Operate: postSign
testedInstance.postSign(document, signatureValue); si.postSign(document, signatureValue);
DOMValidateContext domValidateContext = new DOMValidateContext( DOMValidateContext domValidateContext = new DOMValidateContext(
KeySelector.singletonKeySelector(keyPair.getPublic()), KeySelector.singletonKeySelector(keyPair.getPublic()),
@ -341,12 +356,13 @@ public class TestSignatureInfo {
signatureConfig.setOpcPackage(pkgCopy); signatureConfig.setOpcPackage(pkgCopy);
signatureConfig.addDefaultFacets(); signatureConfig.addDefaultFacets();
XmlSignatureService signatureService = new XmlSignatureService(signatureConfig); SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
Document document = DocumentHelper.createDocument(); Document document = DocumentHelper.createDocument();
// operate // operate
DigestInfo digestInfo = signatureService.preSign(document, null); DigestInfo digestInfo = si.preSign(document, null);
// verify // verify
assertNotNull(digestInfo); assertNotNull(digestInfo);
@ -357,13 +373,13 @@ public class TestSignatureInfo {
assertNotNull(digestInfo.digestValue); assertNotNull(digestInfo.digestValue);
// setup: key material, signature value // setup: key material, signature value
byte[] signatureValue = SignatureInfo.signDigest(keyPair.getPrivate(), HashAlgorithm.sha1, digestInfo.digestValue); byte[] signatureValue = si.signDigest(digestInfo.digestValue);
// operate: postSign // operate: postSign
signatureService.postSign(document, signatureValue); si.postSign(document, signatureValue);
// verify: signature // verify: signature
SignatureInfo si = new SignatureInfo(pkgCopy); si.getSignatureConfig().setOpcPackage(pkgCopy);
List<X509Certificate> signers = si.getSigners(); List<X509Certificate> signers = si.getSigners();
assertEquals(signerCount, signers.size()); assertEquals(signerCount, signers.size());