1 /*
2  * Copyright (C) 2017 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 test.java.security.Provider;
18 
19 import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
20 
21 import dalvik.system.VMRuntime;
22 
23 import java.lang.reflect.Method;
24 import java.security.AlgorithmParameters;
25 import java.security.GeneralSecurityException;
26 import java.security.KeyFactory;
27 import java.security.KeyPairGenerator;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.security.Provider;
31 import java.security.Security;
32 import java.security.Signature;
33 import java.security.cert.CertificateException;
34 import java.security.cert.CertificateFactory;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.List;
38 import java.util.HashSet;
39 import java.util.Locale;
40 import java.util.Set;
41 import javax.crypto.Cipher;
42 import javax.crypto.KeyAgreement;
43 import javax.crypto.KeyGenerator;
44 import javax.crypto.Mac;
45 import javax.crypto.SecretKeyFactory;
46 
47 import sun.security.jca.Providers;
48 
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertNotNull;
51 import static org.junit.Assert.fail;
52 import org.testng.annotations.Test;
53 
54 /**
55  * Tests that the deprecation of algorithms from the BC provider works as expected.  Requests
56  * from an application targeting an API level before the deprecation should receive them,
57  * but those targeting an API level after the deprecation should cause an exception.  Tests
58  * a representative sample of services and algorithms and various ways of naming them.
59  */
60 public class ProvidersTest {
61 
62     /**
63      * An object that can be called to call an appropriate getInstance method.  Since
64      * each type of object has its own class that the method should be called on,
65      * it's either this or reflection, and this seems more straightforward.
66      */
67     private interface Algorithm {
getInstance()68         Object getInstance() throws GeneralSecurityException;
69     }
70 
71     // getInstance calls that result in requests to BC
72     private static final List<Algorithm> BC_ALGORITHMS = new ArrayList<>();
73     // getInstance calls that result in requests to Conscrypt
74     private static final List<Algorithm> CONSCRYPT_ALGORITHMS = new ArrayList<>();
75     static {
76         // All the same algorithms as for BC, but with no provider, which should produce
77         // the Conscrypt implementation
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return Signature.getInstance("sha224withrsa"); } })78         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
79             @Override
80             public Object getInstance() throws GeneralSecurityException {
81                 return Signature.getInstance("sha224withrsa");
82             }
83         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return KeyFactory.getInstance("EC"); } })84         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
85             @Override
86             public Object getInstance() throws GeneralSecurityException {
87                 return KeyFactory.getInstance("EC");
88             }
89         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return Signature.getInstance("MD5withRSAEncryption"); } })90         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
91             @Override
92             public Object getInstance() throws GeneralSecurityException {
93                 return Signature.getInstance("MD5withRSAEncryption");
94             }
95         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return KeyGenerator.getInstance("HMAC-MD5"); } })96         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
97             @Override
98             public Object getInstance() throws GeneralSecurityException {
99                 return KeyGenerator.getInstance("HMAC-MD5");
100             }
101         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return Mac.getInstance("Hmac/sha256"); } })102         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
103             @Override
104             public Object getInstance() throws GeneralSecurityException {
105                 return Mac.getInstance("Hmac/sha256");
106             }
107         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return Signature.getInstance("SHA384/rsA"); } })108         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
109             @Override
110             public Object getInstance() throws GeneralSecurityException {
111                 return Signature.getInstance("SHA384/rsA");
112             }
113         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return MessageDigest.getInstance("2.16.840.1.101.3.4.2.1"); } })114         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
115             @Override
116             public Object getInstance() throws GeneralSecurityException {
117                 // OID for SHA-256
118                 return MessageDigest.getInstance("2.16.840.1.101.3.4.2.1");
119             }
120         });
CONSCRYPT_ALGORITHMS.add(new Algorithm() { @Override public Object getInstance() throws GeneralSecurityException { return AlgorithmParameters.getInstance("2.16.840.1.101.3.4.1.2"); } })121         CONSCRYPT_ALGORITHMS.add(new Algorithm() {
122             @Override
123             public Object getInstance() throws GeneralSecurityException {
124                 // OID for AES-128
125                 return AlgorithmParameters.getInstance("2.16.840.1.101.3.4.1.2");
126             }
127         });
128     }
129 
130     private static final Set<String> REMOVED_BC_ALGORITHMS = new HashSet<String>();
131     static {
132         REMOVED_BC_ALGORITHMS.addAll(Arrays.asList(
133                 "ALGORITHMPARAMETERS.1.2.840.113549.3.7",
134                 "ALGORITHMPARAMETERS.2.16.840.1.101.3.4.1.2",
135                 "ALGORITHMPARAMETERS.2.16.840.1.101.3.4.1.22",
136                 "ALGORITHMPARAMETERS.2.16.840.1.101.3.4.1.26",
137                 "ALGORITHMPARAMETERS.2.16.840.1.101.3.4.1.42",
138                 "ALGORITHMPARAMETERS.2.16.840.1.101.3.4.1.46",
139                 "ALGORITHMPARAMETERS.2.16.840.1.101.3.4.1.6",
140                 "ALGORITHMPARAMETERS.AES",
141                 "ALGORITHMPARAMETERS.DESEDE",
142                 "ALGORITHMPARAMETERS.EC",
143                 "ALGORITHMPARAMETERS.GCM",
144                 "ALGORITHMPARAMETERS.OAEP",
145                 "ALGORITHMPARAMETERS.TDEA",
146                 "CERTIFICATEFACTORY.X.509",
147                 "CERTIFICATEFACTORY.X509",
148                 // List of Ciphers produced by ProviderOverlap:
149                 "CIPHER.1.2.840.113549.3.4",
150                 "CIPHER.2.16.840.1.101.3.4.1.26",
151                 "CIPHER.2.16.840.1.101.3.4.1.46",
152                 "CIPHER.2.16.840.1.101.3.4.1.6",
153                 "CIPHER.AES/GCM/NOPADDING",
154                 "CIPHER.ARC4",
155                 "CIPHER.ARCFOUR",
156                 "CIPHER.OID.1.2.840.113549.3.4",
157                 "CIPHER.RC4",
158                 // End of Ciphers produced by ProviderOverlap
159                 // Additional ciphers transformations that will resolve to the same things as
160                 // the automatically-produced overlap due to the Cipher transformation rules.
161                 // These have been added manually.
162                 "CIPHER.ARC4/ECB/NOPADDING",
163                 "CIPHER.ARC4/NONE/NOPADDING",
164                 "CIPHER.ARCFOUR/ECB/NOPADDING",
165                 "CIPHER.ARCFOUR/NONE/NOPADDING",
166                 "CIPHER.RC4/ECB/NOPADDING",
167                 "CIPHER.RC4/NONE/NOPADDING",
168                 // End of additional Ciphers
169                 "KEYAGREEMENT.ECDH",
170                 "KEYFACTORY.1.2.840.10045.2.1",
171                 "KEYFACTORY.1.2.840.113549.1.1.1",
172                 "KEYFACTORY.1.2.840.113549.1.1.7",
173                 "KEYFACTORY.1.3.133.16.840.63.0.2",
174                 "KEYFACTORY.2.5.8.1.1",
175                 "KEYFACTORY.EC",
176                 "KEYGENERATOR.1.2.840.113549.2.10",
177                 "KEYGENERATOR.1.2.840.113549.2.11",
178                 "KEYGENERATOR.1.2.840.113549.2.7",
179                 "KEYGENERATOR.1.2.840.113549.2.8",
180                 "KEYGENERATOR.1.2.840.113549.2.9",
181                 "KEYGENERATOR.1.3.6.1.5.5.8.1.1",
182                 "KEYGENERATOR.1.3.6.1.5.5.8.1.2",
183                 "KEYGENERATOR.2.16.840.1.101.3.4.2.1",
184                 "KEYGENERATOR.AES",
185                 "KEYGENERATOR.DESEDE",
186                 "KEYGENERATOR.HMAC-MD5",
187                 "KEYGENERATOR.HMAC-SHA1",
188                 "KEYGENERATOR.HMAC-SHA224",
189                 "KEYGENERATOR.HMAC-SHA256",
190                 "KEYGENERATOR.HMAC-SHA384",
191                 "KEYGENERATOR.HMAC-SHA512",
192                 "KEYGENERATOR.HMAC/MD5",
193                 "KEYGENERATOR.HMAC/SHA1",
194                 "KEYGENERATOR.HMAC/SHA224",
195                 "KEYGENERATOR.HMAC/SHA256",
196                 "KEYGENERATOR.HMAC/SHA384",
197                 "KEYGENERATOR.HMAC/SHA512",
198                 "KEYGENERATOR.HMACMD5",
199                 "KEYGENERATOR.HMACSHA1",
200                 "KEYGENERATOR.HMACSHA224",
201                 "KEYGENERATOR.HMACSHA256",
202                 "KEYGENERATOR.HMACSHA384",
203                 "KEYGENERATOR.HMACSHA512",
204                 "KEYGENERATOR.TDEA",
205                 "KEYPAIRGENERATOR.1.2.840.10045.2.1",
206                 "KEYPAIRGENERATOR.1.2.840.113549.1.1.1",
207                 "KEYPAIRGENERATOR.1.2.840.113549.1.1.7",
208                 "KEYPAIRGENERATOR.1.3.133.16.840.63.0.2",
209                 "KEYPAIRGENERATOR.2.5.8.1.1",
210                 "KEYPAIRGENERATOR.EC",
211                 "KEYPAIRGENERATOR.RSA",
212                 "MAC.1.2.840.113549.2.10",
213                 "MAC.1.2.840.113549.2.11",
214                 "MAC.1.2.840.113549.2.7",
215                 "MAC.1.2.840.113549.2.8",
216                 "MAC.1.2.840.113549.2.9",
217                 "MAC.1.3.6.1.5.5.8.1.1",
218                 "MAC.1.3.6.1.5.5.8.1.2",
219                 "MAC.2.16.840.1.101.3.4.2.1",
220                 "MAC.HMAC-MD5",
221                 "MAC.HMAC-SHA1",
222                 "MAC.HMAC-SHA224",
223                 "MAC.HMAC-SHA256",
224                 "MAC.HMAC-SHA384",
225                 "MAC.HMAC-SHA512",
226                 "MAC.HMAC/MD5",
227                 "MAC.HMAC/SHA1",
228                 "MAC.HMAC/SHA224",
229                 "MAC.HMAC/SHA256",
230                 "MAC.HMAC/SHA384",
231                 "MAC.HMAC/SHA512",
232                 "MAC.HMACMD5",
233                 "MAC.HMACSHA1",
234                 "MAC.HMACSHA224",
235                 "MAC.HMACSHA256",
236                 "MAC.HMACSHA384",
237                 "MAC.HMACSHA512",
238                 "MAC.PBEWITHHMACSHA224",
239                 "MAC.PBEWITHHMACSHA256",
240                 "MAC.PBEWITHHMACSHA384",
241                 "MAC.PBEWITHHMACSHA512",
242                 "MESSAGEDIGEST.1.2.840.113549.2.5",
243                 "MESSAGEDIGEST.1.3.14.3.2.26",
244                 "MESSAGEDIGEST.2.16.840.1.101.3.4.2.1",
245                 "MESSAGEDIGEST.2.16.840.1.101.3.4.2.2",
246                 "MESSAGEDIGEST.2.16.840.1.101.3.4.2.3",
247                 "MESSAGEDIGEST.2.16.840.1.101.3.4.2.4",
248                 "MESSAGEDIGEST.MD5",
249                 "MESSAGEDIGEST.SHA",
250                 "MESSAGEDIGEST.SHA-1",
251                 "MESSAGEDIGEST.SHA-224",
252                 "MESSAGEDIGEST.SHA-256",
253                 "MESSAGEDIGEST.SHA-384",
254                 "MESSAGEDIGEST.SHA-512",
255                 "MESSAGEDIGEST.SHA1",
256                 "MESSAGEDIGEST.SHA224",
257                 "MESSAGEDIGEST.SHA256",
258                 "MESSAGEDIGEST.SHA384",
259                 "MESSAGEDIGEST.SHA512",
260                 "SECRETKEYFACTORY.DESEDE",
261                 "SECRETKEYFACTORY.TDEA",
262                 "SIGNATURE.1.2.840.10045.4.1",
263                 "SIGNATURE.1.2.840.10045.4.3.1",
264                 "SIGNATURE.1.2.840.10045.4.3.2",
265                 "SIGNATURE.1.2.840.10045.4.3.3",
266                 "SIGNATURE.1.2.840.10045.4.3.4",
267                 "SIGNATURE.1.2.840.113549.1.1.11",
268                 "SIGNATURE.1.2.840.113549.1.1.12",
269                 "SIGNATURE.1.2.840.113549.1.1.13",
270                 "SIGNATURE.1.2.840.113549.1.1.14",
271                 "SIGNATURE.1.2.840.113549.1.1.4",
272                 "SIGNATURE.1.2.840.113549.1.1.5",
273                 "SIGNATURE.1.3.14.3.2.29",
274                 "SIGNATURE.ECDSA",
275                 "SIGNATURE.ECDSAWITHSHA1",
276                 "SIGNATURE.MD5/RSA",
277                 "SIGNATURE.MD5WITHRSA",
278                 "SIGNATURE.MD5WITHRSAENCRYPTION",
279                 "SIGNATURE.NONEWITHECDSA",
280                 "SIGNATURE.OID.1.2.840.10045.4.3.1",
281                 "SIGNATURE.OID.1.2.840.10045.4.3.2",
282                 "SIGNATURE.OID.1.2.840.10045.4.3.3",
283                 "SIGNATURE.OID.1.2.840.10045.4.3.4",
284                 "SIGNATURE.OID.1.2.840.113549.1.1.11",
285                 "SIGNATURE.OID.1.2.840.113549.1.1.12",
286                 "SIGNATURE.OID.1.2.840.113549.1.1.13",
287                 "SIGNATURE.OID.1.2.840.113549.1.1.14",
288                 "SIGNATURE.OID.1.2.840.113549.1.1.4",
289                 "SIGNATURE.OID.1.2.840.113549.1.1.5",
290                 "SIGNATURE.OID.1.3.14.3.2.29",
291                 "SIGNATURE.SHA1/RSA",
292                 "SIGNATURE.SHA1WITHECDSA",
293                 "SIGNATURE.SHA1WITHRSA",
294                 "SIGNATURE.SHA1WITHRSAENCRYPTION",
295                 "SIGNATURE.SHA224/ECDSA",
296                 "SIGNATURE.SHA224/RSA",
297                 "SIGNATURE.SHA224WITHECDSA",
298                 "SIGNATURE.SHA224WITHRSA",
299                 "SIGNATURE.SHA224WITHRSAENCRYPTION",
300                 "SIGNATURE.SHA256/ECDSA",
301                 "SIGNATURE.SHA256/RSA",
302                 "SIGNATURE.SHA256WITHECDSA",
303                 "SIGNATURE.SHA256WITHRSA",
304                 "SIGNATURE.SHA256WITHRSAENCRYPTION",
305                 "SIGNATURE.SHA384/ECDSA",
306                 "SIGNATURE.SHA384/RSA",
307                 "SIGNATURE.SHA384WITHECDSA",
308                 "SIGNATURE.SHA384WITHRSA",
309                 "SIGNATURE.SHA384WITHRSAENCRYPTION",
310                 "SIGNATURE.SHA512/ECDSA",
311                 "SIGNATURE.SHA512/RSA",
312                 "SIGNATURE.SHA512WITHECDSA",
313                 "SIGNATURE.SHA512WITHRSA",
314                 "SIGNATURE.SHA512WITHRSAENCRYPTION"
315         ));
316     }
317 
getProvider(Object object)318     private static Provider getProvider(Object object) throws Exception {
319         // Every JCA object has a getProvider() method
320         Method m = object.getClass().getMethod("getProvider");
321         return (Provider) m.invoke(object);
322     }
323 
324     @Test
testBeforeLimit()325     public void testBeforeLimit() throws Exception {
326         // When we're before the limit of the target API, all calls should succeed
327         try {
328             Providers.setMaximumAllowableApiLevelForBcDeprecation(
329                     VMRuntime.getRuntime().getTargetSdkVersion() + 1);
330             for (Algorithm a : BC_ALGORITHMS) {
331                 Object result = a.getInstance();
332                 assertEquals("BC", getProvider(result).getName());
333             }
334             for (Algorithm a : CONSCRYPT_ALGORITHMS) {
335                 Object result = a.getInstance();
336                 assertEquals("AndroidOpenSSL", getProvider(result).getName());
337             }
338         } finally {
339             Providers.setMaximumAllowableApiLevelForBcDeprecation(
340                     Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
341         }
342     }
343 
344     @Test
testAtLimit()345     public void testAtLimit() throws Exception {
346         // When we're at the limit of the target API, all calls should still succeed
347         try {
348             Providers.setMaximumAllowableApiLevelForBcDeprecation(
349                     VMRuntime.getRuntime().getTargetSdkVersion());
350             for (Algorithm a : BC_ALGORITHMS) {
351                 Object result = a.getInstance();
352                 assertEquals("BC", getProvider(result).getName());
353             }
354             for (Algorithm a : CONSCRYPT_ALGORITHMS) {
355                 Object result = a.getInstance();
356                 assertEquals("AndroidOpenSSL", getProvider(result).getName());
357             }
358         } finally {
359             Providers.setMaximumAllowableApiLevelForBcDeprecation(
360                     Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
361         }
362     }
363 
364     @Test
testPastLimit()365     public void testPastLimit() throws Exception {
366         // When we're beyond the limit of the target API, the Conscrypt calls should succeed
367         // but the BC calls should throw NoSuchAlgorithmException
368         try {
369             Providers.setMaximumAllowableApiLevelForBcDeprecation(
370                     VMRuntime.getRuntime().getTargetSdkVersion() - 1);
371             for (Algorithm a : BC_ALGORITHMS) {
372                 try {
373                     a.getInstance();
374                     fail("getInstance should have thrown");
375                 } catch (NoSuchAlgorithmException expected) {
376                 }
377             }
378             for (Algorithm a : CONSCRYPT_ALGORITHMS) {
379                 Object result = a.getInstance();
380                 assertEquals("AndroidOpenSSL", getProvider(result).getName());
381             }
382         } finally {
383             Providers.setMaximumAllowableApiLevelForBcDeprecation(
384                     Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
385         }
386     }
387 
388     @Test
testCustomProvider()389     public void testCustomProvider() throws Exception {
390         // When we install our own separate instance of Bouncy Castle, the system should
391         // respect that and allow us to use its implementation.
392         Provider originalBouncyCastle = null;
393         int originalBouncyCastleIndex = -1;
394         for (int i = 0; i < Security.getProviders().length; i++) {
395             if (Security.getProviders()[i].getName().equals("BC")) {
396                 originalBouncyCastle = Security.getProviders()[i];
397                 originalBouncyCastleIndex = i;
398                 break;
399             }
400         }
401         assertNotNull(originalBouncyCastle);
402         Provider newBouncyCastle = new BouncyCastleProvider();
403         assertEquals("BC", newBouncyCastle.getName());
404         try {
405             // Remove the existing BC provider and replace it with a different one
406             Security.removeProvider("BC");
407             Security.insertProviderAt(newBouncyCastle, originalBouncyCastleIndex);
408             // Set the target API limit such that the BC algorithms are disallowed
409             Providers.setMaximumAllowableApiLevelForBcDeprecation(
410                     VMRuntime.getRuntime().getTargetSdkVersion() - 1);
411             for (Algorithm a : BC_ALGORITHMS) {
412                 Object result = a.getInstance();
413                 assertEquals("BC", getProvider(result).getName());
414             }
415             for (Algorithm a : CONSCRYPT_ALGORITHMS) {
416                 Object result = a.getInstance();
417                 assertEquals("AndroidOpenSSL", getProvider(result).getName());
418             }
419         } finally {
420             Providers.setMaximumAllowableApiLevelForBcDeprecation(
421                     Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
422             Security.removeProvider("BC");
423             Security.insertProviderAt(originalBouncyCastle, originalBouncyCastleIndex);
424         }
425     }
426 
427     @Test
testRemovedBCAlgorithms()428     public void testRemovedBCAlgorithms() throws Exception {
429         for (String fullAlgorithm : REMOVED_BC_ALGORITHMS) {
430             String[] parts = fullAlgorithm.split("\\.", 2);
431             assertEquals("Algortihm names are expected to be of format Type.Name",
432                 2, parts.length);
433 
434             Provider bcProvider = Security.getProvider("BC");
435             String type = parts[0];
436             String algorithm = parts[1];
437             try {
438                 switch (parts[0]) {
439                     case "ALGORITHMPARAMETERS":
440                         AlgorithmParameters.getInstance(algorithm, bcProvider);
441                     case "CERTIFICATEFACTORY":
442                         CertificateFactory.getInstance(algorithm, bcProvider);
443                     case "CIPHER":
444                         Cipher.getInstance(algorithm, bcProvider);
445                     case "KEYAGREEMENT":
446                         KeyAgreement.getInstance(algorithm, bcProvider);
447                     case "KEYFACTORY":
448                         KeyFactory.getInstance(algorithm, bcProvider);
449                     case "KEYGENERATOR":
450                         KeyGenerator.getInstance(algorithm, bcProvider);
451                     case "KEYPAIRGENERATOR":
452                         KeyPairGenerator.getInstance(algorithm, bcProvider);
453                     case "MAC":
454                         Mac.getInstance(algorithm, bcProvider);
455                     case "MESSAGEDIGEST":
456                         MessageDigest.getInstance(algorithm, bcProvider);
457                     case "SECRETKEYFACTORY":
458                         SecretKeyFactory.getInstance(algorithm, bcProvider);
459                     case "SIGNATURE":
460                         Signature.getInstance(algorithm, bcProvider);
461                     default:
462                         fail("unhandled algorithm type " + parts[0]);
463                 }
464                 fail("getInstance should have thrown for type: " + parts[0] + ", name: " + algorithm);
465             } catch(CertificateException | NoSuchAlgorithmException expected) {
466             }
467         }
468     }
469 }