javasecuritymanagerjavapolicy

Which permission to set, to avoid error with Security-Manager with https-URLS?


In a software for a customer we have to read given URLs to parse their content. Also the customer needs to activate Tomcat-Security-Manager to let Java-Policies control what the program does.

Now, with reading URLs the exception "javax.net.ssl.SSLKeyException: RSA premaster secret error" happens, but only under certain conditions:

The Security-violation happens somewhere in Java-Code, an AllPermission restricted to our codebase doesn't prevent the error.

So, does someone has an idea, which permission to set for Java 6, so that it can process HTTPS?

Other information: It's running inside a tomcat, on a Debian-Linux with OpenJDK.

EDIT: I added the Java-Param "-Djava.security.debug=access,failure" to Tomcats /etc/default/tomcat6 in the variable JAVA_OPTS. But in the Logs I have no additional messages. Might it be possible the code asks the permissions before triggering them?

EDIT2: I found the correct place and got the full stacktrace (removed specific customer parts):

javax.net.ssl.SSLKeyException: RSA premaster secret error

            at [...]
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at java.lang.Thread.run(Thread.java:701)
    Caused by: java.security.NoSuchAlgorithmException: SunTlsRsaPremasterSecret KeyGenerator not available
            at javax.crypto.KeyGenerator.<init>(KeyGenerator.java:141)
            at javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:191)
            ... 14 more

EDIT3: So far I was under the assumption that the Java-class URL was used to access the contents of the resource. But that is untrue. It is using from Grails-Code the Groovy-URL-object with the getText()-method:

new URL(params.url).text

The error is happening on this line. It's Grails-version 2.2.4.


Solution

  • Solution following several comments and OP confirmation of resolution (summary)

    The root cause is the presence of sunjce_provider.jar in multiple locations. This was discovered by the OP after it was suggested as one of a number of possible root causes (see the very end of this answer and the comment trail). As per OP's comment:

    I have the sunjce_provider.jar in multiple directories. I tried to give all three locations for Java 6 the rights, although clearly only one is JAVA_HOME - and it worked. Somehow one of the other locations is used, although it isn't in the java.ext.dirs-property

    Therefore the resolution in this case was to ensure that the app had rights to access the correct copy of sunjce_provider.jar

    I've left the main points from my original answer and the comments that helped with diagnosis below for anyone who finds this later

    Original answer and comments that led to solution

    1. This will not happen with http because your web app (that is the client for this connection, even though it's running in tomcat), does not need to generate a key in this configuration.

    2. The fact it only occurs when SecurityManager is enabled, but not if disabled or with global AllPermission suggests its a file permission error. It suggests that it is not a problem with the key length (e.g. the one mentioned here)

    Other similar reports on the web indicate that the likely root cause is a missing jar (usually sunjce_provider.jar is cited). The stack trace confirms that the root cause exception is a NoSuchAlgorithmException where the KeyGenerator is looking for algorithm SunTlsRsaPremasterSecret and can't find it. In your case, as this only occurs with a particular SecurityManager configuration, it could be an inaccessible jar (due to security permissions).

    My guess would be that you have not enabled grant codeBase permissions to the correct directory that contains the jar needed for your RSA keygen algorithm. My suggested course of action would be to go through your webapp and JRE directory structure to find where runtime jars are kept and ensure that they have permissions granted in catalina.policy.

    In the default configuration - for instance - you should see somewhere

    // These permissions apply to all shared system extensions
    grant codeBase "file:${java.home}/jre/lib/ext/-" {
            permission java.security.AllPermission;
    };
    

    For details of what this means exactly see this section of the tomcat security manager "How To". You need to check a few things - make sure that ${java.home}/jre/lib/ext/ is where your runtime jars are. If not - alter the path to point to the right place (it is where they are on my version of OpenJDK 6 - build 27). In particular you should see sunjce_provider.jar and sunpkcs11.jar in there. Make sure the above section exists in your policy file.

    It may be that the code is depending on some jars that are within your webapp - e.g. in ${catalina.base}/path/to/your/webapp/WEB-INF/classes/ - in which case you need to grant permissions to that directory.


    Other problems that cause same or similar symptoms

    1. The app being unable to find or accesssunpkcs11.jar will give the same error message (verified on Ubuntu+openjdk6+tomcat6 system). It is likely that duplicate copies of that jar will, too.

    2. check /etc/java-6-openjdk/security/java.security. It should list providers in there - check there's a line something like security.provider.n = sun.security.pkcs11.SunPKCS11 in there - if that line is missing you also get this error (verified on same system)

    3. This Debian bug report talks about problems with the location of jars when running under a SecurityManager


    Debugging comment

    As per the other answer, you might try adding -Djava.security.debug=access,failure to CATALINA_OPTS or JAVA_OPTS in your catalina.sh to enable debugging - which should log to catalina.out by default (or wherever you have set your logging to via CATALINA_OUT in catalina.sh. You should see output from the SecurityManager there.

    You can also try -Djava.security.debug=all. You will get a huge catalina.out`, but you can grep for words that might help (like "fail"!!!)


    Follow the code from the stack trace

    Your exception is being thrown here. Looking at how that exception could be thrown - this method must return null. It swallows Exceptions - which isn't nice and makes it hard to diagnose exactly which part of that code is failing. My money would be on this line - where canUseProvider() might return false. This all points back to the provider jar being incaccessible for some reason.

    I'm assuming you didn't see any access violations in the output, even with -Djava.security.debug=access,failure. You could try -Djava.security.debug=all, although that may well simply produce more irrelevant logging. If there is no access violation, you may have two versions of that jar on your classpath somehow and the runtime is accessing (or trying to access the wrong one). A case similar to this is described in this Q/A.