]> source.dussan.org Git - poi.git/commitdiff
more tests, some refactoring
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 28 Sep 2014 22:30:02 +0000 (22:30 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 28 Sep 2014 22:30:02 +0000 (22:30 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1628107 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/KeyInfoKeySelector.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/EnvelopedSignatureFacet.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java
test-data/xmldsign/chaintest.pfx [new file with mode: 0644]

index 8f2efc2f7179636894fce8689b6eb5aae376a6b8..6a490b01480dd27b27bb63960a83073b59460000 100644 (file)
 \r
 package org.apache.poi.poifs.crypt;\r
 \r
-import javax.xml.crypto.dsig.DigestMethod;\r
-\r
 import org.apache.poi.EncryptedDocumentException;\r
 \r
 public enum HashAlgorithm {\r
-    none     (         "", 0x0000,           "",  0,               "", null, false),\r
-    sha1     (    "SHA-1", 0x8004,       "SHA1", 20,       "HmacSHA1", DigestMethod.SHA1, false),\r
-    sha256   (  "SHA-256", 0x800C,     "SHA256", 32,     "HmacSHA256", DigestMethod.SHA256, false),\r
-    sha384   (  "SHA-384", 0x800D,     "SHA384", 48,     "HmacSHA384", null, false),\r
-    sha512   (  "SHA-512", 0x800E,     "SHA512", 64,     "HmacSHA512", DigestMethod.SHA512, false),\r
+    none     (         "", 0x0000,           "",  0,               "", false),\r
+    sha1     (    "SHA-1", 0x8004,       "SHA1", 20,       "HmacSHA1", false),\r
+    sha256   (  "SHA-256", 0x800C,     "SHA256", 32,     "HmacSHA256", false),\r
+    sha384   (  "SHA-384", 0x800D,     "SHA384", 48,     "HmacSHA384", false),\r
+    sha512   (  "SHA-512", 0x800E,     "SHA512", 64,     "HmacSHA512", false),\r
     /* only for agile encryption */\r
-    md5      (      "MD5",     -1,        "MD5", 16,        "HmacMD5", null, false),\r
+    md5      (      "MD5",     -1,        "MD5", 16,        "HmacMD5", false),\r
     // although sunjc2 supports md2, hmac-md2 is only supported by bouncycastle\r
-    md2      (      "MD2",     -1,        "MD2", 16,       "Hmac-MD2", null, true),\r
-    md4      (      "MD4",     -1,        "MD4", 16,       "Hmac-MD4", null, true),\r
-    ripemd128("RipeMD128",     -1, "RIPEMD-128", 16, "HMac-RipeMD128", null, true),\r
-    ripemd160("RipeMD160",     -1, "RIPEMD-160", 20, "HMac-RipeMD160", DigestMethod.RIPEMD160, true),\r
-    whirlpool("Whirlpool",     -1,  "WHIRLPOOL", 64, "HMac-Whirlpool", null, true),\r
+    md2      (      "MD2",     -1,        "MD2", 16,       "Hmac-MD2", true),\r
+    md4      (      "MD4",     -1,        "MD4", 16,       "Hmac-MD4", true),\r
+    ripemd128("RipeMD128",     -1, "RIPEMD-128", 16, "HMac-RipeMD128", true),\r
+    ripemd160("RipeMD160",     -1, "RIPEMD-160", 20, "HMac-RipeMD160", true),\r
+    whirlpool("Whirlpool",     -1,  "WHIRLPOOL", 64, "HMac-Whirlpool", true),\r
+    // only for xml signing\r
+    sha224   (  "SHA-224",     -1,     "SHA224", 28,     "HmacSHA224", true);\r
     ;\r
 \r
     public final String jceId;\r
@@ -42,16 +42,14 @@ public enum HashAlgorithm {
     public final String ecmaString;\r
     public final int hashSize;\r
     public final String jceHmacId;\r
-    public final String xmlSignUri;\r
     public final boolean needsBouncyCastle;\r
     \r
-    HashAlgorithm(String jceId, int ecmaId, String ecmaString, int hashSize, String jceHmacId, String xmlSignUri, boolean needsBouncyCastle) {\r
+    HashAlgorithm(String jceId, int ecmaId, String ecmaString, int hashSize, String jceHmacId, boolean needsBouncyCastle) {\r
         this.jceId = jceId;\r
         this.ecmaId = ecmaId;\r
         this.ecmaString = ecmaString;\r
         this.hashSize = hashSize;\r
         this.jceHmacId = jceHmacId;\r
-        this.xmlSignUri = xmlSignUri;\r
         this.needsBouncyCastle = needsBouncyCastle;\r
     }\r
     \r
index c24c36fc49c06a5cad0746f5a2e18fb7184c05b2..61fedcb9ec793dac5695b9464f43579205133872 100644 (file)
@@ -26,6 +26,7 @@ package org.apache.poi.poifs.crypt.dsig;
 \r
 import java.security.Key;\r
 import java.security.cert.X509Certificate;\r
+import java.util.ArrayList;\r
 import java.util.List;\r
 \r
 import javax.xml.crypto.AlgorithmMethod;\r
@@ -48,7 +49,7 @@ public class KeyInfoKeySelector extends KeySelector implements KeySelectorResult
 \r
     private static final POILogger LOG = POILogFactory.getLogger(KeyInfoKeySelector.class);\r
 \r
-    private X509Certificate certificate;\r
+    private List<X509Certificate> certChain = new ArrayList<X509Certificate>();\r
 \r
     @SuppressWarnings("unchecked")\r
     @Override\r
@@ -58,35 +59,31 @@ public class KeyInfoKeySelector extends KeySelector implements KeySelectorResult
             throw new KeySelectorException("no ds:KeyInfo present");\r
         }\r
         List<XMLStructure> keyInfoContent = keyInfo.getContent();\r
-        this.certificate = null;\r
+        certChain.clear();\r
         for (XMLStructure keyInfoStructure : keyInfoContent) {\r
-            if (false == (keyInfoStructure instanceof X509Data)) {\r
+            if (!(keyInfoStructure instanceof X509Data)) {\r
                 continue;\r
             }\r
             X509Data x509Data = (X509Data) keyInfoStructure;\r
             List<Object> x509DataList = x509Data.getContent();\r
             for (Object x509DataObject : x509DataList) {\r
-                if (false == (x509DataObject instanceof X509Certificate)) {\r
+                if (!(x509DataObject instanceof X509Certificate)) {\r
                     continue;\r
                 }\r
                 X509Certificate certificate = (X509Certificate) x509DataObject;\r
                 LOG.log(POILogger.DEBUG, "certificate", certificate.getSubjectX500Principal());\r
-                if (null == this.certificate) {\r
-                    /*\r
-                     * The first certificate is presumably the signer.\r
-                     */\r
-                    this.certificate = certificate;\r
-                }\r
-            }\r
-            if (null != this.certificate) {\r
-                return this;\r
+                certChain.add(certificate);\r
             }\r
         }\r
-        throw new KeySelectorException("No key found!");\r
+        if (certChain.isEmpty()) {\r
+            throw new KeySelectorException("No key found!");\r
+        }\r
+        return this;\r
     }\r
 \r
     public Key getKey() {\r
-        return this.certificate.getPublicKey();\r
+        // The first certificate is presumably the signer.\r
+        return certChain.isEmpty() ? null : certChain.get(0).getPublicKey();\r
     }\r
 \r
     /**\r
@@ -95,7 +92,12 @@ public class KeyInfoKeySelector extends KeySelector implements KeySelectorResult
      * \r
      * @return\r
      */\r
-    public X509Certificate getCertificate() {\r
-        return this.certificate;\r
+    public X509Certificate getSigner() {\r
+        // The first certificate is presumably the signer.\r
+        return certChain.isEmpty() ? null : certChain.get(0);\r
+    }\r
+    \r
+    public List<X509Certificate> getCertChain() {\r
+        return certChain;\r
     }\r
 }\r
index d60753e479f2e1e0c712ffd9339ad2d19105c0e5..7c59fbcae061bf276a562e71d2ca6a221ce43411 100644 (file)
@@ -31,6 +31,7 @@ import java.util.UUID;
 \r
 import javax.xml.crypto.URIDereferencer;\r
 import javax.xml.crypto.dsig.CanonicalizationMethod;\r
+import javax.xml.crypto.dsig.DigestMethod;\r
 \r
 import org.apache.poi.EncryptedDocumentException;\r
 import org.apache.poi.openxml4j.opc.OPCPackage;\r
@@ -87,7 +88,10 @@ public class SignatureConfig {
     // timestamp service provider URL\r
     private String tspUrl;\r
     private boolean tspOldProtocol = false;\r
-    private HashAlgorithm tspDigestAlgo = HashAlgorithm.sha1;\r
+    /**\r
+     * if not defined, it's the same as the main digest\r
+     */\r
+    private HashAlgorithm tspDigestAlgo = null;\r
     private String tspUser;\r
     private String tspPass;\r
     private TimeStampServiceValidator tspValidator;\r
@@ -103,7 +107,10 @@ public class SignatureConfig {
      * When <code>null</code> the signature will be limited to XAdES-T only.\r
      */\r
     private RevocationDataService revocationDataService;\r
-    private HashAlgorithm xadesDigestAlgo = HashAlgorithm.sha1;\r
+    /**\r
+     * if not defined, it's the same as the main digest\r
+     */\r
+    private HashAlgorithm xadesDigestAlgo = null;\r
     private String xadesRole = null;\r
     private String xadesSignatureId = null;\r
     private boolean xadesSignaturePolicyImplied = true;\r
@@ -290,9 +297,7 @@ public class SignatureConfig {
         return packageSignatureId;\r
     }\r
     public void setPackageSignatureId(String packageSignatureId) {\r
-        this.packageSignatureId = (packageSignatureId != null)\r
-            ? packageSignatureId\r
-            : "xmldsig-" + UUID.randomUUID();\r
+        this.packageSignatureId = nvl(packageSignatureId,"xmldsig-"+UUID.randomUUID());\r
     }\r
     public String getTspUrl() {\r
         return tspUrl;\r
@@ -307,7 +312,7 @@ public class SignatureConfig {
         this.tspOldProtocol = tspOldProtocol;\r
     }\r
     public HashAlgorithm getTspDigestAlgo() {\r
-        return tspDigestAlgo;\r
+        return nvl(tspDigestAlgo,digestAlgo);\r
     }\r
     public void setTspDigestAlgo(HashAlgorithm tspDigestAlgo) {\r
         this.tspDigestAlgo = tspDigestAlgo;\r
@@ -349,7 +354,7 @@ public class SignatureConfig {
         this.revocationDataService = revocationDataService;\r
     }\r
     public HashAlgorithm getXadesDigestAlgo() {\r
-        return xadesDigestAlgo;\r
+        return nvl(xadesDigestAlgo,digestAlgo);\r
     }\r
     public void setXadesDigestAlgo(HashAlgorithm xadesDigestAlgo) {\r
         this.xadesDigestAlgo = xadesDigestAlgo;\r
@@ -420,4 +425,81 @@ public class SignatureConfig {
     public void setNamespacePrefixes(Map<String, String> namespacePrefixes) {\r
         this.namespacePrefixes = namespacePrefixes;\r
     }\r
+    protected static <T> T nvl(T value, T defaultValue)  {\r
+        return value == null ? defaultValue : value;\r
+    }\r
+    public byte[] getHashMagic() {\r
+        // see https://www.ietf.org/rfc/rfc3110.txt\r
+        // RSA/SHA1 SIG Resource Records\r
+        byte result[];\r
+        switch (getDigestAlgo()) {\r
+        case sha1: result = new byte[]\r
+            { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e\r
+            , 0x03, 0x02, 0x1a, 0x04, 0x14 };\r
+            break;\r
+        case sha224: result = new byte[] \r
+            { 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+            , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, 0x1c };\r
+            break;\r
+        case sha256: result = new byte[]\r
+            { 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+            , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20 };\r
+            break;\r
+        case sha384: result = new byte[]\r
+            { 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+            , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30 };\r
+            break;\r
+        case sha512: result  = new byte[]\r
+            { 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+            , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40 };\r
+            break;\r
+        case ripemd128: result = new byte[]\r
+            { 0x30, 0x1b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24\r
+            , 0x03, 0x02, 0x02, 0x04, 0x10 };\r
+            break;\r
+        case ripemd160: result = new byte[]\r
+            { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24\r
+            , 0x03, 0x02, 0x01, 0x04, 0x14 };\r
+            break;\r
+        // case ripemd256: result = new byte[]\r
+        //    { 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24\r
+        //    , 0x03, 0x02, 0x03, 0x04, 0x20 };\r
+        //    break;\r
+        default: throw new EncryptedDocumentException("Hash algorithm "\r
+            +getDigestAlgo()+" not supported for signing.");\r
+        }\r
+        \r
+        return result;\r
+    }\r
+\r
+    public String getSignatureMethod() {\r
+        switch (getDigestAlgo()) {\r
+        case sha1:   return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;\r
+        case sha224: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA224;\r
+        case sha256: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;\r
+        case sha384: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;\r
+        case sha512: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;\r
+        case ripemd160: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160;\r
+        default: throw new EncryptedDocumentException("Hash algorithm "\r
+            +getDigestAlgo()+" not supported for signing.");\r
+        }\r
+    }\r
+    \r
+    public String getDigestMethodUri() {\r
+        return getDigestMethodUri(getDigestAlgo());\r
+    }\r
+    \r
+    public static String getDigestMethodUri(HashAlgorithm digestAlgo) {\r
+        switch (digestAlgo) {\r
+        case sha1:   return DigestMethod.SHA1;\r
+        case sha224: return "http://www.w3.org/2001/04/xmldsig-more#sha224";\r
+        case sha256: return DigestMethod.SHA256;\r
+        case sha384: return "http://www.w3.org/2001/04/xmldsig-more#sha384";\r
+        case sha512: return DigestMethod.SHA512;\r
+        case ripemd160: return DigestMethod.RIPEMD160;\r
+        default: throw new EncryptedDocumentException("Hash algorithm "\r
+            +digestAlgo+" not supported for signing.");\r
+        }\r
+    }\r
+    \r
 }\r
index a4006af3ac82a34738bfc2efede29a117984fdd6..69a771b40f91746d3a8f82c1473f62b7d6420e1a 100644 (file)
 package org.apache.poi.poifs.crypt.dsig;\r
 \r
 import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_DIGSIG_NS;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;\r
 \r
 import java.io.ByteArrayOutputStream;\r
 import java.io.File;\r
@@ -113,36 +108,6 @@ import org.xml.sax.SAXException;
 \r
 public class SignatureInfo implements SignatureConfigurable {\r
 \r
-    // see https://www.ietf.org/rfc/rfc3110.txt\r
-    // RSA/SHA1 SIG Resource Records\r
-    public static final byte[] SHA1_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14 };\r
-\r
-    public static final byte[] SHA224_DIGEST_INFO_PREFIX = new byte[] \r
-        { 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
-        , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, 0x1c };\r
-\r
-    public static final byte[] SHA256_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
-        , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20 };\r
-\r
-    public static final byte[] SHA384_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
-        , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30 };\r
-\r
-    public static final byte[] SHA512_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
-        , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40 };\r
-\r
-    public static final byte[] RIPEMD128_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x1b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x02, 0x04, 0x10 };\r
-\r
-    public static final byte[] RIPEMD160_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x01, 0x04, 0x14 };\r
-\r
-    public static final byte[] RIPEMD256_DIGEST_INFO_PREFIX = new byte[]\r
-        { 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x03, 0x04, 0x20 };\r
-\r
     private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);\r
     private static boolean isInitialized = false;\r
     \r
@@ -151,6 +116,7 @@ public class SignatureInfo implements SignatureConfigurable {
     public class SignaturePart {\r
         private final PackagePart signaturePart;\r
         private X509Certificate signer;\r
+        private List<X509Certificate> certChain;\r
         \r
         private SignaturePart(PackagePart signaturePart) {\r
             this.signaturePart = signaturePart;\r
@@ -164,6 +130,10 @@ public class SignatureInfo implements SignatureConfigurable {
             return signer;\r
         }\r
         \r
+        public List<X509Certificate> getCertChain() {\r
+            return certChain;\r
+        }\r
+        \r
         public SignatureDocument getSignatureDocument() throws IOException, XmlException {\r
             // TODO: check for XXE\r
             return SignatureDocument.Factory.parse(signaturePart.getInputStream());\r
@@ -188,7 +158,8 @@ public class SignatureInfo implements SignatureConfigurable {
                 boolean valid = xmlSignature.validate(domValidateContext);\r
 \r
                 if (valid) {\r
-                    signer = keySelector.getCertificate();\r
+                    signer = keySelector.getSigner();\r
+                    certChain = keySelector.getCertChain();\r
                 }\r
                 \r
                 return valid;\r
@@ -240,7 +211,7 @@ public class SignatureInfo implements SignatureConfigurable {
             \r
         try {\r
             ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();\r
-            digestInfoValueBuf.write(getHashMagic());\r
+            digestInfoValueBuf.write(signatureConfig.getHashMagic());\r
             digestInfoValueBuf.write(digest);\r
             byte[] digestInfoValue = digestInfoValueBuf.toByteArray();\r
             byte[] signatureValue = cipher.doFinal(digestInfoValue);\r
@@ -324,31 +295,6 @@ public class SignatureInfo implements SignatureConfigurable {
         throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!");\r
     }\r
     \r
-    protected byte[] getHashMagic() {\r
-        switch (signatureConfig.getDigestAlgo()) {\r
-        case sha1: return SHA1_DIGEST_INFO_PREFIX;\r
-        // sha224: return SHA224_DIGEST_INFO_PREFIX;\r
-        case sha256: return SHA256_DIGEST_INFO_PREFIX;\r
-        case sha384: return SHA384_DIGEST_INFO_PREFIX;\r
-        case sha512: return SHA512_DIGEST_INFO_PREFIX;\r
-        case ripemd128: return RIPEMD128_DIGEST_INFO_PREFIX;\r
-        case ripemd160: return RIPEMD160_DIGEST_INFO_PREFIX;\r
-        // case ripemd256: return RIPEMD256_DIGEST_INFO_PREFIX;\r
-        default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");\r
-        }\r
-    }\r
-\r
-    protected String getSignatureMethod() {\r
-        switch (signatureConfig.getDigestAlgo()) {\r
-        case sha1:   return ALGO_ID_SIGNATURE_RSA_SHA1;\r
-        case sha256: return ALGO_ID_SIGNATURE_RSA_SHA256;\r
-        case sha384: return ALGO_ID_SIGNATURE_RSA_SHA384;\r
-        case sha512: return ALGO_ID_SIGNATURE_RSA_SHA512;\r
-        case ripemd160: return ALGO_ID_MAC_HMAC_RIPEMD160;\r
-        default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");\r
-        }\r
-    }\r
-    \r
     protected static synchronized void initXmlProvider() {\r
         if (isInitialized) return;\r
         isInitialized = true;\r
@@ -409,8 +355,8 @@ public class SignatureInfo implements SignatureConfigurable {
         for (DigestInfo digestInfo : safe(digestInfos)) {\r
             byte[] documentDigestValue = digestInfo.digestValue;\r
 \r
-            DigestMethod digestMethod = signatureFactory.newDigestMethod(\r
-                            digestInfo.hashAlgo.xmlSignUri, null);\r
+            DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+                (signatureConfig.getDigestMethodUri(), null);\r
 \r
             String uri = new File(digestInfo.description).getName();\r
 \r
@@ -431,7 +377,8 @@ public class SignatureInfo implements SignatureConfigurable {
         /*\r
          * ds:SignedInfo\r
          */\r
-        SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(), null);\r
+        SignatureMethod signatureMethod = signatureFactory.newSignatureMethod\r
+            (signatureConfig.getSignatureMethod(), null);\r
         CanonicalizationMethod canonicalizationMethod = signatureFactory\r
             .newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),\r
             (C14NMethodParameterSpec) null);\r
index c96e932a5da3e3ed0759887b7a6419ce786f8901..b9c743548f81ea2b4900281fa967be0b2034be2b 100644 (file)
@@ -42,16 +42,15 @@ public class EnvelopedSignatureFacet implements SignatureFacet {
         , List<Reference> references\r
         , List<XMLObject> objects)\r
     throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {\r
-        DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+        DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+            (signatureConfig.getDigestMethodUri(), null);\r
 \r
         List<Transform> transforms = new ArrayList<Transform>();\r
-        Transform envelopedTransform = signatureFactory\r
-                .newTransform(CanonicalizationMethod.ENVELOPED,\r
-                        (TransformParameterSpec) null);\r
+        Transform envelopedTransform = signatureFactory.newTransform\r
+            (CanonicalizationMethod.ENVELOPED, (TransformParameterSpec) null);\r
         transforms.add(envelopedTransform);\r
-        Transform exclusiveTransform = signatureFactory\r
-                .newTransform(CanonicalizationMethod.EXCLUSIVE,\r
-                        (TransformParameterSpec) null);\r
+        Transform exclusiveTransform = signatureFactory.newTransform\r
+            (CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null);\r
         transforms.add(exclusiveTransform);\r
 \r
         Reference reference = signatureFactory.newReference("", digestMethod,\r
index b30c077641e6c91dfd5dd52fef668624052836d1..28626e8270d20b2bbb48f992341c9f97bb977a9c 100644 (file)
@@ -123,7 +123,8 @@ public class OOXMLSignatureFacet implements SignatureFacet {
         XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null);\r
         objects.add(xo);\r
 \r
-        DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+        DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+            (signatureConfig.getDigestMethodUri(), null);\r
         Reference reference = signatureFactory.newReference\r
             ("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null);\r
         references.add(reference);\r
@@ -136,7 +137,8 @@ public class OOXMLSignatureFacet implements SignatureFacet {
         OPCPackage ooxml = signatureConfig.getOpcPackage();\r
         List<PackagePart> relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART);\r
 \r
-        DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+        DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+            (signatureConfig.getDigestMethodUri(), null);\r
         Set<String> digestedPartNames = new HashSet<String>();\r
         for (PackagePart pp : relsEntryNames) {\r
             String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");\r
@@ -252,7 +254,7 @@ public class OOXMLSignatureFacet implements SignatureFacet {
 \r
         SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance();\r
         CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1();\r
-        ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestAlgo().xmlSignUri);\r
+        ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri());\r
         Element n = (Element)document.importNode(ctSigV1.getDomNode(), true);\r
         n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS);\r
         \r
@@ -271,7 +273,8 @@ public class OOXMLSignatureFacet implements SignatureFacet {
         String objectId = "idOfficeObject";\r
         objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null));\r
 \r
-        DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+        DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+            (signatureConfig.getDigestMethodUri(), null);\r
         Reference reference = signatureFactory.newReference\r
             ("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null);\r
         references.add(reference);\r
index 576fa9f514407012cbf5beef226a0008d78366c9..d34b367ddae3f70f6e3970fb6b628143bb8bc44b 100644 (file)
@@ -213,7 +213,7 @@ public class XAdESSignatureFacet implements SignatureFacet {
         objects.add(xadesObject);\r
 \r
         // add XAdES ds:Reference\r
-        DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+        DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestMethodUri(), null);\r
         List<Transform> transforms = new ArrayList<Transform>();\r
         Transform exclusiveTransform = signatureFactory\r
                 .newTransform(CanonicalizationMethod.INCLUSIVE,\r
@@ -236,11 +236,11 @@ public class XAdESSignatureFacet implements SignatureFacet {
     protected static void setDigestAlgAndValue(\r
             DigestAlgAndValueType digestAlgAndValue,\r
             byte[] data,\r
-            HashAlgorithm hashAlgo) {\r
+            HashAlgorithm digestAlgo) {\r
         DigestMethodType digestMethod = digestAlgAndValue.addNewDigestMethod();\r
-        digestMethod.setAlgorithm(hashAlgo.xmlSignUri);\r
+        digestMethod.setAlgorithm(SignatureConfig.getDigestMethodUri(digestAlgo));\r
         \r
-        MessageDigest messageDigest = CryptoFunctions.getMessageDigest(hashAlgo);\r
+        MessageDigest messageDigest = CryptoFunctions.getMessageDigest(digestAlgo);\r
         byte[] digestValue = messageDigest.digest(data);\r
         digestAlgAndValue.setDigestValue(digestValue);\r
     }\r
index 77299c937d589d13b232c5d5e74448ad0d361707..4444abe89d6dd536769cf7f3ce8df372e4dbc426 100644 (file)
@@ -24,6 +24,7 @@
 package org.apache.poi.poifs.crypt;\r
 \r
 import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertFalse;\r
 import static org.junit.Assert.assertNotNull;\r
 import static org.junit.Assert.assertTrue;\r
 \r
@@ -31,6 +32,8 @@ import java.io.File;
 import java.io.FileInputStream;\r
 import java.io.FileOutputStream;\r
 import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.lang.reflect.Method;\r
 import java.net.MalformedURLException;\r
 import java.net.URL;\r
 import java.net.URLClassLoader;\r
@@ -68,6 +71,7 @@ import org.apache.poi.util.DocumentHelper;
 import org.apache.poi.util.IOUtils;\r
 import org.apache.poi.util.POILogFactory;\r
 import org.apache.poi.util.POILogger;\r
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;\r
 import org.apache.xmlbeans.XmlObject;\r
 import org.bouncycastle.asn1.x509.KeyUsage;\r
 import org.bouncycastle.cert.ocsp.OCSPResp;\r
@@ -207,6 +211,35 @@ public class TestSignatureInfo {
         pkg.close();\r
     }\r
 \r
+    @Test\r
+    public void testManipulation() throws Exception {\r
+        // sign & validate\r
+        String testFile = "hello-world-unsigned.xlsx";\r
+        OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+        sign(pkg, "Test", "CN=Test", 1);\r
+        \r
+        // manipulate\r
+        XSSFWorkbook wb = new XSSFWorkbook(pkg);\r
+        wb.setSheetName(0, "manipulated");\r
+        // ... I don't know, why commit is protected ...\r
+        Method m = XSSFWorkbook.class.getDeclaredMethod("commit");\r
+        m.setAccessible(true);\r
+        m.invoke(wb);\r
+\r
+        // todo: test a manipulation on a package part, which is not signed\r
+        // ... maybe in combination with #56164 \r
+        \r
+        // validate\r
+        SignatureConfig sic = new SignatureConfig();\r
+        sic.setOpcPackage(pkg);\r
+        SignatureInfo si = new SignatureInfo();\r
+        si.setSignatureConfig(sic);\r
+        boolean b = si.verifySignature();\r
+        assertFalse("signature should be broken", b);\r
+        \r
+        wb.close();\r
+    }\r
+    \r
     @Test\r
     public void testSignSpreadsheetWithSignatureInfo() throws Exception {\r
         initKeyPair("Test", "CN=Test");\r
@@ -321,7 +354,7 @@ public class TestSignatureInfo {
             "$this/ds:Signature/ds:SignedInfo/ds:Reference";\r
         for (ReferenceType rt : (ReferenceType[])sigDoc.selectPath(digestValXQuery)) {\r
             assertNotNull(rt.getDigestValue());\r
-            assertEquals(HashAlgorithm.sha1.xmlSignUri, rt.getDigestMethod().getAlgorithm());\r
+            assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());\r
         }\r
 \r
         String certDigestXQuery = declareNS +\r
@@ -341,8 +374,83 @@ public class TestSignatureInfo {
 \r
         pkg.close();\r
     }\r
+\r
+    @Test\r
+    public void testCertChain() throws Exception {\r
+        KeyStore keystore = KeyStore.getInstance("PKCS12");\r
+        String password = "test";\r
+        InputStream is = testdata.openResourceAsStream("chaintest.pfx");\r
+        keystore.load(is, password.toCharArray());\r
+        is.close();\r
+\r
+        Key key = keystore.getKey("poitest", password.toCharArray());\r
+        Certificate chainList[] = keystore.getCertificateChain("poitest");\r
+        List<X509Certificate> certChain = new ArrayList<X509Certificate>();\r
+        for (Certificate c : chainList) {\r
+            certChain.add((X509Certificate)c);\r
+        }\r
+        x509 = certChain.get(0);\r
+        keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);\r
+        \r
+        String testFile = "hello-world-unsigned.xlsx";\r
+        OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+\r
+        SignatureConfig signatureConfig = new SignatureConfig();\r
+        signatureConfig.setKey(keyPair.getPrivate());\r
+        signatureConfig.setSigningCertificateChain(certChain);\r
+        Calendar cal = Calendar.getInstance();\r
+        cal.set(2007, 7, 1);\r
+        signatureConfig.setExecutionTime(cal.getTime());\r
+        signatureConfig.setDigestAlgo(HashAlgorithm.sha1);\r
+        signatureConfig.setOpcPackage(pkg);\r
+        \r
+        SignatureInfo si = new SignatureInfo();\r
+        si.setSignatureConfig(signatureConfig);\r
+\r
+        si.confirmSignature();\r
+        \r
+        for (SignaturePart sp : si.getSignatureParts()){\r
+            boolean b = sp.validate();\r
+            assertTrue(b);\r
+            X509Certificate signer = sp.getSigner();\r
+            assertNotNull("signer undefined?!", signer);\r
+            List<X509Certificate> certChainRes = sp.getCertChain();\r
+            assertEquals(3, certChainRes.size());\r
+        }\r
+        \r
+        pkg.close();\r
+    }\r
+\r
+    @Test\r
+    public void testNonSha1() throws Exception {\r
+        String testFile = "hello-world-unsigned.xlsx";\r
+        initKeyPair("Test", "CN=Test");\r
+\r
+        SignatureConfig signatureConfig = new SignatureConfig();\r
+        signatureConfig.setKey(keyPair.getPrivate());\r
+        signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));\r
+\r
+        HashAlgorithm testAlgo[] = { HashAlgorithm.sha224, HashAlgorithm.sha256\r
+            , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160 }; \r
+        \r
+        for (HashAlgorithm ha : testAlgo) {\r
+            signatureConfig.setDigestAlgo(ha);\r
+            OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+            signatureConfig.setOpcPackage(pkg);\r
+            \r
+            SignatureInfo si = new SignatureInfo();\r
+            si.setSignatureConfig(signatureConfig);\r
+    \r
+            si.confirmSignature();\r
+            boolean b = si.verifySignature();\r
+            pkg.close();\r
     \r
-    private OPCPackage sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {\r
+            assertTrue(b);\r
+        }\r
+    }\r
+    \r
+    \r
+    private void sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {\r
         initKeyPair(alias, signerDn);\r
 \r
         SignatureConfig signatureConfig = new SignatureConfig();\r
@@ -383,8 +491,6 @@ public class TestSignatureInfo {
             }\r
         }\r
         assertEquals(signerCount, result.size());\r
-\r
-        return pkgCopy;\r
     }\r
 \r
     private void initKeyPair(String alias, String subjectDN) throws Exception {\r
diff --git a/test-data/xmldsign/chaintest.pfx b/test-data/xmldsign/chaintest.pfx
new file mode 100644 (file)
index 0000000..e92106d
Binary files /dev/null and b/test-data/xmldsign/chaintest.pfx differ