1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.java.security; 18 19 import java.security.InvalidAlgorithmParameterException; 20 import java.security.InvalidParameterException; 21 import java.security.NoSuchAlgorithmException; 22 import java.security.Provider; 23 import java.security.SecureRandom; 24 import java.security.SecureRandomSpi; 25 import java.security.Security; 26 import java.security.cert.CRL; 27 import java.security.cert.CRLSelector; 28 import java.security.cert.CertSelector; 29 import java.security.cert.CertStoreException; 30 import java.security.cert.CertStoreParameters; 31 import java.security.cert.CertStoreSpi; 32 import java.security.cert.Certificate; 33 import java.security.cert.CollectionCertStoreParameters; 34 import java.security.interfaces.RSAPrivateKey; 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 import java.util.Collection; 38 import java.util.Collections; 39 import java.util.Comparator; 40 import java.util.Enumeration; 41 import java.util.HashMap; 42 import java.util.HashSet; 43 import java.util.Iterator; 44 import java.util.List; 45 import java.util.Locale; 46 import java.util.Map; 47 import java.util.Map.Entry; 48 import java.util.Objects; 49 import java.util.Set; 50 import java.util.TreeMap; 51 import java.util.TreeSet; 52 import java.util.function.BiFunction; 53 import java.util.function.Consumer; 54 import java.util.function.Function; 55 import java.util.regex.Matcher; 56 import java.util.regex.Pattern; 57 import javax.crypto.Cipher; 58 import javax.crypto.EncryptedPrivateKeyInfo; 59 import javax.crypto.NoSuchPaddingException; 60 import libcore.javax.crypto.MockKey; 61 import libcore.junit.junit3.TestCaseWithRules; 62 import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule; 63 import org.junit.Rule; 64 import org.junit.rules.TestRule; 65 66 public class ProviderTest extends TestCaseWithRules { 67 68 // Allow access to deprecated BC algorithms in this test, so we can ensure they 69 // continue to work 70 @Rule 71 public TestRule enableDeprecatedBCAlgorithmsRule = 72 EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance(); 73 74 private static final boolean LOG_DEBUG = false; 75 76 /** 77 * Makes sure all all expected implementations (but not aliases) 78 * and that there are no extras, according to what we expect from 79 * StandardNames 80 */ test_Provider_getServices()81 public void test_Provider_getServices() throws Exception { 82 // build set of expected algorithms 83 Map<String,Set<String>> remainingExpected 84 = new HashMap<String,Set<String>>(StandardNames.PROVIDER_ALGORITHMS); 85 for (Entry<String,Set<String>> entry : remainingExpected.entrySet()) { 86 entry.setValue(new HashSet<String>(entry.getValue())); 87 } 88 89 Map<String,List<String>> extra = new HashMap<>(); 90 List<String> missing = new ArrayList<String>(); 91 92 Provider[] providers = Security.getProviders(); 93 for (Provider provider : providers) { 94 String providerName = provider.getName(); 95 // ignore BouncyCastle provider if it is installed on the RI 96 if (StandardNames.IS_RI && providerName.equals("BC")) { 97 continue; 98 } 99 extra.put(providerName, new ArrayList<>()); 100 Set<Provider.Service> services = provider.getServices(); 101 assertNotNull(services); 102 assertFalse(services.isEmpty()); 103 if (LOG_DEBUG) { 104 Set<Provider.Service> originalServices = services; 105 services = new TreeSet<Provider.Service>( 106 new Comparator<Provider.Service>() { 107 public int compare(Provider.Service a, Provider.Service b) { 108 int typeCompare = a.getType().compareTo(b.getType()); 109 if (typeCompare != 0) { 110 return typeCompare; 111 } 112 return a.getAlgorithm().compareTo(b.getAlgorithm()); 113 } 114 }); 115 services.addAll(originalServices); 116 } 117 118 for (Provider.Service service : services) { 119 String type = service.getType(); 120 String algorithm = service.getAlgorithm().toUpperCase(); 121 String className = service.getClassName(); 122 if (LOG_DEBUG) { 123 System.out.println(providerName 124 + " " + type 125 + " " + algorithm 126 + " " + className); 127 } 128 129 // remove from remaining, assert unknown if missing 130 Set<String> remainingAlgorithms = remainingExpected.get(type); 131 if (remainingAlgorithms == null || !remainingAlgorithms.remove(algorithm)) { 132 // seems to be missing, but sometimes the same 133 // algorithm is available from multiple providers 134 // (e.g. KeyFactory RSA is available from 135 // SunRsaSign and SunJSSE), so double check in 136 // original source before giving error 137 if (!(StandardNames.PROVIDER_ALGORITHMS.containsKey(type) 138 && StandardNames.PROVIDER_ALGORITHMS.get(type).contains(algorithm))) { 139 extra.get(providerName). 140 add("Unknown " + type + " " + algorithm + " " + providerName + "\n"); 141 } 142 } else if ("Cipher".equals(type) && !algorithm.contains("/")) { 143 /* 144 * Cipher selection follows special rules where you can 145 * specify the mode and padding during the getInstance call. 146 * Try to see if the service supports this. 147 */ 148 Set<String> toRemove = new HashSet<String>(); 149 for (String remainingAlgo : remainingAlgorithms) { 150 String[] parts = remainingAlgo.split("/"); 151 if (parts.length == 3 && algorithm.equals(parts[0])) { 152 try { 153 Cipher.getInstance(remainingAlgo, provider); 154 toRemove.add(remainingAlgo); 155 } catch (NoSuchAlgorithmException ignored) { 156 } catch (NoSuchPaddingException ignored) { 157 } 158 } 159 } 160 remainingAlgorithms.removeAll(toRemove); 161 } 162 163 // make sure class exists and can be initialized 164 try { 165 assertNotNull(Class.forName(className, 166 true, 167 provider.getClass().getClassLoader())); 168 } catch (ClassNotFoundException e) { 169 // Sun forgot their own class 170 if (!className.equals("sun.security.pkcs11.P11MAC")) { 171 missing.add(className); 172 } 173 } 174 175 // Try to create an instance. Some algorithms require a parameter, 176 // so we need to feed them something they'll be happy with. 177 Object param = null; 178 if (algorithm.equals("COLLECTION")) { 179 param = new CollectionCertStoreParameters(); 180 } 181 assertNotNull("Failed to instantiate " + providerName + " " + type + " " + algorithm 182 + " " + className, 183 service.newInstance(param)); 184 } 185 186 // last chance: some algorithms might only be provided by their alias 187 remainingExpected.entrySet() 188 .forEach(entry -> 189 entry.getValue() 190 .removeIf(algorithm -> 191 provider.getService(entry.getKey(), algorithm) != null) 192 ); 193 } 194 195 // assert that we don't have any extra in the implementation 196 for (String providerName : extra.keySet()) { 197 List<String> extraList = extra.get(providerName); 198 Collections.sort(extraList); // sort so that its grouped by type 199 if (StandardNames.JSSE_PROVIDER_NAME.equalsIgnoreCase(providerName)) { 200 if (LOG_DEBUG) { 201 System.out.println("Algorithms are provided but not present in StandardNames" 202 + " " + extraList); 203 } 204 } else { 205 assertEquals("Algorithms are provided but not present in StandardNames", 206 Collections.EMPTY_LIST, extraList); 207 } 208 } 209 210 if (remainingExpected.containsKey("Cipher")) { 211 // For any remaining ciphers, they may be aliases for other ciphers or otherwise 212 // don't show up as a service but can still be instantiated. 213 for (Iterator<String> cipherIt = remainingExpected.get("Cipher").iterator(); 214 cipherIt.hasNext(); ) { 215 String missingCipher = cipherIt.next(); 216 try { 217 Cipher.getInstance(missingCipher); 218 cipherIt.remove(); 219 } catch (NoSuchAlgorithmException|NoSuchPaddingException e) { 220 } 221 } 222 } 223 224 remainingExpected.entrySet() 225 .removeIf(entry -> 226 entry.getValue().isEmpty()); 227 228 // assert that we don't have any missing in the implementation 229 assertEquals("Algorithms are present in StandardNames but not provided", 230 Collections.EMPTY_MAP, remainingExpected); 231 232 // assert that we don't have any missing classes 233 Collections.sort(missing); // sort it for readability 234 assertEquals("Missing classes", Collections.EMPTY_LIST, missing); 235 } 236 237 // This tests the CDD requirement that specifies the first seven security providers 238 // (section 3.5, [C-0-9] as of P). testProviderList()239 public void testProviderList() { 240 Provider[] providers = Security.getProviders(); 241 assertTrue(providers.length >= 7); 242 assertProviderProperties(providers[0], "AndroidNSSP", 243 "android.security.net.config.NetworkSecurityConfigProvider"); 244 assertProviderProperties(providers[1], "AndroidOpenSSL", 245 "com.android.org.conscrypt.OpenSSLProvider"); 246 assertProviderProperties(providers[2], "CertPathProvider", 247 "sun.security.provider.CertPathProvider"); 248 assertProviderProperties(providers[3], "AndroidKeyStoreBCWorkaround", 249 "android.security.keystore2.AndroidKeyStoreBCWorkaroundProvider"); 250 assertProviderProperties(providers[4], "BC", 251 "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider"); 252 assertProviderProperties(providers[5], "HarmonyJSSE", 253 "com.android.org.conscrypt.JSSEProvider"); 254 assertProviderProperties(providers[6], "AndroidKeyStore", 255 "android.security.keystore2.AndroidKeyStoreProvider"); 256 } 257 assertProviderProperties(Provider p, String name, String className)258 private void assertProviderProperties(Provider p, String name, String className) { 259 assertEquals(name, p.getName()); 260 assertEquals(className, p.getClass().getName()); 261 } 262 263 private static final Pattern alias = Pattern.compile("Alg\\.Alias\\.([^.]*)\\.(.*)"); 264 265 /** 266 * Makes sure all provider properties either point to a class 267 * implementation that exists or are aliases to known algorithms. 268 */ test_Provider_Properties()269 public void test_Provider_Properties() throws Exception { 270 /* 271 * A useful reference on Provider properties 272 * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html"> 273 * How to Implement a Provider in the Java ™ Cryptography Architecture 274 * </a> 275 */ 276 277 Provider[] providers = Security.getProviders(); 278 for (Provider provider : providers) { 279 // check Provider.id proprieties 280 assertEquals(provider.getName(), 281 provider.get("Provider.id name")); 282 assertEquals(String.valueOf(provider.getVersion()), 283 provider.get("Provider.id version")); 284 assertEquals(provider.getInfo(), 285 provider.get("Provider.id info")); 286 assertEquals(provider.getClass().getName(), 287 provider.get("Provider.id className")); 288 289 // build map of all known aliases and implementations 290 Map<String,String> aliases = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 291 Map<String,String> implementations = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 292 for (Entry<Object,Object> entry : provider.entrySet()) { 293 Object k = entry.getKey(); 294 Object v = entry.getValue(); 295 assertEquals(String.class, k.getClass()); 296 assertEquals(String.class, v.getClass()); 297 String key = (String)k; 298 String value = (String)v; 299 300 // skip Provider.id keys, we check well known ones values above 301 if (key.startsWith("Provider.id ")) { 302 continue; 303 } 304 305 // skip property settings such as: "Signature.SHA1withDSA ImplementedIn" "Software" 306 if (key.indexOf(' ') != -1) { 307 continue; 308 } 309 310 Matcher m = alias.matcher(key); 311 if (m.find()) { 312 String type = m.group(1); 313 aliases.put(key, type + "." + value); 314 } else { 315 implementations.put(key, value); 316 } 317 } 318 319 // verify implementation classes are available 320 for (Entry<String,String> entry : implementations.entrySet()) { 321 String typeAndAlgorithm = entry.getKey(); 322 String className = entry.getValue(); 323 try { 324 assertNotNull(Class.forName(className, 325 true, 326 provider.getClass().getClassLoader())); 327 } catch (ClassNotFoundException e) { 328 // Sun forgot their own class 329 if (!className.equals("sun.security.pkcs11.P11MAC")) { 330 fail("Could not find class " + className + " for " + typeAndAlgorithm 331 + " [provider=" + provider.getName() + "]"); 332 } 333 } 334 } 335 336 // make sure all aliases point to some known implementation 337 for (Entry<String,String> entry : aliases.entrySet()) { 338 String alias = entry.getKey(); 339 String actual = entry.getValue(); 340 assertTrue("Could not find implementation " + actual + " for alias " + alias + 341 " [provider=" + provider.getName() + "]", 342 implementations.containsKey(actual)); 343 } 344 } 345 } 346 347 /** 348 * Helper function to fetch services for Service.Algorithm IDs 349 */ getService(Provider p, String id)350 private static Provider.Service getService(Provider p, String id) { 351 String[] typeAndAlg = id.split("\\.", 2); 352 assertEquals(id + " is not formatted as expected.", 2, typeAndAlg.length); 353 return p.getService(typeAndAlg[0], typeAndAlg[1]); 354 } 355 356 /** 357 * Identifiers provided by Bouncy Castle that we exclude from consideration 358 * when checking that all Bouncy Castle identifiers are also covered by Conscrypt. 359 * Each block of excluded identifiers is preceded by the justification specific 360 * to those IDs. 361 */ 362 private static final Set<String> BC_OVERRIDE_EXCEPTIONS = new HashSet<>(); 363 static { 364 // A typo caused Bouncy Castle to accept these incorrect OIDs for AES, and they 365 // maintain these aliases for backwards compatibility. We don't want to continue 366 // this in Conscrypt. 367 BC_OVERRIDE_EXCEPTIONS.add("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.2"); 368 BC_OVERRIDE_EXCEPTIONS.add("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.22"); 369 BC_OVERRIDE_EXCEPTIONS.add("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.42"); 370 371 // BC uses the same class to implement AlgorithmParameters.DES and 372 // AlgorithmParameters.DESEDE. Conscrypt doesn't support DES, so it doesn't 373 // include an implementation of AlgorithmParameters.DES, and this isn't a problem. 374 BC_OVERRIDE_EXCEPTIONS.add("AlgorithmParameters.DES"); 375 BC_OVERRIDE_EXCEPTIONS.add("Alg.Alias.AlgorithmParameters.1.3.14.3.2.7"); 376 BC_OVERRIDE_EXCEPTIONS.add("Alg.Alias.AlgorithmParameters.OID.1.3.14.3.2.7"); 377 } 378 379 /** 380 * Ensures that, for all algorithms provided by Conscrypt, there is no alias from 381 * the BC provider that's not provided by Conscrypt. If there is, then a request 382 * for that alias with no provider specified will return the BC implementation of 383 * it even though we have a Conscrypt implementation available. 384 */ test_Provider_ConscryptOverridesBouncyCastle()385 public void test_Provider_ConscryptOverridesBouncyCastle() throws Exception { 386 if (StandardNames.IS_RI) { 387 // These providers aren't installed on RI 388 return; 389 } 390 Provider conscrypt = Security.getProvider("AndroidOpenSSL"); 391 Provider bc = Security.getProvider("BC"); 392 393 // 1. Find all the algorithms provided by Conscrypt. 394 Set<String> conscryptAlgs = new HashSet<>(); 395 for (Entry<Object, Object> entry : conscrypt.entrySet()) { 396 String key = (String) entry.getKey(); 397 if (key.contains(" ")) { 398 // These are implementation properties like "Provider.id name" 399 continue; 400 } 401 if (key.startsWith("Alg.Alias.")) { 402 // Ignore aliases, we only want the concrete algorithms 403 continue; 404 } 405 conscryptAlgs.add(key); 406 } 407 408 // 2. Determine which classes in BC implement those algorithms 409 Set<String> bcClasses = new HashSet<>(); 410 for (String conscryptAlg : conscryptAlgs) { 411 Provider.Service service = getService(bc, conscryptAlg); 412 if (service != null) { 413 bcClasses.add(service.getClassName()); 414 } 415 } 416 assertTrue(bcClasses.size() > 0); 417 418 // 3. Determine which IDs in BC point to that set of classes 419 Set<String> shouldBeOverriddenBcIds = new HashSet<>(); 420 for (Object keyObject : bc.keySet()) { 421 String key = (String) keyObject; 422 if (key.contains(" ")) { 423 continue; 424 } 425 if (BC_OVERRIDE_EXCEPTIONS.contains(key)) { 426 continue; 427 } 428 if (key.startsWith("Alg.Alias.")) { 429 key = key.substring("Alg.Alias.".length()); 430 } 431 Provider.Service service = getService(bc, key); 432 if (bcClasses.contains(service.getClassName())) { 433 shouldBeOverriddenBcIds.add(key); 434 } 435 } 436 assertTrue(shouldBeOverriddenBcIds.size() > 0); 437 438 // 4. Check each of those IDs to ensure that it's present in Conscrypt 439 Set<String> nonOverriddenIds = new TreeSet<>(); 440 for (String shouldBeOverridenBcId : shouldBeOverriddenBcIds) { 441 if (getService(conscrypt, shouldBeOverridenBcId) == null) { 442 nonOverriddenIds.add(shouldBeOverridenBcId); 443 } 444 } 445 assertTrue("Conscrypt does not provide IDs " + nonOverriddenIds 446 + ", but it does provide other IDs that point to the same implementation(s)" 447 + " in BouncyCastle.", 448 nonOverriddenIds.isEmpty()); 449 } 450 451 private static final String[] TYPES_SERVICES_CHECKED = new String[] { 452 "KeyFactory", "CertPathBuilder", "Cipher", "SecureRandom", 453 "AlgorithmParameterGenerator", "Signature", "KeyPairGenerator", "CertificateFactory", 454 "MessageDigest", "KeyAgreement", "CertStore", "SSLContext", "AlgorithmParameters", 455 "TrustManagerFactory", "KeyGenerator", "Mac", "CertPathValidator", "SecretKeyFactory", 456 "KeyManagerFactory", "KeyStore", 457 }; 458 459 private static final HashSet<String> TYPES_SUPPORTS_PARAMETER = new HashSet<String>( 460 Arrays.asList(new String[] { 461 "Mac", "KeyAgreement", "Cipher", "Signature", 462 })); 463 464 private static final HashSet<String> TYPES_NOT_SUPPORTS_PARAMETER = new HashSet<String>( 465 Arrays.asList(TYPES_SERVICES_CHECKED)); 466 static { 467 TYPES_NOT_SUPPORTS_PARAMETER.removeAll(TYPES_SUPPORTS_PARAMETER); 468 } 469 test_Provider_getServices_supportsParameter()470 public void test_Provider_getServices_supportsParameter() throws Exception { 471 HashSet<String> remainingTypes = new HashSet<String>(Arrays.asList(TYPES_SERVICES_CHECKED)); 472 473 HashSet<String> supportsParameterTypes = new HashSet<String>(); 474 HashSet<String> noSupportsParameterTypes = new HashSet<String>(); 475 476 Provider[] providers = Security.getProviders(); 477 for (Provider provider : providers) { 478 Set<Provider.Service> services = provider.getServices(); 479 assertNotNull(services); 480 assertFalse(services.isEmpty()); 481 482 for (Provider.Service service : services) { 483 final String type = service.getType(); 484 remainingTypes.remove(type); 485 try { 486 service.supportsParameter(new MockKey()); 487 supportsParameterTypes.add(type); 488 } catch (InvalidParameterException e) { 489 noSupportsParameterTypes.add(type); 490 try { 491 service.supportsParameter(new Object()); 492 fail("Should throw on non-Key parameter"); 493 } catch (InvalidParameterException expected) { 494 } 495 } 496 } 497 } 498 499 supportsParameterTypes.retainAll(TYPES_SUPPORTS_PARAMETER); 500 assertEquals("Types that should support parameters", TYPES_SUPPORTS_PARAMETER, 501 supportsParameterTypes); 502 503 noSupportsParameterTypes.retainAll(TYPES_NOT_SUPPORTS_PARAMETER); 504 assertEquals("Types that should not support parameters", TYPES_NOT_SUPPORTS_PARAMETER, 505 noSupportsParameterTypes); 506 507 assertEquals("Types that should be checked", Collections.EMPTY_SET, remainingTypes); 508 } 509 510 public static class MockSpi { 511 public Object parameter; 512 MockSpi(MockKey parameter)513 public MockSpi(MockKey parameter) { 514 this.parameter = parameter; 515 } 516 }; 517 518 @SuppressWarnings("serial") testProviderService_supportsParameter_UnknownService_Success()519 public void testProviderService_supportsParameter_UnknownService_Success() throws Exception { 520 Provider provider = new MockProvider("MockProvider") { 521 public void setup() { 522 put("Fake.FOO", MockSpi.class.getName()); 523 } 524 }; 525 526 Security.addProvider(provider); 527 try { 528 Provider.Service service = provider.getService("Fake", "FOO"); 529 assertTrue(service.supportsParameter(new Object())); 530 } finally { 531 Security.removeProvider(provider.getName()); 532 } 533 } 534 535 @SuppressWarnings("serial") testProviderService_supportsParameter_KnownService_NoClassInitialization_Success()536 public void testProviderService_supportsParameter_KnownService_NoClassInitialization_Success() 537 throws Exception { 538 Provider provider = new MockProvider("MockProvider") { 539 public void setup() { 540 put("Signature.FOO", MockSpi.class.getName()); 541 put("Signature.FOO SupportedKeyClasses", getClass().getName() 542 + ".UninitializedMockKey"); 543 } 544 }; 545 546 Security.addProvider(provider); 547 try { 548 Provider.Service service = provider.getService("Signature", "FOO"); 549 assertFalse(service.supportsParameter(new MockKey())); 550 } finally { 551 Security.removeProvider(provider.getName()); 552 } 553 } 554 555 @SuppressWarnings("serial") 556 public static class UninitializedMockKey extends MockKey { 557 static { 558 fail("This should not be initialized"); 559 } 560 } 561 562 @SuppressWarnings("serial") testProviderService_supportsParameter_TypeDoesNotSupportParameter_Failure()563 public void testProviderService_supportsParameter_TypeDoesNotSupportParameter_Failure() 564 throws Exception { 565 Provider provider = new MockProvider("MockProvider") { 566 public void setup() { 567 put("KeyFactory.FOO", MockSpi.class.getName()); 568 } 569 }; 570 571 Security.addProvider(provider); 572 try { 573 Provider.Service service = provider.getService("KeyFactory", "FOO"); 574 try { 575 service.supportsParameter(new MockKey()); 576 fail("Should always throw exception"); 577 } catch (InvalidParameterException expected) { 578 } 579 } finally { 580 Security.removeProvider(provider.getName()); 581 } 582 } 583 584 @SuppressWarnings("serial") testProviderService_supportsParameter_SupportedKeyClasses_NonKeyClass_Success()585 public void testProviderService_supportsParameter_SupportedKeyClasses_NonKeyClass_Success() 586 throws Exception { 587 Provider provider = new MockProvider("MockProvider") { 588 public void setup() { 589 put("Signature.FOO", MockSpi.class.getName()); 590 put("Signature.FOO SupportedKeyClasses", MockSpi.class.getName()); 591 } 592 }; 593 594 Security.addProvider(provider); 595 try { 596 Provider.Service service = provider.getService("Signature", "FOO"); 597 assertFalse(service.supportsParameter(new MockKey())); 598 } finally { 599 Security.removeProvider(provider.getName()); 600 } 601 } 602 603 @SuppressWarnings("serial") testProviderService_supportsParameter_KnownService_NonKey_Failure()604 public void testProviderService_supportsParameter_KnownService_NonKey_Failure() 605 throws Exception { 606 Provider provider = new MockProvider("MockProvider") { 607 public void setup() { 608 put("Signature.FOO", MockSpi.class.getName()); 609 } 610 }; 611 612 Security.addProvider(provider); 613 try { 614 Provider.Service service = provider.getService("Signature", "FOO"); 615 try { 616 service.supportsParameter(new Object()); 617 fail("Should throw when non-Key passed in"); 618 } catch (InvalidParameterException expected) { 619 } 620 } finally { 621 Security.removeProvider(provider.getName()); 622 } 623 } 624 625 @SuppressWarnings("serial") testProviderService_supportsParameter_KnownService_SupportedKeyClasses_NonKey_Failure()626 public void testProviderService_supportsParameter_KnownService_SupportedKeyClasses_NonKey_Failure() 627 throws Exception { 628 Provider provider = new MockProvider("MockProvider") { 629 public void setup() { 630 put("Signature.FOO", MockSpi.class.getName()); 631 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName()); 632 } 633 }; 634 635 Security.addProvider(provider); 636 try { 637 Provider.Service service = provider.getService("Signature", "FOO"); 638 try { 639 service.supportsParameter(new Object()); 640 fail("Should throw on non-Key instance passed in"); 641 } catch (InvalidParameterException expected) { 642 } 643 } finally { 644 Security.removeProvider(provider.getName()); 645 } 646 } 647 648 @SuppressWarnings("serial") testProviderService_supportsParameter_KnownService_Null_Failure()649 public void testProviderService_supportsParameter_KnownService_Null_Failure() throws Exception { 650 Provider provider = new MockProvider("MockProvider") { 651 public void setup() { 652 put("Signature.FOO", MockSpi.class.getName()); 653 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName()); 654 } 655 }; 656 657 Security.addProvider(provider); 658 try { 659 Provider.Service service = provider.getService("Signature", "FOO"); 660 assertFalse(service.supportsParameter(null)); 661 } finally { 662 Security.removeProvider(provider.getName()); 663 } 664 } 665 666 @SuppressWarnings("serial") testProviderService_supportsParameter_SupportedKeyClasses_Success()667 public void testProviderService_supportsParameter_SupportedKeyClasses_Success() 668 throws Exception { 669 Provider provider = new MockProvider("MockProvider") { 670 public void setup() { 671 put("Signature.FOO", MockSpi.class.getName()); 672 put("Signature.FOO SupportedKeyClasses", MockKey.class.getName()); 673 } 674 }; 675 676 Security.addProvider(provider); 677 try { 678 Provider.Service service = provider.getService("Signature", "FOO"); 679 assertTrue(service.supportsParameter(new MockKey())); 680 } finally { 681 Security.removeProvider(provider.getName()); 682 } 683 } 684 685 @SuppressWarnings("serial") testProviderService_supportsParameter_SupportedKeyClasses_Failure()686 public void testProviderService_supportsParameter_SupportedKeyClasses_Failure() 687 throws Exception { 688 Provider provider = new MockProvider("MockProvider") { 689 public void setup() { 690 put("Signature.FOO", MockSpi.class.getName()); 691 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName()); 692 } 693 }; 694 695 Security.addProvider(provider); 696 try { 697 Provider.Service service = provider.getService("Signature", "FOO"); 698 assertFalse(service.supportsParameter(new MockKey())); 699 } finally { 700 Security.removeProvider(provider.getName()); 701 } 702 } 703 704 @SuppressWarnings("serial") testProviderService_supportsParameter_SupportedKeyFormats_Success()705 public void testProviderService_supportsParameter_SupportedKeyFormats_Success() 706 throws Exception { 707 Provider provider = new MockProvider("MockProvider") { 708 public void setup() { 709 put("Signature.FOO", MockSpi.class.getName()); 710 put("Signature.FOO SupportedKeyFormats", new MockKey().getFormat()); 711 } 712 }; 713 714 Security.addProvider(provider); 715 try { 716 Provider.Service service = provider.getService("Signature", "FOO"); 717 assertTrue(service.supportsParameter(new MockKey())); 718 } finally { 719 Security.removeProvider(provider.getName()); 720 } 721 } 722 723 @SuppressWarnings("serial") testProviderService_supportsParameter_SupportedKeyFormats_Failure()724 public void testProviderService_supportsParameter_SupportedKeyFormats_Failure() 725 throws Exception { 726 Provider provider = new MockProvider("MockProvider") { 727 public void setup() { 728 put("Signature.FOO", MockSpi.class.getName()); 729 put("Signature.FOO SupportedKeyFormats", "Invalid"); 730 } 731 }; 732 733 Security.addProvider(provider); 734 try { 735 Provider.Service service = provider.getService("Signature", "FOO"); 736 assertFalse(service.supportsParameter(new MockKey())); 737 } finally { 738 Security.removeProvider(provider.getName()); 739 } 740 } 741 742 @SuppressWarnings("serial") testProviderService_newInstance_DoesNotCallSupportsParameter_Success()743 public void testProviderService_newInstance_DoesNotCallSupportsParameter_Success() 744 throws Exception { 745 MockProvider provider = new MockProvider("MockProvider"); 746 747 provider.putServiceForTest(new Provider.Service(provider, "CertStore", "FOO", 748 MyCertStoreSpi.class.getName(), null, null) { 749 @Override 750 public boolean supportsParameter(Object parameter) { 751 fail("This should not be called"); 752 return false; 753 } 754 }); 755 756 Security.addProvider(provider); 757 try { 758 Provider.Service service = provider.getService("CertStore", "FOO"); 759 assertNotNull(service.newInstance(new MyCertStoreParameters())); 760 } finally { 761 Security.removeProvider(provider.getName()); 762 } 763 } 764 765 @SuppressWarnings("serial") testProviderService_newInstance_PrivateClass_throws()766 public void testProviderService_newInstance_PrivateClass_throws() 767 throws Exception { 768 MockProvider provider = new MockProvider("MockProvider"); 769 770 provider.putServiceForTest(new Provider.Service(provider, "CertStore", "FOO", 771 CertStoreSpiPrivateClass.class.getName(), null, null)); 772 773 Security.addProvider(provider); 774 // The class for the service is private, it must fail with NoSuchAlgorithmException 775 try { 776 Provider.Service service = provider.getService("CertStore", "FOO"); 777 service.newInstance(null); 778 fail(); 779 } catch (NoSuchAlgorithmException expected) { 780 } finally { 781 Security.removeProvider(provider.getName()); 782 } 783 } 784 785 @SuppressWarnings("serial") testProviderService_newInstance_PrivateEmptyConstructor_throws()786 public void testProviderService_newInstance_PrivateEmptyConstructor_throws() 787 throws Exception { 788 MockProvider provider = new MockProvider("MockProvider"); 789 790 provider.putServiceForTest(new Provider.Service(provider, "CertStore", "FOO", 791 CertStoreSpiPrivateEmptyConstructor.class.getName(), null, null)); 792 793 Security.addProvider(provider); 794 // The empty constructor is private, it must fail with NoSuchAlgorithmException 795 try { 796 Provider.Service service = provider.getService("CertStore", "FOO"); 797 service.newInstance(null); 798 fail(); 799 } catch (NoSuchAlgorithmException expected) { 800 } finally { 801 Security.removeProvider(provider.getName()); 802 } 803 } 804 805 @SuppressWarnings("serial") testProviderService_AliasDoesNotEraseCanonical_Success()806 public void testProviderService_AliasDoesNotEraseCanonical_Success() 807 throws Exception { 808 // Make sure we start with a "known good" alias for this OID. 809 { 810 EncryptedPrivateKeyInfo epki1 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5", 811 new byte[1]); 812 assertEquals("SHA1WITHRSA", epki1.getAlgName().toUpperCase(Locale.US)); 813 } 814 815 Provider provider = new MockProvider("MockProvider") { 816 public void setup() { 817 put("Signature.FOO", MockSpi.class.getName()); 818 put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "FOO"); 819 } 820 }; 821 822 Security.addProvider(provider); 823 try { 824 // This triggers a re-indexing of the algorithm id data: 825 try { 826 new EncryptedPrivateKeyInfo("nonexistent", new byte[1]); 827 fail("Should not find 'nonexistent' algorithm"); 828 } catch (NoSuchAlgorithmException expected) { 829 } 830 831 EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5", new byte[1]); 832 assertEquals("SHA1WITHRSA", epki2.getAlgName().toUpperCase(Locale.US)); 833 } finally { 834 Security.removeProvider(provider.getName()); 835 } 836 } 837 838 @SuppressWarnings("serial") testProviderService_CanFindNewOID_Success()839 public void testProviderService_CanFindNewOID_Success() 840 throws Exception { 841 Provider provider = new MockProvider("MockProvider") { 842 public void setup() { 843 put("Signature.NEWALG", MockSpi.class.getName()); 844 put("Alg.Alias.Signature.OID.1.2.9999.9999.9999", "NEWALG"); 845 } 846 }; 847 848 Security.addProvider(provider); 849 try { 850 EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.9999.9999.9999", new byte[1]); 851 assertEquals("NEWALG", epki2.getAlgName().toUpperCase(Locale.US)); 852 } finally { 853 Security.removeProvider(provider.getName()); 854 } 855 } 856 testProvider_removeProvider_Success()857 public void testProvider_removeProvider_Success() throws Exception { 858 MockProvider provider = new MockProvider("MockProvider"); 859 assertNull(Security.getProvider(provider.getName())); 860 Security.addProvider(provider); 861 assertNotNull(Security.getProvider(provider.getName())); 862 Security.removeProvider(provider.getName()); 863 assertNull(Security.getProvider(provider.getName())); 864 } 865 866 public static class MyCertStoreSpi extends CertStoreSpi { MyCertStoreSpi(CertStoreParameters params)867 public MyCertStoreSpi(CertStoreParameters params) throws InvalidAlgorithmParameterException { 868 super(params); 869 } 870 871 @Override engineGetCertificates(CertSelector selector)872 public Collection<? extends Certificate> engineGetCertificates(CertSelector selector) 873 throws CertStoreException { 874 throw new UnsupportedOperationException(); 875 } 876 877 @Override engineGetCRLs(CRLSelector selector)878 public Collection<? extends CRL> engineGetCRLs(CRLSelector selector) 879 throws CertStoreException { 880 throw new UnsupportedOperationException(); 881 } 882 } 883 884 private static class CertStoreSpiPrivateClass extends CertStoreSpi { CertStoreSpiPrivateClass()885 public CertStoreSpiPrivateClass() 886 throws InvalidAlgorithmParameterException { 887 super(null); 888 } 889 890 @Override engineGetCertificates(CertSelector selector)891 public Collection<? extends Certificate> engineGetCertificates(CertSelector selector) 892 throws CertStoreException { 893 throw new UnsupportedOperationException(); 894 } 895 896 @Override engineGetCRLs(CRLSelector selector)897 public Collection<? extends CRL> engineGetCRLs(CRLSelector selector) 898 throws CertStoreException { 899 throw new UnsupportedOperationException(); 900 } 901 } 902 903 private static class CertStoreSpiPrivateEmptyConstructor extends CertStoreSpi { CertStoreSpiPrivateEmptyConstructor(CertStoreParameters params)904 private CertStoreSpiPrivateEmptyConstructor(CertStoreParameters params) 905 throws InvalidAlgorithmParameterException { 906 super(null); 907 } 908 909 @Override engineGetCertificates(CertSelector selector)910 public Collection<? extends Certificate> engineGetCertificates(CertSelector selector) 911 throws CertStoreException { 912 throw new UnsupportedOperationException(); 913 } 914 915 @Override engineGetCRLs(CRLSelector selector)916 public Collection<? extends CRL> engineGetCRLs(CRLSelector selector) 917 throws CertStoreException { 918 throw new UnsupportedOperationException(); 919 } 920 } 921 922 923 public static class MyCertStoreParameters implements CertStoreParameters { clone()924 public Object clone() { 925 return new MyCertStoreParameters(); 926 } 927 } 928 929 /** 930 * http://code.google.com/p/android/issues/detail?id=21449 931 */ testSecureRandomImplementationOrder()932 public void testSecureRandomImplementationOrder() { 933 @SuppressWarnings("serial") 934 Provider srp = new MockProvider("SRProvider") { 935 public void setup() { 936 put("SecureRandom.SecureRandom1", SecureRandom1.class.getName()); 937 put("SecureRandom.SecureRandom2", SecureRandom2.class.getName()); 938 put("SecureRandom.SecureRandom3", SecureRandom3.class.getName()); 939 } 940 }; 941 try { 942 int position = Security.insertProviderAt(srp, 1); // first is one, not zero 943 assertEquals(1, position); 944 SecureRandom sr = new SecureRandom(); 945 if (!sr.getAlgorithm().equals("SecureRandom1")) { 946 throw new IllegalStateException("Expected SecureRandom1 was " + sr.getAlgorithm()); 947 } 948 } finally { 949 Security.removeProvider(srp.getName()); 950 } 951 } 952 953 // TODO(29631070): this is a general testing mechanism to test other operations that are 954 // going to be added. testHashMapOperations()955 public void testHashMapOperations() { 956 performHashMapOperationAndCheckResults( 957 PUT /* operation */, 958 mapOf("class1.algorithm1", "impl1") /* initialStatus */, 959 new Pair("class2.algorithm2", "impl2") /* operationParameters */, 960 mapOf("class1.algorithm1", "impl1", 961 "class2.algorithm2", "impl2"), 962 true /* mustChangeSecurityVersion */); 963 performHashMapOperationAndCheckResults( 964 PUT_ALL, 965 mapOf("class1.algorithm1", "impl1"), 966 mapOf("class2.algorithm2", "impl2", "class3.algorithm3", "impl3"), 967 mapOf("class1.algorithm1", "impl1", 968 "class2.algorithm2", "impl2", 969 "class3.algorithm3", "impl3"), 970 true /* mustChangeSecurityVersion */); 971 performHashMapOperationAndCheckResults( 972 REMOVE, 973 mapOf("class1.algorithm1", "impl1"), 974 "class1.algorithm1", 975 mapOf(), 976 true /* mustChangeSecurityVersion */); 977 performHashMapOperationAndCheckResults( 978 REMOVE, 979 mapOf("class1.algorithm1", "impl1"), 980 "class2.algorithm1", 981 mapOf("class1.algorithm1", "impl1"), 982 true /* mustChangeSecurityVersion */); 983 performHashMapOperationAndCheckResults( 984 COMPUTE, 985 mapOf("class1.algorithm1", "impl1"), 986 // It's really difficult to find an example of this that sounds realistic 987 // for a Provider... 988 new Pair("class1.algorithm1", CONCAT), 989 mapOf("class1.algorithm1", "class1.algorithm1impl1"), 990 true); 991 performHashMapOperationAndCheckResults( 992 PUT_IF_ABSENT, 993 mapOf("class1.algorithm1", "impl1"), 994 new Pair("class1.algorithm1", "impl2"), 995 // Don't put because key is absent. 996 mapOf("class1.algorithm1", "impl1"), 997 true); 998 performHashMapOperationAndCheckResults( 999 PUT_IF_ABSENT, 1000 mapOf("class1.algorithm1", "impl1"), 1001 new Pair("class2.algorithm2", "impl2"), 1002 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1003 true); 1004 performHashMapOperationAndCheckResults( 1005 PUT_IF_ABSENT, 1006 mapOf("class1.algorithm1", "impl1"), 1007 new Pair("class2.algorithm2", "impl2"), 1008 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1009 true); 1010 performHashMapOperationAndCheckResults( 1011 COMPUTE_IF_PRESENT, 1012 mapOf("class1.algorithm1", "impl1"), 1013 new Pair("class1.algorithm1", CONCAT), 1014 mapOf("class1.algorithm1", "class1.algorithm1impl1"), 1015 true); 1016 performHashMapOperationAndCheckResults( 1017 COMPUTE_IF_PRESENT, 1018 mapOf("class1.algorithm1", "impl1"), 1019 new Pair("class2.algorithm2", CONCAT), 1020 // Don't compute because is not present. 1021 mapOf("class1.algorithm1", "impl1"), 1022 true); 1023 performHashMapOperationAndCheckResults( 1024 COMPUTE_IF_ABSENT, 1025 mapOf("class1.algorithm1", "impl1"), 1026 new Pair("class2.algorithm2", TO_UPPER_CASE), 1027 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "CLASS2.ALGORITHM2"), 1028 true); 1029 performHashMapOperationAndCheckResults( 1030 COMPUTE_IF_ABSENT, 1031 mapOf("class1.algorithm1", "impl1"), 1032 new Pair("class1.algorithm1", TO_UPPER_CASE), 1033 // Don't compute because if not absent. 1034 mapOf("class1.algorithm1", "impl1"), 1035 true); 1036 performHashMapOperationAndCheckResults( 1037 REPLACE_USING_KEY, 1038 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1039 new Pair("class1.algorithm1", "impl3"), 1040 mapOf("class1.algorithm1", "impl3", "class2.algorithm2", "impl2"), 1041 true); 1042 performHashMapOperationAndCheckResults( 1043 REPLACE_USING_KEY, 1044 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1045 new Pair("class1.algorithm3", "impl3"), 1046 // Do not replace as the key is not present. 1047 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1048 true); 1049 performHashMapOperationAndCheckResults( 1050 REPLACE_USING_KEY_AND_VALUE, 1051 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1052 new Pair(new Pair("class1.algorithm1", "impl1"), "impl3"), 1053 mapOf("class1.algorithm1", "impl3", "class2.algorithm2", "impl2"), 1054 true); 1055 performHashMapOperationAndCheckResults( 1056 REPLACE_USING_KEY_AND_VALUE, 1057 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1058 new Pair(new Pair("class1.algorithm1", "impl4"), "impl3"), 1059 // Do not replace as the key/value pair is not present. 1060 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1061 true); 1062 performHashMapOperationAndCheckResults( 1063 REPLACE_ALL, 1064 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1065 // Applying simply CONCAT will affect internal mappings of the provider (version, 1066 // info, name, etc) 1067 CONCAT_IF_STARTING_WITH_CLASS, 1068 mapOf("class1.algorithm1", "class1.algorithm1impl1", 1069 "class2.algorithm2", "class2.algorithm2impl2"), 1070 true); 1071 performHashMapOperationAndCheckResults( 1072 MERGE, 1073 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1074 new Pair(new Pair("class1.algorithm1", "impl3"), CONCAT), 1075 // The key is present, so the function is used. 1076 mapOf("class1.algorithm1", "impl1impl3", 1077 "class2.algorithm2", "impl2"), 1078 true); 1079 performHashMapOperationAndCheckResults( 1080 MERGE, 1081 mapOf("class1.algorithm1", "impl1", "class2.algorithm2", "impl2"), 1082 new Pair(new Pair("class3.algorithm3", "impl3"), CONCAT), 1083 // The key is not present, so the value is used. 1084 mapOf("class1.algorithm1", "impl1", 1085 "class2.algorithm2", "impl2", 1086 "class3.algorithm3", "impl3"), 1087 true); 1088 } 1089 test_getOrDefault()1090 public void test_getOrDefault() { 1091 Provider p = new MockProvider("MockProvider"); 1092 p.put("class1.algorithm1", "impl1"); 1093 assertEquals("impl1", p.getOrDefault("class1.algorithm1", "default")); 1094 assertEquals("default", p.getOrDefault("thisIsNotInTheProvider", "default")); 1095 } 1096 test_elements()1097 public void test_elements() { 1098 Provider p = new MockProvider("MockProvider"); 1099 p.put("class1.algorithm1", "impl1"); 1100 Enumeration<Object> elements = p.elements(); 1101 boolean isImpl1Found = false; 1102 while (elements.hasMoreElements()) { 1103 if ("impl1".equals(elements.nextElement())) { 1104 isImpl1Found = true; 1105 break; 1106 } 1107 } 1108 1109 assertTrue("impl1 is not found.", isImpl1Found); 1110 } 1111 1112 private static class Pair<A, B> { 1113 private final A first; 1114 private final B second; Pair(A first, B second)1115 Pair(A first, B second) { 1116 this.first = first; 1117 this.second = second; 1118 } 1119 } 1120 1121 /* Holder class for the provider parameter and the parameter for the operation. */ 1122 private static class ProviderAndOperationParameter<T> { 1123 private final Provider provider; 1124 private final T operationParameters; ProviderAndOperationParameter(Provider p, T o)1125 ProviderAndOperationParameter(Provider p, T o) { 1126 provider = p; 1127 operationParameters = o; 1128 } 1129 } 1130 1131 private static final Consumer<ProviderAndOperationParameter<Pair<String, String>>> PUT = 1132 provAndParam -> 1133 provAndParam.provider.put( 1134 provAndParam.operationParameters.first, 1135 provAndParam.operationParameters.second); 1136 1137 private static final Consumer<ProviderAndOperationParameter<Map<String, String>>> PUT_ALL = 1138 provAndParam -> provAndParam.provider.putAll(provAndParam.operationParameters); 1139 1140 private static final Consumer<ProviderAndOperationParameter<String>> REMOVE = 1141 provAndParam -> provAndParam.provider.remove(provAndParam.operationParameters); 1142 1143 private static final Consumer<ProviderAndOperationParameter< 1144 Pair<String, BiFunction<Object, Object, Object>>>> COMPUTE = 1145 provAndParam -> provAndParam.provider.compute( 1146 provAndParam.operationParameters.first, 1147 provAndParam.operationParameters.second); 1148 1149 private static final BiFunction<Object, Object, Object> CONCAT = 1150 (a, b) -> Objects.toString(a) + Objects.toString(b); 1151 1152 private static final Consumer<ProviderAndOperationParameter<Pair<String, String>>> 1153 PUT_IF_ABSENT = provAndParam -> 1154 provAndParam.provider.putIfAbsent( 1155 provAndParam.operationParameters.first, 1156 provAndParam.operationParameters.second); 1157 1158 private static final Consumer<ProviderAndOperationParameter< 1159 Pair<String, BiFunction<Object, Object, Object>>>> COMPUTE_IF_PRESENT = 1160 provAndParam -> provAndParam.provider.computeIfPresent( 1161 provAndParam.operationParameters.first, 1162 provAndParam.operationParameters.second); 1163 1164 private static final Consumer<ProviderAndOperationParameter< 1165 Pair<String, Function<Object, Object>>>> COMPUTE_IF_ABSENT = 1166 provAndParam -> provAndParam.provider.computeIfAbsent( 1167 provAndParam.operationParameters.first, 1168 provAndParam.operationParameters.second); 1169 1170 private static final Function<Object, Object> TO_UPPER_CASE = 1171 s -> Objects.toString(s).toUpperCase(); 1172 1173 private static final Consumer<ProviderAndOperationParameter<Pair<String, String>>> 1174 REPLACE_USING_KEY = provAndParam -> 1175 provAndParam.provider.replace( 1176 provAndParam.operationParameters.first, 1177 provAndParam.operationParameters.second); 1178 1179 private static final Consumer<ProviderAndOperationParameter<Pair<Pair<String, String>, String>>> 1180 REPLACE_USING_KEY_AND_VALUE = provAndParam -> 1181 provAndParam.provider.replace( 1182 provAndParam.operationParameters.first.first, 1183 provAndParam.operationParameters.first.second, 1184 provAndParam.operationParameters.second); 1185 1186 private static final Consumer<ProviderAndOperationParameter< 1187 BiFunction<Object, Object, Object>>> REPLACE_ALL = 1188 provAndParam -> provAndParam.provider.replaceAll( 1189 provAndParam.operationParameters); 1190 1191 private static final BiFunction<Object, Object, Object> CONCAT_IF_STARTING_WITH_CLASS = 1192 (a, b) -> (Objects.toString(a).startsWith("class")) 1193 ? Objects.toString(a) + Objects.toString(b) 1194 : b; 1195 1196 private static final Consumer<ProviderAndOperationParameter< 1197 Pair<Pair<String, String>, BiFunction<Object, Object, Object>>>> 1198 MERGE = provAndParam -> provAndParam.provider.merge( 1199 provAndParam.operationParameters.first.first, 1200 provAndParam.operationParameters.first.second, 1201 provAndParam.operationParameters.second); 1202 1203 1204 mapOf(String... elements)1205 private static Map<String, String> mapOf(String... elements) { 1206 Map<String, String> ret = new HashMap<String, String>(); 1207 for (int i = 0; i < elements.length; i += 2) { 1208 ret.put(elements[i], elements[i + 1]); 1209 } 1210 return ret; 1211 } 1212 1213 performHashMapOperationAndCheckResults( Consumer<ProviderAndOperationParameter<A>> operation, Map<String, String> initialState, A operationParameters, Map<String, String> expectedResult, boolean mustChangeVersion)1214 private <A> void performHashMapOperationAndCheckResults( 1215 Consumer<ProviderAndOperationParameter<A>> operation, 1216 Map<String, String> initialState, 1217 A operationParameters, 1218 Map<String, String> expectedResult, 1219 boolean mustChangeVersion) { 1220 Provider p = new MockProvider("MockProvider"); 1221 // Need to set as registered so that the security version will change on update. 1222 p.setRegistered(); 1223 int securityVersionBeforeOperation = Security.getVersion(); 1224 p.putAll(initialState); 1225 1226 // Perform the operation. 1227 operation.accept(new ProviderAndOperationParameter<A>(p, operationParameters)); 1228 1229 // Check that elements are correctly mapped to services. 1230 HashMap<String, String> services = new HashMap<String, String>(); 1231 for (Provider.Service s : p.getServices()) { 1232 services.put(s.getType() + "." + s.getAlgorithm(), s.getClassName()); 1233 } 1234 assertEquals(expectedResult.entrySet(), services.entrySet()); 1235 1236 // Check that elements are in the provider hash map. 1237 // The hash map in the provider has info other than services, include those in the 1238 // expected results. 1239 HashMap<String, String> hashExpectedResult = new HashMap<String, String>(); 1240 hashExpectedResult.putAll(expectedResult); 1241 hashExpectedResult.put("Provider.id info", p.getInfo()); 1242 hashExpectedResult.put("Provider.id className", p.getClass().getName()); 1243 hashExpectedResult.put("Provider.id version", String.valueOf(p.getVersion())); 1244 hashExpectedResult.put("Provider.id name", p.getName()); 1245 1246 assertEquals(hashExpectedResult.entrySet(), p.entrySet()); 1247 1248 if (mustChangeVersion) { 1249 assertTrue(securityVersionBeforeOperation != Security.getVersion()); 1250 } 1251 } 1252 1253 @SuppressWarnings("serial") 1254 private static class MockProvider extends Provider { MockProvider(String name)1255 public MockProvider(String name) { 1256 super(name, 1.0, "Mock provider used for testing"); 1257 setup(); 1258 } 1259 setup()1260 public void setup() { 1261 } 1262 putServiceForTest(Provider.Service service)1263 public void putServiceForTest(Provider.Service service) { 1264 putService(service); 1265 } 1266 } 1267 1268 @SuppressWarnings("serial") 1269 public static abstract class AbstractSecureRandom extends SecureRandomSpi { engineSetSeed(byte[] seed)1270 protected void engineSetSeed(byte[] seed) { 1271 throw new UnsupportedOperationException(); 1272 } engineNextBytes(byte[] bytes)1273 protected void engineNextBytes(byte[] bytes) { 1274 throw new UnsupportedOperationException(); 1275 } engineGenerateSeed(int numBytes)1276 protected byte[] engineGenerateSeed(int numBytes) { 1277 throw new UnsupportedOperationException(); 1278 } 1279 } 1280 1281 @SuppressWarnings("serial") 1282 public static class SecureRandom1 extends AbstractSecureRandom {} 1283 1284 @SuppressWarnings("serial") 1285 public static class SecureRandom2 extends AbstractSecureRandom {} 1286 1287 @SuppressWarnings("serial") 1288 public static class SecureRandom3 extends AbstractSecureRandom {} 1289 1290 } 1291