Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/security/pkcs11/PKCS11Test.java
38840 views
/*1* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/222324// common infrastructure for SunPKCS11 tests2526import java.io.BufferedReader;27import java.io.ByteArrayOutputStream;28import java.io.File;29import java.io.FileInputStream;30import java.io.IOException;31import java.io.InputStreamReader;32import java.io.StringReader;33import java.lang.reflect.Constructor;34import java.nio.charset.StandardCharsets;35import java.security.AlgorithmParameters;36import java.security.InvalidAlgorithmParameterException;37import java.security.KeyPairGenerator;38import java.security.NoSuchProviderException;39import java.security.Provider;40import java.security.ProviderException;41import java.security.Security;4243import java.security.spec.ECGenParameterSpec;44import java.security.spec.ECParameterSpec;45import java.util.ArrayList;46import java.util.Arrays;47import java.util.HashMap;48import java.util.Iterator;49import java.util.List;50import java.util.Map;51import java.util.Properties;52import java.util.ServiceLoader;53import java.util.Set;5455public abstract class PKCS11Test {5657private boolean enableSM = false;5859static final Properties props = System.getProperties();6061static final String PKCS11 = "PKCS11";6263// directory of the test source64static final String BASE = System.getProperty("test.src", ".");6566static final char SEP = File.separatorChar;6768private static final String DEFAULT_POLICY =69BASE + SEP + ".." + SEP + "policy";7071// directory corresponding to BASE in the /closed hierarchy72static final String CLOSED_BASE;7374static {75// hack76String absBase = new File(BASE).getAbsolutePath();77int k = absBase.indexOf(SEP + "test" + SEP + "sun" + SEP);78if (k < 0) k = 0;79String p1 = absBase.substring(0, k + 6);80String p2 = absBase.substring(k + 5);81CLOSED_BASE = p1 + "closed" + p2;8283// set it as a system property to make it available in policy file84System.setProperty("closed.base", CLOSED_BASE);85}8687static String NSPR_PREFIX = "";8889// NSS version info90public static enum ECCState { None, Basic, Extended };91static double nss_version = -1;92static ECCState nss_ecc_status = ECCState.Extended;9394// The NSS library we need to search for in getNSSLibDir()95// Default is "libsoftokn3.so", listed as "softokn3"96// The other is "libnss3.so", listed as "nss3".97static String nss_library = "softokn3";9899// NSS versions of each library. It is simplier to keep nss_version100// for quick checking for generic testing than many if-else statements.101static double softoken3_version = -1;102static double nss3_version = -1;103104static Provider getSunPKCS11(String config) throws Exception {105Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11");106Constructor cons = clazz.getConstructor(new Class[] {String.class});107Object obj = cons.newInstance(new Object[] {config});108return (Provider)obj;109}110111public abstract void main(Provider p) throws Exception;112113private void premain(Provider p) throws Exception {114// set a security manager and policy before a test case runs,115// and disable them after the test case finished116try {117if (enableSM) {118System.setSecurityManager(new SecurityManager());119}120long start = System.currentTimeMillis();121System.out.printf(122"Running test with provider %s (security manager %s) ...%n",123p.getName(), enableSM ? "enabled" : "disabled");124main(p);125long stop = System.currentTimeMillis();126System.out.println("Completed test with provider " + p.getName() +127" (" + (stop - start) + " ms).");128} finally {129if (enableSM) {130System.setSecurityManager(null);131}132}133}134135public static void main(PKCS11Test test) throws Exception {136main(test, null);137}138139public static void main(PKCS11Test test, String[] args) throws Exception {140if (args != null) {141if (args.length > 0 && "sm".equals(args[0])) {142test.enableSM = true;143}144if (test.enableSM) {145System.setProperty("java.security.policy",146(args.length > 1) ? BASE + SEP + args[1]147: DEFAULT_POLICY);148}149}150151Provider[] oldProviders = Security.getProviders();152try {153System.out.println("Beginning test run " + test.getClass().getName() + "...");154testDefault(test);155testNSS(test);156testDeimos(test);157} finally {158// NOTE: Do not place a 'return' in any finally block159// as it will suppress exceptions and hide test failures.160Provider[] newProviders = Security.getProviders();161boolean found = true;162// Do not restore providers if nothing changed. This is especailly163// useful for ./Provider/Login.sh, where a SecurityManager exists.164if (oldProviders.length == newProviders.length) {165found = false;166for (int i = 0; i<oldProviders.length; i++) {167if (oldProviders[i] != newProviders[i]) {168found = true;169break;170}171}172}173if (found) {174for (Provider p: newProviders) {175Security.removeProvider(p.getName());176}177for (Provider p: oldProviders) {178Security.addProvider(p);179}180}181}182}183184public static void testDeimos(PKCS11Test test) throws Exception {185if (new File("/opt/SUNWconn/lib/libpkcs11.so").isFile() == false ||186"true".equals(System.getProperty("NO_DEIMOS"))) {187return;188}189String base = getBase();190String p11config = base + SEP + "nss" + SEP + "p11-deimos.txt";191Provider p = getSunPKCS11(p11config);192test.premain(p);193}194195public static void testDefault(PKCS11Test test) throws Exception {196// run test for default configured PKCS11 providers (if any)197198if ("true".equals(System.getProperty("NO_DEFAULT"))) {199return;200}201202Provider[] providers = Security.getProviders();203for (int i = 0; i < providers.length; i++) {204Provider p = providers[i];205if (p.getName().startsWith("SunPKCS11-")) {206test.premain(p);207}208}209}210211private static String PKCS11_BASE;212static {213try {214PKCS11_BASE = getBase();215} catch (Exception e) {216// ignore217}218}219220private final static String PKCS11_REL_PATH = "sun/security/pkcs11";221222public static String getBase() throws Exception {223if (PKCS11_BASE != null) {224return PKCS11_BASE;225}226File cwd = new File(System.getProperty("test.src", ".")).getCanonicalFile();227while (true) {228File file = new File(cwd, "TEST.ROOT");229if (file.isFile()) {230break;231}232cwd = cwd.getParentFile();233if (cwd == null) {234throw new Exception("Test root directory not found");235}236}237PKCS11_BASE = new File(cwd, PKCS11_REL_PATH.replace('/', SEP)).getAbsolutePath();238return PKCS11_BASE;239}240241public static String getNSSLibDir() throws Exception {242return getNSSLibDir(nss_library);243}244245static String getNSSLibDir(String library) throws Exception {246String osName = props.getProperty("os.name");247if (osName.startsWith("Win")) {248osName = "Windows";249NSPR_PREFIX = "lib";250}251String osid = osName + "-"252+ props.getProperty("os.arch") + "-" + props.getProperty("sun.arch.data.model");253String[] nssLibDirs = osMap.get(osid);254if (nssLibDirs == null) {255System.out.println("Unsupported OS, skipping: " + osid);256return null;257}258if (nssLibDirs.length == 0) {259System.out.println("NSS not supported on this platform, skipping test");260return null;261}262String nssLibDir = null;263for (String dir : nssLibDirs) {264if (new File(dir).exists() &&265new File(dir + System.mapLibraryName(library)).exists()) {266nssLibDir = dir;267System.setProperty("pkcs11test.nss.libdir", nssLibDir);268break;269}270}271return nssLibDir;272}273274static boolean isBadNSSVersion(Provider p) {275if (isNSS(p) && badNSSVersion) {276System.out.println("NSS 3.11 has a DER issue that recent " +277"version do not.");278return true;279}280return false;281}282283protected static void safeReload(String lib) throws Exception {284try {285System.load(lib);286} catch (UnsatisfiedLinkError e) {287if (e.getMessage().contains("already loaded")) {288return;289}290}291}292293static boolean loadNSPR(String libdir) throws Exception {294// load NSS softoken dependencies in advance to avoid resolver issues295safeReload(libdir + System.mapLibraryName(NSPR_PREFIX + "nspr4"));296safeReload(libdir + System.mapLibraryName(NSPR_PREFIX + "plc4"));297safeReload(libdir + System.mapLibraryName(NSPR_PREFIX + "plds4"));298safeReload(libdir + System.mapLibraryName("sqlite3"));299safeReload(libdir + System.mapLibraryName("nssutil3"));300return true;301}302303// Check the provider being used is NSS304public static boolean isNSS(Provider p) {305return p.getName().toUpperCase().equals("SUNPKCS11-NSS");306}307308static double getNSSVersion() {309if (nss_version == -1)310getNSSInfo();311return nss_version;312}313314static ECCState getNSSECC() {315if (nss_version == -1)316getNSSInfo();317return nss_ecc_status;318}319320public static double getLibsoftokn3Version() {321if (softoken3_version == -1)322return getNSSInfo("softokn3");323return softoken3_version;324}325326public static double getLibnss3Version() {327if (nss3_version == -1)328return getNSSInfo("nss3");329return nss3_version;330}331332/* Read the library to find out the verison */333static void getNSSInfo() {334getNSSInfo(nss_library);335}336337// Try to parse the version for the specified library.338// Assuming the library contains either of the following patterns:339// $Header: NSS <version>340// Version: NSS <version>341// Here, <version> stands for NSS version.342static double getNSSInfo(String library) {343// look for two types of headers in NSS libraries344String nssHeader1 = "$Header: NSS";345String nssHeader2 = "Version: NSS";346boolean found = false;347String s = null;348int i = 0;349String libfile = "";350351if (library.compareTo("softokn3") == 0 && softoken3_version > -1)352return softoken3_version;353if (library.compareTo("nss3") == 0 && nss3_version > -1)354return nss3_version;355356try {357String libdir = getNSSLibDir();358if (libdir == null) {359return 0.0;360}361libfile = libdir + System.mapLibraryName(library);362try (FileInputStream is = new FileInputStream(libfile)) {363byte[] data = new byte[1000];364int read = 0;365366while (is.available() > 0) {367if (read == 0) {368read = is.read(data, 0, 1000);369} else {370// Prepend last 100 bytes in case the header was split371// between the reads.372System.arraycopy(data, 900, data, 0, 100);373read = 100 + is.read(data, 100, 900);374}375376s = new String(data, 0, read, StandardCharsets.US_ASCII);377i = s.indexOf(nssHeader1);378if (i > 0 || (i = s.indexOf(nssHeader2)) > 0) {379found = true;380// If the nssHeader is before 920 we can break, otherwise381// we may not have the whole header so do another read. If382// no bytes are in the stream, that is ok, found is true.383if (i < 920) {384break;385}386}387}388}389} catch (Exception e) {390e.printStackTrace();391}392393if (!found) {394System.out.println("lib" + library +395" version not found, set to 0.0: " + libfile);396nss_version = 0.0;397return nss_version;398}399400// the index after whitespace after nssHeader401int afterheader = s.indexOf("NSS", i) + 4;402String version = String.valueOf(s.charAt(afterheader));403for (char c = s.charAt(++afterheader);404c == '.' || (c >= '0' && c <= '9');405c = s.charAt(++afterheader)) {406version += c;407}408409// If a "dot dot" release, strip the extra dots for double parsing410String[] dot = version.split("\\.");411if (dot.length > 2) {412version = dot[0]+"."+dot[1];413for (int j = 2; dot.length > j; j++) {414version += dot[j];415}416}417418// Convert to double for easier version value checking419try {420nss_version = Double.parseDouble(version);421} catch (NumberFormatException e) {422System.out.println("===== Content start =====");423System.out.println(s);424System.out.println("===== Content end =====");425System.out.println("Failed to parse lib" + library +426" version. Set to 0.0");427e.printStackTrace();428}429430System.out.print("lib" + library + " version = "+version+". ");431432// Check for ECC433if (s.indexOf("Basic") > 0) {434nss_ecc_status = ECCState.Basic;435System.out.println("ECC Basic.");436} else if (s.indexOf("Extended") > 0) {437nss_ecc_status = ECCState.Extended;438System.out.println("ECC Extended.");439} else {440System.out.println("ECC None.");441}442443if (library.compareTo("softokn3") == 0) {444softoken3_version = nss_version;445} else if (library.compareTo("nss3") == 0) {446nss3_version = nss_version;447}448449return nss_version;450}451452// Used to set the nss_library file to search for libsoftokn3.so453public static void useNSS() {454nss_library = "nss3";455}456457public static void testNSS(PKCS11Test test) throws Exception {458String libdir = getNSSLibDir();459if (libdir == null) {460return;461}462String base = getBase();463464if (loadNSPR(libdir) == false) {465return;466}467468String libfile = libdir + System.mapLibraryName(nss_library);469470String customDBdir = System.getProperty("CUSTOM_DB_DIR");471String dbdir = (customDBdir != null) ?472customDBdir :473base + SEP + "nss" + SEP + "db";474// NSS always wants forward slashes for the config path475dbdir = dbdir.replace('\\', '/');476477String customConfig = System.getProperty("CUSTOM_P11_CONFIG");478String customConfigName = System.getProperty("CUSTOM_P11_CONFIG_NAME", "p11-nss.txt");479String p11config = (customConfig != null) ?480customConfig :481base + SEP + "nss" + SEP + customConfigName;482483System.setProperty("pkcs11test.nss.lib", libfile);484System.setProperty("pkcs11test.nss.db", dbdir);485Provider p = getSunPKCS11(p11config);486test.premain(p);487}488489// Generate a vector of supported elliptic curves of a given provider490static List<ECParameterSpec> getKnownCurves(Provider p) throws Exception {491int index;492int begin;493int end;494String curve;495496List<ECParameterSpec> results = new ArrayList<>();497// Get Curves to test from SunEC.498String kcProp = Security.getProvider("SunEC").499getProperty("AlgorithmParameters.EC SupportedCurves");500501if (kcProp == null) {502throw new RuntimeException(503"\"AlgorithmParameters.EC SupportedCurves property\" not found");504}505506System.out.println("Finding supported curves using list from SunEC\n");507index = 0;508for (;;) {509// Each set of curve names is enclosed with brackets.510begin = kcProp.indexOf('[', index);511end = kcProp.indexOf(']', index);512if (begin == -1 || end == -1) {513break;514}515516/*517* Each name is separated by a comma.518* Just get the first name in the set.519*/520index = end + 1;521begin++;522end = kcProp.indexOf(',', begin);523if (end == -1) {524// Only one name in the set.525end = index -1;526}527528curve = kcProp.substring(begin, end);529ECParameterSpec e = getECParameterSpec(p, curve);530System.out.print("\t "+ curve + ": ");531try {532KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p);533kpg.initialize(e);534kpg.generateKeyPair();535results.add(e);536System.out.println("Supported");537} catch (ProviderException ex) {538System.out.println("Unsupported: PKCS11: " +539ex.getCause().getMessage());540} catch (InvalidAlgorithmParameterException ex) {541System.out.println("Unsupported: Key Length: " +542ex.getMessage());543}544}545546if (results.size() == 0) {547throw new RuntimeException("No supported EC curves found");548}549550return results;551}552553private static ECParameterSpec getECParameterSpec(Provider p, String name)554throws Exception {555556AlgorithmParameters parameters =557AlgorithmParameters.getInstance("EC", p);558559parameters.init(new ECGenParameterSpec(name));560561return parameters.getParameterSpec(ECParameterSpec.class);562}563564// Check support for a curve with a provided Vector of EC support565boolean checkSupport(List<ECParameterSpec> supportedEC,566ECParameterSpec curve) {567for (ECParameterSpec ec: supportedEC) {568if (ec.equals(curve)) {569return true;570}571}572return false;573}574575private static final Map<String,String[]> osMap;576577// Location of the NSS libraries on each supported platform578static {579osMap = new HashMap<>();580osMap.put("SunOS-sparc-32", new String[]{"/usr/lib/mps/"});581osMap.put("SunOS-sparcv9-64", new String[]{"/usr/lib/mps/64/"});582osMap.put("SunOS-x86-32", new String[]{"/usr/lib/mps/"});583osMap.put("SunOS-amd64-64", new String[]{"/usr/lib/mps/64/"});584osMap.put("Linux-i386-32", new String[]{585"/usr/lib/i386-linux-gnu/", "/usr/lib32/", "/usr/lib/"});586osMap.put("Linux-amd64-64", new String[]{587"/usr/lib/x86_64-linux-gnu/", "/usr/lib/x86_64-linux-gnu/nss/",588"/usr/lib64/"});589osMap.put("Linux-ppc64-64", new String[]{"/usr/lib64/"});590osMap.put("Linux-ppc64le-64", new String[]{"/usr/lib64/"});591osMap.put("Windows-x86-32", new String[]{592PKCS11_BASE + "/nss/lib/windows-i586/".replace('/', SEP)});593osMap.put("Windows-amd64-64", new String[]{594PKCS11_BASE + "/nss/lib/windows-amd64/".replace('/', SEP)});595osMap.put("MacOSX-x86_64-64", new String[]{596PKCS11_BASE + "/nss/lib/macosx-x86_64/"});597}598599private final static char[] hexDigits = "0123456789abcdef".toCharArray();600601static final boolean badNSSVersion =602getNSSVersion() >= 3.11 && getNSSVersion() < 3.12;603604public static String toString(byte[] b) {605if (b == null) {606return "(null)";607}608StringBuilder sb = new StringBuilder(b.length * 3);609for (int i = 0; i < b.length; i++) {610int k = b[i] & 0xff;611if (i != 0) {612sb.append(':');613}614sb.append(hexDigits[k >>> 4]);615sb.append(hexDigits[k & 0xf]);616}617return sb.toString();618}619620public static byte[] parse(String s) {621if (s.equals("(null)")) {622return null;623}624try {625int n = s.length();626ByteArrayOutputStream out = new ByteArrayOutputStream(n / 3);627StringReader r = new StringReader(s);628while (true) {629int b1 = nextNibble(r);630if (b1 < 0) {631break;632}633int b2 = nextNibble(r);634if (b2 < 0) {635throw new RuntimeException("Invalid string " + s);636}637int b = (b1 << 4) | b2;638out.write(b);639}640return out.toByteArray();641} catch (IOException e) {642throw new RuntimeException(e);643}644}645646private static int nextNibble(StringReader r) throws IOException {647while (true) {648int ch = r.read();649if (ch == -1) {650return -1;651} else if ((ch >= '0') && (ch <= '9')) {652return ch - '0';653} else if ((ch >= 'a') && (ch <= 'f')) {654return ch - 'a' + 10;655} else if ((ch >= 'A') && (ch <= 'F')) {656return ch - 'A' + 10;657}658}659}660661static byte[] generateData(int length) {662byte data[] = new byte[length];663for (int i=0; i<data.length; i++) {664data[i] = (byte) (i % 256);665}666return data;667}668669<T> T[] concat(T[] a, T[] b) {670if ((b == null) || (b.length == 0)) {671return a;672}673T[] r = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), a.length + b.length);674System.arraycopy(a, 0, r, 0, a.length);675System.arraycopy(b, 0, r, a.length, b.length);676return r;677}678679/**680* Returns supported algorithms of specified type.681*/682static List<String> getSupportedAlgorithms(String type, String alg,683Provider p) {684// prepare a list of supported algorithms685List<String> algorithms = new ArrayList<>();686Set<Provider.Service> services = p.getServices();687for (Provider.Service service : services) {688if (service.getType().equals(type)689&& service.getAlgorithm().startsWith(alg)) {690algorithms.add(service.getAlgorithm());691}692}693return algorithms;694}695696}697698699