test/jdk/sun/security/pkcs11/PKCS11Test.java
changeset 47216 71c04702a3d5
parent 42366 b1483ec50db1
child 48248 55b9b1e184c6
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2003, 2016, 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 // common infrastructure for SunPKCS11 tests
       
    26 
       
    27 import java.io.BufferedReader;
       
    28 import java.io.ByteArrayOutputStream;
       
    29 import java.io.File;
       
    30 import java.io.FileInputStream;
       
    31 import java.io.IOException;
       
    32 import java.io.InputStreamReader;
       
    33 import java.io.StringReader;
       
    34 import java.security.AlgorithmParameters;
       
    35 import java.security.InvalidAlgorithmParameterException;
       
    36 import java.security.KeyPairGenerator;
       
    37 import java.security.NoSuchProviderException;
       
    38 import java.security.Provider;
       
    39 import java.security.ProviderException;
       
    40 import java.security.Security;
       
    41 import java.security.spec.ECGenParameterSpec;
       
    42 import java.security.spec.ECParameterSpec;
       
    43 import java.util.ArrayList;
       
    44 import java.util.Arrays;
       
    45 import java.util.HashMap;
       
    46 import java.util.Iterator;
       
    47 import java.util.List;
       
    48 import java.util.Map;
       
    49 import java.util.Properties;
       
    50 import java.util.ServiceConfigurationError;
       
    51 import java.util.ServiceLoader;
       
    52 import java.util.Set;
       
    53 
       
    54 public abstract class PKCS11Test {
       
    55 
       
    56     private boolean enableSM = false;
       
    57 
       
    58     static final Properties props = System.getProperties();
       
    59 
       
    60     static final String PKCS11 = "PKCS11";
       
    61 
       
    62     // directory of the test source
       
    63     static final String BASE = System.getProperty("test.src", ".");
       
    64 
       
    65     static final char SEP = File.separatorChar;
       
    66 
       
    67     private static final String DEFAULT_POLICY =
       
    68             BASE + SEP + ".." + SEP + "policy";
       
    69 
       
    70     // directory corresponding to BASE in the /closed hierarchy
       
    71     static final String CLOSED_BASE;
       
    72 
       
    73     static {
       
    74         // hack
       
    75         String absBase = new File(BASE).getAbsolutePath();
       
    76         int k = absBase.indexOf(SEP + "test" + SEP + "sun" + SEP);
       
    77         if (k < 0) k = 0;
       
    78         String p1 = absBase.substring(0, k + 6);
       
    79         String p2 = absBase.substring(k + 5);
       
    80         CLOSED_BASE = p1 + "closed" + p2;
       
    81 
       
    82         // set it as a system property to make it available in policy file
       
    83         System.setProperty("closed.base", CLOSED_BASE);
       
    84     }
       
    85 
       
    86     // NSS version info
       
    87     public static enum ECCState { None, Basic, Extended };
       
    88     static double nss_version = -1;
       
    89     static ECCState nss_ecc_status = ECCState.Extended;
       
    90 
       
    91     // The NSS library we need to search for in getNSSLibDir()
       
    92     // Default is "libsoftokn3.so", listed as "softokn3"
       
    93     // The other is "libnss3.so", listed as "nss3".
       
    94     static String nss_library = "softokn3";
       
    95 
       
    96     // NSS versions of each library.  It is simplier to keep nss_version
       
    97     // for quick checking for generic testing than many if-else statements.
       
    98     static double softoken3_version = -1;
       
    99     static double nss3_version = -1;
       
   100     static Provider pkcs11;
       
   101 
       
   102     // Goes through ServiceLoader instead of Provider.getInstance() since it
       
   103     // works on all platforms
       
   104     static {
       
   105         ServiceLoader sl = ServiceLoader.load(java.security.Provider.class);
       
   106         Iterator<Provider> iter = sl.iterator();
       
   107         Provider p = null;
       
   108         boolean found = false;
       
   109         while (iter.hasNext()) {
       
   110             try {
       
   111                 p = iter.next();
       
   112                 if (p.getName().equals("SunPKCS11")) {
       
   113                     found = true;
       
   114                     break;
       
   115                 }
       
   116             } catch (Exception | ServiceConfigurationError e) {
       
   117                 // ignore and move on to the next one
       
   118             }
       
   119         }
       
   120         // Nothing found through ServiceLoader; fall back to reflection
       
   121         if (!found) {
       
   122             try {
       
   123                 Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11");
       
   124                 p = (Provider) clazz.newInstance();
       
   125             } catch (Exception ex) {
       
   126                 ex.printStackTrace();
       
   127             }
       
   128         }
       
   129         pkcs11 = p;
       
   130     }
       
   131 
       
   132     /*
       
   133      * Use Solaris SPARC 11.2 or later to avoid an intermittent failure
       
   134      * when running SunPKCS11-Solaris (8044554)
       
   135      */
       
   136     static boolean isBadSolarisSparc(Provider p) {
       
   137         if ("SunPKCS11-Solaris".equals(p.getName()) && badSolarisSparc) {
       
   138             System.out.println("SunPKCS11-Solaris provider requires " +
       
   139                 "Solaris SPARC 11.2 or later, skipping");
       
   140             return true;
       
   141         }
       
   142         return false;
       
   143     }
       
   144 
       
   145     // Return a SunPKCS11 provider configured with the specified config file
       
   146     static Provider getSunPKCS11(String config) throws Exception {
       
   147         if (pkcs11 == null) {
       
   148             throw new NoSuchProviderException("No PKCS11 provider available");
       
   149         }
       
   150         return pkcs11.configure(config);
       
   151     }
       
   152 
       
   153     public abstract void main(Provider p) throws Exception;
       
   154 
       
   155     private void premain(Provider p) throws Exception {
       
   156         // set a security manager and policy before a test case runs,
       
   157         // and disable them after the test case finished
       
   158         try {
       
   159             if (enableSM) {
       
   160                 System.setSecurityManager(new SecurityManager());
       
   161             }
       
   162             long start = System.currentTimeMillis();
       
   163             System.out.printf(
       
   164                     "Running test with provider %s (security manager %s) ...%n",
       
   165                         p.getName(), enableSM ? "enabled" : "disabled");
       
   166             main(p);
       
   167             long stop = System.currentTimeMillis();
       
   168             System.out.println("Completed test with provider " + p.getName() +
       
   169                 " (" + (stop - start) + " ms).");
       
   170         } finally {
       
   171             if (enableSM) {
       
   172                 System.setSecurityManager(null);
       
   173             }
       
   174         }
       
   175     }
       
   176 
       
   177     public static void main(PKCS11Test test) throws Exception {
       
   178         main(test, null);
       
   179     }
       
   180 
       
   181     public static void main(PKCS11Test test, String[] args) throws Exception {
       
   182         if (args != null) {
       
   183             if (args.length > 0) {
       
   184                 if ("sm".equals(args[0])) {
       
   185                     test.enableSM = true;
       
   186                 } else {
       
   187                     throw new RuntimeException("Unknown Command, use 'sm' as "
       
   188                             + "first arguemtn to enable security manager");
       
   189                 }
       
   190             }
       
   191             if (test.enableSM) {
       
   192                 System.setProperty("java.security.policy",
       
   193                         (args.length > 1) ? BASE + SEP + args[1]
       
   194                                 : DEFAULT_POLICY);
       
   195             }
       
   196         }
       
   197 
       
   198         Provider[] oldProviders = Security.getProviders();
       
   199         try {
       
   200             System.out.println("Beginning test run " + test.getClass().getName() + "...");
       
   201             testDefault(test);
       
   202             testNSS(test);
       
   203             testDeimos(test);
       
   204         } finally {
       
   205             // NOTE: Do not place a 'return' in any finally block
       
   206             // as it will suppress exceptions and hide test failures.
       
   207             Provider[] newProviders = Security.getProviders();
       
   208             boolean found = true;
       
   209             // Do not restore providers if nothing changed. This is especailly
       
   210             // useful for ./Provider/Login.sh, where a SecurityManager exists.
       
   211             if (oldProviders.length == newProviders.length) {
       
   212                 found = false;
       
   213                 for (int i = 0; i<oldProviders.length; i++) {
       
   214                     if (oldProviders[i] != newProviders[i]) {
       
   215                         found = true;
       
   216                         break;
       
   217                     }
       
   218                 }
       
   219             }
       
   220             if (found) {
       
   221                 for (Provider p: newProviders) {
       
   222                     Security.removeProvider(p.getName());
       
   223                 }
       
   224                 for (Provider p: oldProviders) {
       
   225                     Security.addProvider(p);
       
   226                 }
       
   227             }
       
   228         }
       
   229     }
       
   230 
       
   231     public static void testDeimos(PKCS11Test test) throws Exception {
       
   232         if (new File("/opt/SUNWconn/lib/libpkcs11.so").isFile() == false ||
       
   233             "true".equals(System.getProperty("NO_DEIMOS"))) {
       
   234             return;
       
   235         }
       
   236         String base = getBase();
       
   237         String p11config = base + SEP + "nss" + SEP + "p11-deimos.txt";
       
   238         Provider p = getSunPKCS11(p11config);
       
   239         test.premain(p);
       
   240     }
       
   241 
       
   242     public static void testDefault(PKCS11Test test) throws Exception {
       
   243         // run test for default configured PKCS11 providers (if any)
       
   244 
       
   245         if ("true".equals(System.getProperty("NO_DEFAULT"))) {
       
   246             return;
       
   247         }
       
   248 
       
   249         Provider[] providers = Security.getProviders();
       
   250         for (int i = 0; i < providers.length; i++) {
       
   251             Provider p = providers[i];
       
   252             if (p.getName().startsWith("SunPKCS11-")) {
       
   253                 test.premain(p);
       
   254             }
       
   255         }
       
   256     }
       
   257 
       
   258     private static String PKCS11_BASE;
       
   259     static {
       
   260         try {
       
   261             PKCS11_BASE = getBase();
       
   262         } catch (Exception e) {
       
   263             // ignore
       
   264         }
       
   265     }
       
   266 
       
   267     private final static String PKCS11_REL_PATH = "sun/security/pkcs11";
       
   268 
       
   269     public static String getBase() throws Exception {
       
   270         if (PKCS11_BASE != null) {
       
   271             return PKCS11_BASE;
       
   272         }
       
   273         File cwd = new File(System.getProperty("test.src", ".")).getCanonicalFile();
       
   274         while (true) {
       
   275             File file = new File(cwd, "TEST.ROOT");
       
   276             if (file.isFile()) {
       
   277                 break;
       
   278             }
       
   279             cwd = cwd.getParentFile();
       
   280             if (cwd == null) {
       
   281                 throw new Exception("Test root directory not found");
       
   282             }
       
   283         }
       
   284         PKCS11_BASE = new File(cwd, PKCS11_REL_PATH.replace('/', SEP)).getAbsolutePath();
       
   285         return PKCS11_BASE;
       
   286     }
       
   287 
       
   288     public static String getNSSLibDir() throws Exception {
       
   289         return getNSSLibDir(nss_library);
       
   290     }
       
   291 
       
   292     static String getNSSLibDir(String library) throws Exception {
       
   293         String osName = props.getProperty("os.name");
       
   294         if (osName.startsWith("Win")) {
       
   295             osName = "Windows";
       
   296         } else if (osName.equals("Mac OS X")) {
       
   297             osName = "MacOSX";
       
   298         }
       
   299         String osid = osName + "-"
       
   300                 + props.getProperty("os.arch") + "-" + props.getProperty("sun.arch.data.model");
       
   301         String[] nssLibDirs = osMap.get(osid);
       
   302         if (nssLibDirs == null) {
       
   303             System.out.println("Warning: unsupported OS: " + osid
       
   304                     + ", please initialize NSS librarys location firstly, skipping test");
       
   305             return null;
       
   306         }
       
   307         if (nssLibDirs.length == 0) {
       
   308             System.out.println("Warning: NSS not supported on this platform, skipping test");
       
   309             return null;
       
   310         }
       
   311         String nssLibDir = null;
       
   312         for (String dir : nssLibDirs) {
       
   313             if (new File(dir).exists() &&
       
   314                 new File(dir + System.mapLibraryName(library)).exists()) {
       
   315                 nssLibDir = dir;
       
   316                 System.setProperty("pkcs11test.nss.libdir", nssLibDir);
       
   317                 break;
       
   318             }
       
   319         }
       
   320         if (nssLibDir == null) {
       
   321             System.out.println("Warning: can't find NSS librarys on this machine, skipping test");
       
   322             return null;
       
   323         }
       
   324         return nssLibDir;
       
   325     }
       
   326 
       
   327     static boolean isBadNSSVersion(Provider p) {
       
   328         if (isNSS(p) && badNSSVersion) {
       
   329             System.out.println("NSS 3.11 has a DER issue that recent " +
       
   330                     "version do not.");
       
   331             return true;
       
   332         }
       
   333         return false;
       
   334     }
       
   335 
       
   336     protected static void safeReload(String lib) throws Exception {
       
   337         try {
       
   338             System.load(lib);
       
   339         } catch (UnsatisfiedLinkError e) {
       
   340             if (e.getMessage().contains("already loaded")) {
       
   341                 return;
       
   342             }
       
   343         }
       
   344     }
       
   345 
       
   346     static boolean loadNSPR(String libdir) throws Exception {
       
   347         // load NSS softoken dependencies in advance to avoid resolver issues
       
   348         safeReload(libdir + System.mapLibraryName("nspr4"));
       
   349         safeReload(libdir + System.mapLibraryName("plc4"));
       
   350         safeReload(libdir + System.mapLibraryName("plds4"));
       
   351         safeReload(libdir + System.mapLibraryName("sqlite3"));
       
   352         safeReload(libdir + System.mapLibraryName("nssutil3"));
       
   353         return true;
       
   354     }
       
   355 
       
   356     // Check the provider being used is NSS
       
   357     public static boolean isNSS(Provider p) {
       
   358         return p.getName().toUpperCase().equals("SUNPKCS11-NSS");
       
   359     }
       
   360 
       
   361     static double getNSSVersion() {
       
   362         if (nss_version == -1)
       
   363             getNSSInfo();
       
   364         return nss_version;
       
   365     }
       
   366 
       
   367     static ECCState getNSSECC() {
       
   368         if (nss_version == -1)
       
   369             getNSSInfo();
       
   370         return nss_ecc_status;
       
   371     }
       
   372 
       
   373     public static double getLibsoftokn3Version() {
       
   374         if (softoken3_version == -1)
       
   375             return getNSSInfo("softokn3");
       
   376         return softoken3_version;
       
   377     }
       
   378 
       
   379     public static double getLibnss3Version() {
       
   380         if (nss3_version == -1)
       
   381             return getNSSInfo("nss3");
       
   382         return nss3_version;
       
   383     }
       
   384 
       
   385     /* Read the library to find out the verison */
       
   386     static void getNSSInfo() {
       
   387         getNSSInfo(nss_library);
       
   388     }
       
   389 
       
   390     static double getNSSInfo(String library) {
       
   391         // look for two types of headers in NSS libraries
       
   392         String nssHeader1 = "$Header: NSS";
       
   393         String nssHeader2 = "Version: NSS";
       
   394         boolean found = false;
       
   395         String s = null;
       
   396         int i = 0;
       
   397         String libfile = "";
       
   398 
       
   399         if (library.compareTo("softokn3") == 0 && softoken3_version > -1)
       
   400             return softoken3_version;
       
   401         if (library.compareTo("nss3") == 0 && nss3_version > -1)
       
   402             return nss3_version;
       
   403 
       
   404         try {
       
   405             libfile = getNSSLibDir() + System.mapLibraryName(library);
       
   406             try (FileInputStream is = new FileInputStream(libfile)) {
       
   407                 byte[] data = new byte[1000];
       
   408                 int read = 0;
       
   409 
       
   410                 while (is.available() > 0) {
       
   411                     if (read == 0) {
       
   412                         read = is.read(data, 0, 1000);
       
   413                     } else {
       
   414                         // Prepend last 100 bytes in case the header was split
       
   415                         // between the reads.
       
   416                         System.arraycopy(data, 900, data, 0, 100);
       
   417                         read = 100 + is.read(data, 100, 900);
       
   418                     }
       
   419 
       
   420                     s = new String(data, 0, read);
       
   421                     i = s.indexOf(nssHeader1);
       
   422                     if (i > 0 || (i = s.indexOf(nssHeader2)) > 0) {
       
   423                         found = true;
       
   424                         // If the nssHeader is before 920 we can break, otherwise
       
   425                         // we may not have the whole header so do another read.  If
       
   426                         // no bytes are in the stream, that is ok, found is true.
       
   427                         if (i < 920) {
       
   428                             break;
       
   429                         }
       
   430                     }
       
   431                 }
       
   432             }
       
   433         } catch (Exception e) {
       
   434             e.printStackTrace();
       
   435         }
       
   436 
       
   437         if (!found) {
       
   438             System.out.println("lib" + library +
       
   439                     " version not found, set to 0.0: " + libfile);
       
   440             nss_version = 0.0;
       
   441             return nss_version;
       
   442         }
       
   443 
       
   444         // the index after whitespace after nssHeader
       
   445         int afterheader = s.indexOf("NSS", i) + 4;
       
   446         String version = s.substring(afterheader, s.indexOf(' ', afterheader));
       
   447 
       
   448         // If a "dot dot" release, strip the extra dots for double parsing
       
   449         String[] dot = version.split("\\.");
       
   450         if (dot.length > 2) {
       
   451             version = dot[0]+"."+dot[1];
       
   452             for (int j = 2; dot.length > j; j++) {
       
   453                 version += dot[j];
       
   454             }
       
   455         }
       
   456 
       
   457         // Convert to double for easier version value checking
       
   458         try {
       
   459             nss_version = Double.parseDouble(version);
       
   460         } catch (NumberFormatException e) {
       
   461             System.out.println("Failed to parse lib" + library +
       
   462                     " version. Set to 0.0");
       
   463             e.printStackTrace();
       
   464         }
       
   465 
       
   466         System.out.print("lib" + library + " version = "+version+".  ");
       
   467 
       
   468         // Check for ECC
       
   469         if (s.indexOf("Basic") > 0) {
       
   470             nss_ecc_status = ECCState.Basic;
       
   471             System.out.println("ECC Basic.");
       
   472         } else if (s.indexOf("Extended") > 0) {
       
   473             nss_ecc_status = ECCState.Extended;
       
   474             System.out.println("ECC Extended.");
       
   475         } else {
       
   476             System.out.println("ECC None.");
       
   477         }
       
   478 
       
   479         if (library.compareTo("softokn3") == 0) {
       
   480             softoken3_version = nss_version;
       
   481         } else if (library.compareTo("nss3") == 0) {
       
   482             nss3_version = nss_version;
       
   483         }
       
   484 
       
   485         return nss_version;
       
   486     }
       
   487 
       
   488     // Used to set the nss_library file to search for libsoftokn3.so
       
   489     public static void useNSS() {
       
   490         nss_library = "nss3";
       
   491     }
       
   492 
       
   493     public static void testNSS(PKCS11Test test) throws Exception {
       
   494         String libdir = getNSSLibDir();
       
   495         if (libdir == null) {
       
   496             return;
       
   497         }
       
   498         String base = getBase();
       
   499 
       
   500         if (loadNSPR(libdir) == false) {
       
   501             return;
       
   502         }
       
   503 
       
   504         String libfile = libdir + System.mapLibraryName(nss_library);
       
   505 
       
   506         String customDBdir = System.getProperty("CUSTOM_DB_DIR");
       
   507         String dbdir = (customDBdir != null) ?
       
   508                                 customDBdir :
       
   509                                 base + SEP + "nss" + SEP + "db";
       
   510         // NSS always wants forward slashes for the config path
       
   511         dbdir = dbdir.replace('\\', '/');
       
   512 
       
   513         String customConfig = System.getProperty("CUSTOM_P11_CONFIG");
       
   514         String customConfigName = System.getProperty("CUSTOM_P11_CONFIG_NAME", "p11-nss.txt");
       
   515         String p11config = (customConfig != null) ?
       
   516                                 customConfig :
       
   517                                 base + SEP + "nss" + SEP + customConfigName;
       
   518 
       
   519         System.setProperty("pkcs11test.nss.lib", libfile);
       
   520         System.setProperty("pkcs11test.nss.db", dbdir);
       
   521         Provider p = getSunPKCS11(p11config);
       
   522         test.premain(p);
       
   523     }
       
   524 
       
   525     // Generate a vector of supported elliptic curves of a given provider
       
   526     static List<ECParameterSpec> getKnownCurves(Provider p) throws Exception {
       
   527         int index;
       
   528         int begin;
       
   529         int end;
       
   530         String curve;
       
   531 
       
   532         List<ECParameterSpec> results = new ArrayList<>();
       
   533         // Get Curves to test from SunEC.
       
   534         String kcProp = Security.getProvider("SunEC").
       
   535                 getProperty("AlgorithmParameters.EC SupportedCurves");
       
   536 
       
   537         if (kcProp == null) {
       
   538             throw new RuntimeException(
       
   539             "\"AlgorithmParameters.EC SupportedCurves property\" not found");
       
   540         }
       
   541 
       
   542         System.out.println("Finding supported curves using list from SunEC\n");
       
   543         index = 0;
       
   544         for (;;) {
       
   545             // Each set of curve names is enclosed with brackets.
       
   546             begin = kcProp.indexOf('[', index);
       
   547             end = kcProp.indexOf(']', index);
       
   548             if (begin == -1 || end == -1) {
       
   549                 break;
       
   550             }
       
   551 
       
   552             /*
       
   553              * Each name is separated by a comma.
       
   554              * Just get the first name in the set.
       
   555              */
       
   556             index = end + 1;
       
   557             begin++;
       
   558             end = kcProp.indexOf(',', begin);
       
   559             if (end == -1) {
       
   560                 // Only one name in the set.
       
   561                 end = index -1;
       
   562             }
       
   563 
       
   564             curve = kcProp.substring(begin, end);
       
   565             ECParameterSpec e = getECParameterSpec(p, curve);
       
   566             System.out.print("\t "+ curve + ": ");
       
   567             try {
       
   568                 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p);
       
   569                 kpg.initialize(e);
       
   570                 kpg.generateKeyPair();
       
   571                 results.add(e);
       
   572                 System.out.println("Supported");
       
   573             } catch (ProviderException ex) {
       
   574                 System.out.println("Unsupported: PKCS11: " +
       
   575                         ex.getCause().getMessage());
       
   576             } catch (InvalidAlgorithmParameterException ex) {
       
   577                 System.out.println("Unsupported: Key Length: " +
       
   578                         ex.getMessage());
       
   579             }
       
   580         }
       
   581 
       
   582         if (results.size() == 0) {
       
   583             throw new RuntimeException("No supported EC curves found");
       
   584         }
       
   585 
       
   586         return results;
       
   587     }
       
   588 
       
   589     private static ECParameterSpec getECParameterSpec(Provider p, String name)
       
   590             throws Exception {
       
   591 
       
   592         AlgorithmParameters parameters =
       
   593             AlgorithmParameters.getInstance("EC", p);
       
   594 
       
   595         parameters.init(new ECGenParameterSpec(name));
       
   596 
       
   597         return parameters.getParameterSpec(ECParameterSpec.class);
       
   598     }
       
   599 
       
   600     // Check support for a curve with a provided Vector of EC support
       
   601     boolean checkSupport(List<ECParameterSpec> supportedEC,
       
   602             ECParameterSpec curve) {
       
   603         for (ECParameterSpec ec: supportedEC) {
       
   604             if (ec.equals(curve)) {
       
   605                 return true;
       
   606             }
       
   607         }
       
   608         return false;
       
   609     }
       
   610 
       
   611     private static final Map<String,String[]> osMap;
       
   612 
       
   613     // Location of the NSS libraries on each supported platform
       
   614     static {
       
   615         osMap = new HashMap<>();
       
   616         osMap.put("SunOS-sparc-32", new String[]{"/usr/lib/mps/"});
       
   617         osMap.put("SunOS-sparcv9-64", new String[]{"/usr/lib/mps/64/"});
       
   618         osMap.put("SunOS-x86-32", new String[]{"/usr/lib/mps/"});
       
   619         osMap.put("SunOS-amd64-64", new String[]{"/usr/lib/mps/64/"});
       
   620         osMap.put("Linux-i386-32", new String[]{
       
   621             "/usr/lib/i386-linux-gnu/", "/usr/lib32/", "/usr/lib/"});
       
   622         osMap.put("Linux-amd64-64", new String[]{
       
   623             "/usr/lib/x86_64-linux-gnu/", "/usr/lib/x86_64-linux-gnu/nss/",
       
   624             "/usr/lib64/"});
       
   625         osMap.put("Linux-ppc64-64", new String[]{"/usr/lib64/"});
       
   626         osMap.put("Linux-ppc64le-64", new String[]{"/usr/lib64/"});
       
   627         osMap.put("Windows-x86-32", new String[]{
       
   628             PKCS11_BASE + "/nss/lib/windows-i586/".replace('/', SEP)});
       
   629         osMap.put("Windows-amd64-64", new String[]{
       
   630             PKCS11_BASE + "/nss/lib/windows-amd64/".replace('/', SEP)});
       
   631         osMap.put("MacOSX-x86_64-64", new String[]{
       
   632             PKCS11_BASE + "/nss/lib/macosx-x86_64/"});
       
   633         osMap.put("Linux-arm-32", new String[]{
       
   634             "/usr/lib/arm-linux-gnueabi/nss/",
       
   635             "/usr/lib/arm-linux-gnueabihf/nss/"});
       
   636         osMap.put("Linux-aarch64-64", new String[]{
       
   637             "/usr/lib/aarch64-linux-gnu/nss/"});
       
   638     }
       
   639 
       
   640     private final static char[] hexDigits = "0123456789abcdef".toCharArray();
       
   641 
       
   642     static final boolean badNSSVersion =
       
   643             getNSSVersion() >= 3.11 && getNSSVersion() < 3.12;
       
   644 
       
   645     private static final String distro = distro();
       
   646 
       
   647     static final boolean badSolarisSparc =
       
   648             System.getProperty("os.name").equals("SunOS") &&
       
   649             System.getProperty("os.arch").equals("sparcv9") &&
       
   650             System.getProperty("os.version").compareTo("5.11") <= 0 &&
       
   651             getDistro().compareTo("11.2") < 0;
       
   652 
       
   653     public static String toString(byte[] b) {
       
   654         if (b == null) {
       
   655             return "(null)";
       
   656         }
       
   657         StringBuilder sb = new StringBuilder(b.length * 3);
       
   658         for (int i = 0; i < b.length; i++) {
       
   659             int k = b[i] & 0xff;
       
   660             if (i != 0) {
       
   661                 sb.append(':');
       
   662             }
       
   663             sb.append(hexDigits[k >>> 4]);
       
   664             sb.append(hexDigits[k & 0xf]);
       
   665         }
       
   666         return sb.toString();
       
   667     }
       
   668 
       
   669     public static byte[] parse(String s) {
       
   670         if (s.equals("(null)")) {
       
   671             return null;
       
   672         }
       
   673         try {
       
   674             int n = s.length();
       
   675             ByteArrayOutputStream out = new ByteArrayOutputStream(n / 3);
       
   676             StringReader r = new StringReader(s);
       
   677             while (true) {
       
   678                 int b1 = nextNibble(r);
       
   679                 if (b1 < 0) {
       
   680                     break;
       
   681                 }
       
   682                 int b2 = nextNibble(r);
       
   683                 if (b2 < 0) {
       
   684                     throw new RuntimeException("Invalid string " + s);
       
   685                 }
       
   686                 int b = (b1 << 4) | b2;
       
   687                 out.write(b);
       
   688             }
       
   689             return out.toByteArray();
       
   690         } catch (IOException e) {
       
   691             throw new RuntimeException(e);
       
   692         }
       
   693     }
       
   694 
       
   695     private static int nextNibble(StringReader r) throws IOException {
       
   696         while (true) {
       
   697             int ch = r.read();
       
   698             if (ch == -1) {
       
   699                 return -1;
       
   700             } else if ((ch >= '0') && (ch <= '9')) {
       
   701                 return ch - '0';
       
   702             } else if ((ch >= 'a') && (ch <= 'f')) {
       
   703                 return ch - 'a' + 10;
       
   704             } else if ((ch >= 'A') && (ch <= 'F')) {
       
   705                 return ch - 'A' + 10;
       
   706             }
       
   707         }
       
   708     }
       
   709 
       
   710     <T> T[] concat(T[] a, T[] b) {
       
   711         if ((b == null) || (b.length == 0)) {
       
   712             return a;
       
   713         }
       
   714         T[] r = Arrays.copyOf(a, a.length + b.length);
       
   715         System.arraycopy(b, 0, r, a.length, b.length);
       
   716         return r;
       
   717     }
       
   718 
       
   719     /**
       
   720      * Returns supported algorithms of specified type.
       
   721      */
       
   722     static List<String> getSupportedAlgorithms(String type, String alg,
       
   723             Provider p) {
       
   724         // prepare a list of supported algorithms
       
   725         List<String> algorithms = new ArrayList<>();
       
   726         Set<Provider.Service> services = p.getServices();
       
   727         for (Provider.Service service : services) {
       
   728             if (service.getType().equals(type)
       
   729                     && service.getAlgorithm().startsWith(alg)) {
       
   730                 algorithms.add(service.getAlgorithm());
       
   731             }
       
   732         }
       
   733         return algorithms;
       
   734     }
       
   735 
       
   736     /**
       
   737      * Get the identifier for the operating system distribution
       
   738      */
       
   739     static String getDistro() {
       
   740         return distro;
       
   741     }
       
   742 
       
   743     private static String distro() {
       
   744         try (BufferedReader in =
       
   745             new BufferedReader(new InputStreamReader(
       
   746                 Runtime.getRuntime().exec("uname -v").getInputStream()))) {
       
   747 
       
   748             return in.readLine();
       
   749         } catch (Exception e) {
       
   750             throw new RuntimeException("Failed to determine distro.", e);
       
   751         }
       
   752     }
       
   753 
       
   754     static byte[] generateData(int length) {
       
   755         byte data[] = new byte[length];
       
   756         for (int i=0; i<data.length; i++) {
       
   757             data[i] = (byte) (i % 256);
       
   758         }
       
   759         return data;
       
   760     }
       
   761 }