diff -r 4ebc2e2fb97c -r 71c04702a3d5 test/jdk/sun/security/pkcs11/PKCS11Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,761 @@ +/* + * Copyright (c) 2003, 2016, 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. + */ + + +// common infrastructure for SunPKCS11 tests + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPairGenerator; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.ProviderException; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.Set; + +public abstract class PKCS11Test { + + private boolean enableSM = false; + + static final Properties props = System.getProperties(); + + static final String PKCS11 = "PKCS11"; + + // directory of the test source + static final String BASE = System.getProperty("test.src", "."); + + static final char SEP = File.separatorChar; + + private static final String DEFAULT_POLICY = + BASE + SEP + ".." + SEP + "policy"; + + // directory corresponding to BASE in the /closed hierarchy + static final String CLOSED_BASE; + + static { + // hack + String absBase = new File(BASE).getAbsolutePath(); + int k = absBase.indexOf(SEP + "test" + SEP + "sun" + SEP); + if (k < 0) k = 0; + String p1 = absBase.substring(0, k + 6); + String p2 = absBase.substring(k + 5); + CLOSED_BASE = p1 + "closed" + p2; + + // set it as a system property to make it available in policy file + System.setProperty("closed.base", CLOSED_BASE); + } + + // NSS version info + public static enum ECCState { None, Basic, Extended }; + static double nss_version = -1; + static ECCState nss_ecc_status = ECCState.Extended; + + // The NSS library we need to search for in getNSSLibDir() + // Default is "libsoftokn3.so", listed as "softokn3" + // The other is "libnss3.so", listed as "nss3". + static String nss_library = "softokn3"; + + // NSS versions of each library. It is simplier to keep nss_version + // for quick checking for generic testing than many if-else statements. + static double softoken3_version = -1; + static double nss3_version = -1; + static Provider pkcs11; + + // Goes through ServiceLoader instead of Provider.getInstance() since it + // works on all platforms + static { + ServiceLoader sl = ServiceLoader.load(java.security.Provider.class); + Iterator iter = sl.iterator(); + Provider p = null; + boolean found = false; + while (iter.hasNext()) { + try { + p = iter.next(); + if (p.getName().equals("SunPKCS11")) { + found = true; + break; + } + } catch (Exception | ServiceConfigurationError e) { + // ignore and move on to the next one + } + } + // Nothing found through ServiceLoader; fall back to reflection + if (!found) { + try { + Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11"); + p = (Provider) clazz.newInstance(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + pkcs11 = p; + } + + /* + * Use Solaris SPARC 11.2 or later to avoid an intermittent failure + * when running SunPKCS11-Solaris (8044554) + */ + static boolean isBadSolarisSparc(Provider p) { + if ("SunPKCS11-Solaris".equals(p.getName()) && badSolarisSparc) { + System.out.println("SunPKCS11-Solaris provider requires " + + "Solaris SPARC 11.2 or later, skipping"); + return true; + } + return false; + } + + // Return a SunPKCS11 provider configured with the specified config file + static Provider getSunPKCS11(String config) throws Exception { + if (pkcs11 == null) { + throw new NoSuchProviderException("No PKCS11 provider available"); + } + return pkcs11.configure(config); + } + + public abstract void main(Provider p) throws Exception; + + private void premain(Provider p) throws Exception { + // set a security manager and policy before a test case runs, + // and disable them after the test case finished + try { + if (enableSM) { + System.setSecurityManager(new SecurityManager()); + } + long start = System.currentTimeMillis(); + System.out.printf( + "Running test with provider %s (security manager %s) ...%n", + p.getName(), enableSM ? "enabled" : "disabled"); + main(p); + long stop = System.currentTimeMillis(); + System.out.println("Completed test with provider " + p.getName() + + " (" + (stop - start) + " ms)."); + } finally { + if (enableSM) { + System.setSecurityManager(null); + } + } + } + + public static void main(PKCS11Test test) throws Exception { + main(test, null); + } + + public static void main(PKCS11Test test, String[] args) throws Exception { + if (args != null) { + if (args.length > 0) { + if ("sm".equals(args[0])) { + test.enableSM = true; + } else { + throw new RuntimeException("Unknown Command, use 'sm' as " + + "first arguemtn to enable security manager"); + } + } + if (test.enableSM) { + System.setProperty("java.security.policy", + (args.length > 1) ? BASE + SEP + args[1] + : DEFAULT_POLICY); + } + } + + Provider[] oldProviders = Security.getProviders(); + try { + System.out.println("Beginning test run " + test.getClass().getName() + "..."); + testDefault(test); + testNSS(test); + testDeimos(test); + } finally { + // NOTE: Do not place a 'return' in any finally block + // as it will suppress exceptions and hide test failures. + Provider[] newProviders = Security.getProviders(); + boolean found = true; + // Do not restore providers if nothing changed. This is especailly + // useful for ./Provider/Login.sh, where a SecurityManager exists. + if (oldProviders.length == newProviders.length) { + found = false; + for (int i = 0; i -1) + return softoken3_version; + if (library.compareTo("nss3") == 0 && nss3_version > -1) + return nss3_version; + + try { + libfile = getNSSLibDir() + System.mapLibraryName(library); + try (FileInputStream is = new FileInputStream(libfile)) { + byte[] data = new byte[1000]; + int read = 0; + + while (is.available() > 0) { + if (read == 0) { + read = is.read(data, 0, 1000); + } else { + // Prepend last 100 bytes in case the header was split + // between the reads. + System.arraycopy(data, 900, data, 0, 100); + read = 100 + is.read(data, 100, 900); + } + + s = new String(data, 0, read); + i = s.indexOf(nssHeader1); + if (i > 0 || (i = s.indexOf(nssHeader2)) > 0) { + found = true; + // If the nssHeader is before 920 we can break, otherwise + // we may not have the whole header so do another read. If + // no bytes are in the stream, that is ok, found is true. + if (i < 920) { + break; + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + if (!found) { + System.out.println("lib" + library + + " version not found, set to 0.0: " + libfile); + nss_version = 0.0; + return nss_version; + } + + // the index after whitespace after nssHeader + int afterheader = s.indexOf("NSS", i) + 4; + String version = s.substring(afterheader, s.indexOf(' ', afterheader)); + + // If a "dot dot" release, strip the extra dots for double parsing + String[] dot = version.split("\\."); + if (dot.length > 2) { + version = dot[0]+"."+dot[1]; + for (int j = 2; dot.length > j; j++) { + version += dot[j]; + } + } + + // Convert to double for easier version value checking + try { + nss_version = Double.parseDouble(version); + } catch (NumberFormatException e) { + System.out.println("Failed to parse lib" + library + + " version. Set to 0.0"); + e.printStackTrace(); + } + + System.out.print("lib" + library + " version = "+version+". "); + + // Check for ECC + if (s.indexOf("Basic") > 0) { + nss_ecc_status = ECCState.Basic; + System.out.println("ECC Basic."); + } else if (s.indexOf("Extended") > 0) { + nss_ecc_status = ECCState.Extended; + System.out.println("ECC Extended."); + } else { + System.out.println("ECC None."); + } + + if (library.compareTo("softokn3") == 0) { + softoken3_version = nss_version; + } else if (library.compareTo("nss3") == 0) { + nss3_version = nss_version; + } + + return nss_version; + } + + // Used to set the nss_library file to search for libsoftokn3.so + public static void useNSS() { + nss_library = "nss3"; + } + + public static void testNSS(PKCS11Test test) throws Exception { + String libdir = getNSSLibDir(); + if (libdir == null) { + return; + } + String base = getBase(); + + if (loadNSPR(libdir) == false) { + return; + } + + String libfile = libdir + System.mapLibraryName(nss_library); + + String customDBdir = System.getProperty("CUSTOM_DB_DIR"); + String dbdir = (customDBdir != null) ? + customDBdir : + base + SEP + "nss" + SEP + "db"; + // NSS always wants forward slashes for the config path + dbdir = dbdir.replace('\\', '/'); + + String customConfig = System.getProperty("CUSTOM_P11_CONFIG"); + String customConfigName = System.getProperty("CUSTOM_P11_CONFIG_NAME", "p11-nss.txt"); + String p11config = (customConfig != null) ? + customConfig : + base + SEP + "nss" + SEP + customConfigName; + + System.setProperty("pkcs11test.nss.lib", libfile); + System.setProperty("pkcs11test.nss.db", dbdir); + Provider p = getSunPKCS11(p11config); + test.premain(p); + } + + // Generate a vector of supported elliptic curves of a given provider + static List getKnownCurves(Provider p) throws Exception { + int index; + int begin; + int end; + String curve; + + List results = new ArrayList<>(); + // Get Curves to test from SunEC. + String kcProp = Security.getProvider("SunEC"). + getProperty("AlgorithmParameters.EC SupportedCurves"); + + if (kcProp == null) { + throw new RuntimeException( + "\"AlgorithmParameters.EC SupportedCurves property\" not found"); + } + + System.out.println("Finding supported curves using list from SunEC\n"); + index = 0; + for (;;) { + // Each set of curve names is enclosed with brackets. + begin = kcProp.indexOf('[', index); + end = kcProp.indexOf(']', index); + if (begin == -1 || end == -1) { + break; + } + + /* + * Each name is separated by a comma. + * Just get the first name in the set. + */ + index = end + 1; + begin++; + end = kcProp.indexOf(',', begin); + if (end == -1) { + // Only one name in the set. + end = index -1; + } + + curve = kcProp.substring(begin, end); + ECParameterSpec e = getECParameterSpec(p, curve); + System.out.print("\t "+ curve + ": "); + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); + kpg.initialize(e); + kpg.generateKeyPair(); + results.add(e); + System.out.println("Supported"); + } catch (ProviderException ex) { + System.out.println("Unsupported: PKCS11: " + + ex.getCause().getMessage()); + } catch (InvalidAlgorithmParameterException ex) { + System.out.println("Unsupported: Key Length: " + + ex.getMessage()); + } + } + + if (results.size() == 0) { + throw new RuntimeException("No supported EC curves found"); + } + + return results; + } + + private static ECParameterSpec getECParameterSpec(Provider p, String name) + throws Exception { + + AlgorithmParameters parameters = + AlgorithmParameters.getInstance("EC", p); + + parameters.init(new ECGenParameterSpec(name)); + + return parameters.getParameterSpec(ECParameterSpec.class); + } + + // Check support for a curve with a provided Vector of EC support + boolean checkSupport(List supportedEC, + ECParameterSpec curve) { + for (ECParameterSpec ec: supportedEC) { + if (ec.equals(curve)) { + return true; + } + } + return false; + } + + private static final Map osMap; + + // Location of the NSS libraries on each supported platform + static { + osMap = new HashMap<>(); + osMap.put("SunOS-sparc-32", new String[]{"/usr/lib/mps/"}); + osMap.put("SunOS-sparcv9-64", new String[]{"/usr/lib/mps/64/"}); + osMap.put("SunOS-x86-32", new String[]{"/usr/lib/mps/"}); + osMap.put("SunOS-amd64-64", new String[]{"/usr/lib/mps/64/"}); + osMap.put("Linux-i386-32", new String[]{ + "/usr/lib/i386-linux-gnu/", "/usr/lib32/", "/usr/lib/"}); + osMap.put("Linux-amd64-64", new String[]{ + "/usr/lib/x86_64-linux-gnu/", "/usr/lib/x86_64-linux-gnu/nss/", + "/usr/lib64/"}); + osMap.put("Linux-ppc64-64", new String[]{"/usr/lib64/"}); + osMap.put("Linux-ppc64le-64", new String[]{"/usr/lib64/"}); + osMap.put("Windows-x86-32", new String[]{ + PKCS11_BASE + "/nss/lib/windows-i586/".replace('/', SEP)}); + osMap.put("Windows-amd64-64", new String[]{ + PKCS11_BASE + "/nss/lib/windows-amd64/".replace('/', SEP)}); + osMap.put("MacOSX-x86_64-64", new String[]{ + PKCS11_BASE + "/nss/lib/macosx-x86_64/"}); + osMap.put("Linux-arm-32", new String[]{ + "/usr/lib/arm-linux-gnueabi/nss/", + "/usr/lib/arm-linux-gnueabihf/nss/"}); + osMap.put("Linux-aarch64-64", new String[]{ + "/usr/lib/aarch64-linux-gnu/nss/"}); + } + + private final static char[] hexDigits = "0123456789abcdef".toCharArray(); + + static final boolean badNSSVersion = + getNSSVersion() >= 3.11 && getNSSVersion() < 3.12; + + private static final String distro = distro(); + + static final boolean badSolarisSparc = + System.getProperty("os.name").equals("SunOS") && + System.getProperty("os.arch").equals("sparcv9") && + System.getProperty("os.version").compareTo("5.11") <= 0 && + getDistro().compareTo("11.2") < 0; + + public static String toString(byte[] b) { + if (b == null) { + return "(null)"; + } + StringBuilder sb = new StringBuilder(b.length * 3); + for (int i = 0; i < b.length; i++) { + int k = b[i] & 0xff; + if (i != 0) { + sb.append(':'); + } + sb.append(hexDigits[k >>> 4]); + sb.append(hexDigits[k & 0xf]); + } + return sb.toString(); + } + + public static byte[] parse(String s) { + if (s.equals("(null)")) { + return null; + } + try { + int n = s.length(); + ByteArrayOutputStream out = new ByteArrayOutputStream(n / 3); + StringReader r = new StringReader(s); + while (true) { + int b1 = nextNibble(r); + if (b1 < 0) { + break; + } + int b2 = nextNibble(r); + if (b2 < 0) { + throw new RuntimeException("Invalid string " + s); + } + int b = (b1 << 4) | b2; + out.write(b); + } + return out.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static int nextNibble(StringReader r) throws IOException { + while (true) { + int ch = r.read(); + if (ch == -1) { + return -1; + } else if ((ch >= '0') && (ch <= '9')) { + return ch - '0'; + } else if ((ch >= 'a') && (ch <= 'f')) { + return ch - 'a' + 10; + } else if ((ch >= 'A') && (ch <= 'F')) { + return ch - 'A' + 10; + } + } + } + + T[] concat(T[] a, T[] b) { + if ((b == null) || (b.length == 0)) { + return a; + } + T[] r = Arrays.copyOf(a, a.length + b.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; + } + + /** + * Returns supported algorithms of specified type. + */ + static List getSupportedAlgorithms(String type, String alg, + Provider p) { + // prepare a list of supported algorithms + List algorithms = new ArrayList<>(); + Set services = p.getServices(); + for (Provider.Service service : services) { + if (service.getType().equals(type) + && service.getAlgorithm().startsWith(alg)) { + algorithms.add(service.getAlgorithm()); + } + } + return algorithms; + } + + /** + * Get the identifier for the operating system distribution + */ + static String getDistro() { + return distro; + } + + private static String distro() { + try (BufferedReader in = + new BufferedReader(new InputStreamReader( + Runtime.getRuntime().exec("uname -v").getInputStream()))) { + + return in.readLine(); + } catch (Exception e) { + throw new RuntimeException("Failed to determine distro.", e); + } + } + + static byte[] generateData(int length) { + byte data[] = new byte[length]; + for (int i=0; i