Author: kiwiwings
Date: Wed Sep 24 22:54:21 2014
New Revision: 1627434

URL: http://svn.apache.org/r1627434
Log:
more flexible signer verification through Iterable-Interface

Modified:
    
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
    
poi/branches/xml_signature/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java

Modified: 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
URL: 
http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java?rev=1627434&r1=1627433&r2=1627434&view=diff
==============================================================================
--- 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
 (original)
+++ 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
 Wed Sep 24 22:54:21 2014
@@ -44,8 +44,10 @@ import java.security.cert.X509Certificat
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 
 import javax.crypto.Cipher;
 import javax.xml.crypto.MarshalException;
@@ -142,6 +144,58 @@ public class SignatureInfo implements Si
 
     public static final byte[] RIPEMD256_DIGEST_INFO_PREFIX = new byte[]
         { 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x03, 
0x04, 0x20 };
+
+    private static final POILogger LOG = 
POILogFactory.getLogger(SignatureInfo.class);
+    private static boolean isInitialized = false;
+    
+    private SignatureConfig signatureConfig;
+
+    public class SignaturePart {
+        private final PackagePart signaturePart;
+        private X509Certificate signer;
+        
+        private SignaturePart(PackagePart signaturePart) {
+            this.signaturePart = signaturePart;
+        }
+        
+        public PackagePart getPackagePart() {
+            return signaturePart;
+        }
+        
+        public X509Certificate getSigner() {
+            return signer;
+        }
+        
+        public SignatureDocument getSignatureDocument() throws IOException, 
XmlException {
+            // TODO: check for XXE
+            return 
SignatureDocument.Factory.parse(signaturePart.getInputStream());
+        }
+        
+        public boolean validate() {
+            KeyInfoKeySelector keySelector = new KeyInfoKeySelector();
+            try {
+                Document doc = 
DocumentHelper.readDocument(signaturePart.getInputStream());
+                registerIds(doc);
+                
+                DOMValidateContext domValidateContext = new 
DOMValidateContext(keySelector, doc);
+                
domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", 
Boolean.TRUE);
+                
domValidateContext.setURIDereferencer(signatureConfig.getUriDereferencer());
+    
+                XMLSignatureFactory xmlSignatureFactory = 
getSignatureFactory();
+                XMLSignature xmlSignature = 
xmlSignatureFactory.unmarshalXMLSignature(domValidateContext);
+                boolean valid = xmlSignature.validate(domValidateContext);
+
+                if (valid) {
+                    signer = keySelector.getCertificate();
+                }
+                
+                return valid;
+            } catch (Exception e) {
+                LOG.log(POILogger.ERROR, "error in marshalling and validating 
the signature", e);
+                return false;
+            }
+        }
+    }
     
     protected static class SignCreationListener implements EventListener, 
SignatureConfigurable {
         ThreadLocal<EventTarget> target = new ThreadLocal<EventTarget>();
@@ -168,11 +222,10 @@ public class SignatureInfo implements Si
     }
     
     
-    private static final POILogger LOG = 
POILogFactory.getLogger(SignatureInfo.class);
-    private static boolean isInitialized = false;
+    public SignatureInfo() {
+        initXmlProvider();        
+    }
     
-    private SignatureConfig signatureConfig;
-
     public SignatureConfig getSignatureConfig() {
         return signatureConfig;
     }
@@ -182,10 +235,12 @@ public class SignatureInfo implements Si
     }
 
     public boolean verifySignature() {
-        initXmlProvider();
         // 
http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
-        List<X509Certificate> signers = new ArrayList<X509Certificate>();
-        return getSignersAndValidate(signers, true);
+        for (SignaturePart sp : getSignatureParts()){
+            // only validate first part
+            return sp.validate();
+        }
+        return false;
     }
 
     public void confirmSignature()
@@ -218,77 +273,50 @@ public class SignatureInfo implements Si
         }
     }
     
-    public List<X509Certificate> getSigners() {
-        initXmlProvider();
-        List<X509Certificate> signers = new ArrayList<X509Certificate>();
-        getSignersAndValidate(signers, false);
-        return signers;
-    }
-    
-    protected boolean getSignersAndValidate(List<X509Certificate> signers, 
boolean onlyFirst) {
-        signatureConfig.init(true);
-        
-        boolean allValid = true;
-        List<PackagePart> signatureParts = getSignatureParts(onlyFirst);
-        if (signatureParts.isEmpty()) {
-            LOG.log(POILogger.DEBUG, "no signature resources");
-            allValid = false;
-        }
-
-        for (PackagePart signaturePart : signatureParts) {
-            KeyInfoKeySelector keySelector = new KeyInfoKeySelector();
-
-            try {
-                Document doc = 
DocumentHelper.readDocument(signaturePart.getInputStream());
-                registerIds(doc);
-                
-                DOMValidateContext domValidateContext = new 
DOMValidateContext(keySelector, doc);
-                
domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", 
Boolean.TRUE);
-                
domValidateContext.setURIDereferencer(signatureConfig.getUriDereferencer());
-    
-                XMLSignatureFactory xmlSignatureFactory = 
getSignatureFactory();
-                XMLSignature xmlSignature = 
xmlSignatureFactory.unmarshalXMLSignature(domValidateContext);
-                boolean validity = xmlSignature.validate(domValidateContext);
-                allValid &= validity;
-                if (!validity) continue;
-                // TODO: check what has been signed.
-            } catch (Exception e) {
-                LOG.log(POILogger.ERROR, "error in marshalling and validating 
the signature", e);
-                continue;
-            }
-
-            X509Certificate signer = keySelector.getCertificate();
-            signers.add(signer);
-        }
-        
-        return allValid;
-    }
-
-    protected List<PackagePart> getSignatureParts(boolean onlyFirst) {
-        List<PackagePart> packageParts = new ArrayList<PackagePart>();
-        OPCPackage pkg = signatureConfig.getOpcPackage();
-        
-        PackageRelationshipCollection sigOrigRels = 
pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
-        for (PackageRelationship rel : sigOrigRels) {
-            PackagePart sigPart = pkg.getPart(rel);
-            LOG.log(POILogger.DEBUG, "Digital Signature Origin part", sigPart);
-
-            try {
-                PackageRelationshipCollection sigRels = 
sigPart.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE);
-                for (PackageRelationship sigRel : sigRels) {
-                    PackagePart sigRelPart = sigPart.getRelatedPart(sigRel); 
-                    LOG.log(POILogger.DEBUG, "XML Signature part", sigRelPart);
-                    packageParts.add(sigRelPart);
-                    if (onlyFirst) break;
-                }
-            } catch (InvalidFormatException e) {
-                LOG.log(POILogger.WARN, "Reference to signature is invalid.", 
e);
+    public Iterable<SignaturePart> getSignatureParts() {
+        return new Iterable<SignaturePart>() {
+            public Iterator<SignaturePart> iterator() {
+                return new Iterator<SignaturePart>() {
+                    OPCPackage pkg = signatureConfig.getOpcPackage();
+                    Iterator<PackageRelationship> sigOrigRels = 
+                        
pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN).iterator();
+                    Iterator<PackageRelationship> sigRels = null;
+                    PackagePart sigPart = null;
+                    
+                    public boolean hasNext() {
+                        while (sigRels == null || !sigRels.hasNext()) {
+                            if (!sigOrigRels.hasNext()) return false;
+                            sigPart = pkg.getPart(sigOrigRels.next());
+                            LOG.log(POILogger.DEBUG, "Digital Signature Origin 
part", sigPart);
+                            try {
+                                sigRels = 
sigPart.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE).iterator();
+                            } catch (InvalidFormatException e) {
+                                LOG.log(POILogger.WARN, "Reference to 
signature is invalid.", e);
+                            }
+                        }
+                        return true;
+                    }
+                    
+                    public SignaturePart next() {
+                        PackagePart sigRelPart = null;
+                        do {
+                            try {
+                                if (!hasNext()) throw new 
NoSuchElementException();
+                                sigRelPart = 
sigPart.getRelatedPart(sigRels.next()); 
+                                LOG.log(POILogger.DEBUG, "XML Signature part", 
sigRelPart);
+                            } catch (InvalidFormatException e) {
+                                LOG.log(POILogger.WARN, "Reference to 
signature is invalid.", e);
+                            }
+                        } while (sigPart == null);
+                        return new SignaturePart(sigRelPart);
+                    }
+                    
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
             }
-            
-            if (onlyFirst && !packageParts.isEmpty()) break;
-        }
-
-        return packageParts;
+        };
     }
     
     public static XMLSignatureFactory getSignatureFactory() {

Modified: 
poi/branches/xml_signature/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
URL: 
http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java?rev=1627434&r1=1627433&r2=1627434&view=diff
==============================================================================
--- 
poi/branches/xml_signature/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
 (original)
+++ 
poi/branches/xml_signature/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
 Wed Sep 24 22:54:21 2014
@@ -45,19 +45,16 @@ import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.List;
 import java.util.TimeZone;
 
-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;
 import org.apache.poi.openxml4j.opc.PackageAccess;
 import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
 import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
+import org.apache.poi.poifs.crypt.dsig.SignatureInfo.SignaturePart;
 import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
 import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
 import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
@@ -78,6 +75,7 @@ import org.etsi.uri.x01903.v13.DigestAlg
 import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.w3.x2000.x09.xmldsig.ReferenceType;
 import org.w3.x2000.x09.xmldsig.SignatureDocument;
 import org.w3c.dom.Document;
 
@@ -122,7 +120,12 @@ public class TestSignatureInfo {
             sic.setOpcPackage(pkg);
             SignatureInfo si = new SignatureInfo();
             si.setSignatureConfig(sic);
-            List<X509Certificate> result = si.getSigners();
+            List<X509Certificate> result = new ArrayList<X509Certificate>();
+            for (SignaturePart sp : si.getSignatureParts()) {
+                if (sp.validate()) {
+                    result.add(sp.getSigner());
+                }
+            }
             pkg.revert();
             pkg.close();
             assertNotNull(result);
@@ -151,7 +154,12 @@ public class TestSignatureInfo {
             sic.setOpcPackage(pkg);
             SignatureInfo si = new SignatureInfo();
             si.setSignatureConfig(sic);
-            List<X509Certificate> result = si.getSigners();
+            List<X509Certificate> result = new ArrayList<X509Certificate>();
+            for (SignaturePart sp : si.getSignatureParts()) {
+                if (sp.validate()) {
+                    result.add(sp.getSigner());
+                }
+            }
 
             assertNotNull(result);
             assertEquals("test-file: "+testFile, 1, result.size());
@@ -172,7 +180,12 @@ public class TestSignatureInfo {
         sic.setOpcPackage(pkg);
         SignatureInfo si = new SignatureInfo();
         si.setSignatureConfig(sic);
-        List<X509Certificate> result = si.getSigners();
+        List<X509Certificate> result = new ArrayList<X509Certificate>();
+        for (SignaturePart sp : si.getSignatureParts()) {
+            if (sp.validate()) {
+                result.add(sp.getSigner());
+            }
+        }
 
         assertNotNull(result);
         assertEquals("test-file: "+testFile, 2, result.size());
@@ -207,12 +220,16 @@ public class TestSignatureInfo {
         si.setSignatureConfig(sic);
         // hash > sha1 doesn't work in excel viewer ...
         si.confirmSignature();
-        List<X509Certificate> signer = si.getSigners();
-        assertEquals(1, signer.size());
+        List<X509Certificate> result = new ArrayList<X509Certificate>();
+        for (SignaturePart sp : si.getSignatureParts()) {
+            if (sp.validate()) {
+                result.add(sp.getSigner());
+            }
+        }
+        assertEquals(1, result.size());
         pkg.close();
     }
 
-    @SuppressWarnings("unused")
     @Test
     public void testSignEnvelopingDocument() throws Exception {
         String testFile = "hello-world-unsigned.xlsx";
@@ -283,60 +300,45 @@ public class TestSignatureInfo {
         };
         signatureConfig.setRevocationDataService(revocationDataService);
 
+        // operate
         SignatureInfo si = new SignatureInfo();
         si.setSignatureConfig(signatureConfig);
+        si.confirmSignature();
         
-        Document document = DocumentHelper.createDocument();
-        
-        // operate
-        DigestInfo digestInfo = si.preSign(document, null);
-
         // verify
-        assertNotNull(digestInfo);
-        assertEquals(HashAlgorithm.sha1, digestInfo.hashAlgo);
-        assertNotNull(digestInfo.digestValue);
-        
-        SignatureDocument sigDoc = SignatureDocument.Factory.parse(document);
-        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";
+        Iterator<SignaturePart> spIter = si.getSignatureParts().iterator();
+        assertTrue(spIter.hasNext());
+        SignaturePart sp = spIter.next();
+        boolean valid = sp.validate();
+        assertTrue(valid);
+        
+        SignatureDocument sigDoc = sp.getSignatureDocument();
+        String declareNS = 
+            "declare namespace xades='http://uri.etsi.org/01903/v1.3.2#'; "
+          + "declare namespace ds='http://www.w3.org/2000/09/xmldsig#'; ";
+        
+        String digestValXQuery = declareNS +
+            "$this/ds:Signature/ds:SignedInfo/ds:Reference";
+        for (ReferenceType rt : 
(ReferenceType[])sigDoc.selectPath(digestValXQuery)) {
+            assertNotNull(rt.getDigestValue());
+            assertEquals(HashAlgorithm.sha1.xmlSignUri, 
rt.getDigestMethod().getAlgorithm());
+        }
+
+        String certDigestXQuery = declareNS +
+            "$this//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 = si.signDigest(digestInfo.digestValue);
-
-        // Operate: postSign
-        si.postSign(document, signatureValue);
-        
-        DOMValidateContext domValidateContext = new DOMValidateContext(
-                KeySelector.singletonKeySelector(keyPair.getPublic()),
-                document);
-        XMLSignatureFactory xmlSignatureFactory = 
SignatureInfo.getSignatureFactory();
-        XMLSignature xmlSignature = xmlSignatureFactory
-                .unmarshalXMLSignature(domValidateContext);
-        boolean validity = xmlSignature.validate(domValidateContext);
-        assertTrue(validity);
-
-        sigDoc = SignatureDocument.Factory.parse(document);
-        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";
+        String qualPropXQuery = declareNS +
+            "$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);
-        
+
         pkg.close();
     }
     
@@ -374,8 +376,13 @@ public class TestSignatureInfo {
 
         // verify: signature
         si.getSignatureConfig().setOpcPackage(pkgCopy);
-        List<X509Certificate> signers = si.getSigners();
-        assertEquals(signerCount, signers.size());
+        List<X509Certificate> result = new ArrayList<X509Certificate>();
+        for (SignaturePart sp : si.getSignatureParts()) {
+            if (sp.validate()) {
+                result.add(sp.getSigner());
+            }
+        }
+        assertEquals(signerCount, result.size());
 
         return pkgCopy;
     }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to