/* * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.launcher; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import java.io.IOException; import java.io.PrintStream; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.Security; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import jdk.internal.access.SharedSecrets; /** * A utility class for security libs functionality * in the -XshowSettings:security output */ public final class SecuritySettings { private static final String INDENT = " "; private static final String TWOINDENT = INDENT + INDENT; private static final String THREEINDENT = TWOINDENT + INDENT; private static final String PROV_INFO_STRING = "Provider information: "; private static PrintStream ostream = null; static void printSecuritySettings(LauncherHelper.Option o, PrintStream stream, boolean verbose) { ostream = stream; if (!verbose) { printSecuritySummarySettings(); return; } switch (o) { case SECURITY_PROPERTIES -> printSecurityProperties(); case SECURITY_PROVIDERS -> printSecurityProviderConfig(true); case SECURITY_TLS -> printSecurityTLSConfig(true); case SECURITY, SECURITY_ALL -> printAllSecurityConfig(); } } // A non-verbose description of some core security configuration settings static void printSecuritySummarySettings() { ostream.println("Security settings summary:"); ostream.println(INDENT + "Use \"-XshowSettings:security\" " + "option for verbose security settings options"); printSecurityProviderConfig(false); printSecurityTLSConfig(false); } static void printAllSecurityConfig() { ostream.println("Security settings:"); printSecurityProperties(); printSecurityProviderConfig(true); printSecurityTLSConfig(true); } private static void printSecurityProperties() { ostream.println(INDENT + "Security properties:"); Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getInitialProperties(); for (String key : p.stringPropertyNames().stream().sorted().toList()) { String val = p.getProperty(key); if (val.length() > 60) { splitLongPropertyLines(key, val); } else { ostream.println(TWOINDENT + key + "=" + val); } } ostream.println(); } private static void splitLongPropertyLines(String key, String val) { // split long property values which use well known separator if (val.contains(",") || val.contains(";")) { String separator = (val.contains(",")) ? "," : ";"; ostream.println(TWOINDENT + key + "="); String[] values = val.split(separator); String lastValue = values[values.length -1].trim(); List.of(values).forEach( s -> ostream.println(THREEINDENT + s.trim() + (s.trim().equals(lastValue) ? "" : separator))); } else { ostream.println(TWOINDENT + key + "=" + val); } } private static void printSecurityTLSConfig(boolean verbose) { SSLSocket ssls; SSLContext sslContext; try { sslContext = SSLContext.getDefault(); ssls = (SSLSocket)sslContext.getSocketFactory().createSocket(); } catch (IOException | NoSuchAlgorithmException e) { ostream.println(INDENT + "Failed to create SSL socket"); ostream.println(INDENT + e + "\n"); return; } ostream.println(INDENT + "Security TLS configuration (" + sslContext.getProvider().getName() + " provider):"); ostream.println(TWOINDENT + "Enabled Protocols:"); for (String s : ssls.getEnabledProtocols()) { ostream.println(THREEINDENT + s); } if (verbose) { ostream.println("\n" + TWOINDENT + "Enabled Cipher Suites:"); for (String s : ssls.getEnabledCipherSuites()) { ostream.println(THREEINDENT + s); } } ostream.println(); } private static void printSecurityProviderConfig(boolean verbose) { ostream.println(INDENT + "Security provider static configuration: (in order of preference)"); for (Provider p : Security.getProviders()) { if (verbose) { // separate the views out ostream.println(TWOINDENT + "-".repeat(40)); } ostream.println(TWOINDENT + "Provider name: " + p.getName()); if (verbose) { ostream.println(wrappedString(PROV_INFO_STRING + p.getInfo(), 80, TWOINDENT, THREEINDENT)); ostream.println(TWOINDENT + "Provider services: (type : algorithm)"); Set services = p.getServices(); Set keys = Collections.list(p.keys()) .stream() .map(String.class::cast) .filter(s -> s.startsWith("Alg.Alias.")) .collect(Collectors.toSet()); if (!services.isEmpty()) { services.stream() .sorted(Comparator.comparing(Provider.Service::getType) .thenComparing(Provider.Service::getAlgorithm)) .forEach(ps -> { ostream.println(THREEINDENT + ps.getType() + "." + ps.getAlgorithm()); List aliases = keys .stream() .filter(s -> s.startsWith("Alg.Alias." + ps.getType())) .filter(s -> p.getProperty(s).equals(ps.getAlgorithm())) .map(s -> s.substring(("Alg.Alias." + ps.getType() + ".").length())) .toList(); if (!aliases.isEmpty()) { ostream.println(wrappedString( aliases.stream() .collect(Collectors.joining(", ", INDENT + " aliases: [", "]")), 80, " " + TWOINDENT, INDENT + THREEINDENT)); } }); } else { ostream.println(THREEINDENT + ""); } } } if (verbose) { ostream.println(); } } // return a string split across multiple lines which aims to limit max length private static String wrappedString(String orig, int limit, String initIndent, String successiveIndent) { if (orig == null || orig.isEmpty() || limit <= 0) { // bad input return orig; } StringBuilder sb = new StringBuilder(); int widthCount = 0; for (String s : orig.split(" ")) { if (widthCount == 0) { // first iteration only sb.append(initIndent + s); widthCount = s.length() + initIndent.length(); } else { if (widthCount + s.length() > limit) { sb.append("\n" + successiveIndent + s); widthCount = s.length() + successiveIndent.length(); } else { sb.append(" " + s); widthCount += s.length() + 1; } } } return sb.toString(); } }