1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.event;
  27 
  28 import java.time.Duration;
  29 import java.time.Instant;
  30 import java.util.Date;
  31 
  32 /**
  33  * A helper class to have events committed to both the JFR and Logger
  34  * frameworks, when configured. JFR functionality may be enhanced
  35  * at a later time to allow for configuration of logging directly from
  36  * JFR Event classes.
  37  */
  38 
  39 public final class EventHelper {
  40 
  41     private static final System.Logger.Level LOG_LEVEL = System.Logger.Level.DEBUG;
  42 
  43     // helper class used for logging security related events for now
  44     private static final String SECURITY_LOGGER_NAME = "jdk.event.security";
  45     private static final System.Logger SECURITY_LOGGER =
  46             System.getLogger(SECURITY_LOGGER_NAME);
  47     private static final boolean LOGGING_SECURITY =
  48             SECURITY_LOGGER.isLoggable(LOG_LEVEL);
  49 
  50     /**
  51      * Helper method to commit a TLSHandshakeEvent to both the JFR
  52      * and Logging frameworks.
  53      */
  54     public static void commitTLSHandshakeEvent(TLSHandshakeEvent event,
  55                                                Instant start,
  56                                                String remoteHost,
  57                                                int remotePort,
  58                                                String cipherSuite,
  59                                                String protocolVersion,
  60                                                String certChain) {
  61         if (event != null && event.shouldCommit()) {
  62             event.remoteHost = remoteHost;
  63             event.remotePort = remotePort;
  64             event.cipherSuite = cipherSuite;
  65             event.protocolVersion = protocolVersion;
  66             event.certificateChain = certChain;
  67             event.commit();
  68         }
  69         if (isLoggingSecurity()) {
  70             String prepend = getDurationString(start);
  71             SECURITY_LOGGER.log(LOG_LEVEL, prepend +
  72             " TLSHandshake: {0}:{1,number,#}, {2}, {3}, {4}",
  73             remoteHost, remotePort, protocolVersion, cipherSuite, certChain);
  74         }
  75     }
  76 
  77     /**
  78      * Helper method to commit a SecurityPropertyEvent to both the JFR
  79      * and Logging frameworks.
  80      */
  81     public static void commitSecurityPropertyEvent(SecurityPropertyEvent event,
  82                                                    String key,
  83                                                    String value) {
  84         if (event.shouldCommit()) {
  85             event.name = key;
  86             event.value = value;
  87             event.commit();
  88         }
  89         if (isLoggingSecurity()) {
  90             SECURITY_LOGGER.log(LOG_LEVEL,
  91                 "SecurityProperty: key:{0}, value:{1}", key, value);
  92         }
  93     }
  94 
  95     /**
  96      * Helper method to commit a CertChainEvent to both the JFR
  97      * and Logging frameworks.
  98      */
  99     public static void commitCertChainEvent(CertificateChainEvent event,
 100                                             String certs) {
 101         if (event.shouldCommit()) {
 102             event.serialNumbers = certs;
 103             event.commit();
 104         }
 105         if (isLoggingSecurity()) {
 106             SECURITY_LOGGER.log(LOG_LEVEL, "CertificateChain: {0}", certs);
 107         }
 108     }
 109 
 110     /**
 111      * Helper method to commit an X509CertEvent to both the JFR
 112      * and Logging frameworks.
 113      */
 114     public static void commitX509CertEvent(X509CertEvent event,
 115                                            String algId,
 116                                            String serialNum,
 117                                            String subject,
 118                                            String issuer,
 119                                            String keyType,
 120                                            int length,
 121                                            long beginDate,
 122                                            long endDate) {
 123         if (event.shouldCommit()) {
 124             event.algorithm = algId;
 125             event.serialNumber = serialNum;
 126             event.subject = subject;
 127             event.issuer = issuer;
 128             event.keyType = keyType;
 129             event.length = length;
 130             event.validFrom = beginDate;
 131             event.validUntil = endDate;
 132             event.commit();
 133         }
 134         if (isLoggingSecurity()) {
 135             SECURITY_LOGGER.log(LOG_LEVEL, "X509Certificate: Alg:{0}, Serial:{1}" +
 136                 ", Subject:{2}, Issuer:{3}, Key type:{4}, Length:{5,number,#}" +
 137                 ", Valid from:{6}, Valid until:{7}", algId, serialNum, subject,
 138                 issuer, keyType, length, new Date(beginDate), new Date(endDate));
 139         }
 140     }
 141 
 142     /**
 143      * Method to calculate a duration timestamp for events which measure
 144      * the start and end times of certain operations.
 145      * @param start Instant indicating when event started recording
 146      * @return A string representing duraction from start time to
 147      * time of this method call. Empty string is start is null.
 148      */
 149     private static String getDurationString(Instant start) {
 150         if (start != null) {
 151             Duration duration = Duration.between(start, Instant.now());
 152             long micros = duration.toNanos() / 1_000;
 153             if (micros < 1_000_000) {
 154                 return "duration = " + (micros / 1_000.0) + " ms:";
 155             } else {
 156                 return "duration = " + ((micros / 1_000) / 1_000.0) + " s:";
 157             }
 158         } else {
 159             return "";
 160         }
 161     }
 162 
 163     /**
 164      * Helper to determine if security events are being logged
 165      * at a preconfigured logging level. The configuration value
 166      * is read once at class initialization.
 167      *
 168      * @return boolean indicating whether an event should be logged
 169      */
 170     public static boolean isLoggingSecurity() {
 171         return LOGGING_SECURITY;
 172     }
 173 }