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 libcore.java.security; 18 19 import android.net.PskKeyManager; 20 21 import java.security.NoSuchAlgorithmException; 22 import java.security.Provider; 23 import java.security.Security; 24 import java.util.Arrays; 25 import java.util.Comparator; 26 import java.util.Set; 27 import java.util.TreeSet; 28 import javax.crypto.Cipher; 29 import javax.crypto.NoSuchPaddingException; 30 import javax.net.ssl.KeyManager; 31 import javax.net.ssl.SSLContext; 32 import javax.net.ssl.SSLEngine; 33 import javax.net.ssl.SSLSocketFactory; 34 import javax.net.ssl.TrustManager; 35 36 /** 37 * Prints a list of all algorithms provided by security providers. Intended to be run 38 * via vogar as part of the algorithm documentation update process. 39 * <p> 40 * {@code vogar libcore/tools/src/java/libcore/java/security/ListProviders.java} 41 */ 42 public class ListProviders { 43 44 private static final boolean SHOW_PROVIDER = false; 45 46 // These algorithms were previously provided, but now are aliases for a different 47 // algorithm. For documentation purposes, we want to continue having them show up 48 // as supported. 49 private static final Set<String> KNOWN_ALIASES = new TreeSet<>(Arrays.asList(new String[]{ 50 "Alg.Alias.Signature.DSA", 51 "Alg.Alias.Signature.DSAwithSHA1", 52 "Alg.Alias.Signature.ECDSA", 53 "Alg.Alias.Signature.ECDSAwithSHA1", 54 })); 55 56 // Ciphers come in algorithm/mode/padding combinations, and not all combinations are explicitly 57 // registered by the providers (sometimes only the base algorithm is registered). While there 58 // is a mechanism for providers to specify which modes and/or paddings are supported for a 59 // given algorithm, none of our providers use it. Thus, when a base algorithm is seen, all 60 // combinations of modes and paddings will be tried to see which ones are supported. 61 private static final Set<String> CIPHER_MODES = new TreeSet<>(Arrays.asList(new String[]{ 62 "CBC", 63 "CFB", 64 "CTR", 65 "CTS", 66 "ECB", 67 "GCM", 68 "OFB", 69 "NONE", 70 })); 71 private static final Set<String> CIPHER_PADDINGS = new TreeSet<>(Arrays.asList(new String[]{ 72 "NoPadding", 73 "OAEPPadding", 74 "OAEPwithSHA-1andMGF1Padding", 75 "OAEPwithSHA-224andMGF1Padding", 76 "OAEPwithSHA-256andMGF1Padding", 77 "OAEPwithSHA-384andMGF1Padding", 78 "OAEPwithSHA-512andMGF1Padding", 79 "PKCS1Padding", 80 "PKCS5Padding", 81 "ISO10126Padding", 82 })); 83 print(Provider p, String type, String algorithm)84 private static void print(Provider p, String type, String algorithm) { 85 System.out.println((SHOW_PROVIDER ? p.getName() + ": " : "") + type + " " + algorithm); 86 } 87 main(String[] argv)88 public static void main(String[] argv) throws Exception { 89 System.out.println("BEGIN ALGORITHM LIST"); 90 for (Provider p : Security.getProviders()) { 91 Set<Provider.Service> services = new TreeSet<Provider.Service>( 92 new Comparator<Provider.Service>() { 93 public int compare(Provider.Service a, Provider.Service b) { 94 int typeCompare = a.getType().compareTo(b.getType()); 95 if (typeCompare != 0) { 96 return typeCompare; 97 } 98 return a.getAlgorithm().compareTo(b.getAlgorithm()); 99 } 100 }); 101 services.addAll(p.getServices()); 102 for (Provider.Service s : services) { 103 if (s.getType().equals("Cipher") && s.getAlgorithm().startsWith("PBE")) { 104 // PBE ciphers are a mess and generally don't do anything but delegate 105 // to the underlying cipher. We don't want to document them. 106 continue; 107 } 108 if (s.getType().equals("Cipher") && s.getAlgorithm().indexOf('/') == -1) { 109 for (String mode : CIPHER_MODES) { 110 for (String padding : CIPHER_PADDINGS) { 111 try { 112 String name = s.getAlgorithm() + "/" + mode + "/" + padding; 113 Cipher.getInstance(name, p); 114 print(p, s.getType(), name); 115 } catch (NoSuchAlgorithmException 116 |NoSuchPaddingException 117 |IllegalArgumentException e) { 118 // This combination doesn't work 119 } 120 } 121 } 122 } else { 123 print(p, s.getType(), s.getAlgorithm()); 124 } 125 } 126 for (String alias : KNOWN_ALIASES) { 127 if (p.containsKey(alias)) { 128 String[] elements = alias.split("\\."); // Split takes a regex 129 print(p, elements[2], elements[3]); 130 } 131 } 132 } 133 // SSLEngine and SSLSocket algorithms are handled outside the default provider system 134 SSLContext defaultContext = SSLContext.getDefault(); 135 // PSK cipher suites are only enabled when a PskKeyManager is available, but some other 136 // suites are disabled in that case, so check for both 137 SSLContext pskContext = SSLContext.getInstance("TLS"); 138 pskContext.init( 139 new KeyManager[] {new PskKeyManager(){}}, 140 new TrustManager[0], 141 null); 142 for (SSLContext sslContext : new SSLContext[] {defaultContext, pskContext}) { 143 SSLEngine engine = sslContext.createSSLEngine(); 144 for (String suite : engine.getSupportedCipherSuites()) { 145 print(sslContext.getProvider(), "SSLEngine.Supported", suite); 146 } 147 for (String suite : engine.getEnabledCipherSuites()) { 148 print(sslContext.getProvider(), "SSLEngine.Enabled", suite); 149 } 150 SSLSocketFactory socketFactory = sslContext.getSocketFactory(); 151 for (String suite : socketFactory.getSupportedCipherSuites()) { 152 print(sslContext.getProvider(), "SSLSocket.Supported", suite); 153 } 154 for (String suite : socketFactory.getDefaultCipherSuites()) { 155 print(sslContext.getProvider(), "SSLSocket.Enabled", suite); 156 } 157 } 158 System.out.println("END ALGORITHM LIST"); 159 } 160 }