The Supreme Goodness, Water-Like Andrew Fan's Weblog

星期五 十一月 10, 2006

You're supposed  to familiar with the java.security.debug property, otherwise please refer to the sample chapter of "Java Security".

Before Java 6, if the security debug property, java.security.debug, is enabled, a large volume of debug output will be dumped. For example, if  java.security.debug deinfed as access:stack, every stack will be dumped if a permission is checked on. Even for a simple application, the output normally runs over several pages. In server products, such as Sun Web Server and App Server, the amount of output is overwhelming, analysis them manually  is a nightmare. So customers often give up in frustration while trying to follow it to diagnose problems.

Things get changed at Java 6, the java security packages introduced two new java.security.debug options, permission and codebase. Let's have a look at the help message of security debugger.

    $ java -Djava.security.debug=help Foo

all turn on all debugging
access print all checkPermission results
combiner SubjectDomainCombiner debugging
gssloginconfig
GSS LoginConfigImpl debugging
jar jar verification
logincontext login context results
policy loading and granting
provider security provider debugging
scl permissions SecureClassLoader assigns

The following can be used with access:

stack include stack trace
domain dump all domains in context
failure before throwing exception, dump stack
and domain that didn't have permission

The following can be used with stack and domain:

permission.<classname>
only dump output if specified permission
is being checked
codebase.<URL>
only dump output if specified codebase
is being checked

Note: Separate multiple options with a comma


 Note that there's a bug on the help message that "permission.<classname>" should be "permission=<classname>", and "codebase.<URL>" should be "codebase=<URL>". And in the two options, spaces are not allowed before and after the sign "=".

Let's show the two options with a sample class, Foo.

// Sample class to illustrate debug options

import java.io.FileInputStream;
import java.io.ObjectInputStream;


public class Foo {
public static void main(String[] args) throws Exception {
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream("./foo.obj");
ois = new ObjectInputStream(fis);
Object dummy = ois.readObject();
} finally {
if (ois != null) {
ois.close();
}
}
}
}


permission=<classname>:

permission=<classname> option is used with stack trace or domain option, when a certain classname is specified, the security debugger will only dump the stacks or the domain that checking the specified permission. Here, classname is the canonical class name of the specified permission, and the classname is case sensitive.

The option is particularly useful for customers who have their own permissions to take care of, or only care to follow the evaluation details of some certain permissions.

 For the above sample class, the Java security will check the following permissions on Foo.main():

  1. java.io.FilePermission (1 time)
  2. java.lang.RuntimePermission (1 time)
  3. java.lang.reflect.ReflectPermission (5 times)

Sometimes, users maybe only want to trace the stacks that checking java.io.FilePermission, or really do not want to care java.lang.reflect.ReflectPermission. Try to run the example and see what happened.

$ java -Djava.security.manager \
-Djava.security.debug=access,stack Foo

(The output omitted)

$ java -Djava.security.manager \
-Djava.security.debug=access,stack,permission=java.io.FilePermission Foo

java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1206)
at java.security.AccessController.checkPermission(AccessController.java:532)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
at java.io.File.isDirectory(File.java:752)
at sun.net.www.ParseUtil.fileToEncodedURL(ParseUtil.java:242)
at sun.security.provider.PolicyFile.canonicalizeCodebase(PolicyFile.java:1806)
at sun.security.provider.PolicyFile.access$700(PolicyFile.java:263)
at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1220)
at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1218)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1217)
at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1165)
at sun.security.provider.PolicyFile.implies(PolicyFile.java:1120)
at java.security.ProtectionDomain.implies(ProtectionDomain.java:213)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:301)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
at java.io.FileInputStream.<init>(FileInputStream.java:100)
at java.io.FileInputStream.<init>(FileInputStream.java:66)
at Foo.main(Foo.java:11)
access: access allowed (java.io.FilePermission /some/somedir read)

$ java -Djava.security.manager \
-Djava.security.debug="access,stack,permission=java.io.FilePermission \
permission=java.lang.RuntimePermission" Foo

(The output omitted)

codebase=<URL>:

codebase=<URL> option is used with stack trace or domain option, when a certain codebase is specified, the security debugger will only dump the stacks or the protection domain that from the specified code source defined by the codebase. Here, URL is the location of the specified code base. Note that because the comma (',") is used as multi options separator, if the URL contains comma, the security debugger would not work properly as expected, it is recommended that the URL should not include character comma (','), semicolon (';'), and  space.

This option would be useful when customer desires to trace the permissions impact of only the code in a given code souce, such as jar file.

星期一 三月 13, 2006

A KeyStore manages different types of entries, including cryptographic keys and certificates. Each entry in a keystore is identified by an "alias" string.

Before Java SE 6, the java spec didn't declare whether the alias should be case sesitive or not. As result in different implementation, as I known, Bouncy Castle Crypto package treats the keystore alias as case-sensitive data, while Sun and IBM providers regard it as case-insensitive for "JKS/JCEKS/PKCS12" keystore. However, with the support of PKCS11 key store, because of the PKCS#11 specification, the keystore alias is case sensitive for PKCS11 keystore.

In many documents, it is said that the keystore alias is case-insensitive. Which is not always true, it is also depend on the key store type except the keystore provider.

As a application, it used to use the default keystore provider and default keystore type. It is unfair or uncomfortable to identify the case sensitive property for a application if it want to rely on case-sensitive aliases.

At last, the current situation is: it is not certain that whether or not a keystore alias is case sensitive or not for different provider or different keystore.

Java SE 6 will delcare the situation in the key store specification: "Whether aliases are case sensitive is implementation dependent. In order to avoid problems, it is recommended not to use aliases in a KeyStore that only differ in case."

What should I do if I have no choice but case-sensitive keystore alias? There's a way, but no recommended. At and after Java SE 5.0 update 1 or java 1.4.2_07, there's a CaseExactJKS, which is basically JKS with case-sensitive aliases, not yet well documented.

    KeyStore ks;
    try {
        ks = Keystore.getInstance("CaseExactJKS");
    } catch (KeyStoreException e) {
        ks = KeyStore.getInstance("JKS");
    }

But, try to idependent from cases.