< 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 >