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