diff --git a/build.xml b/build.xml
index 4423a7833..18e817232 100644
--- a/build.xml
+++ b/build.xml
@@ -145,8 +145,12 @@ under the License.
+
+
+
+
-
+
@@ -159,7 +163,7 @@ under the License.
-
+
@@ -431,6 +435,14 @@ under the License.
+
+
+
+
+
+
+
+
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
index 142d56bc0..96ac896a6 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
@@ -126,26 +126,28 @@ public class SignatureInfo {
DigestInfo digestInfo = signatureService.preSign(null, x509Chain, null, null, null);
// setup: key material, signature value
-
- Cipher cipher = CryptoFunctions.getCipher(key, CipherAlgorithm.rsa
- , ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
-
- byte[] signatureValue;
- try {
- ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();
- digestInfoValueBuf.write(getHashMagic(hashAlgo));
- digestInfoValueBuf.write(digestInfo.digestValue);
- byte[] digestInfoValue = digestInfoValueBuf.toByteArray();
- signatureValue = cipher.doFinal(digestInfoValue);
- } catch (Exception e) {
- throw new EncryptedDocumentException(e);
- }
-
+ byte[] signatureValue = signDigest(key, hashAlgo, digestInfo.digestValue);
// operate: postSign
signatureService.postSign(signatureValue, Collections.singletonList(x509));
}
+ public static byte[] signDigest(Key key, HashAlgorithm hashAlgo, byte digest[]) {
+ Cipher cipher = CryptoFunctions.getCipher(key, CipherAlgorithm.rsa
+ , ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
+
+ try {
+ ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();
+ digestInfoValueBuf.write(getHashMagic(hashAlgo));
+ digestInfoValueBuf.write(digest);
+ byte[] digestInfoValue = digestInfoValueBuf.toByteArray();
+ byte[] signatureValue = cipher.doFinal(digestInfoValue);
+ return signatureValue;
+ } catch (Exception e) {
+ throw new EncryptedDocumentException(e);
+ }
+ }
+
public XmlSignatureService createSignatureService(HashAlgorithm hashAlgo, OPCPackage pkg) {
XmlSignatureService signatureService = new XmlSignatureService(hashAlgo, pkg);
signatureService.initFacets(new Date());
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
index ade2494f0..2b590fdd2 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESXLSignatureFacet.java
@@ -49,8 +49,6 @@ 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;
@@ -62,6 +60,8 @@ 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.HorribleProxy;
+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.RevocationDataService;
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
@@ -373,25 +373,22 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
}
public static byte[] getC14nValue(List nodeList, String c14nAlgoId) {
- byte[] c14nValue = null;
+ ByteArrayOutputStream c14nValue = new ByteArrayOutputStream();
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();
+ CanonicalizerIf c14n = HorribleProxy.createProxy(CanonicalizerIf.class, "getInstance", c14nAlgoId);
+ c14nValue.write(c14n.canonicalizeSubtree(node));
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("c14n error: " + e.getMessage(), e);
}
- return c14nValue;
+ return c14nValue.toByteArray();
}
public void preSign(XMLSignatureFactory signatureFactory,
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java
index bea765343..91ed1646b 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java
@@ -112,7 +112,7 @@ public class XmlSignatureService implements SignatureService {
protected final List signatureFacets;
private String signatureNamespacePrefix;
- private String signatureId;
+ private String signatureId = "idPackageSignature";
private final HashAlgorithm hashAlgo;
private final OPCPackage opcPackage;
private SignatureDocument sigDoc;
@@ -124,7 +124,6 @@ public class XmlSignatureService implements SignatureService {
public XmlSignatureService(HashAlgorithm digestAlgo, OPCPackage opcPackage) {
this.signatureFacets = new LinkedList();
this.signatureNamespacePrefix = null;
- this.signatureId = null;
this.hashAlgo = digestAlgo;
this.opcPackage = opcPackage;
this.sigDoc = null;
@@ -142,7 +141,6 @@ public class XmlSignatureService implements SignatureService {
* Work-around for Office 2010.
*/
this.xadesSignatureFacet.setIssuerNameNoReverseOrder(true);
- setSignatureId("idPackageSignature");
addSignatureFacet(this.xadesSignatureFacet);
addSignatureFacet(new Office2010SignatureFacet());
}
@@ -398,8 +396,9 @@ public class XmlSignatureService implements SignatureService {
registerIds(doc);
Element el = doc.getElementById("idPackageObject");
- assert (el != null);
- el.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:mdssi", PackageNamespaces.DIGITAL_SIGNATURE);
+ if (el != null) {
+ el.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:mdssi", PackageNamespaces.DIGITAL_SIGNATURE);
+ }
/*
@@ -549,6 +548,10 @@ public class XmlSignatureService implements SignatureService {
public String getFilesDigestAlgorithm() {
return null;
}
+
+ public SignatureDocument getSignatureDocument() {
+ return sigDoc;
+ }
protected String getCanonicalizationMethod() {
return CanonicalizationMethod.INCLUSIVE;
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
index 191066014..73f6b2381 100644
--- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
+++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
@@ -29,6 +29,8 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
@@ -54,6 +56,10 @@ import java.util.List;
import java.util.TimeZone;
import javax.crypto.Cipher;
+import javax.xml.crypto.KeySelector;
+import javax.xml.crypto.dsig.XMLSignature;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.dom.DOMValidateContext;
import org.apache.poi.POIDataSamples;
import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -75,10 +81,14 @@ import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
+import org.apache.xmlbeans.XmlObject;
+import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
+import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.w3.x2000.x09.xmldsig.SignatureDocument;
public class TestSignatureInfo {
private static final POILogger LOG = POILogFactory.getLogger(TestSignatureInfo.class);
@@ -244,8 +254,52 @@ public class TestSignatureInfo {
// verify
assertNotNull(digestInfo);
- assertEquals("SHA-1", digestInfo.hashAlgo);
+ assertEquals(HashAlgorithm.sha1, digestInfo.hashAlgo);
assertNotNull(digestInfo.digestValue);
+
+ SignatureDocument sigDoc = testedInstance.getSignatureDocument();
+ String certDigestXQuery =
+ "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
+ + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; "
+ + "$this/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties/xades:SignedSignatureProperties/xades:SigningCertificate/xades:Cert/xades:CertDigest";
+ XmlObject xoList[] = sigDoc.selectPath(certDigestXQuery);
+ assertEquals(xoList.length, 1);
+ DigestAlgAndValueType certDigest = (DigestAlgAndValueType)xoList[0];
+ assertNotNull(certDigest.getDigestValue());
+
+ // Sign the received XML signature digest value.
+ byte[] signatureValue = SignatureInfo.signDigest(keyPair.getPrivate(), HashAlgorithm.sha1, digestInfo.digestValue);
+
+ // Operate: postSign
+ testedInstance.postSign(signatureValue, certificateChain);
+
+ // verify
+ verify(mockTimeStampService, times(2)).timeStamp(any(byte[].class), any(RevocationData.class));
+ verify(mockRevocationDataService).getRevocationData(certificateChain);
+
+ DOMValidateContext domValidateContext = new DOMValidateContext(
+ KeySelector.singletonKeySelector(keyPair.getPublic()),
+ testedInstance.getSignatureDocument().getDomNode());
+ XMLSignatureFactory xmlSignatureFactory = SignatureInfo.getSignatureFactory();
+ XMLSignature xmlSignature = xmlSignatureFactory
+ .unmarshalXMLSignature(domValidateContext);
+ boolean validity = xmlSignature.validate(domValidateContext);
+ assertTrue(validity);
+
+ xoList = sigDoc.selectPath(certDigestXQuery);
+ assertEquals(xoList.length, 1);
+ certDigest = (DigestAlgAndValueType)xoList[0];
+ assertNotNull(certDigest.getDigestValue());
+
+ String qualPropXQuery =
+ "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
+ + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; "
+ + "$this/ds:Signature/ds:Object/xades:QualifyingProperties";
+ xoList = sigDoc.selectPath(qualPropXQuery);
+ assertEquals(xoList.length, 1);
+ QualifyingPropertiesType qualProp = (QualifyingPropertiesType)xoList[0];
+ boolean qualPropXsdOk = qualProp.validate();
+ assertTrue(qualPropXsdOk);
}
private OPCPackage sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {