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