1 /*
   2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @bug 4635230 6365103 6366054 6824440 7131084 8046724
  27  * @summary Basic unit tests for validating XML Signatures with JSR 105
  28  * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java
  29  *     X509KeySelector.java ValidationTests.java
  30  * @run main/othervm ValidationTests
  31  * @author Sean Mullan
  32  */
  33 import java.io.File;
  34 import java.io.FileInputStream;
  35 import java.security.*;
  36 import javax.xml.crypto.Data;
  37 import javax.xml.crypto.KeySelector;
  38 import javax.xml.crypto.OctetStreamData;
  39 import javax.xml.crypto.URIDereferencer;
  40 import javax.xml.crypto.URIReference;
  41 import javax.xml.crypto.URIReferenceException;
  42 import javax.xml.crypto.XMLCryptoContext;
  43 import javax.xml.crypto.dsig.XMLSignatureException;
  44 import javax.xml.crypto.dsig.XMLSignatureFactory;
  45 
  46 public class ValidationTests {
  47 
  48     private static SignatureValidator validator;
  49     private final static String DIR = System.getProperty("test.src", ".");
  50     private final static String DATA_DIR =
  51         DIR + System.getProperty("file.separator") + "data";
  52     private final static String KEYSTORE =
  53         DATA_DIR + System.getProperty("file.separator") + "certs" +
  54         System.getProperty("file.separator") + "xmldsig.jks";
  55     private final static String STYLESHEET =
  56         "http://www.w3.org/TR/xml-stylesheet";
  57     private final static String STYLESHEET_B64 =
  58         "http://www.w3.org/Signature/2002/04/xml-stylesheet.b64";
  59 
  60     static class Test {
  61         String file;
  62         KeySelector ks;
  63         Test(String file, KeySelector ks) {
  64             this.file = file;
  65             this.ks = ks;
  66         }
  67     }
  68 
  69     static KeySelector skks;
  70     static {
  71         try {
  72             skks =
  73                 new KeySelectors.SecretKeySelector("secret".getBytes("ASCII"));
  74         } catch (Exception e) {
  75             //should not occur
  76         }
  77     }
  78     private final static KeySelector SKKS = skks;
  79     private final static KeySelector KVKS =
  80         new KeySelectors.KeyValueKeySelector();
  81     private final static KeySelector CKS =
  82         new KeySelectors.CollectionKeySelector(new File(DATA_DIR));
  83     private final static KeySelector RXKS =
  84         new KeySelectors.RawX509KeySelector();
  85     private final static KeySelector XKS = null;
  86     private static URIDereferencer httpUd = null;
  87 
  88     private final static Test[] VALID_TESTS = {
  89         new Test("signature-enveloped-dsa.xml", KVKS),
  90         new Test("signature-enveloping-b64-dsa.xml", KVKS),
  91         new Test("signature-enveloping-dsa.xml", KVKS),
  92         new Test("signature-enveloping-rsa.xml", KVKS),
  93         new Test("signature-enveloping-p256-sha1.xml", KVKS),
  94         new Test("signature-enveloping-hmac-sha1.xml", SKKS),
  95         new Test("signature-external-dsa.xml", KVKS),
  96         new Test("signature-external-b64-dsa.xml", KVKS),
  97         new Test("signature-retrievalmethod-rawx509crt.xml", CKS),
  98         new Test("signature-keyname.xml", CKS),
  99         new Test("signature-x509-crt-crl.xml", RXKS),
 100         new Test("signature-x509-crt.xml", RXKS),
 101         new Test("signature-x509-is.xml", CKS),
 102         new Test("signature-x509-ski.xml", CKS),
 103         new Test("signature-x509-sn.xml", CKS),
 104         new Test("signature.xml", XKS),
 105         new Test("exc-signature.xml", KVKS),
 106         new Test("sign-spec.xml", RXKS),
 107         new Test("xmldsig-xfilter2.xml", KVKS)
 108     };
 109 
 110     private final static Test[] INVALID_TESTS = {
 111         new Test("signature-enveloping-hmac-sha1-40.xml", SKKS),
 112         new Test("signature-enveloping-hmac-sha1-trunclen-0-attack.xml", SKKS),
 113         new Test("signature-enveloping-hmac-sha1-trunclen-8-attack.xml", SKKS)
 114     };
 115 
 116     public static void main(String args[]) throws Exception {
 117         httpUd = new HttpURIDereferencer();
 118 
 119         validator = new SignatureValidator(new File(DATA_DIR));
 120 
 121         boolean atLeastOneFailed = false;
 122         for (Test test : VALID_TESTS) {
 123             System.out.println("Validating " + test.file);
 124             if (test_signature(test)) {
 125                 System.out.println("PASSED");
 126             } else {
 127                 System.out.println("FAILED");
 128                 atLeastOneFailed = true;
 129             }
 130         }
 131         // test with reference caching enabled
 132         System.out.println("Validating sign-spec.xml with caching enabled");
 133         if (test_signature(new Test("sign-spec.xml", RXKS), true)) {
 134             System.out.println("PASSED");
 135         } else {
 136             System.out.println("FAILED");
 137             atLeastOneFailed = true;
 138         }
 139 
 140         for (Test test : INVALID_TESTS) {
 141             System.out.println("Validating " + test.file);
 142             try {
 143                 test_signature(test);
 144                 System.out.println("FAILED");
 145                 atLeastOneFailed = true;
 146             } catch (XMLSignatureException xse) {
 147                 System.out.println(xse.getMessage());
 148                 System.out.println("PASSED");
 149             }
 150         }
 151 
 152         if (atLeastOneFailed) {
 153             throw new Exception
 154                 ("At least one signature did not validate as expected");
 155         }
 156     }
 157 
 158     public static boolean test_signature(Test test) throws Exception {
 159         return test_signature(test, false);
 160     }
 161 
 162     public static boolean test_signature(Test test, boolean cache)
 163         throws Exception
 164     {
 165         if (test.ks == null) {
 166             KeyStore keystore = KeyStore.getInstance("JKS");
 167             try (FileInputStream fis = new FileInputStream(KEYSTORE)) {
 168                 keystore.load(fis, "changeit".toCharArray());
 169                 test.ks = new X509KeySelector(keystore, false);
 170             }
 171         }
 172         return validator.validate(test.file, test.ks, httpUd, cache);
 173     }
 174 
 175     /**
 176      * This URIDereferencer returns locally cached copies of http content to
 177      * avoid test failures due to network glitches, etc.
 178      */
 179     private static class HttpURIDereferencer implements URIDereferencer {
 180         private URIDereferencer defaultUd;
 181 
 182         HttpURIDereferencer() {
 183             defaultUd = XMLSignatureFactory.getInstance().getURIDereferencer();
 184         }
 185 
 186         public Data dereference(final URIReference ref, XMLCryptoContext ctx)
 187         throws URIReferenceException {
 188             String uri = ref.getURI();
 189             if (uri.equals(STYLESHEET) || uri.equals(STYLESHEET_B64)) {
 190                 try {
 191                     FileInputStream fis = new FileInputStream(new File
 192                         (DATA_DIR, uri.substring(uri.lastIndexOf('/'))));
 193                     return new OctetStreamData(fis,ref.getURI(),ref.getType());
 194                 } catch (Exception e) { throw new URIReferenceException(e); }
 195             }
 196 
 197             // fallback on builtin deref
 198             return defaultUd.dereference(ref, ctx);
 199         }
 200     }
 201 }