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