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
27import java.io.BufferedReader;
28import java.io.ByteArrayOutputStream;
29import java.io.File;
30import java.io.FileInputStream;
31import java.io.IOException;
32import java.io.InputStreamReader;
33import java.io.StringReader;
34import java.security.AlgorithmParameters;
35import java.security.InvalidAlgorithmParameterException;
36import java.security.KeyPairGenerator;
37import java.security.NoSuchProviderException;
38import java.security.Provider;
39import java.security.ProviderException;
40import java.security.Security;
41import java.security.spec.ECGenParameterSpec;
42import java.security.spec.ECParameterSpec;
43import java.util.ArrayList;
44import java.util.Arrays;
45import java.util.HashMap;
46import java.util.Iterator;
47import java.util.List;
48import java.util.Map;
49import java.util.Properties;
50import java.util.ServiceConfigurationError;
51import java.util.ServiceLoader;
52import java.util.Set;
53
54public 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}
762