You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2014/08/10 20:25:12 UTC
svn commit: r1617141 [2/5] - in /poi/branches/xml_signature: ./
src/java/org/apache/poi/poifs/crypt/
src/ooxml/java/org/apache/poi/openxml4j/opc/
src/ooxml/java/org/apache/poi/openxml4j/opc/internal/
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/ src/...
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,194 @@
+/* ====================================================================
+ 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.facets;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.Key;
+import java.security.KeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.dom.DOMCryptoContext;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.dom.DOMSignContext;
+import javax.xml.crypto.dsig.keyinfo.KeyInfo;
+import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
+import javax.xml.crypto.dsig.keyinfo.KeyValue;
+import javax.xml.crypto.dsig.keyinfo.X509Data;
+
+import org.apache.poi.poifs.crypt.dsig.HorribleProxy;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DOMKeyInfoIf;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.w3.x2000.x09.xmldsig.ObjectType;
+import org.w3.x2000.x09.xmldsig.SignatureType;
+import org.w3c.dom.Node;
+
+/**
+ * Signature Facet implementation that adds ds:KeyInfo to the XML signature.
+ *
+ * @author Frank Cornelis
+ *
+ */
+public class KeyInfoSignatureFacet implements SignatureFacet {
+
+ private static final POILogger LOG = POILogFactory.getLogger(KeyInfoSignatureFacet.class);
+
+ private final boolean includeEntireCertificateChain;
+
+ private final boolean includeIssuerSerial;
+
+ private final boolean includeKeyValue;
+
+ /**
+ * Main constructor.
+ *
+ * @param includeEntireCertificateChain
+ * @param includeIssuerSerial
+ * @param includeKeyValue
+ */
+ public KeyInfoSignatureFacet(boolean includeEntireCertificateChain,
+ boolean includeIssuerSerial, boolean includeKeyValue) {
+ this.includeEntireCertificateChain = includeEntireCertificateChain;
+ this.includeIssuerSerial = includeIssuerSerial;
+ this.includeKeyValue = includeKeyValue;
+ }
+
+ public void postSign(SignatureType signatureElement,
+ List<X509Certificate> signingCertificateChain) {
+ LOG.log(POILogger.DEBUG, "postSign");
+
+ List<ObjectType> objList = signatureElement.getObjectList();
+
+ /*
+ * Make sure we insert right after the ds:SignatureValue element, just
+ * before the first ds:Object element.
+ */
+ Node nextSibling = (objList.isEmpty()) ? null : objList.get(0).getDomNode();
+
+ /*
+ * Construct the ds:KeyInfo element using JSR 105.
+ */
+ String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
+ Provider xmlDSigProv;
+ try {
+ xmlDSigProv = (Provider) Class.forName(providerName).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!", e);
+ }
+
+ KeyInfoFactory keyInfoFactory = KeyInfoFactory.getInstance("DOM", xmlDSigProv);
+ List<Object> x509DataObjects = new LinkedList<Object>();
+ X509Certificate signingCertificate = signingCertificateChain.get(0);
+
+ List<Object> keyInfoContent = new LinkedList<Object>();
+
+ if (this.includeKeyValue) {
+ KeyValue keyValue;
+ try {
+ keyValue = keyInfoFactory.newKeyValue(signingCertificate.getPublicKey());
+ } catch (KeyException e) {
+ throw new RuntimeException("key exception: " + e.getMessage(), e);
+ }
+ keyInfoContent.add(keyValue);
+ }
+
+ if (this.includeIssuerSerial) {
+ x509DataObjects.add(keyInfoFactory.newX509IssuerSerial(
+ signingCertificate.getIssuerX500Principal().toString(),
+ signingCertificate.getSerialNumber()));
+ }
+
+ if (this.includeEntireCertificateChain) {
+ for (X509Certificate certificate : signingCertificateChain) {
+ x509DataObjects.add(certificate);
+ }
+ } else {
+ x509DataObjects.add(signingCertificate);
+ }
+
+ if (false == x509DataObjects.isEmpty()) {
+ X509Data x509Data = keyInfoFactory.newX509Data(x509DataObjects);
+ keyInfoContent.add(x509Data);
+ }
+ KeyInfo keyInfo = keyInfoFactory.newKeyInfo(keyInfoContent);
+ DOMKeyInfoIf domKeyInfo;
+ try {
+ domKeyInfo = HorribleProxy.newProxy(DOMKeyInfoIf.class, keyInfo);
+ } catch (Exception e) {
+ throw new RuntimeException("DOMKeyInfo instance error: " + e.getMessage(), e);
+ }
+
+ Key key = new Key() {
+ private static final long serialVersionUID = 1L;
+
+ public String getAlgorithm() {
+ return null;
+ }
+
+ public byte[] getEncoded() {
+ return null;
+ }
+
+ public String getFormat() {
+ return null;
+ }
+ };
+
+ DOMSignContext domSignContext = new DOMSignContext(key, signatureElement.getDomNode());
+ DOMCryptoContext domCryptoContext = domSignContext;
+ String signatureNamespacePrefix = "xd";
+ try {
+ domKeyInfo.marshal(signatureElement.getDomNode(), nextSibling,
+ signatureNamespacePrefix, domCryptoContext);
+ } catch (MarshalException e) {
+ throw new RuntimeException("marshall error: " + e.getMessage(), e);
+ }
+ }
+
+ public void preSign(XMLSignatureFactory signatureFactory,
+ String signatureId,
+ List<X509Certificate> signingCertificateChain,
+ List<Reference> references,
+ List<XMLObject> objects
+ ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ // empty
+ }
+
+ public Map<String,String> getNamespacePrefixMapping() {
+ Map<String,String> map = new HashMap<String,String>();
+ // map.put("xd", "http://www.w3.org/2000/09/xmldsig#");
+ return map;
+ }
+
+}
\ No newline at end of file
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,541 @@
+/* ====================================================================
+ 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.facets;
+
+import static org.apache.poi.poifs.crypt.dsig.SignatureInfo.setPrefix;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import javax.xml.crypto.XMLStructure;
+import javax.xml.crypto.dom.DOMStructure;
+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.SignatureProperties;
+import javax.xml.crypto.dsig.SignatureProperty;
+import javax.xml.crypto.dsig.Transform;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.spec.TransformParameterSpec;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.ContentTypes;
+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.PackagingURIHelper;
+import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
+import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService.RelationshipTransformParameterSpec;
+import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService;
+import org.apache.poi.poifs.crypt.dsig.spi.Constants;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.xmlbeans.XmlException;
+import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.CTSignatureTime;
+import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.SignatureTimeDocument;
+import org.w3.x2000.x09.xmldsig.SignatureType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.microsoft.schemas.office.x2006.digsig.CTSignatureInfoV1;
+import com.microsoft.schemas.office.x2006.digsig.SignatureInfoV1Document;
+
+/**
+ * Office OpenXML Signature Facet implementation.
+ *
+ * @author fcorneli
+ * @see http://msdn.microsoft.com/en-us/library/cc313071.aspx
+ */
+public class OOXMLSignatureFacet implements SignatureFacet {
+
+ private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class);
+
+ public static final String OOXML_DIGSIG_NS = "http://schemas.openxmlformats.org/package/2006/digital-signature";
+ public static final String OFFICE_DIGSIG_NS = "http://schemas.microsoft.com/office/2006/digsig";
+
+ private final XmlSignatureService signatureService;
+
+ private final Date clock;
+
+ private final HashAlgorithm hashAlgo;
+
+ /**
+ * Main constructor.
+ */
+ public OOXMLSignatureFacet(XmlSignatureService signatureService, Date clock, HashAlgorithm hashAlgo) {
+ this.signatureService = signatureService;
+ this.clock = (clock == null ? new Date() : clock);
+ this.hashAlgo = (hashAlgo == null ? HashAlgorithm.sha1 : hashAlgo);
+ }
+
+ public void preSign(XMLSignatureFactory signatureFactory,
+ String signatureId,
+ List<X509Certificate> signingCertificateChain,
+ List<Reference> references, List<XMLObject> objects)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ LOG.log(POILogger.DEBUG, "pre sign");
+ addManifestObject(signatureFactory, signatureId, references, objects);
+ addSignatureInfo(signatureFactory, signatureId, references, objects);
+ }
+
+ private void addManifestObject(XMLSignatureFactory signatureFactory,
+ String signatureId, List<Reference> references,
+ List<XMLObject> objects) throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException {
+ Manifest manifest = constructManifest(signatureFactory);
+ String objectId = "idPackageObject"; // really has to be this value.
+ List<XMLStructure> objectContent = new LinkedList<XMLStructure>();
+ objectContent.add(manifest);
+
+ addSignatureTime(signatureFactory, signatureId, objectContent);
+
+ objects.add(signatureFactory.newXMLObject(objectContent, objectId,
+ null, null));
+
+ DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null);
+ Reference reference = signatureFactory.newReference("#" + objectId,
+ digestMethod, null, "http://www.w3.org/2000/09/xmldsig#Object",
+ null);
+ references.add(reference);
+ }
+
+ private Manifest constructManifest(XMLSignatureFactory signatureFactory)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ List<Reference> manifestReferences = new ArrayList<Reference>();
+
+ try {
+ addManifestReferences(signatureFactory, manifestReferences);
+ } catch (Exception e) {
+ throw new RuntimeException("error: " + e.getMessage(), e);
+ }
+
+ return signatureFactory.newManifest(manifestReferences);
+ }
+
+ private void addManifestReferences(XMLSignatureFactory signatureFactory, List<Reference> manifestReferences)
+ throws IOException, NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException, URISyntaxException, XmlException {
+
+ OPCPackage ooxml = this.signatureService.getOfficeOpenXMLDocument();
+ List<PackagePart> relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART);
+
+
+ DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null);
+ Set<String> digestedPartNames = new HashSet<String>();
+ for (PackagePart pp : relsEntryNames) {
+ String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");
+
+ PackageRelationshipCollection prc;
+ try {
+ prc = new PackageRelationshipCollection(ooxml);
+ prc.parseRelationshipsPart(pp);
+ } catch (InvalidFormatException e) {
+ throw new IOException("Invalid relationship descriptor: "+pp.getPartName().getName(), e);
+ }
+
+ RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec();
+ for (PackageRelationship relationship : prc) {
+ String relationshipType = relationship.getRelationshipType();
+
+ if (TargetMode.EXTERNAL == relationship.getTargetMode()) {
+ /*
+ * ECMA-376 Part 2 - 3rd edition
+ * 13.2.4.16 Manifest Element
+ * "The producer shall not create a Manifest element that references any data outside of the package."
+ */
+ continue;
+ }
+
+ if (!isSignedRelationship(relationshipType)) continue;
+
+ parameterSpec.addRelationshipReference(relationship.getId());
+
+ // TODO: find a better way ...
+ String partName = baseUri + relationship.getTargetURI().toString();
+ partName = new URI(partName).normalize().getPath().replace('\\', '/');
+ LOG.log(POILogger.DEBUG, "part name: " + partName);
+
+ String contentType;
+ try {
+ PackagePartName relName = PackagingURIHelper.createPartName(partName);
+ PackagePart pp2 = ooxml.getPart(relName);
+ contentType = pp2.getContentType();
+ } catch (InvalidFormatException e) {
+ throw new IOException(e);
+ }
+ if (relationshipType.endsWith("customXml")
+ && !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) {
+ LOG.log(POILogger.DEBUG, "skipping customXml with content type: " + contentType);
+ continue;
+ }
+
+ if (!digestedPartNames.contains(partName)) {
+ // We only digest a part once.
+ String uri = partName + "?ContentType=" + contentType;
+ Reference reference = signatureFactory.newReference(uri, digestMethod);
+ manifestReferences.add(reference);
+ digestedPartNames.add(partName);
+ }
+ }
+
+ if (parameterSpec.hasSourceIds()) {
+ List<Transform> transforms = new LinkedList<Transform>();
+ transforms.add(signatureFactory.newTransform(
+ RelationshipTransformService.TRANSFORM_URI,
+ parameterSpec));
+ transforms.add(signatureFactory.newTransform(
+ CanonicalizationMethod.INCLUSIVE,
+ (TransformParameterSpec) null));
+ String uri = pp.getPartName().getName()
+ + "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
+ Reference reference = signatureFactory.newReference(uri, digestMethod, transforms, null, null);
+ manifestReferences.add(reference);
+ }
+ }
+ }
+
+
+ private void addSignatureTime(XMLSignatureFactory signatureFactory,
+ String signatureId,
+ List<XMLStructure> objectContent) {
+ /*
+ * SignatureTime
+ */
+ DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String nowStr = fmt.format(this.clock);
+ LOG.log(POILogger.DEBUG, "now: " + nowStr);
+
+ SignatureTimeDocument sigTime = SignatureTimeDocument.Factory.newInstance();
+ CTSignatureTime ctTime = sigTime.addNewSignatureTime();
+ ctTime.setFormat("YYYY-MM-DDThh:mm:ssTZD");
+ ctTime.setValue(nowStr);
+
+ // TODO: find better method to have xmlbeans + export the prefix
+ Node n = ctTime.getDomNode();
+ setPrefix(ctTime, PackageNamespaces.DIGITAL_SIGNATURE, "mdssi");
+
+ List<XMLStructure> signatureTimeContent = new LinkedList<XMLStructure>();
+ signatureTimeContent.add(new DOMStructure(n));
+ SignatureProperty signatureTimeSignatureProperty = signatureFactory
+ .newSignatureProperty(signatureTimeContent, "#" + signatureId,
+ "idSignatureTime");
+ List<SignatureProperty> signaturePropertyContent = new LinkedList<SignatureProperty>();
+ signaturePropertyContent.add(signatureTimeSignatureProperty);
+ SignatureProperties signatureProperties = signatureFactory
+ .newSignatureProperties(signaturePropertyContent,
+ "id-signature-time-" + this.clock.getTime());
+ objectContent.add(signatureProperties);
+ }
+
+ private void addSignatureInfo(XMLSignatureFactory signatureFactory,
+ String signatureId, List<Reference> references,
+ List<XMLObject> objects) throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException {
+ List<XMLStructure> objectContent = new LinkedList<XMLStructure>();
+
+ SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance();
+ CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1();
+ ctSigV1.setManifestHashAlgorithm("http://www.w3.org/2000/09/xmldsig#sha1");
+ Node n = ctSigV1.getDomNode();
+ ((Element)n).setAttributeNS(Constants.NamespaceSpecNS, "xmlns", "http://schemas.microsoft.com/office/2006/digsig");
+
+ List<XMLStructure> signatureInfoContent = new LinkedList<XMLStructure>();
+ signatureInfoContent.add(new DOMStructure(n));
+ SignatureProperty signatureInfoSignatureProperty = signatureFactory
+ .newSignatureProperty(signatureInfoContent, "#" + signatureId,
+ "idOfficeV1Details");
+
+ List<SignatureProperty> signaturePropertyContent = new LinkedList<SignatureProperty>();
+ signaturePropertyContent.add(signatureInfoSignatureProperty);
+ SignatureProperties signatureProperties = signatureFactory
+ .newSignatureProperties(signaturePropertyContent, null);
+ objectContent.add(signatureProperties);
+
+ String objectId = "idOfficeObject";
+ objects.add(signatureFactory.newXMLObject(objectContent, objectId,
+ null, null));
+
+ DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null);
+ Reference reference = signatureFactory.newReference("#" + objectId,
+ digestMethod, null, "http://www.w3.org/2000/09/xmldsig#Object",
+ null);
+ references.add(reference);
+ }
+
+ public void postSign(SignatureType signatureElement,
+ List<X509Certificate> signingCertificateChain) {
+ // empty
+ }
+
+ public static String getRelationshipReferenceURI(String zipEntryName) {
+
+ return "/"
+ + zipEntryName
+ + "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
+ }
+
+ public static String getResourceReferenceURI(String resourceName,
+ String contentType) {
+
+ return "/" + resourceName + "?ContentType=" + contentType;
+ }
+
+ public static String[] contentTypes = {
+
+ /*
+ * Word
+ */
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
+ "application/vnd.openxmlformats-officedocument.theme+xml",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml",
+
+ /*
+ * Word 2010
+ */
+ "application/vnd.ms-word.stylesWithEffects+xml",
+
+ /*
+ * Excel
+ */
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
+
+ /*
+ * Powerpoint
+ */
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slide+xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml",
+
+ /*
+ * Powerpoint 2010
+ */
+ "application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml" };
+
+ public static boolean isSignedRelationship(String relationshipType) {
+ LOG.log(POILogger.DEBUG, "relationship type: " + relationshipType);
+ for (String signedTypeExtension : signed) {
+ if (relationshipType.endsWith(signedTypeExtension)) {
+ return true;
+ }
+ }
+ if (relationshipType.endsWith("customXml")) {
+ LOG.log(POILogger.DEBUG, "customXml relationship type");
+ return true;
+ }
+ return false;
+ }
+
+ public Map<String,String> getNamespacePrefixMapping() {
+ Map<String,String> m = new HashMap<String,String>();
+ m.put("mdssi", OOXML_DIGSIG_NS);
+ m.put("xd", "http://uri.etsi.org/01903/v1.3.2#");
+ return m;
+ }
+
+
+ /**
+ * Office 2010 list of signed types (extensions).
+ */
+ public static String[] signed = { "powerPivotData", //
+ "activeXControlBinary", //
+ "attachedToolbars", //
+ "connectorXml", //
+ "downRev", //
+ "functionPrototypes", //
+ "graphicFrameDoc", //
+ "groupShapeXml", //
+ "ink", //
+ "keyMapCustomizations", //
+ "legacyDiagramText", //
+ "legacyDocTextInfo", //
+ "officeDocument", //
+ "pictureXml", //
+ "shapeXml", //
+ "smartTags", //
+ "ui/altText", //
+ "ui/buttonSize", //
+ "ui/controlID", //
+ "ui/description", //
+ "ui/enabled", //
+ "ui/extensibility", //
+ "ui/helperText", //
+ "ui/imageID", //
+ "ui/imageMso", //
+ "ui/keyTip", //
+ "ui/label", //
+ "ui/lcid", //
+ "ui/loud", //
+ "ui/pressed", //
+ "ui/progID", //
+ "ui/ribbonID", //
+ "ui/showImage", //
+ "ui/showLabel", //
+ "ui/supertip", //
+ "ui/target", //
+ "ui/text", //
+ "ui/title", //
+ "ui/tooltip", //
+ "ui/userCustomization", //
+ "ui/visible", //
+ "userXmlData", //
+ "vbaProject", //
+ "wordVbaData", //
+ "wsSortMap", //
+ "xlBinaryIndex", //
+ "xlExternalLinkPath/xlAlternateStartup", //
+ "xlExternalLinkPath/xlLibrary", //
+ "xlExternalLinkPath/xlPathMissing", //
+ "xlExternalLinkPath/xlStartup", //
+ "xlIntlMacrosheet", //
+ "xlMacrosheet", //
+ "customData", //
+ "diagramDrawing", //
+ "hdphoto", //
+ "inkXml", //
+ "media", //
+ "slicer", //
+ "slicerCache", //
+ "stylesWithEffects", //
+ "ui/extensibility", //
+ "chartColorStyle", //
+ "chartLayout", //
+ "chartStyle", //
+ "dictionary", //
+ "timeline", //
+ "timelineCache", //
+ "aFChunk", //
+ "attachedTemplate", //
+ "audio", //
+ "calcChain", //
+ "chart", //
+ "chartsheet", //
+ "chartUserShapes", //
+ "commentAuthors", //
+ "comments", //
+ "connections", //
+ "control", //
+ "customProperty", //
+ "customXml", //
+ "diagramColors", //
+ "diagramData", //
+ "diagramLayout", //
+ "diagramQuickStyle", //
+ "dialogsheet", //
+ "drawing", //
+ "endnotes", //
+ "externalLink", //
+ "externalLinkPath", //
+ "font", //
+ "fontTable", //
+ "footer", //
+ "footnotes", //
+ "glossaryDocument", //
+ "handoutMaster", //
+ "header", //
+ "hyperlink", //
+ "image", //
+ "mailMergeHeaderSource", //
+ "mailMergeRecipientData", //
+ "mailMergeSource", //
+ "notesMaster", //
+ "notesSlide", //
+ "numbering", //
+ "officeDocument", //
+ "oleObject", //
+ "package", //
+ "pivotCacheDefinition", //
+ "pivotCacheRecords", //
+ "pivotTable", //
+ "presProps", //
+ "printerSettings", //
+ "queryTable", //
+ "recipientData", //
+ "settings", //
+ "sharedStrings", //
+ "sheetMetadata", //
+ "slide", //
+ "slideLayout", //
+ "slideMaster", //
+ "slideUpdateInfo", //
+ "slideUpdateUrl", //
+ "styles", //
+ "table", //
+ "tableSingleCells", //
+ "tableStyles", //
+ "tags", //
+ "theme", //
+ "themeOverride", //
+ "transform", //
+ "video", //
+ "viewProps", //
+ "volatileDependencies", //
+ "webSettings", //
+ "worksheet", //
+ "xmlMaps", //
+ "ctrlProp", //
+ "customData", //
+ "diagram", //
+ "diagramColorsHeader", //
+ "diagramLayoutHeader", //
+ "diagramQuickStyleHeader", //
+ "documentParts", //
+ "slicer", //
+ "slicerCache", //
+ "vmlDrawing" //
+ };
+}
\ No newline at end of file
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/Office2010SignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/Office2010SignatureFacet.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/Office2010SignatureFacet.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/Office2010SignatureFacet.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,101 @@
+/* ====================================================================
+ 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.facets;
+
+import static org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet.XADES_NAMESPACE;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.namespace.QName;
+
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
+import org.etsi.uri.x01903.v13.UnsignedPropertiesType;
+import org.etsi.uri.x01903.v13.UnsignedSignaturePropertiesType;
+import org.w3.x2000.x09.xmldsig.ObjectType;
+import org.w3.x2000.x09.xmldsig.SignatureType;
+
+/**
+ * Work-around for Office2010 to accept the XAdES-BES/EPES signature.
+ *
+ * xades:UnsignedProperties/xades:UnsignedSignatureProperties needs to be
+ * present.
+ *
+ * @author Frank Cornelis
+ *
+ */
+public class Office2010SignatureFacet implements SignatureFacet {
+
+ public void preSign(XMLSignatureFactory signatureFactory,
+ String signatureId,
+ List<X509Certificate> signingCertificateChain,
+ List<Reference> references,
+ List<XMLObject> objects
+ ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ }
+
+ public void postSign(SignatureType signatureElement, List<X509Certificate> signingCertificateChain) {
+ QualifyingPropertiesType qualProps = null;
+
+ try {
+ // check for XAdES-BES
+ for (ObjectType ot : signatureElement.getObjectList()) {
+ XmlObject xo[] = ot.selectChildren(new QName(XADES_NAMESPACE, "QualifyingProperties"));
+ if (xo != null && xo.length > 0) {
+ qualProps = QualifyingPropertiesType.Factory.parse(xo[0].getDomNode());
+ break;
+ }
+ }
+ } catch (XmlException e) {
+ throw new RuntimeException("signature decoding error", e);
+ }
+
+ if (qualProps == null) {
+ throw new IllegalArgumentException("no XAdES-BES extension present");
+ }
+
+ // create basic XML container structure
+ UnsignedPropertiesType unsignedProps = qualProps.getUnsignedProperties();
+ if (unsignedProps == null) {
+ unsignedProps = qualProps.addNewUnsignedProperties();
+ }
+ UnsignedSignaturePropertiesType unsignedSigProps = unsignedProps.getUnsignedSignatureProperties();
+ if (unsignedSigProps == null) {
+ unsignedSigProps = unsignedProps.addNewUnsignedSignatureProperties();
+ }
+ }
+
+ public Map<String,String> getNamespacePrefixMapping() {
+ return null;
+ }
+}
\ No newline at end of file
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignatureFacet.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignatureFacet.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignatureFacet.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,83 @@
+/* ====================================================================
+ 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.facets;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+
+import org.w3.x2000.x09.xmldsig.SignatureType;
+
+/**
+ * JSR105 Signature Facet interface.
+ *
+ * @author Frank Cornelis
+ *
+ */
+public interface SignatureFacet {
+
+ /**
+ * This method is being invoked by the XML signature service engine during
+ * pre-sign phase. Via this method a signature facet implementation can add
+ * signature facets to an XML signature.
+ *
+ * @param signatureFactory
+ * @param document
+ * @param signatureId
+ * @param signingCertificateChain
+ * the optional signing certificate chain
+ * @param references
+ * @param objects
+ * @throws InvalidAlgorithmParameterException
+ * @throws NoSuchAlgorithmException
+ */
+ void preSign(
+ XMLSignatureFactory signatureFactory
+ , String signatureId
+ , List<X509Certificate> signingCertificateChain
+ , List<Reference> references
+ , List<XMLObject> objects
+ ) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException;
+
+ /**
+ * This method is being invoked by the XML signature service engine during
+ * the post-sign phase. Via this method a signature facet can extend the XML
+ * signatures with for example key information.
+ *
+ * @param signatureElement
+ * @param signingCertificateChain
+ */
+ void postSign(
+ SignatureType signatureElement
+ , List<X509Certificate> signingCertificateChain);
+
+ Map<String,String> getNamespacePrefixMapping();
+}
\ No newline at end of file
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignaturePolicyService.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignaturePolicyService.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignaturePolicyService.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/SignaturePolicyService.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,65 @@
+/* ====================================================================
+ 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.facets;
+
+/**
+ * Interface for the signature policy service.
+ *
+ * @author Frank Cornelis
+ *
+ */
+public interface SignaturePolicyService {
+
+ /**
+ * Gives back the signature policy identifier URI.
+ *
+ * @return
+ */
+ String getSignaturePolicyIdentifier();
+
+ /**
+ * Gives back the short description of the signature policy or
+ * <code>null</code> if a description is not available.
+ *
+ * @return the description, or <code>null</code>.
+ */
+ String getSignaturePolicyDescription();
+
+ /**
+ * Gives back the download URL where the signature policy document can be
+ * found. Can be <code>null</code> in case such a download location does not
+ * exist.
+ *
+ * @return the download URL, or <code>null</code>.
+ */
+ String getSignaturePolicyDownloadUrl();
+
+ /**
+ * Gives back the signature policy document.
+ *
+ * @return the bytes of the signature policy document.
+ */
+ byte[] getSignaturePolicyDocument();
+}
\ No newline at end of file
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,385 @@
+/* ====================================================================
+ 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.facets;
+
+import static org.apache.poi.poifs.crypt.dsig.SignatureInfo.setPrefix;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import javax.xml.crypto.XMLStructure;
+import javax.xml.crypto.dom.DOMStructure;
+import javax.xml.crypto.dsig.CanonicalizationMethod;
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.Transform;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.spec.TransformParameterSpec;
+
+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.spi.Constants;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.xmlbeans.XmlString;
+import org.etsi.uri.x01903.v13.AnyType;
+import org.etsi.uri.x01903.v13.CertIDListType;
+import org.etsi.uri.x01903.v13.CertIDType;
+import org.etsi.uri.x01903.v13.ClaimedRolesListType;
+import org.etsi.uri.x01903.v13.DataObjectFormatType;
+import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
+import org.etsi.uri.x01903.v13.IdentifierType;
+import org.etsi.uri.x01903.v13.ObjectIdentifierType;
+import org.etsi.uri.x01903.v13.QualifyingPropertiesDocument;
+import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
+import org.etsi.uri.x01903.v13.SigPolicyQualifiersListType;
+import org.etsi.uri.x01903.v13.SignaturePolicyIdType;
+import org.etsi.uri.x01903.v13.SignaturePolicyIdentifierType;
+import org.etsi.uri.x01903.v13.SignedDataObjectPropertiesType;
+import org.etsi.uri.x01903.v13.SignedPropertiesType;
+import org.etsi.uri.x01903.v13.SignedSignaturePropertiesType;
+import org.etsi.uri.x01903.v13.SignerRoleType;
+import org.w3.x2000.x09.xmldsig.DigestMethodType;
+import org.w3.x2000.x09.xmldsig.SignatureType;
+import org.w3.x2000.x09.xmldsig.X509IssuerSerialType;
+import org.w3c.dom.Element;
+
+/**
+ * XAdES Signature Facet. Implements XAdES v1.4.1 which is compatible with XAdES
+ * v1.3.2. The implemented XAdES format is XAdES-BES/EPES. It's up to another
+ * part of the signature service to upgrade the XAdES-BES to a XAdES-X-L.
+ *
+ * This implementation has been tested against an implementation that
+ * participated multiple ETSI XAdES plugtests.
+ *
+ * @author Frank Cornelis
+ * @see http://en.wikipedia.org/wiki/XAdES
+ *
+ */
+public class XAdESSignatureFacet implements SignatureFacet {
+
+ private static final POILogger LOG = POILogFactory.getLogger(XAdESSignatureFacet.class);
+
+ private static final String XADES_TYPE = "http://uri.etsi.org/01903#SignedProperties";
+
+ private final Date clock;
+
+ private final HashAlgorithm hashAlgo;
+
+ private final SignaturePolicyService signaturePolicyService;
+
+ private String idSignedProperties;
+
+ private boolean signaturePolicyImplied;
+
+ private String role;
+
+ private boolean issuerNameNoReverseOrder = false;
+
+ private Map<String, String> dataObjectFormatMimeTypes;
+
+ /**
+ * Main constructor.
+ *
+ * @param clock
+ * the clock to be used for determining the xades:SigningTime,
+ * defaults to now when null
+ * @param hashAlgo
+ * the digest algorithm to be used for all required XAdES digest
+ * operations. Possible values: "SHA-1", "SHA-256", or "SHA-512",
+ * defaults to SHA-1 when null
+ * @param signaturePolicyService
+ * the optional signature policy service used for XAdES-EPES.
+ */
+ public XAdESSignatureFacet(Date clock, HashAlgorithm hashAlgo,
+ SignaturePolicyService signaturePolicyService) {
+ this.clock = (clock == null ? new Date() : clock);
+ this.hashAlgo = (hashAlgo == null ? HashAlgorithm.sha1 : hashAlgo);
+ this.signaturePolicyService = signaturePolicyService;
+ this.dataObjectFormatMimeTypes = new HashMap<String, String>();
+ }
+
+ public void postSign(SignatureType signatureElement,
+ List<X509Certificate> signingCertificateChain) {
+ LOG.log(POILogger.DEBUG, "postSign");
+ }
+
+ public void preSign(XMLSignatureFactory signatureFactory,
+ String signatureId,
+ List<X509Certificate> signingCertificateChain,
+ List<Reference> references, List<XMLObject> objects)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ LOG.log(POILogger.DEBUG, "preSign");
+
+ // QualifyingProperties
+ QualifyingPropertiesDocument qualDoc = QualifyingPropertiesDocument.Factory.newInstance();
+ QualifyingPropertiesType qualifyingProperties = qualDoc.addNewQualifyingProperties();
+ qualifyingProperties.setTarget("#" + signatureId);
+
+ // SignedProperties
+ SignedPropertiesType signedProperties = qualifyingProperties.addNewSignedProperties();
+ String signedPropertiesId;
+ if (null != this.idSignedProperties) {
+ signedPropertiesId = this.idSignedProperties;
+ } else {
+ signedPropertiesId = signatureId + "-xades";
+ }
+ signedProperties.setId(signedPropertiesId);
+
+ // SignedSignatureProperties
+ SignedSignaturePropertiesType signedSignatureProperties = signedProperties.addNewSignedSignatureProperties();
+
+ // SigningTime
+ Calendar xmlGregorianCalendar = Calendar.getInstance();
+ xmlGregorianCalendar.setTimeZone(TimeZone.getTimeZone("Z"));
+ xmlGregorianCalendar.setTime(this.clock);
+ xmlGregorianCalendar.clear(Calendar.MILLISECOND);
+ signedSignatureProperties.setSigningTime(xmlGregorianCalendar);
+
+ // SigningCertificate
+ if (null == signingCertificateChain
+ || signingCertificateChain.isEmpty()) {
+ throw new RuntimeException("no signing certificate chain available");
+ }
+ CertIDListType signingCertificates = signedSignatureProperties.addNewSigningCertificate();
+ CertIDType certId = signingCertificates.addNewCert();
+ X509Certificate signingCertificate = signingCertificateChain.get(0);
+ setCertID(certId, signingCertificate, this.hashAlgo, this.issuerNameNoReverseOrder);
+
+ // ClaimedRole
+ if (null != this.role && false == this.role.isEmpty()) {
+ SignerRoleType signerRole = signedSignatureProperties.addNewSignerRole();
+ signedSignatureProperties.setSignerRole(signerRole);
+ ClaimedRolesListType claimedRolesList = signerRole.addNewClaimedRoles();
+ AnyType claimedRole = claimedRolesList.addNewClaimedRole();
+ XmlString roleString = XmlString.Factory.newInstance();
+ roleString.setStringValue(this.role);
+ SignatureInfo.insertXChild(claimedRole, roleString);
+ }
+
+ // XAdES-EPES
+ if (null != this.signaturePolicyService) {
+ SignaturePolicyIdentifierType signaturePolicyIdentifier =
+ signedSignatureProperties.addNewSignaturePolicyIdentifier();
+
+ SignaturePolicyIdType signaturePolicyId = signaturePolicyIdentifier.addNewSignaturePolicyId();
+
+ ObjectIdentifierType objectIdentifier = signaturePolicyId.addNewSigPolicyId();
+ objectIdentifier.setDescription(this.signaturePolicyService.getSignaturePolicyDescription());
+
+ IdentifierType identifier = objectIdentifier.addNewIdentifier();
+ identifier.setStringValue(this.signaturePolicyService.getSignaturePolicyIdentifier());
+
+ byte[] signaturePolicyDocumentData = this.signaturePolicyService.getSignaturePolicyDocument();
+ DigestAlgAndValueType sigPolicyHash = signaturePolicyId.addNewSigPolicyHash();
+ setDigestAlgAndValue(sigPolicyHash, signaturePolicyDocumentData, this.hashAlgo);
+
+ String signaturePolicyDownloadUrl = this.signaturePolicyService
+ .getSignaturePolicyDownloadUrl();
+ if (null != signaturePolicyDownloadUrl) {
+ SigPolicyQualifiersListType sigPolicyQualifiers = signaturePolicyId.addNewSigPolicyQualifiers();
+ AnyType sigPolicyQualifier = sigPolicyQualifiers.addNewSigPolicyQualifier();
+ XmlString spUriElement = XmlString.Factory.newInstance();
+ spUriElement.setStringValue(signaturePolicyDownloadUrl);
+ SignatureInfo.insertXChild(sigPolicyQualifier, spUriElement);
+ }
+ } else if (this.signaturePolicyImplied) {
+ SignaturePolicyIdentifierType signaturePolicyIdentifier =
+ signedSignatureProperties.addNewSignaturePolicyIdentifier();
+ signaturePolicyIdentifier.addNewSignaturePolicyImplied();
+ }
+
+ // DataObjectFormat
+ if (false == this.dataObjectFormatMimeTypes.isEmpty()) {
+ SignedDataObjectPropertiesType signedDataObjectProperties =
+ signedProperties.addNewSignedDataObjectProperties();
+
+ List<DataObjectFormatType> dataObjectFormats = signedDataObjectProperties
+ .getDataObjectFormatList();
+ for (Map.Entry<String, String> dataObjectFormatMimeType : this.dataObjectFormatMimeTypes
+ .entrySet()) {
+ DataObjectFormatType dataObjectFormat = DataObjectFormatType.Factory.newInstance();
+ dataObjectFormat.setObjectReference("#" + dataObjectFormatMimeType.getKey());
+ dataObjectFormat.setMimeType(dataObjectFormatMimeType.getValue());
+ dataObjectFormats.add(dataObjectFormat);
+ }
+ }
+
+ // marshall XAdES QualifyingProperties
+ // ((Element)qualifyingProperties.getSignedProperties().getDomNode()).setIdAttribute("Id", true);
+
+ // add XAdES ds:Object
+ List<XMLStructure> xadesObjectContent = new LinkedList<XMLStructure>();
+ Element qualDocEl = (Element)qualifyingProperties.getDomNode();
+ qualDocEl.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:xd", "http://uri.etsi.org/01903/v1.3.2#");
+ setPrefix(qualifyingProperties, "http://uri.etsi.org/01903/v1.3.2#", "xd");
+ xadesObjectContent.add(new DOMStructure(qualDocEl));
+ XMLObject xadesObject = signatureFactory.newXMLObject(xadesObjectContent, null, null, null);
+ objects.add(xadesObject);
+
+ // add XAdES ds:Reference
+ DigestMethod digestMethod = signatureFactory.newDigestMethod(hashAlgo.xmlSignUri, null);
+ List<Transform> transforms = new LinkedList<Transform>();
+ Transform exclusiveTransform = signatureFactory
+ .newTransform(CanonicalizationMethod.INCLUSIVE,
+ (TransformParameterSpec) null);
+ transforms.add(exclusiveTransform);
+ Reference reference = signatureFactory.newReference("#"
+ + signedPropertiesId, digestMethod, transforms, XADES_TYPE,
+ null);
+ references.add(reference);
+ }
+
+ /**
+ * Gives back the JAXB DigestAlgAndValue data structure.
+ *
+ * @param data
+ * @param xadesObjectFactory
+ * @param xmldsigObjectFactory
+ * @param hashAlgo
+ * @return
+ */
+ protected static void setDigestAlgAndValue(
+ DigestAlgAndValueType digestAlgAndValue,
+ byte[] data,
+ HashAlgorithm hashAlgo) {
+ DigestMethodType digestMethod = digestAlgAndValue.addNewDigestMethod();
+ digestMethod.setAlgorithm(hashAlgo.xmlSignUri);
+
+ MessageDigest messageDigest = CryptoFunctions.getMessageDigest(hashAlgo);
+ byte[] digestValue = messageDigest.digest(data);
+ digestAlgAndValue.setDigestValue(digestValue);
+ }
+
+ /**
+ * Gives back the JAXB CertID data structure.
+ *
+ * @param certificate
+ * @param xadesObjectFactory
+ * @param xmldsigObjectFactory
+ * @param digestAlgorithm
+ * @return
+ */
+ protected static void setCertID(
+ CertIDType certId,
+ X509Certificate certificate,
+ HashAlgorithm digestAlgorithm, boolean issuerNameNoReverseOrder) {
+ X509IssuerSerialType issuerSerial = certId.addNewIssuerSerial();
+ String issuerName;
+ if (issuerNameNoReverseOrder) {
+ /*
+ * Make sure the DN is encoded using the same order as present
+ * within the certificate. This is an Office2010 work-around.
+ * Should be reverted back.
+ *
+ * XXX: not correct according to RFC 4514.
+ */
+ // TODO: check if issuerName is different on getTBSCertificate
+ // issuerName = PrincipalUtil.getIssuerX509Principal(certificate).getName().replace(",", ", ");
+ issuerName = certificate.getIssuerDN().getName().replace(",", ", ");
+ } else {
+ issuerName = certificate.getIssuerX500Principal().toString();
+ }
+ issuerSerial.setX509IssuerName(issuerName);
+ issuerSerial.setX509SerialNumber(certificate.getSerialNumber());
+
+ byte[] encodedCertificate;
+ try {
+ encodedCertificate = certificate.getEncoded();
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException("certificate encoding error: "
+ + e.getMessage(), e);
+ }
+ DigestAlgAndValueType certDigest = certId.addNewCertDigest();
+ setDigestAlgAndValue(certDigest, encodedCertificate, digestAlgorithm);
+ }
+
+ /**
+ * Adds a mime-type for the given ds:Reference (referred via its @URI). This
+ * information is added via the xades:DataObjectFormat element.
+ *
+ * @param dsReferenceUri
+ * @param mimetype
+ */
+ public void addMimeType(String dsReferenceUri, String mimetype) {
+ this.dataObjectFormatMimeTypes.put(dsReferenceUri, mimetype);
+ }
+
+ /**
+ * Sets the Id that will be used on the SignedProperties element;
+ *
+ * @param idSignedProperties
+ */
+ public void setIdSignedProperties(String idSignedProperties) {
+ this.idSignedProperties = idSignedProperties;
+ }
+
+ /**
+ * Sets the signature policy to implied.
+ *
+ * @param signaturePolicyImplied
+ */
+ public void setSignaturePolicyImplied(boolean signaturePolicyImplied) {
+ this.signaturePolicyImplied = signaturePolicyImplied;
+ }
+
+ /**
+ * Sets the XAdES claimed role.
+ *
+ * @param role
+ */
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ /**
+ * Work-around for Office 2010 IssuerName encoding.
+ *
+ * @param reverseOrder
+ */
+ public void setIssuerNameNoReverseOrder(boolean reverseOrder) {
+ this.issuerNameNoReverseOrder = reverseOrder;
+ }
+
+
+ public Map<String,String> getNamespacePrefixMapping() {
+ Map<String,String> map = new HashMap<String,String>();
+ map.put("xd", "http://uri.etsi.org/01903/v1.3.2#");
+ return map;
+ }
+
+}
\ No newline at end of file
Added: poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
URL: http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java (added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java Sun Aug 10 18:25:10 2014
@@ -0,0 +1,492 @@
+/* ====================================================================
+ 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.facets;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.xml.crypto.dsig.CanonicalizationMethod;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.namespace.QName;
+
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxy;
+import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ASN1InputStreamIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ASN1OctetStringIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.BasicOCSPRespIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.CanonicalizerIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DERIntegerIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DERTaggedObjectIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.InitIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.OCSPRespIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.RespIDIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ResponderIDIf;
+import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509NameIf;
+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.TimeStampService;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+import org.etsi.uri.x01903.v13.CRLIdentifierType;
+import org.etsi.uri.x01903.v13.CRLRefType;
+import org.etsi.uri.x01903.v13.CRLRefsType;
+import org.etsi.uri.x01903.v13.CRLValuesType;
+import org.etsi.uri.x01903.v13.CertIDListType;
+import org.etsi.uri.x01903.v13.CertIDType;
+import org.etsi.uri.x01903.v13.CertificateValuesType;
+import org.etsi.uri.x01903.v13.CompleteCertificateRefsType;
+import org.etsi.uri.x01903.v13.CompleteRevocationRefsType;
+import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
+import org.etsi.uri.x01903.v13.EncapsulatedPKIDataType;
+import org.etsi.uri.x01903.v13.OCSPIdentifierType;
+import org.etsi.uri.x01903.v13.OCSPRefType;
+import org.etsi.uri.x01903.v13.OCSPRefsType;
+import org.etsi.uri.x01903.v13.OCSPValuesType;
+import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
+import org.etsi.uri.x01903.v13.ResponderIDType;
+import org.etsi.uri.x01903.v13.RevocationValuesType;
+import org.etsi.uri.x01903.v13.UnsignedPropertiesType;
+import org.etsi.uri.x01903.v13.UnsignedSignaturePropertiesType;
+import org.etsi.uri.x01903.v13.XAdESTimeStampType;
+import org.etsi.uri.x01903.v14.ValidationDataType;
+import org.w3.x2000.x09.xmldsig.CanonicalizationMethodType;
+import org.w3.x2000.x09.xmldsig.ObjectType;
+import org.w3.x2000.x09.xmldsig.SignatureType;
+import org.w3.x2000.x09.xmldsig.SignatureValueType;
+import org.w3c.dom.Node;
+
+/**
+ * XAdES-X-L v1.4.1 signature facet. This signature facet implementation will
+ * upgrade a given XAdES-BES/EPES signature to XAdES-X-L.
+ *
+ * We don't inherit from XAdESSignatureFacet as we also want to be able to use
+ * this facet out of the context of a signature creation. This signature facet
+ * assumes that the signature is already XAdES-BES/EPES compliant.
+ *
+ * This implementation has been tested against an implementation that
+ * participated multiple ETSI XAdES plugtests.
+ *
+ * @author Frank Cornelis
+ * @see XAdESSignatureFacet
+ */
+public class XAdESXLSignatureFacet implements SignatureFacet {
+
+ private static final POILogger LOG = POILogFactory.getLogger(XAdESXLSignatureFacet.class);
+
+ public static final String XADES_NAMESPACE = "http://uri.etsi.org/01903/v1.3.2#";
+
+ public static final String XADES141_NAMESPACE = "http://uri.etsi.org/01903/v1.4.1#";
+
+ private final TimeStampService timeStampService;
+
+ private String c14nAlgoId;
+
+ private final RevocationDataService revocationDataService;
+
+ private final CertificateFactory certificateFactory;
+
+ private final HashAlgorithm hashAlgo;
+
+ static {
+ try {
+ HorribleProxy.createProxy(InitIf.class, "init");
+ } catch (Exception e) {
+ throw new RuntimeException("Can't initialize JDK xml signature classes - feature unsupported by the this JDK?!", e);
+ }
+ }
+
+ /**
+ * Convenience constructor.
+ *
+ * @param timeStampService
+ * the time-stamp service used for XAdES-T and XAdES-X.
+ * @param revocationDataService
+ * the optional revocation data service used for XAdES-C and
+ * XAdES-X-L. When <code>null</code> the signature will be
+ * limited to XAdES-T only.
+ */
+ public XAdESXLSignatureFacet(TimeStampService timeStampService,
+ RevocationDataService revocationDataService) {
+ this(timeStampService, revocationDataService, HashAlgorithm.sha1);
+ }
+
+ /**
+ * Main constructor.
+ *
+ * @param timeStampService
+ * the time-stamp service used for XAdES-T and XAdES-X.
+ * @param revocationDataService
+ * the optional revocation data service used for XAdES-C and
+ * XAdES-X-L. When <code>null</code> the signature will be
+ * limited to XAdES-T only.
+ * @param digestAlgorithm
+ * the digest algorithm to be used for construction of the
+ * XAdES-X-L elements.
+ */
+ public XAdESXLSignatureFacet(TimeStampService timeStampService,
+ RevocationDataService revocationDataService,
+ HashAlgorithm digestAlgorithm) {
+ this.c14nAlgoId = CanonicalizationMethod.EXCLUSIVE;
+ this.hashAlgo = digestAlgorithm;
+ this.timeStampService = timeStampService;
+ this.revocationDataService = revocationDataService;
+
+ try {
+ this.certificateFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new RuntimeException("X509 JCA error: " + e.getMessage(), e);
+ }
+ }
+
+ public void setCanonicalizerAlgorithm(String c14nAlgoId) {
+ this.c14nAlgoId = c14nAlgoId;
+ }
+
+ public void postSign(SignatureType signatureElement,
+ List<X509Certificate> signingCertificateChain) {
+ LOG.log(POILogger.DEBUG, "XAdES-X-L post sign phase");
+
+ QualifyingPropertiesType qualProps = null;
+
+ try {
+ // check for XAdES-BES
+ for (ObjectType ot : signatureElement.getObjectList()) {
+ XmlObject xo[] = ot.selectChildren(new QName(XADES_NAMESPACE, "QualifyingProperties"));
+ if (xo != null && xo.length > 0) {
+ qualProps = QualifyingPropertiesType.Factory.parse(xo[0].getDomNode());
+ break;
+ }
+ }
+ } catch (XmlException e) {
+ throw new RuntimeException("signature decoding error", e);
+ }
+
+ if (qualProps == null) {
+ throw new IllegalArgumentException("no XAdES-BES extension present");
+ }
+
+ // create basic XML container structure
+ UnsignedPropertiesType unsignedProps = qualProps.getUnsignedProperties();
+ if (unsignedProps == null) {
+ unsignedProps = qualProps.addNewUnsignedProperties();
+ }
+ UnsignedSignaturePropertiesType unsignedSigProps = unsignedProps.getUnsignedSignatureProperties();
+ if (unsignedSigProps == null) {
+ unsignedSigProps = unsignedProps.addNewUnsignedSignatureProperties();
+ }
+
+
+ // create the XAdES-T time-stamp
+ SignatureValueType svt = signatureElement.getSignatureValue();
+
+ RevocationData tsaRevocationDataXadesT = new RevocationData();
+ LOG.log(POILogger.DEBUG, "creating XAdES-T time-stamp");
+ XAdESTimeStampType signatureTimeStamp = createXAdESTimeStamp(
+ Collections.singletonList(svt.getDomNode()),
+ tsaRevocationDataXadesT, this.c14nAlgoId,
+ this.timeStampService);
+
+ // marshal the XAdES-T extension
+ unsignedSigProps.addNewSignatureTimeStamp().set(signatureTimeStamp);
+
+ // xadesv141::TimeStampValidationData
+ if (tsaRevocationDataXadesT.hasRevocationDataEntries()) {
+ ValidationDataType validationData = createValidationData(tsaRevocationDataXadesT);
+ SignatureInfo.insertXChild(unsignedSigProps, validationData);
+ }
+
+ if (null == this.revocationDataService) {
+ /*
+ * Without revocation data service we cannot construct the XAdES-C
+ * extension.
+ */
+ return;
+ }
+
+ // XAdES-C: complete certificate refs
+ CompleteCertificateRefsType completeCertificateRefs =
+ unsignedSigProps.addNewCompleteCertificateRefs();
+
+ CertIDListType certIdList = completeCertificateRefs.addNewCertRefs();
+ for (int certIdx = 1; certIdx < signingCertificateChain.size(); certIdx++) {
+ /*
+ * We skip the signing certificate itself according to section
+ * 4.4.3.2 of the XAdES 1.4.1 specification.
+ */
+ X509Certificate certificate = signingCertificateChain.get(certIdx);
+ CertIDType certId = certIdList.addNewCert();
+ XAdESSignatureFacet.setCertID(certId, certificate, this.hashAlgo, false);
+ }
+
+ // XAdES-C: complete revocation refs
+ CompleteRevocationRefsType completeRevocationRefs =
+ unsignedSigProps.addNewCompleteRevocationRefs();
+ RevocationData revocationData = this.revocationDataService
+ .getRevocationData(signingCertificateChain);
+ if (revocationData.hasCRLs()) {
+ CRLRefsType crlRefs = completeRevocationRefs.addNewCRLRefs();
+ completeRevocationRefs.setCRLRefs(crlRefs);
+
+ for (byte[] encodedCrl : revocationData.getCRLs()) {
+ CRLRefType crlRef = crlRefs.addNewCRLRef();
+ X509CRL crl;
+ try {
+ crl = (X509CRL) this.certificateFactory
+ .generateCRL(new ByteArrayInputStream(encodedCrl));
+ } catch (CRLException e) {
+ throw new RuntimeException("CRL parse error: "
+ + e.getMessage(), e);
+ }
+
+ CRLIdentifierType crlIdentifier = crlRef.addNewCRLIdentifier();
+ String issuerName = crl.getIssuerDN().getName().replace(",", ", ");
+ crlIdentifier.setIssuer(issuerName);
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(crl.getThisUpdate());
+ crlIdentifier.setIssueTime(cal);
+ crlIdentifier.setNumber(getCrlNumber(crl));
+
+ DigestAlgAndValueType digestAlgAndValue = crlRef.addNewDigestAlgAndValue();
+ XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, encodedCrl, this.hashAlgo);
+ }
+ }
+ if (revocationData.hasOCSPs()) {
+ OCSPRefsType ocspRefs = completeRevocationRefs.addNewOCSPRefs();
+ for (byte[] ocsp : revocationData.getOCSPs()) {
+ try {
+ OCSPRefType ocspRef = ocspRefs.addNewOCSPRef();
+
+ DigestAlgAndValueType digestAlgAndValue = ocspRef.addNewDigestAlgAndValue();
+ XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, ocsp, this.hashAlgo);
+
+ OCSPIdentifierType ocspIdentifier = ocspRef.addNewOCSPIdentifier();
+
+ OCSPRespIf ocspResp = HorribleProxy.newProxy(OCSPRespIf.class, ocsp);
+
+ BasicOCSPRespIf basicOcspResp = ocspResp.getResponseObject();
+
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(basicOcspResp.getProducedAt());
+ ocspIdentifier.setProducedAt(cal);
+
+ ResponderIDType responderId = ocspIdentifier.addNewResponderID();
+
+ RespIDIf respId = basicOcspResp.getResponderId();
+ ResponderIDIf ocspResponderId = respId.toASN1Object();
+ DERTaggedObjectIf derTaggedObject = ocspResponderId.toASN1Object();
+ if (2 == derTaggedObject.getTagNo()) {
+ ASN1OctetStringIf keyHashOctetString = derTaggedObject.getObject$String();
+ byte key[] = keyHashOctetString.getOctets();
+ responderId.setByKey(key);
+ } else {
+ X509NameIf name = HorribleProxy.createProxy(X509NameIf.class, "getInstance", derTaggedObject.getObject$Object());
+ String nameStr = name.toString$delegate();
+ responderId.setByName(nameStr);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("OCSP decoding error: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ // marshal XAdES-C
+
+ // XAdES-X Type 1 timestamp
+
+
+
+ List<Node> timeStampNodesXadesX1 = new LinkedList<Node>();
+ timeStampNodesXadesX1.add(signatureElement.getDomNode());
+ timeStampNodesXadesX1.add(signatureTimeStamp.getDomNode());
+ timeStampNodesXadesX1.add(completeCertificateRefs.getDomNode());
+ timeStampNodesXadesX1.add(completeRevocationRefs.getDomNode());
+
+ RevocationData tsaRevocationDataXadesX1 = new RevocationData();
+ LOG.log(POILogger.DEBUG, "creating XAdES-X time-stamp");
+ XAdESTimeStampType timeStampXadesX1 = createXAdESTimeStamp(
+ timeStampNodesXadesX1, tsaRevocationDataXadesX1,
+ this.c14nAlgoId, this.timeStampService);
+ if (tsaRevocationDataXadesX1.hasRevocationDataEntries()) {
+ ValidationDataType timeStampXadesX1ValidationData = createValidationData(tsaRevocationDataXadesX1);
+ SignatureInfo.insertXChild(unsignedSigProps, timeStampXadesX1ValidationData);
+ }
+
+ // marshal XAdES-X
+
+ // XAdES-X-L
+ CertificateValuesType certificateValues = unsignedSigProps.addNewCertificateValues();
+ for (X509Certificate certificate : signingCertificateChain) {
+ EncapsulatedPKIDataType encapsulatedPKIDataType = certificateValues.addNewEncapsulatedX509Certificate();
+ try {
+ encapsulatedPKIDataType.setByteArrayValue(certificate.getEncoded());
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException("certificate encoding error: " + e.getMessage(), e);
+ }
+ }
+
+ RevocationValuesType revocationValues = unsignedSigProps.addNewRevocationValues();
+ createRevocationValues(revocationValues, revocationData);
+
+ // marshal XAdES-X-L
+ }
+
+ public static byte[] getC14nValue(List<Node> nodeList, String c14nAlgoId) {
+ byte[] c14nValue = null;
+ try {
+ for (Node node : nodeList) {
+ /*
+ * Re-initialize the c14n else the namespaces will get cached
+ * and will be missing from the c14n resulting nodes.
+ */
+ CanonicalizerIf c14n = HorribleProxy.createProxy(CanonicalizerIf.class, "newInstance", c14nAlgoId);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ bos.write(c14nValue);
+ bos.write(c14n.canonicalizeSubtree(node));
+ c14nValue = bos.toByteArray();
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException("c14n error: " + e.getMessage(), e);
+ }
+ return c14nValue;
+ }
+
+ public void preSign(XMLSignatureFactory signatureFactory,
+ String signatureId,
+ List<X509Certificate> signingCertificateChain,
+ List<Reference> references, List<XMLObject> objects)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ // nothing to do here
+ }
+
+ private BigInteger getCrlNumber(X509CRL crl) {
+ byte[] crlNumberExtensionValue = crl.getExtensionValue("2.5.29.20" /*CRLNumber*/);
+ if (null == crlNumberExtensionValue) {
+ return null;
+ }
+ try {
+ ASN1InputStreamIf asn1InputStream = HorribleProxy.newProxy(ASN1InputStreamIf.class, crlNumberExtensionValue);
+ ASN1OctetStringIf octetString = asn1InputStream.readObject$ASNString();
+ byte[] octets = octetString.getOctets();
+ asn1InputStream = HorribleProxy.newProxy(ASN1InputStreamIf.class, octets);
+ DERIntegerIf integer = asn1InputStream.readObject$Integer();
+ BigInteger crlNumber = integer.getPositiveValue();
+ return crlNumber;
+ } catch (Exception e) {
+ throw new RuntimeException("I/O error: " + e.getMessage(), e);
+ }
+ }
+
+ public static XAdESTimeStampType createXAdESTimeStamp(
+ List<Node> nodeList,
+ RevocationData revocationData,
+ String c14nAlgoId,
+ TimeStampService timeStampService) {
+ byte[] c14nSignatureValueElement = getC14nValue(nodeList, c14nAlgoId);
+
+ return createXAdESTimeStamp(c14nSignatureValueElement, revocationData,
+ c14nAlgoId, timeStampService);
+ }
+
+ public static XAdESTimeStampType createXAdESTimeStamp(
+ byte[] data,
+ RevocationData revocationData,
+ String c14nAlgoId,
+ TimeStampService timeStampService) {
+ // create the time-stamp
+ byte[] timeStampToken;
+ try {
+ timeStampToken = timeStampService.timeStamp(data, revocationData);
+ } catch (Exception e) {
+ throw new RuntimeException("error while creating a time-stamp: "
+ + e.getMessage(), e);
+ }
+
+ // create a XAdES time-stamp container
+ XAdESTimeStampType xadesTimeStamp = XAdESTimeStampType.Factory.newInstance();
+ xadesTimeStamp.setId("time-stamp-" + UUID.randomUUID().toString());
+ CanonicalizationMethodType c14nMethod = xadesTimeStamp.addNewCanonicalizationMethod();
+ c14nMethod.setAlgorithm(c14nAlgoId);
+
+ // embed the time-stamp
+ EncapsulatedPKIDataType encapsulatedTimeStamp = xadesTimeStamp.addNewEncapsulatedTimeStamp();
+ encapsulatedTimeStamp.setByteArrayValue(timeStampToken);
+ encapsulatedTimeStamp.setId("time-stamp-token-" + UUID.randomUUID().toString());
+
+ return xadesTimeStamp;
+ }
+
+ private ValidationDataType createValidationData(
+ RevocationData revocationData) {
+ ValidationDataType validationData = ValidationDataType.Factory.newInstance();
+ RevocationValuesType revocationValues = validationData.addNewRevocationValues();
+ createRevocationValues(revocationValues, revocationData);
+ return validationData;
+ }
+
+ private void createRevocationValues(
+ RevocationValuesType revocationValues, RevocationData revocationData) {
+ if (revocationData.hasCRLs()) {
+ CRLValuesType crlValues = revocationValues.addNewCRLValues();
+ for (byte[] crl : revocationData.getCRLs()) {
+ EncapsulatedPKIDataType encapsulatedCrlValue = crlValues.addNewEncapsulatedCRLValue();
+ encapsulatedCrlValue.setByteArrayValue(crl);
+ }
+ }
+ if (revocationData.hasOCSPs()) {
+ OCSPValuesType ocspValues = revocationValues.addNewOCSPValues();
+ for (byte[] ocsp : revocationData.getOCSPs()) {
+ EncapsulatedPKIDataType encapsulatedOcspValue = ocspValues.addNewEncapsulatedOCSPValue();
+ encapsulatedOcspValue.setByteArrayValue(ocsp);
+ }
+ }
+ }
+
+ public Map<String,String> getNamespacePrefixMapping() {
+ return null;
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org