1 /*
  2  * Copyright (c) 1998, 2017, 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 sun.security.util;
 27 
 28 import java.io.PrintStream;
 29 import java.math.BigInteger;
 30 import java.util.regex.Pattern;
 31 import java.util.regex.Matcher;
 32 import java.util.Locale;
 33 import sun.security.action.GetPropertyAction;
 34 
 35 /**
 36  * A utility class for debugging.
 37  *
 38  * @author Roland Schemers
 39  */
 40 public class Debug {
 41 
 42     private String prefix;
 43 
 44     private static String args;
 45 
 46     static {
 47         args = GetPropertyAction.privilegedGetProperty("java.security.debug");
 48 
 49         String args2 = GetPropertyAction
 50                 .privilegedGetProperty("java.security.auth.debug");
 51 
 52         if (args == null) {
 53             args = args2;
 54         } else {
 55             if (args2 != null)
 56                args = args + "," + args2;
 57         }
 58 
 59         if (args != null) {
 60             args = marshal(args);
 61             if (args.equals("help")) {
 62                 Help();
 63             }
 64         }
 65     }
 66 
 67     public static void Help()
 68     {
 69         System.err.println();
 70         System.err.println("all           turn on all debugging");
 71         System.err.println("access        print all checkPermission results");
 72         System.err.println("certpath      PKIX CertPathBuilder and");
 73         System.err.println("              CertPathValidator debugging");
 74         System.err.println("combiner      SubjectDomainCombiner debugging");
 75         System.err.println("gssloginconfig");
 76         System.err.println("              GSS LoginConfigImpl debugging");
 77         System.err.println("configfile    JAAS ConfigFile loading");
 78         System.err.println("configparser  JAAS ConfigFile parsing");
 79         System.err.println("jar           jar verification");
 80         System.err.println("logincontext  login context results");
 81         System.err.println("jca           JCA engine class debugging");
 82         System.err.println("keystore      KeyStore debugging");
 83         System.err.println("policy        loading and granting");
 84         System.err.println("provider      security provider debugging");
 85         System.err.println("pkcs11        PKCS11 session manager debugging");
 86         System.err.println("pkcs11keystore");
 87         System.err.println("              PKCS11 KeyStore debugging");
 88         System.err.println("pkcs12        PKCS12 KeyStore debugging");
 89         System.err.println("sunpkcs11     SunPKCS11 provider debugging");
 90         System.err.println("scl           permissions SecureClassLoader assigns");
 91         System.err.println("securerandom  SecureRandom");
 92         System.err.println("ts            timestamping");
 93         System.err.println();
 94         System.err.println("The following can be used with access:");
 95         System.err.println();
 96         System.err.println("stack         include stack trace");
 97         System.err.println("domain        dump all domains in context");
 98         System.err.println("failure       before throwing exception, dump stack");
 99         System.err.println("              and domain that didn't have permission");
100         System.err.println();
101         System.err.println("The following can be used with stack and domain:");
102         System.err.println();
103         System.err.println("permission=<classname>");
104         System.err.println("              only dump output if specified permission");
105         System.err.println("              is being checked");
106         System.err.println("codebase=<URL>");
107         System.err.println("              only dump output if specified codebase");
108         System.err.println("              is being checked");
109         System.err.println();
110         System.err.println("The following can be used with provider:");
111         System.err.println();
112         System.err.println("engine=<engines>");
113         System.err.println("              only dump output for the specified list");
114         System.err.println("              of JCA engines. Supported values:");
115         System.err.println("              Cipher, KeyAgreement, KeyGenerator,");
116         System.err.println("              KeyPairGenerator, KeyStore, Mac,");
117         System.err.println("              MessageDigest, SecureRandom, Signature.");
118         System.err.println();
119         System.err.println("The following can be used with certpath:");
120         System.err.println();
121         System.err.println("ocsp          dump the OCSP protocol exchanges");
122         System.err.println("verbose       verbose debugging");
123         System.err.println();
124         System.err.println("Note: Separate multiple options with a comma");
125         System.exit(0);
126     }
127 
128 
129     /**
130      * Get a Debug object corresponding to whether or not the given
131      * option is set. Set the prefix to be the same as option.
132      */
133 
134     public static Debug getInstance(String option)
135     {
136         return getInstance(option, option);
137     }
138 
139     /**
140      * Get a Debug object corresponding to whether or not the given
141      * option is set. Set the prefix to be prefix.
142      */
143     public static Debug getInstance(String option, String prefix)
144     {
145         if (isOn(option)) {
146             Debug d = new Debug();
147             d.prefix = prefix;
148             return d;
149         } else {
150             return null;
151         }
152     }
153 
154     /**
155      * True if the system property "security.debug" contains the
156      * string "option".
157      */
158     public static boolean isOn(String option)
159     {
160         if (args == null)
161             return false;
162         else {
163             if (args.indexOf("all") != -1)
164                 return true;
165             else
166                 return (args.indexOf(option) != -1);
167         }
168     }
169 
170     /**
171      * Check if verbose messages is enabled for extra debugging.
172      */
173     public static boolean isVerbose() {
174         return isOn("verbose");
175     }
176 
177     /**
178      * print a message to stderr that is prefixed with the prefix
179      * created from the call to getInstance.
180      */
181 
182     public void println(String message)
183     {
184         System.err.println(prefix + ": "+message);
185     }
186 
187     /**
188      * print a message to stderr that is prefixed with the prefix
189      * created from the call to getInstance and obj.
190      */
191     public void println(Object obj, String message)
192     {
193         System.err.println(prefix + " [" + obj.getClass().getSimpleName() +
194                 "@" + System.identityHashCode(obj) + "]: "+message);
195     }
196 
197     /**
198      * print a blank line to stderr that is prefixed with the prefix.
199      */
200 
201     public void println()
202     {
203         System.err.println(prefix + ":");
204     }
205 
206     /**
207      * print a message to stderr that is prefixed with the prefix.
208      */
209 
210     public static void println(String prefix, String message)
211     {
212         System.err.println(prefix + ": "+message);
213     }
214 
215     /**
216      * PrintStream for debug methods. Currently only System.err is supported.
217      */
218     public PrintStream getPrintStream() {
219         return System.err;
220     }
221 
222     /**
223      * return a hexadecimal printed representation of the specified
224      * BigInteger object. the value is formatted to fit on lines of
225      * at least 75 characters, with embedded newlines. Words are
226      * separated for readability, with eight words (32 bytes) per line.
227      */
228     public static String toHexString(BigInteger b) {
229         String hexValue = b.toString(16);
230         StringBuilder sb = new StringBuilder(hexValue.length()*2);
231 
232         if (hexValue.startsWith("-")) {
233             sb.append("   -");
234             hexValue = hexValue.substring(1);
235         } else {
236             sb.append("    ");     // four spaces
237         }
238         if ((hexValue.length()%2) != 0) {
239             // add back the leading 0
240             hexValue = "0" + hexValue;
241         }
242         int i=0;
243         while (i < hexValue.length()) {
244             // one byte at a time
245             sb.append(hexValue.substring(i, i + 2));
246             i+=2;
247             if (i!= hexValue.length()) {
248                 if ((i%64) == 0) {
249                     sb.append("\n    ");     // line after eight words
250                 } else if (i%8 == 0) {
251                     sb.append(" ");     // space between words
252                 }
253             }
254         }
255         return sb.toString();
256     }
257 
258     /**
259      * change a string into lower case except permission classes and URLs.
260      */
261     private static String marshal(String args) {
262         if (args != null) {
263             StringBuilder target = new StringBuilder();
264             StringBuffer source = new StringBuffer(args);
265 
266             // obtain the "permission=<classname>" options
267             // the syntax of classname: IDENTIFIER.IDENTIFIER
268             // the regular express to match a class name:
269             // "[a-zA-Z_$][a-zA-Z0-9_$]*([.][a-zA-Z_$][a-zA-Z0-9_$]*)*"
270             String keyReg = "[Pp][Ee][Rr][Mm][Ii][Ss][Ss][Ii][Oo][Nn]=";
271             String keyStr = "permission=";
272             String reg = keyReg +
273                 "[a-zA-Z_$][a-zA-Z0-9_$]*([.][a-zA-Z_$][a-zA-Z0-9_$]*)*";
274             Pattern pattern = Pattern.compile(reg);
275             Matcher matcher = pattern.matcher(source);
276             StringBuffer left = new StringBuffer();
277             while (matcher.find()) {
278                 String matched = matcher.group();
279                 target.append(matched.replaceFirst(keyReg, keyStr));
280                 target.append("  ");
281 
282                 // delete the matched sequence
283                 matcher.appendReplacement(left, "");
284             }
285             matcher.appendTail(left);
286             source = left;
287 
288             // obtain the "codebase=<URL>" options
289             // the syntax of URL is too flexible, and here assumes that the
290             // URL contains no space, comma(','), and semicolon(';'). That
291             // also means those characters also could be used as separator
292             // after codebase option.
293             // However, the assumption is incorrect in some special situation
294             // when the URL contains comma or semicolon
295             keyReg = "[Cc][Oo][Dd][Ee][Bb][Aa][Ss][Ee]=";
296             keyStr = "codebase=";
297             reg = keyReg + "[^, ;]*";
298             pattern = Pattern.compile(reg);
299             matcher = pattern.matcher(source);
300             left = new StringBuffer();
301             while (matcher.find()) {
302                 String matched = matcher.group();
303                 target.append(matched.replaceFirst(keyReg, keyStr));
304                 target.append("  ");
305 
306                 // delete the matched sequence
307                 matcher.appendReplacement(left, "");
308             }
309             matcher.appendTail(left);
310             source = left;
311 
312             // convert the rest to lower-case characters
313             target.append(source.toString().toLowerCase(Locale.ENGLISH));
314 
315             return target.toString();
316         }
317 
318         return null;
319     }
320 
321     private static final char[] hexDigits = "0123456789abcdef".toCharArray();
322 
323     public static String toString(byte[] b) {
324         if (b == null) {
325             return "(null)";
326         }
327         StringBuilder sb = new StringBuilder(b.length * 3);
328         for (int i = 0; i < b.length; i++) {
329             int k = b[i] & 0xff;
330             if (i != 0) {
331                 sb.append(':');
332             }
333             sb.append(hexDigits[k >>> 4]);
334             sb.append(hexDigits[k & 0xf]);
335         }
336         return sb.toString();
337     }
338 
339 }