Home | History | Annotate | Download | only in security
      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.interfaces.RSAPrivateKey;
     34 import java.util.ArrayList;
     35 import java.util.Arrays;
     36 import java.util.Collection;
     37 import java.util.Collections;
     38 import java.util.HashMap;
     39 import java.util.HashSet;
     40 import java.util.List;
     41 import java.util.Locale;
     42 import java.util.Map;
     43 import java.util.Map.Entry;
     44 import java.util.Set;
     45 import java.util.TreeMap;
     46 import java.util.regex.Matcher;
     47 import java.util.regex.Pattern;
     48 import javax.crypto.Cipher;
     49 import javax.crypto.EncryptedPrivateKeyInfo;
     50 import javax.crypto.NoSuchPaddingException;
     51 import junit.framework.TestCase;
     52 import libcore.javax.crypto.MockKey;
     53 
     54 public class ProviderTest extends TestCase {
     55     private static final boolean LOG_DEBUG = false;
     56 
     57     /**
     58      * Makes sure all all expected implementations (but not aliases)
     59      * and that there are no extras, according to what we expect from
     60      * StandardNames
     61      */
     62     public void test_Provider_getServices() throws Exception {
     63         // build set of expected algorithms
     64         Map<String,Set<String>> remainingExpected
     65                 = new HashMap<String,Set<String>>(StandardNames.PROVIDER_ALGORITHMS);
     66         for (Entry<String,Set<String>> entry : remainingExpected.entrySet()) {
     67             entry.setValue(new HashSet<String>(entry.getValue()));
     68         }
     69 
     70         List<String> extra = new ArrayList<String>();
     71         List<String> missing = new ArrayList<String>();
     72 
     73         Provider[] providers = Security.getProviders();
     74         for (Provider provider : providers) {
     75             String providerName = provider.getName();
     76             // ignore BouncyCastle provider if it is installed on the RI
     77             if (StandardNames.IS_RI && providerName.equals("BC")) {
     78                 continue;
     79             }
     80             Set<Provider.Service> services = provider.getServices();
     81             assertNotNull(services);
     82             assertFalse(services.isEmpty());
     83 
     84             for (Provider.Service service : services) {
     85                 String type = service.getType();
     86                 String algorithm = service.getAlgorithm().toUpperCase();
     87                 String className = service.getClassName();
     88                 if (LOG_DEBUG) {
     89                     System.out.println(providerName
     90                                        + " " + type
     91                                        + " " + algorithm
     92                                        + " " + className);
     93                 }
     94 
     95                 // remove from remaining, assert unknown if missing
     96                 Set<String> remainingAlgorithms = remainingExpected.get(type);
     97                 if (remainingAlgorithms == null || !remainingAlgorithms.remove(algorithm)) {
     98                     // seems to be missing, but sometimes the same
     99                     // algorithm is available from multiple providers
    100                     // (e.g. KeyFactory RSA is available from
    101                     // SunRsaSign and SunJSSE), so double check in
    102                     // original source before giving error
    103                     if (!(StandardNames.PROVIDER_ALGORITHMS.containsKey(type)
    104                             && StandardNames.PROVIDER_ALGORITHMS.get(type).contains(algorithm))) {
    105                         extra.add("Unknown " + type + " " + algorithm + " " + providerName + "\n");
    106                     }
    107                 } else if ("Cipher".equals(type) && !algorithm.contains("/")) {
    108                     /*
    109                      * Cipher selection follows special rules where you can
    110                      * specify the mode and padding during the getInstance call.
    111                      * Try to see if the service supports this.
    112                      */
    113                     Set<String> toRemove = new HashSet<String>();
    114                     for (String remainingAlgo : remainingAlgorithms) {
    115                         String[] parts = remainingAlgo.split("/");
    116                         if (parts.length == 3 && algorithm.equals(parts[0])) {
    117                             try {
    118                                 Cipher.getInstance(remainingAlgo, provider);
    119                                 toRemove.add(remainingAlgo);
    120                             } catch (NoSuchAlgorithmException ignored) {
    121                             } catch (NoSuchPaddingException ignored) {
    122                             }
    123                         }
    124                     }
    125                     remainingAlgorithms.removeAll(toRemove);
    126                 }
    127                 if (remainingAlgorithms != null && remainingAlgorithms.isEmpty()) {
    128                     remainingExpected.remove(type);
    129                 }
    130 
    131                 // make sure class exists and can be initialized
    132                 try {
    133                     assertNotNull(Class.forName(className,
    134                                                 true,
    135                                                 provider.getClass().getClassLoader()));
    136                 } catch (ClassNotFoundException e) {
    137                     // Sun forgot their own class
    138                     if (!className.equals("sun.security.pkcs11.P11MAC")) {
    139                         missing.add(className);
    140                     }
    141                 }
    142             }
    143         }
    144 
    145         // assert that we don't have any extra in the implementation
    146         Collections.sort(extra); // sort so that its grouped by type
    147         assertEquals("Extra algorithms", Collections.EMPTY_LIST, extra);
    148 
    149         // assert that we don't have any missing in the implementation
    150         assertEquals("Missing algorithms", Collections.EMPTY_MAP, remainingExpected);
    151 
    152         // assert that we don't have any missing classes
    153         Collections.sort(missing); // sort it for readability
    154         assertEquals("Missing classes", Collections.EMPTY_LIST, missing);
    155     }
    156 
    157     private static final Pattern alias = Pattern.compile("Alg\\.Alias\\.([^.]*)\\.(.*)");
    158 
    159     /**
    160      * Makes sure all provider properties either point to a class
    161      * implementation that exists or are aliases to known algorithms.
    162      */
    163     public void test_Provider_Properties() throws Exception {
    164         /*
    165          * A useful reference on Provider properties
    166          * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
    167          * How to Implement a Provider in the Java &trade; Cryptography Architecture
    168          * </a>
    169          */
    170 
    171         Provider[] providers = Security.getProviders();
    172         for (Provider provider : providers) {
    173             // check Provider.id proprieties
    174             assertEquals(provider.getName(),
    175                          provider.get("Provider.id name"));
    176             assertEquals(String.valueOf(provider.getVersion()),
    177                          provider.get("Provider.id version"));
    178             assertEquals(provider.getInfo(),
    179                          provider.get("Provider.id info"));
    180             assertEquals(provider.getClass().getName(),
    181                          provider.get("Provider.id className"));
    182 
    183             // build map of all known aliases and implementations
    184             Map<String,String> aliases = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    185             Map<String,String> implementations = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    186             for (Entry<Object,Object> entry : provider.entrySet()) {
    187                 Object k = entry.getKey();
    188                 Object v = entry.getValue();
    189                 assertEquals(String.class, k.getClass());
    190                 assertEquals(String.class, v.getClass());
    191                 String key = (String)k;
    192                 String value = (String)v;
    193 
    194                 // skip Provider.id keys, we check well known ones values above
    195                 if (key.startsWith("Provider.id ")) {
    196                     continue;
    197                 }
    198 
    199                 // skip property settings such as: "Signature.SHA1withDSA ImplementedIn" "Software"
    200                 if (key.indexOf(' ') != -1) {
    201                     continue;
    202                 }
    203 
    204                 Matcher m = alias.matcher(key);
    205                 if (m.find()) {
    206                     String type = m.group(1);
    207                     aliases.put(key, type + "." + value);
    208                 } else {
    209                     implementations.put(key, value);
    210                 }
    211             }
    212 
    213             // verify implementation classes are available
    214             for (Entry<String,String> entry : implementations.entrySet()) {
    215                 String typeAndAlgorithm = entry.getKey();
    216                 String className = entry.getValue();
    217                 try {
    218                     assertNotNull(Class.forName(className,
    219                                                 true,
    220                                                 provider.getClass().getClassLoader()));
    221                 } catch (ClassNotFoundException e) {
    222                     // Sun forgot their own class
    223                     if (!className.equals("sun.security.pkcs11.P11MAC")) {
    224                         fail("Could not find class " + className + " for " + typeAndAlgorithm
    225                         + " [provider=" + provider.getName() + "]");
    226                     }
    227                 }
    228             }
    229 
    230             // make sure all aliases point to some known implementation
    231             for (Entry<String,String> entry : aliases.entrySet()) {
    232                 String alias  = entry.getKey();
    233                 String actual = entry.getValue();
    234                 assertTrue("Could not find implementation " + actual + " for alias " + alias +
    235                         " [provider=" + provider.getName() + "]",
    236                         implementations.containsKey(actual));
    237             }
    238         }
    239     }
    240 
    241     private static final String[] TYPES_SERVICES_CHECKED = new String[] {
    242             "KeyFactory", "CertPathBuilder", "Cipher", "SecureRandom",
    243             "AlgorithmParameterGenerator", "Signature", "KeyPairGenerator", "CertificateFactory",
    244             "MessageDigest", "KeyAgreement", "CertStore", "SSLContext", "AlgorithmParameters",
    245             "TrustManagerFactory", "KeyGenerator", "Mac", "CertPathValidator", "SecretKeyFactory",
    246             "KeyManagerFactory", "KeyStore",
    247     };
    248 
    249     private static final HashSet<String> TYPES_SUPPORTS_PARAMETER = new HashSet<String>(
    250             Arrays.asList(new String[] {
    251                     "Mac", "KeyAgreement", "Cipher", "Signature",
    252             }));
    253 
    254     private static final HashSet<String> TYPES_NOT_SUPPORTS_PARAMETER = new HashSet<String>(
    255             Arrays.asList(TYPES_SERVICES_CHECKED));
    256     static {
    257         TYPES_NOT_SUPPORTS_PARAMETER.removeAll(TYPES_SUPPORTS_PARAMETER);
    258     }
    259 
    260     public void test_Provider_getServices_supportsParameter() throws Exception {
    261         HashSet<String> remainingTypes = new HashSet<String>(Arrays.asList(TYPES_SERVICES_CHECKED));
    262 
    263         HashSet<String> supportsParameterTypes = new HashSet<String>();
    264         HashSet<String> noSupportsParameterTypes = new HashSet<String>();
    265 
    266         Provider[] providers = Security.getProviders();
    267         for (Provider provider : providers) {
    268             Set<Provider.Service> services = provider.getServices();
    269             assertNotNull(services);
    270             assertFalse(services.isEmpty());
    271 
    272             for (Provider.Service service : services) {
    273                 final String type = service.getType();
    274                 remainingTypes.remove(type);
    275                 try {
    276                     service.supportsParameter(new MockKey());
    277                     supportsParameterTypes.add(type);
    278                 } catch (InvalidParameterException e) {
    279                     noSupportsParameterTypes.add(type);
    280                     try {
    281                         service.supportsParameter(new Object());
    282                         fail("Should throw on non-Key parameter");
    283                     } catch (InvalidParameterException expected) {
    284                     }
    285                 }
    286             }
    287         }
    288 
    289         supportsParameterTypes.retainAll(TYPES_SUPPORTS_PARAMETER);
    290         assertEquals("Types that should support parameters", TYPES_SUPPORTS_PARAMETER,
    291                 supportsParameterTypes);
    292 
    293         noSupportsParameterTypes.retainAll(TYPES_NOT_SUPPORTS_PARAMETER);
    294         assertEquals("Types that should not support parameters", TYPES_NOT_SUPPORTS_PARAMETER,
    295                 noSupportsParameterTypes);
    296 
    297         assertEquals("Types that should be checked", Collections.EMPTY_SET, remainingTypes);
    298     }
    299 
    300     public static class MockSpi {
    301         public Object parameter;
    302 
    303         public MockSpi(MockKey parameter) {
    304             this.parameter = parameter;
    305         }
    306     };
    307 
    308     @SuppressWarnings("serial")
    309     public void testProviderService_supportsParameter_UnknownService_Success() throws Exception {
    310         Provider provider = new MockProvider("MockProvider") {
    311             public void setup() {
    312                 put("Fake.FOO", MockSpi.class.getName());
    313             }
    314         };
    315 
    316         Security.addProvider(provider);
    317         try {
    318             Provider.Service service = provider.getService("Fake", "FOO");
    319             assertTrue(service.supportsParameter(new Object()));
    320         } finally {
    321             Security.removeProvider(provider.getName());
    322         }
    323     }
    324 
    325     @SuppressWarnings("serial")
    326     public void testProviderService_supportsParameter_KnownService_NoClassInitialization_Success()
    327             throws Exception {
    328         Provider provider = new MockProvider("MockProvider") {
    329             public void setup() {
    330                 put("Signature.FOO", MockSpi.class.getName());
    331                 put("Signature.FOO SupportedKeyClasses", getClass().getName()
    332                         + ".UninitializedMockKey");
    333             }
    334         };
    335 
    336         Security.addProvider(provider);
    337         try {
    338             Provider.Service service = provider.getService("Signature", "FOO");
    339             assertFalse(service.supportsParameter(new MockKey()));
    340         } finally {
    341             Security.removeProvider(provider.getName());
    342         }
    343     }
    344 
    345     @SuppressWarnings("serial")
    346     public static class UninitializedMockKey extends MockKey {
    347         static {
    348             fail("This should not be initialized");
    349         }
    350     }
    351 
    352     @SuppressWarnings("serial")
    353     public void testProviderService_supportsParameter_TypeDoesNotSupportParameter_Failure()
    354             throws Exception {
    355         Provider provider = new MockProvider("MockProvider") {
    356             public void setup() {
    357                 put("KeyFactory.FOO", MockSpi.class.getName());
    358             }
    359         };
    360 
    361         Security.addProvider(provider);
    362         try {
    363             Provider.Service service = provider.getService("KeyFactory", "FOO");
    364             try {
    365                 service.supportsParameter(new MockKey());
    366                 fail("Should always throw exception");
    367             } catch (InvalidParameterException expected) {
    368             }
    369         } finally {
    370             Security.removeProvider(provider.getName());
    371         }
    372     }
    373 
    374     @SuppressWarnings("serial")
    375     public void testProviderService_supportsParameter_SupportedKeyClasses_NonKeyClass_Success()
    376             throws Exception {
    377         Provider provider = new MockProvider("MockProvider") {
    378             public void setup() {
    379                 put("Signature.FOO", MockSpi.class.getName());
    380                 put("Signature.FOO SupportedKeyClasses", MockSpi.class.getName());
    381             }
    382         };
    383 
    384         Security.addProvider(provider);
    385         try {
    386             Provider.Service service = provider.getService("Signature", "FOO");
    387             assertFalse(service.supportsParameter(new MockKey()));
    388         } finally {
    389             Security.removeProvider(provider.getName());
    390         }
    391     }
    392 
    393     @SuppressWarnings("serial")
    394     public void testProviderService_supportsParameter_KnownService_NonKey_Failure()
    395             throws Exception {
    396         Provider provider = new MockProvider("MockProvider") {
    397             public void setup() {
    398                 put("Signature.FOO", MockSpi.class.getName());
    399             }
    400         };
    401 
    402         Security.addProvider(provider);
    403         try {
    404             Provider.Service service = provider.getService("Signature", "FOO");
    405             try {
    406                 service.supportsParameter(new Object());
    407                 fail("Should throw when non-Key passed in");
    408             } catch (InvalidParameterException expected) {
    409             }
    410         } finally {
    411             Security.removeProvider(provider.getName());
    412         }
    413     }
    414 
    415     @SuppressWarnings("serial")
    416     public void testProviderService_supportsParameter_KnownService_SupportedKeyClasses_NonKey_Failure()
    417             throws Exception {
    418         Provider provider = new MockProvider("MockProvider") {
    419             public void setup() {
    420                 put("Signature.FOO", MockSpi.class.getName());
    421                 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName());
    422             }
    423         };
    424 
    425         Security.addProvider(provider);
    426         try {
    427             Provider.Service service = provider.getService("Signature", "FOO");
    428             try {
    429                 service.supportsParameter(new Object());
    430                 fail("Should throw on non-Key instance passed in");
    431             } catch (InvalidParameterException expected) {
    432             }
    433         } finally {
    434             Security.removeProvider(provider.getName());
    435         }
    436     }
    437 
    438     @SuppressWarnings("serial")
    439     public void testProviderService_supportsParameter_KnownService_Null_Failure() throws Exception {
    440         Provider provider = new MockProvider("MockProvider") {
    441             public void setup() {
    442                 put("Signature.FOO", MockSpi.class.getName());
    443                 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName());
    444             }
    445         };
    446 
    447         Security.addProvider(provider);
    448         try {
    449             Provider.Service service = provider.getService("Signature", "FOO");
    450             assertFalse(service.supportsParameter(null));
    451         } finally {
    452             Security.removeProvider(provider.getName());
    453         }
    454     }
    455 
    456     @SuppressWarnings("serial")
    457     public void testProviderService_supportsParameter_SupportedKeyClasses_Success()
    458             throws Exception {
    459         Provider provider = new MockProvider("MockProvider") {
    460             public void setup() {
    461                 put("Signature.FOO", MockSpi.class.getName());
    462                 put("Signature.FOO SupportedKeyClasses", MockKey.class.getName());
    463             }
    464         };
    465 
    466         Security.addProvider(provider);
    467         try {
    468             Provider.Service service = provider.getService("Signature", "FOO");
    469             assertTrue(service.supportsParameter(new MockKey()));
    470         } finally {
    471             Security.removeProvider(provider.getName());
    472         }
    473     }
    474 
    475     @SuppressWarnings("serial")
    476     public void testProviderService_supportsParameter_SupportedKeyClasses_Failure()
    477             throws Exception {
    478         Provider provider = new MockProvider("MockProvider") {
    479             public void setup() {
    480                 put("Signature.FOO", MockSpi.class.getName());
    481                 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName());
    482             }
    483         };
    484 
    485         Security.addProvider(provider);
    486         try {
    487             Provider.Service service = provider.getService("Signature", "FOO");
    488             assertFalse(service.supportsParameter(new MockKey()));
    489         } finally {
    490             Security.removeProvider(provider.getName());
    491         }
    492     }
    493 
    494     @SuppressWarnings("serial")
    495     public void testProviderService_supportsParameter_SupportedKeyFormats_Success()
    496             throws Exception {
    497         Provider provider = new MockProvider("MockProvider") {
    498             public void setup() {
    499                 put("Signature.FOO", MockSpi.class.getName());
    500                 put("Signature.FOO SupportedKeyFormats", new MockKey().getFormat());
    501             }
    502         };
    503 
    504         Security.addProvider(provider);
    505         try {
    506             Provider.Service service = provider.getService("Signature", "FOO");
    507             assertTrue(service.supportsParameter(new MockKey()));
    508         } finally {
    509             Security.removeProvider(provider.getName());
    510         }
    511     }
    512 
    513     @SuppressWarnings("serial")
    514     public void testProviderService_supportsParameter_SupportedKeyFormats_Failure()
    515             throws Exception {
    516         Provider provider = new MockProvider("MockProvider") {
    517             public void setup() {
    518                 put("Signature.FOO", MockSpi.class.getName());
    519                 put("Signature.FOO SupportedKeyFormats", "Invalid");
    520             }
    521         };
    522 
    523         Security.addProvider(provider);
    524         try {
    525             Provider.Service service = provider.getService("Signature", "FOO");
    526             assertFalse(service.supportsParameter(new MockKey()));
    527         } finally {
    528             Security.removeProvider(provider.getName());
    529         }
    530     }
    531 
    532     @SuppressWarnings("serial")
    533     public void testProviderService_newInstance_DoesNotCallSupportsParameter_Success()
    534             throws Exception {
    535         MockProvider provider = new MockProvider("MockProvider");
    536 
    537         provider.putServiceForTest(new Provider.Service(provider, "CertStore", "FOO",
    538                 MyCertStoreSpi.class.getName(), null, null) {
    539             @Override
    540             public boolean supportsParameter(Object parameter) {
    541                 fail("This should not be called");
    542                 return false;
    543             }
    544         });
    545 
    546         Security.addProvider(provider);
    547         try {
    548             Provider.Service service = provider.getService("CertStore", "FOO");
    549             assertNotNull(service.newInstance(new MyCertStoreParameters()));
    550         } finally {
    551             Security.removeProvider(provider.getName());
    552         }
    553     }
    554 
    555     @SuppressWarnings("serial")
    556     public void testProviderService_AliasDoesNotEraseCanonical_Success()
    557             throws Exception {
    558         // Make sure we start with a "known good" alias for this OID.
    559         {
    560             EncryptedPrivateKeyInfo epki1 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5",
    561                     new byte[1]);
    562             assertEquals("SHA1WITHRSA", epki1.getAlgName().toUpperCase(Locale.US));
    563         }
    564 
    565         Provider provider = new MockProvider("MockProvider") {
    566             public void setup() {
    567                 put("Signature.FOO", MockSpi.class.getName());
    568                 put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "FOO");
    569             }
    570         };
    571 
    572         Security.addProvider(provider);
    573         try {
    574             // This triggers a re-indexing of the algorithm id data:
    575             try {
    576                 new EncryptedPrivateKeyInfo("nonexistent", new byte[1]);
    577                 fail("Should not find 'nonexistent' algorithm");
    578             } catch (NoSuchAlgorithmException expected) {
    579             }
    580 
    581             EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5", new byte[1]);
    582             assertEquals("SHA1WITHRSA", epki2.getAlgName().toUpperCase(Locale.US));
    583         } finally {
    584             Security.removeProvider(provider.getName());
    585         }
    586     }
    587 
    588     @SuppressWarnings("serial")
    589     public void testProviderService_CanFindNewOID_Success()
    590             throws Exception {
    591         Provider provider = new MockProvider("MockProvider") {
    592             public void setup() {
    593                 put("Signature.NEWALG", MockSpi.class.getName());
    594                 put("Alg.Alias.Signature.OID.1.2.9999.9999.9999", "NEWALG");
    595             }
    596         };
    597 
    598         Security.addProvider(provider);
    599         try {
    600             EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.9999.9999.9999", new byte[1]);
    601             assertEquals("NEWALG", epki2.getAlgName().toUpperCase(Locale.US));
    602         } finally {
    603             Security.removeProvider(provider.getName());
    604         }
    605     }
    606 
    607     public void testProvider_removeProvider_Success() throws Exception {
    608         MockProvider provider = new MockProvider("MockProvider");
    609         assertNull(Security.getProvider(provider.getName()));
    610         Security.addProvider(provider);
    611         assertNotNull(Security.getProvider(provider.getName()));
    612         Security.removeProvider(provider.getName());
    613         assertNull(Security.getProvider(provider.getName()));
    614     }
    615 
    616     public static class MyCertStoreSpi extends CertStoreSpi {
    617         public MyCertStoreSpi(CertStoreParameters params) throws InvalidAlgorithmParameterException {
    618             super(params);
    619         }
    620 
    621         @Override
    622         public Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
    623                 throws CertStoreException {
    624             throw new UnsupportedOperationException();
    625         }
    626 
    627         @Override
    628         public Collection<? extends CRL> engineGetCRLs(CRLSelector selector)
    629                 throws CertStoreException {
    630             throw new UnsupportedOperationException();
    631         }
    632     }
    633 
    634     public static class MyCertStoreParameters implements CertStoreParameters {
    635         public Object clone() {
    636             return new MyCertStoreParameters();
    637         }
    638     }
    639 
    640     /**
    641      * http://code.google.com/p/android/issues/detail?id=21449
    642      */
    643     public void testSecureRandomImplementationOrder() {
    644         @SuppressWarnings("serial")
    645         Provider srp = new MockProvider("SRProvider") {
    646             public void setup() {
    647                 put("SecureRandom.SecureRandom1", SecureRandom1.class.getName());
    648                 put("SecureRandom.SecureRandom2", SecureRandom2.class.getName());
    649                 put("SecureRandom.SecureRandom3", SecureRandom3.class.getName());
    650             }
    651         };
    652         try {
    653             int position = Security.insertProviderAt(srp, 1); // first is one, not zero
    654             assertEquals(1, position);
    655             SecureRandom sr = new SecureRandom();
    656             if (!sr.getAlgorithm().equals("SecureRandom1")) {
    657                 throw new IllegalStateException("Expected SecureRandom1 was " + sr.getAlgorithm());
    658             }
    659         } finally {
    660             Security.removeProvider(srp.getName());
    661         }
    662     }
    663 
    664     @SuppressWarnings("serial")
    665     private static class MockProvider extends Provider {
    666         public MockProvider(String name) {
    667             super(name, 1.0, "Mock provider used for testing");
    668             setup();
    669         }
    670 
    671         public void setup() {
    672         }
    673 
    674         public void putServiceForTest(Provider.Service service) {
    675             putService(service);
    676         }
    677     }
    678 
    679     @SuppressWarnings("serial")
    680     public static abstract class AbstractSecureRandom extends SecureRandomSpi {
    681         protected void engineSetSeed(byte[] seed) {
    682             throw new UnsupportedOperationException();
    683         }
    684         protected void engineNextBytes(byte[] bytes) {
    685             throw new UnsupportedOperationException();
    686         }
    687         protected byte[] engineGenerateSeed(int numBytes) {
    688             throw new UnsupportedOperationException();
    689         }
    690     }
    691 
    692     @SuppressWarnings("serial")
    693     public static class SecureRandom1 extends AbstractSecureRandom {}
    694 
    695     @SuppressWarnings("serial")
    696     public static class SecureRandom2 extends AbstractSecureRandom {}
    697 
    698     @SuppressWarnings("serial")
    699     public static class SecureRandom3 extends AbstractSecureRandom {}
    700 
    701 }
    702