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