/* * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @test * @bug 4635230 6365103 6366054 6824440 7131084 8046724 8079693 * @summary Basic unit tests for validating XML Signatures with JSR 105 * @modules java.base/sun.security.util * java.base/sun.security.x509 * java.xml.crypto/org.jcp.xml.dsig.internal.dom * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java * X509KeySelector.java ValidationTests.java * @run main/othervm ValidationTests * @author Sean Mullan */ import java.io.File; import java.io.FileInputStream; import java.security.*; import javax.xml.crypto.Data; import javax.xml.crypto.KeySelector; import javax.xml.crypto.MarshalException; import javax.xml.crypto.OctetStreamData; import javax.xml.crypto.URIDereferencer; import javax.xml.crypto.URIReference; import javax.xml.crypto.URIReferenceException; import javax.xml.crypto.XMLCryptoContext; import javax.xml.crypto.dsig.XMLSignatureException; import javax.xml.crypto.dsig.XMLSignatureFactory; public class ValidationTests { private static SignatureValidator validator; private final static String DIR = System.getProperty("test.src", "."); private final static String DATA_DIR = DIR + System.getProperty("file.separator") + "data"; private final static String KEYSTORE = DATA_DIR + System.getProperty("file.separator") + "certs" + System.getProperty("file.separator") + "xmldsig.jks"; private final static String STYLESHEET = "http://www.w3.org/TR/xml-stylesheet"; private final static String STYLESHEET_B64 = "http://www.w3.org/Signature/2002/04/xml-stylesheet.b64"; static class Test { String file; KeySelector ks; Class exception; Test(String file, KeySelector ks, Class exception) { this.file = file; this.ks = ks; this.exception = exception; } // XMLSignatureException is expected by default Test(String file, KeySelector ks) { this(file, ks, XMLSignatureException.class); } } static KeySelector skks; static { try { skks = new KeySelectors.SecretKeySelector("secret".getBytes("ASCII")); } catch (Exception e) { //should not occur } } private final static KeySelector SKKS = skks; private final static KeySelector KVKS = new KeySelectors.KeyValueKeySelector(); private final static KeySelector CKS = new KeySelectors.CollectionKeySelector(new File(DATA_DIR)); private final static KeySelector RXKS = new KeySelectors.RawX509KeySelector(); private final static KeySelector XKS = null; private static URIDereferencer httpUd = null; private final static Test[] VALID_TESTS = { new Test("signature-enveloped-dsa.xml", KVKS), new Test("signature-enveloping-b64-dsa.xml", KVKS), new Test("signature-enveloping-dsa.xml", KVKS), new Test("signature-enveloping-rsa.xml", KVKS), new Test("signature-enveloping-p256-sha1.xml", KVKS), new Test("signature-enveloping-p384-sha1.xml", KVKS), new Test("signature-enveloping-p521-sha1.xml", KVKS), new Test("signature-enveloping-hmac-sha1.xml", SKKS), new Test("signature-external-dsa.xml", KVKS), new Test("signature-external-b64-dsa.xml", KVKS), new Test("signature-retrievalmethod-rawx509crt.xml", CKS), new Test("signature-keyname.xml", CKS), new Test("signature-x509-crt-crl.xml", RXKS), new Test("signature-x509-crt.xml", RXKS), new Test("signature-x509-is.xml", CKS), new Test("signature-x509-ski.xml", CKS), new Test("signature-x509-sn.xml", CKS), new Test("signature.xml", XKS), new Test("exc-signature.xml", KVKS), new Test("sign-spec.xml", RXKS), new Test("xmldsig-xfilter2.xml", KVKS) }; private final static Test[] INVALID_TESTS = { new Test("signature-enveloping-hmac-sha1-40.xml", SKKS), new Test("signature-enveloping-hmac-sha1-trunclen-0-attack.xml", SKKS), new Test("signature-enveloping-hmac-sha1-trunclen-8-attack.xml", SKKS), new Test("signature-extra-text-in-signed-info.xml", SKKS, MarshalException.class), new Test("signature-wrong-canonicalization-method-algorithm.xml", SKKS, MarshalException.class), new Test("signature-wrong-transform-algorithm.xml", SKKS, MarshalException.class), new Test("signature-no-reference-uri.xml", SKKS), new Test("signature-wrong-signature-method-algorithm.xml", SKKS, MarshalException.class), new Test("signature-wrong-tag-names.xml", SKKS, MarshalException.class) }; public static void main(String args[]) throws Exception { httpUd = new HttpURIDereferencer(); validator = new SignatureValidator(new File(DATA_DIR)); boolean atLeastOneFailed = false; for (Test test : VALID_TESTS) { System.out.println("Validating " + test.file); if (test_signature(test)) { System.out.println("PASSED"); } else { System.out.println("FAILED"); atLeastOneFailed = true; } } // test with reference caching enabled System.out.println("Validating sign-spec.xml with caching enabled"); if (test_signature(new Test("sign-spec.xml", RXKS), true)) { System.out.println("PASSED"); } else { System.out.println("FAILED"); atLeastOneFailed = true; } for (Test test : INVALID_TESTS) { System.out.println("Validating " + test.file); try { test_signature(test); System.out.println("FAILED"); atLeastOneFailed = true; } catch (Exception e) { System.out.println("Exception: " + e); if (e.getClass() != test.exception) { System.out.println("FAILED: unexpected exception"); atLeastOneFailed = true; } else { System.out.println("PASSED"); } } } if (atLeastOneFailed) { throw new Exception ("At least one signature did not validate as expected"); } } public static boolean test_signature(Test test) throws Exception { return test_signature(test, false); } public static boolean test_signature(Test test, boolean cache) throws Exception { if (test.ks == null) { KeyStore keystore = KeyStore.getInstance("JKS"); try (FileInputStream fis = new FileInputStream(KEYSTORE)) { keystore.load(fis, "changeit".toCharArray()); test.ks = new X509KeySelector(keystore, false); } } return validator.validate(test.file, test.ks, httpUd, cache); } /** * This URIDereferencer returns locally cached copies of http content to * avoid test failures due to network glitches, etc. */ private static class HttpURIDereferencer implements URIDereferencer { private URIDereferencer defaultUd; HttpURIDereferencer() { defaultUd = XMLSignatureFactory.getInstance().getURIDereferencer(); } public Data dereference(final URIReference ref, XMLCryptoContext ctx) throws URIReferenceException { String uri = ref.getURI(); if (uri.equals(STYLESHEET) || uri.equals(STYLESHEET_B64)) { try { FileInputStream fis = new FileInputStream(new File (DATA_DIR, uri.substring(uri.lastIndexOf('/')))); return new OctetStreamData(fis,ref.getURI(),ref.getType()); } catch (Exception e) { throw new URIReferenceException(e); } } // fallback on builtin deref return defaultUd.dereference(ref, ctx); } } }