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