Difference between revisions of "JGridstart/Bouncycastle and Java Web start"

From PDP/Grid Wiki
Jump to navigationJump to search
m
(make workaround work with OpenJDK as well :))
Line 1: Line 1:
[http://www.bouncycastle.org/java.html BouncyCastle] is a cryptographic library for [http://java.sun.com/ Java] that complements and completes the default [http://java.sun.com/javase/technologies/security/ Java Cryptography Extension]. To use it as a provider (e.g. to to access a [http://java.sun.com/j2se/1.4.2/docs/api/java/security/KeyStore.html KeyStore] that is supported by BouncyCastle), one has to use the [http://en.wikipedia.org/wiki/JAR_%28file_format%29 JAR] file provided by them because that is signed by Sun (because of law-stuff). When creating a [http://java.sun.com/javase/technologies/desktop/javawebstart/ Java Web Start] application, the way to do this is by referencing to a bouncycastle JNLP file using the extension tag. For example the file app.jnlp:
+
[http://www.bouncycastle.org/java.html BouncyCastle] is a cryptographic library for [http://java.sun.com/ Java] that complements and completes the default [http://java.sun.com/javase/technologies/security/ Java Cryptography Extension]. To use it as a provider (e.g. to to access a [http://java.sun.com/j2se/1.4.2/docs/api/java/security/KeyStore.html KeyStore] that is supported by BouncyCastle), one has to use the [http://en.wikipedia.org/wiki/JAR_%28file_format%29 JAR] file provided by them because that is signed by Sun (because of law-stuff). When creating a [http://java.sun.com/javase/technologies/desktop/javawebstart/ Java Web Start] application, the way to do this is by referencing to a bouncycastle JNLP file using the extension tag. For example the file <tt>app.jnlp</tt>:
  
 
  <?xml version="1.0" encoding="utf-8"?>
 
  <?xml version="1.0" encoding="utf-8"?>
Line 19: Line 19:
 
   </jnlp>
 
   </jnlp>
  
References the file bcprov.jnlp which describes the BouncyCastle extension. This can not be put in the application's JNLP because all JARs in a single JNLP file need to be signed by the same key. The file bcprov.jnlp can contain:
+
References the file bcprov.jnlp which describes the BouncyCastle extension. This can not be put in the application's JNLP because all JARs in a single JNLP file need to be signed by the same key. The file <tt>bcprov.jnlp</tt> can contain:
  
 
   <?xml version="1.0" encoding="UTF-8"?>
 
   <?xml version="1.0" encoding="UTF-8"?>
Line 41: Line 41:
 
Now when the Java Web Start application is run, the user has to accept a warning dialog twice: one for the application itself, and one for the BouncyCastle extension. This is a little troublesome, since the user doesn't care about the extension; if he has just consented to grant the application access why does it ask for it again?
 
Now when the Java Web Start application is run, the user has to accept a warning dialog twice: one for the application itself, and one for the BouncyCastle extension. This is a little troublesome, since the user doesn't care about the extension; if he has just consented to grant the application access why does it ask for it again?
  
==Workaround: one warning dialog only==
+
==Workaround: one warning dialog only (Sun JRE)==
 
'''Note that this workaround appears to work only for Sun Java, not for OpenJDK.'''
 
'''Note that this workaround appears to work only for Sun Java, not for OpenJDK.'''
  
 
The security warning for the BouncyCastle extension (the second warning) can be avoided if one uses a policy file in the application. This policy file explicitely grants access to certain operations, and these operations can be BouncyCastle's as well. So we get the following files
 
The security warning for the BouncyCastle extension (the second warning) can be avoided if one uses a policy file in the application. This policy file explicitely grants access to certain operations, and these operations can be BouncyCastle's as well. So we get the following files
  
app.jnlp (note the new property tag):
+
<tt>app.jnlp</tt> (note the new property tag):
 
  <?xml version="1.0" encoding="utf-8"?>
 
  <?xml version="1.0" encoding="utf-8"?>
 
  <jnlp spec="1.0+" href="app.jnlp" codebase="http://somewhere/">
 
  <jnlp spec="1.0+" href="app.jnlp" codebase="http://somewhere/">
Line 66: Line 66:
 
   </jnlp>
 
   </jnlp>
  
bcprov.jnlp, now without any permissions (note the removed security section):
+
<tt>bcprov.jnlp</tt>, now without any permissions (note the removed security section):
 
   <?xml version="1.0" encoding="UTF-8"?>
 
   <?xml version="1.0" encoding="UTF-8"?>
 
   <jnlp spec="1.0+" codebase="http://somewhere/" href="bcprov.jnlp">
 
   <jnlp spec="1.0+" codebase="http://somewhere/" href="bcprov.jnlp">
Line 80: Line 80:
 
   </jnlp>
 
   </jnlp>
  
and a new bcprov.policy, which grants BouncyCastle its access:
+
and a new <tt>bcprov.policy</tt>, which grants BouncyCastle its access:
 
   grant {
 
   grant {
 
   // allow BouncyCastle to register itself
 
   // allow BouncyCastle to register itself
Line 91: Line 91:
 
Note that bcprov.policy is referenced using the full url, it is not located in the application's jar.
 
Note that bcprov.policy is referenced using the full url, it is not located in the application's jar.
  
This method avoids a second permission dialog for the BouncyCastle JAR using the Sun Java runtime environment. OpenJDK's runtime environment still requires <tt>all-permission</tt> in <tt>bcprov.jnlp</tt>'s security section, which triggers the second permission dialog. To make it work for both, one could use a server-side script to distinguish between the two using [[JGridstart/Java user agents|HTTP headers]] and serve a different <tt>bcprov.jnlp</tt> to each.
+
This method avoids a second permission dialog for the BouncyCastle JAR using the Sun Java runtime environment. OpenJDK's runtime environment still requires <tt>all-permissions</tt> in <tt>bcprov.jnlp</tt>'s security section, which triggers the second permission dialog. This is tackled in the next section.
 +
 
 +
==Full workaround: Sun & OpenJDK==
 +
While it is thus possible to avoid the BouncyCastle permission dialog for the Sun JRE, the OpenJDK JRE still requires <tt>all-permissions</tt>. So the Sun Java Web Start application needs to be served a different <tt>bcprov.jnlp</tt> than the OpenJDK Java Web Start application. Luckily, it ''is'' possible to distinguish between the two (altough more an accident that the developers' purpose) by looking at the [[JGridstart/Java_user_agents|HTTP request headers]]: when <tt>UA-Java-Version</tt> exists as a header, it is the Sun JRE; if not, it is the OpenJDK JRE.
 +
 
 +
With the widely used [http://httpd.apache.org/ Apache web server] it is possible to use its [http://httpd.apache.org/docs/2.2/rewrite/ mod_rewrite] to do this easily. One needs the <tt>app.jnlp</tt> as in the previous section (with the security policy), and the two species of <tt>bcprov.jnlp</tt>. Let's call the first version (with <tt>all-permissions</tt> in the security section) <tt>bcprov.policy</tt>, and the second version (without a security section) <tt>bcprov-sun.jnlp</tt> (don't forget to update its <tt>href</tt> accordingly). Now add the following to your <tt>.htaccess</tt> file:
 +
  RewriteEngine On
 +
  # you may need a RewriteBase directive here
 +
  RewriteCond %{HTTP:UA-Java-Version} !^$
 +
  RewriteRule bcprov.jnlp bcprov-sun.jnlp
 +
Now the OpenJDK JRE is served the file <tt>bcprov.jnlp</tt> just like without a <tt>.htaccess</tt>, and the Sun JRE is served <tt>bcprov-sun.jnlp</tt> when it requests <tt>bcprov.jnlp</tt>. So all are happy now!
  
 
----
 
----
 
''I have tested this only with <all-permissions/> in the security section. If you have experiences with <j2ee-permissions/> please notify me and I'll add it here.''
 
''I have tested this only with <all-permissions/> in the security section. If you have experiences with <j2ee-permissions/> please notify me and I'll add it here.''

Revision as of 13:07, 21 December 2009

BouncyCastle is a cryptographic library for Java that complements and completes the default Java Cryptography Extension. To use it as a provider (e.g. to to access a KeyStore that is supported by BouncyCastle), one has to use the JAR file provided by them because that is signed by Sun (because of law-stuff). When creating a Java Web Start application, the way to do this is by referencing to a bouncycastle JNLP file using the extension tag. For example the file app.jnlp:

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" href="app.jnlp" codebase="http://somewhere/">
  <information>
    <title>App</title>
    <vendor>Nikhef</vendor>
    <homepage href="http://somewhere/"/>
  </information>
  <security>
    <all-permissions/>
  </security>
  <resources>
   <j2se href="http://java.sun.com/products/autodl/j2se" version="1.3+"/>
   <jar href="app.jar"/>
   <extension name="BouncyCastle cryptography library" href="bcprov.jnlp"/>
  </resources>
  <application-desc main-class="app.Main"/>
 </jnlp>

References the file bcprov.jnlp which describes the BouncyCastle extension. This can not be put in the application's JNLP because all JARs in a single JNLP file need to be signed by the same key. The file bcprov.jnlp can contain:

 <?xml version="1.0" encoding="UTF-8"?>
 <jnlp spec="1.0+" codebase="http://somewhere/" href="bcprov.jnlp">
  <information>
   <title>bcprov-jdk14</title>
   <vendor>Sun Microsystems, Inc.</vendor>
   <offline-allowed/>
  </information>
  <security>
    <all-permissions/>
  </security>
  <resources>
   <jar href="bcprov-jdk14-142.jar"/>
  </resources>
  <component-desc/>
 </jnlp>

You see that this file also has the all-permissions tag in the security section. This is to allow the file to register itself as a cryptography provider.

Now when the Java Web Start application is run, the user has to accept a warning dialog twice: one for the application itself, and one for the BouncyCastle extension. This is a little troublesome, since the user doesn't care about the extension; if he has just consented to grant the application access why does it ask for it again?

Workaround: one warning dialog only (Sun JRE)

Note that this workaround appears to work only for Sun Java, not for OpenJDK.

The security warning for the BouncyCastle extension (the second warning) can be avoided if one uses a policy file in the application. This policy file explicitely grants access to certain operations, and these operations can be BouncyCastle's as well. So we get the following files

app.jnlp (note the new property tag):

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" href="app.jnlp" codebase="http://somewhere/">
  <information>
    <title>App</title>
    <vendor>Nikhef</vendor>
    <homepage href="http://somewhere/"/>
  </information>
  <security>
    <all-permissions/>
  </security>
  <resources>
   <j2se href="http://java.sun.com/products/autodl/j2se" version="1.3+"/>
   <jar href="app.jar"/>
   <extension name="BouncyCastle cryptography library" href="bcprov.jnlp"/>
   <property name="java.security.policy" value="http://somewhere/bcprov.policy"/>
  </resources>
  <application-desc main-class="app.Main"/>
 </jnlp>

bcprov.jnlp, now without any permissions (note the removed security section):

 <?xml version="1.0" encoding="UTF-8"?>
 <jnlp spec="1.0+" codebase="http://somewhere/" href="bcprov.jnlp">
  <information>
   <title>bcprov-jdk14</title>
   <vendor>Sun Microsystems, Inc.</vendor>
   <offline-allowed/>
  </information>
  <resources>
   <jar href="bcprov-jdk14-142.jar"/>
  </resources>
  <component-desc/>
 </jnlp>

and a new bcprov.policy, which grants BouncyCastle its access:

 grant {
  // allow BouncyCastle to register itself
  permission java.security.SecurityPermission "Security.insertProvider.BC";
  permission java.security.SecurityPermission "putProviderProperty.BC";
  // allow access to BouncyCastle properties
  permission java.util.PropertyPermission "org.bouncycastle.*","read";
 };

Note that bcprov.policy is referenced using the full url, it is not located in the application's jar.

This method avoids a second permission dialog for the BouncyCastle JAR using the Sun Java runtime environment. OpenJDK's runtime environment still requires all-permissions in bcprov.jnlp's security section, which triggers the second permission dialog. This is tackled in the next section.

Full workaround: Sun & OpenJDK

While it is thus possible to avoid the BouncyCastle permission dialog for the Sun JRE, the OpenJDK JRE still requires all-permissions. So the Sun Java Web Start application needs to be served a different bcprov.jnlp than the OpenJDK Java Web Start application. Luckily, it is possible to distinguish between the two (altough more an accident that the developers' purpose) by looking at the HTTP request headers: when UA-Java-Version exists as a header, it is the Sun JRE; if not, it is the OpenJDK JRE.

With the widely used Apache web server it is possible to use its mod_rewrite to do this easily. One needs the app.jnlp as in the previous section (with the security policy), and the two species of bcprov.jnlp. Let's call the first version (with all-permissions in the security section) bcprov.policy, and the second version (without a security section) bcprov-sun.jnlp (don't forget to update its href accordingly). Now add the following to your .htaccess file:

 RewriteEngine On
 # you may need a RewriteBase directive here
 RewriteCond %{HTTP:UA-Java-Version} !^$
 RewriteRule bcprov.jnlp bcprov-sun.jnlp

Now the OpenJDK JRE is served the file bcprov.jnlp just like without a .htaccess, and the Sun JRE is served bcprov-sun.jnlp when it requests bcprov.jnlp. So all are happy now!


I have tested this only with <all-permissions/> in the security section. If you have experiences with <j2ee-permissions/> please notify me and I'll add it here.