< prev index next >

src/java.base/share/classes/sun/security/ssl/SSLLogger.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 1999, 2016, 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 --- 1,7 ---- /* ! * Copyright (c) 2018, 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
*** 23,61 **** * questions. */ package sun.security.ssl; import java.io.PrintStream; ! import java.util.Locale; ! ! import sun.security.util.HexDumpEncoder; import java.nio.ByteBuffer; ! import sun.security.action.GetPropertyAction; /** ! * This class has be shamefully lifted from sun.security.util.Debug * ! * @author Gary Ellison */ ! public class Debug { ! ! private String prefix; ! ! private static String args; static { ! args = GetPropertyAction.privilegedGetProperty("javax.net.debug", ""); ! args = args.toLowerCase(Locale.ENGLISH); ! if (args.equals("help")) { ! Help(); } } ! public static void Help() ! { System.err.println(); System.err.println("all turn on all debugging"); System.err.println("ssl turn on ssl debugging"); System.err.println(); System.err.println("The following can be used with ssl:"); --- 23,93 ---- * questions. */ package sun.security.ssl; + import java.io.ByteArrayInputStream; + import java.io.ByteArrayOutputStream; + import java.io.IOException; import java.io.PrintStream; ! import java.lang.System.Logger; ! import java.lang.System.Logger.Level; import java.nio.ByteBuffer; ! import java.security.cert.Certificate; ! import java.security.cert.Extension; ! import java.security.cert.X509Certificate; ! import java.text.MessageFormat; ! import java.text.SimpleDateFormat; ! import java.util.Date; ! import java.util.Locale; ! import java.util.Map; ! import java.util.ResourceBundle; import sun.security.action.GetPropertyAction; + import sun.security.util.HexDumpEncoder; + import sun.security.x509.*; /** ! * Implementation of SSL logger. * ! * If the system property "javax.net.debug" is not defined, the debug logging ! * is turned off. If the system property "javax.net.debug" is defined as ! * empty, the debug logger is specified by System.getLogger("javax.net.ssl"), ! * and applications can customize and configure the logger or use external ! * logging mechanisms. If the system property "javax.net.debug" is defined ! * and non-empty, a private debug logger implemented in this class is used. */ ! public final class SSLLogger { ! private static final System.Logger logger; ! private static final String property; ! public static final boolean isOn; static { ! String p = GetPropertyAction.privilegedGetProperty("javax.net.debug"); ! if (p != null) { ! if (p.isEmpty()) { ! property = ""; ! logger = System.getLogger("javax.net.ssl"); ! } else { ! property = p.toLowerCase(Locale.ENGLISH); ! if (property.equals("help")) { ! help(); ! } ! ! logger = new SSLConsoleLogger("javax.net.ssl", p); ! } ! isOn = true; ! } else { ! property = null; ! logger = null; ! isOn = false; } } ! private static void help() { ! System.err.println(); ! System.err.println("help print the help messages"); ! System.err.println("expand expand debugging information"); System.err.println(); System.err.println("all turn on all debugging"); System.err.println("ssl turn on ssl debugging"); System.err.println(); System.err.println("The following can be used with ssl:");
*** 80,250 **** System.err.println(); System.exit(0); } /** ! * Get a Debug object corresponding to whether or not the given ! * option is set. Set the prefix to be the same as option. */ ! public static Debug getInstance(String option) ! { ! return getInstance(option, option); } - - /** - * Get a Debug object corresponding to whether or not the given - * option is set. Set the prefix to be prefix. - */ - public static Debug getInstance(String option, String prefix) - { - if (isOn(option)) { - Debug d = new Debug(); - d.prefix = prefix; - return d; - } else { - return null; } } ! /** ! * True if the property "javax.net.debug" contains the ! * string "option". ! */ ! public static boolean isOn(String option) ! { ! if (args == null) { ! return false; ! } else { ! int n = 0; option = option.toLowerCase(Locale.ENGLISH); ! ! if (args.indexOf("all") != -1) { return true; ! } else if ((n = args.indexOf("ssl")) != -1) { ! if (args.indexOf("sslctx", n) == -1) { // don't enable data and plaintext options by default if (!(option.equals("data") || option.equals("packet") || option.equals("plaintext"))) { return true; } } } ! return (args.indexOf(option) != -1); ! } } ! /** ! * print a message to stderr that is prefixed with the prefix ! * created from the call to getInstance. ! */ ! public void println(String message) ! { ! System.err.println(prefix + ": "+message); } ! /** ! * Print a message to stdout. ! */ ! static void log(String message) { ! System.out.println(Thread.currentThread().getName() + ": " + message); } ! /** ! * print a blank line to stderr that is prefixed with the prefix. ! */ ! public void println() ! { ! System.err.println(prefix + ":"); } ! /** ! * print a message to stderr that is prefixed with the prefix. ! */ ! public static void println(String prefix, String message) ! { ! System.err.println(prefix + ": "+message); } ! public static void println(PrintStream s, String name, byte[] data) { ! s.print(name + ": { "); ! if (data == null) { ! s.print("null"); } else { ! for (int i = 0; i < data.length; i++) { ! if (i != 0) s.print(", "); ! s.print(data[i] & 0x0ff); } } - s.println(" }"); } ! /** ! * Return the value of the boolean System property propName. ! * ! * Note use of privileged action. Do NOT make accessible to applications. ! */ ! static boolean getBooleanProperty(String propName, boolean defaultValue) { ! // if set, require value of either true or false ! String b = GetPropertyAction.privilegedGetProperty(propName); ! if (b == null) { ! return defaultValue; ! } else if (b.equalsIgnoreCase("false")) { ! return false; ! } else if (b.equalsIgnoreCase("true")) { ! return true; ! } else { ! throw new RuntimeException("Value of " + propName ! + " must either be 'true' or 'false'"); } } ! static String toString(byte[] b) { ! return sun.security.util.Debug.toString(b); } ! static void printHex(String prefix, byte[] bytes) { ! HexDumpEncoder dump = new HexDumpEncoder(); ! synchronized (System.out) { ! System.out.println(prefix); try { ! dump.encodeBuffer(bytes, System.out); ! } catch (Exception e) { ! // ignore } - System.out.flush(); } } ! static void printHex(String prefix, ByteBuffer bb) { ! HexDumpEncoder dump = new HexDumpEncoder(); ! ! synchronized (System.out) { ! System.out.println(prefix); try { ! dump.encodeBuffer(bb.slice(), System.out); ! } catch (Exception e) { ! // ignore } ! System.out.flush(); } } ! static void printHex(String prefix, byte[] bytes, int offset, int length) { ! HexDumpEncoder dump = new HexDumpEncoder(); ! synchronized (System.out) { ! System.out.println(prefix); try { ! ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length); ! dump.encodeBuffer(bb, System.out); ! } catch (Exception e) { ! // ignore } ! System.out.flush(); } } } --- 112,609 ---- System.err.println(); System.exit(0); } /** ! * Return true if the "javax.net.debug" property contains the ! * debug check points, or System.Logger is used. */ + public static boolean isOn(String checkPoints) { + if (property == null) { // debugging is turned off + return false; + } else if (property.isEmpty()) { // use System.Logger + return true; + } // use provider logger ! String[] options = checkPoints.split(","); ! for (String option : options) { ! option = option.trim(); ! if (!SSLLogger.hasOption(option)) { ! return false; } } + + return true; } ! private static boolean hasOption(String option) { option = option.toLowerCase(Locale.ENGLISH); ! if (property.contains("all")) { return true; ! } else { ! int offset = property.indexOf("ssl"); ! if (offset != -1 && property.indexOf("sslctx", offset) != -1) { // don't enable data and plaintext options by default if (!(option.equals("data") || option.equals("packet") || option.equals("plaintext"))) { return true; } } } ! ! return property.contains(option); } ! public static void severe(String msg, Object... params) { ! SSLLogger.log(Level.ERROR, msg, params); ! } ! public static void warning(String msg, Object... params) { ! SSLLogger.log(Level.WARNING, msg, params); } ! public static void info(String msg, Object... params) { ! SSLLogger.log(Level.INFO, msg, params); } ! public static void fine(String msg, Object... params) { ! SSLLogger.log(Level.DEBUG, msg, params); ! } ! public static void finer(String msg, Object... params) { ! SSLLogger.log(Level.TRACE, msg, params); } ! public static void finest(String msg, Object... params) { ! SSLLogger.log(Level.ALL, msg, params); } ! private static void log(Level level, String msg, Object... params) { ! if (logger.isLoggable(level)) { ! if (params == null || params.length == 0) { ! logger.log(level, msg); } else { ! try { ! String formatted = ! SSLSimpleFormatter.formatParameters(params); ! logger.log(level, msg, formatted); ! } catch (Exception exp) { ! // ignore it, just for debugging. ! } } } } ! static String toString(Object... params) { ! try { ! return SSLSimpleFormatter.formatParameters(params); ! } catch (Exception exp) { ! return "unexpected exception thrown: " + exp.getMessage(); ! } } + + private static class SSLConsoleLogger implements Logger { + private final String loggerName; + private final boolean useCompactFormat; + + SSLConsoleLogger(String loggerName, String options) { + this.loggerName = loggerName; + options = options.toLowerCase(Locale.ENGLISH); + this.useCompactFormat = !options.contains("expand"); } ! @Override ! public String getName() { ! return loggerName; } ! @Override ! public boolean isLoggable(Level level) { ! return (level != Level.OFF); ! } ! @Override ! public void log(Level level, ! ResourceBundle rb, String message, Throwable thrwbl) { ! if (isLoggable(level)) { try { ! String formatted = ! SSLSimpleFormatter.format(this, level, message, thrwbl); ! System.err.write(formatted.getBytes("UTF-8")); ! } catch (Exception exp) { ! // ignore it, just for debugging. } } } ! @Override ! public void log(Level level, ! ResourceBundle rb, String message, Object... params) { ! if (isLoggable(level)) { try { ! String formatted = ! SSLSimpleFormatter.format(this, level, message, params); ! System.err.write(formatted.getBytes("UTF-8")); ! } catch (Exception exp) { ! // ignore it, just for debugging. ! } ! } ! } ! } ! ! private static class SSLSimpleFormatter { ! private static final ThreadLocal<SimpleDateFormat> dateFormat = ! new ThreadLocal<SimpleDateFormat>() { ! @Override protected SimpleDateFormat initialValue() { ! return new SimpleDateFormat( ! "yyyy-MM-dd kk:mm:ss.SSS z", Locale.ENGLISH); ! } ! }; ! ! private static final MessageFormat basicCertFormat = new MessageFormat( ! "\"version\" : \"v{0}\",\n" + ! "\"serial number\" : \"{1}\",\n" + ! "\"signature algorithm\": \"{2}\",\n" + ! "\"issuer\" : \"{3}\",\n" + ! "\"not before\" : \"{4}\",\n" + ! "\"not after\" : \"{5}\",\n" + ! "\"subject\" : \"{6}\",\n" + ! "\"subject public key\" : \"{7}\"\n", ! Locale.ENGLISH); ! ! private static final MessageFormat extendedCertFormart = ! new MessageFormat( ! "\"version\" : \"v{0}\",\n" + ! "\"serial number\" : \"{1}\",\n" + ! "\"signature algorithm\": \"{2}\",\n" + ! "\"issuer\" : \"{3}\",\n" + ! "\"not before\" : \"{4}\",\n" + ! "\"not after\" : \"{5}\",\n" + ! "\"subject\" : \"{6}\",\n" + ! "\"subject public key\" : \"{7}\",\n" + ! "\"extensions\" : [\n" + ! "{8}\n" + ! "]\n", ! Locale.ENGLISH); ! ! // ! // private static MessageFormat certExtFormat = new MessageFormat( ! // "{0} [{1}] '{'\n" + ! // " critical: {2}\n" + ! // " value: {3}\n" + ! // "'}'", ! // Locale.ENGLISH); ! // ! ! private static final MessageFormat messageFormatNoParas = ! new MessageFormat( ! "'{'\n" + ! " \"logger\" : \"{0}\",\n" + ! " \"level\" : \"{1}\",\n" + ! " \"thread id\" : \"{2}\",\n" + ! " \"thread name\" : \"{3}\",\n" + ! " \"time\" : \"{4}\",\n" + ! " \"caller\" : \"{5}\",\n" + ! " \"message\" : \"{6}\"\n" + ! "'}'\n", ! Locale.ENGLISH); ! ! private static final MessageFormat messageCompactFormatNoParas = ! new MessageFormat( ! "{0}|{1}|{2}|{3}|{4}|{5}|{6}\n", ! Locale.ENGLISH); ! ! private static final MessageFormat messageFormatWithParas = ! new MessageFormat( ! "'{'\n" + ! " \"logger\" : \"{0}\",\n" + ! " \"level\" : \"{1}\",\n" + ! " \"thread id\" : \"{2}\",\n" + ! " \"thread name\" : \"{3}\",\n" + ! " \"time\" : \"{4}\",\n" + ! " \"caller\" : \"{5}\",\n" + ! " \"message\" : \"{6}\",\n" + ! " \"specifics\" : [\n" + ! "{7}\n" + ! " ]\n" + ! "'}'\n", ! Locale.ENGLISH); ! ! private static final MessageFormat messageCompactFormatWithParas = ! new MessageFormat( ! "{0}|{1}|{2}|{3}|{4}|{5}|{6} (\n" + ! "{7}\n" + ! ")\n", ! Locale.ENGLISH); ! ! private static final MessageFormat keyObjectFormat = new MessageFormat( ! "\"{0}\" : '{'\n" + ! "{1}" + ! "'}'\n", ! Locale.ENGLISH); ! ! // INFO: [TH: 123450] 2011-08-20 23:12:32.3225 PDT ! // log message ! // log message ! // ... ! private static String format(SSLConsoleLogger logger, Level level, ! String message, Object ... parameters) { ! ! if (parameters == null || parameters.length == 0) { ! Object[] messageFields = { ! logger.loggerName, ! level.getName(), ! Utilities.toHexString(Thread.currentThread().getId()), ! Thread.currentThread().getName(), ! dateFormat.get().format(new Date(System.currentTimeMillis())), ! formatCaller(), ! message ! }; ! ! if (logger.useCompactFormat) { ! return messageCompactFormatNoParas.format(messageFields); ! } else { ! return messageFormatNoParas.format(messageFields); ! } ! } ! ! Object[] messageFields = { ! logger.loggerName, ! level.getName(), ! Utilities.toHexString(Thread.currentThread().getId()), ! Thread.currentThread().getName(), ! dateFormat.get().format(new Date(System.currentTimeMillis())), ! formatCaller(), ! message, ! (logger.useCompactFormat ? ! formatParameters(parameters) : ! Utilities.indent(formatParameters(parameters))) ! }; ! ! if (logger.useCompactFormat) { ! return messageCompactFormatWithParas.format(messageFields); ! } else { ! return messageFormatWithParas.format(messageFields); ! } ! } ! ! private static String formatCaller() { ! boolean isSSLLogger = false; ! for (StackTraceElement ste: (new Throwable()).getStackTrace()) { ! String cn = ste.getClassName(); ! if (cn.equals("sun.security.ssl.SSLLogger")) { ! // May be SSLLogger.log() or SSLLogger.fine(), etc. ! isSSLLogger = true; ! } else if (isSSLLogger) { ! // Here is the caller to SSLLogger.fine(), etc. ! return ste.getFileName() + ":" + ste.getLineNumber(); ! } ! } ! ! return "unknown caller"; ! } ! ! private static boolean isLoggerImpl(StackTraceElement ste) { ! String cn = ste.getClassName(); ! System.out.println("class name: " + cn); ! return cn.equals("sun.security.ssl.SSLLogger"); ! } ! ! private static String formatParameters(Object ... parameters) { ! StringBuilder builder = new StringBuilder(512); ! boolean isFirst = true; ! for (Object parameter : parameters) { ! if (isFirst) { ! isFirst = false; ! } else { ! builder.append(",\n"); ! } ! ! if (parameter instanceof Throwable) { ! builder.append(formatThrowable((Throwable)parameter)); ! } else if (parameter instanceof Certificate) { ! builder.append(formatCertificate((Certificate)parameter)); ! } else if (parameter instanceof ByteArrayInputStream) { ! builder.append(formatByteArrayInputStream( ! (ByteArrayInputStream)parameter)); ! } else if (parameter instanceof ByteBuffer) { ! builder.append(formatByteBuffer((ByteBuffer)parameter)); ! } else if (parameter instanceof byte[]) { ! builder.append(formatByteArrayInputStream( ! new ByteArrayInputStream((byte[])parameter))); ! } else if (parameter instanceof Map.Entry) { ! @SuppressWarnings("unchecked") ! Map.Entry<String, ?> mapParameter = ! (Map.Entry<String, ?>)parameter; ! builder.append(formatMapEntry(mapParameter)); ! } else { ! builder.append(formatObject(parameter)); ! } ! } ! ! return builder.toString(); } ! ! // "throwable": { ! // ... ! // } ! private static String formatThrowable(Throwable throwable) { ! StringBuilder builder = new StringBuilder(512); ! ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); ! try (PrintStream out = new PrintStream(bytesOut)) { ! throwable.printStackTrace(out); ! builder.append(Utilities.indent(bytesOut.toString())); } + Object[] fields = { + "throwable", + builder.toString() + }; + + return keyObjectFormat.format(fields); } ! // "certificate": { ! // ... ! // } ! private static String formatCertificate(Certificate certificate) { ! ! if (!(certificate instanceof X509Certificate)) { ! return Utilities.indent(certificate.toString()); ! } ! StringBuilder builder = new StringBuilder(512); try { ! X509CertImpl x509 = ! X509CertImpl.toImpl((X509Certificate)certificate); ! X509CertInfo certInfo = ! (X509CertInfo)x509.get(X509CertImpl.NAME + "." + ! X509CertImpl.INFO); ! CertificateExtensions certExts = (CertificateExtensions) ! certInfo.get(X509CertInfo.EXTENSIONS); ! if (certExts == null) { ! Object[] certFields = { ! x509.getVersion(), ! Utilities.toHexString( ! x509.getSerialNumber().toByteArray()), ! x509.getSigAlgName(), ! x509.getIssuerX500Principal().toString(), ! dateFormat.get().format(x509.getNotBefore()), ! dateFormat.get().format(x509.getNotAfter()), ! x509.getSubjectX500Principal().toString(), ! x509.getPublicKey().getAlgorithm() ! }; ! builder.append(Utilities.indent( ! basicCertFormat.format(certFields))); ! } else { ! StringBuilder extBuilder = new StringBuilder(512); ! boolean isFirst = true; ! for (Extension certExt : certExts.getAllExtensions()) { ! if (isFirst) { ! isFirst = false; ! } else { ! extBuilder.append(",\n"); } ! extBuilder.append("{\n" + ! Utilities.indent(certExt.toString()) + "\n}"); ! } ! Object[] certFields = { ! x509.getVersion(), ! Utilities.toHexString( ! x509.getSerialNumber().toByteArray()), ! x509.getSigAlgName(), ! x509.getIssuerX500Principal().toString(), ! dateFormat.get().format(x509.getNotBefore()), ! dateFormat.get().format(x509.getNotAfter()), ! x509.getSubjectX500Principal().toString(), ! x509.getPublicKey().getAlgorithm(), ! Utilities.indent(extBuilder.toString()) ! }; ! builder.append(Utilities.indent( ! extendedCertFormart.format(certFields))); ! } ! } catch (Exception ce) { ! // ignore the exception ! } ! ! Object[] fields = { ! "certificate", ! builder.toString() ! }; ! ! return Utilities.indent(keyObjectFormat.format(fields)); ! } ! ! private static String formatByteArrayInputStream( ! ByteArrayInputStream bytes) { ! StringBuilder builder = new StringBuilder(512); ! ! try (ByteArrayOutputStream bytesOut = new ByteArrayOutputStream()) { ! HexDumpEncoder hexEncoder = new HexDumpEncoder(); ! hexEncoder.encodeBuffer(bytes, bytesOut); ! ! builder.append(Utilities.indent(bytesOut.toString())); ! } catch (IOException ioe) { ! // ignore it, just for debugging. ! } ! ! return builder.toString(); ! } ! ! private static String formatByteBuffer(ByteBuffer byteBuffer) { ! StringBuilder builder = new StringBuilder(512); ! try (ByteArrayOutputStream bytesOut = new ByteArrayOutputStream()) { ! HexDumpEncoder hexEncoder = new HexDumpEncoder(); ! hexEncoder.encodeBuffer(byteBuffer.duplicate(), bytesOut); ! builder.append(Utilities.indent(bytesOut.toString())); ! } catch (IOException ioe) { ! // ignore it, just for debugging. ! } ! ! return builder.toString(); ! } ! ! private static String formatMapEntry(Map.Entry<String, ?> entry) { ! String key = entry.getKey(); ! Object value = entry.getValue(); ! ! String formatted; ! if (value instanceof String) { ! // "key": "value" ! formatted = "\"" + key + "\": \"" + (String)value + "\""; ! } else if (value instanceof String[]) { ! // "key": [ "string a", ! // "string b", ! // "string c" ! // ] ! StringBuilder builder = new StringBuilder(512); ! String[] strings = (String[])value; ! builder.append("\"" + key + "\": [\n"); ! for (String string : strings) { ! builder.append(" \"" + string + "\""); ! if (string != strings[strings.length - 1]) { ! builder.append(","); ! } ! builder.append("\n"); ! } ! builder.append(" ]"); ! ! formatted = builder.toString(); ! } else if (value instanceof byte[]) { ! formatted = "\"" + key + "\": \"" + ! Utilities.toHexString((byte[])value) + "\""; ! } else if (value instanceof Byte) { ! formatted = "\"" + key + "\": \"" + ! Utilities.toHexString((byte)value) + "\""; ! } else { ! formatted = "\"" + key + "\": " + ! "\"" + value.toString() + "\""; ! } ! ! return Utilities.indent(formatted); ! } ! ! private static String formatObject(Object obj) { ! return obj.toString(); } } }
< prev index next >