summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2011-09-23 13:17:36 +0200
committerSven Gothel <[email protected]>2011-09-23 13:17:36 +0200
commit9da5bc1fe999caa924bd8dceafeff93ddf9d16a0 (patch)
tree54a0206d47b03d1d914bb55707b52b2cabd829b5
parent675ea2c9ee6308d439b2429d0863a634ba673eff (diff)
TempJarCache/JNILibLoaderBase: Validate the to be loader JarFile's Certificates if caller has any. Add Convenient JNILibLoaderBase.addNativeJarLibs(..) method.
-rw-r--r--src/java/com/jogamp/common/jvm/JNILibLoaderBase.java30
-rw-r--r--src/java/com/jogamp/common/os/Platform.java25
-rw-r--r--src/java/com/jogamp/common/util/JarUtil.java80
-rw-r--r--src/java/com/jogamp/common/util/cache/TempJarCache.java61
-rw-r--r--src/junit/com/jogamp/common/util/TestTempJarCache.java21
5 files changed, 158 insertions, 59 deletions
diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
index 44cbd14..bb0860a 100644
--- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
+++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
@@ -39,12 +39,17 @@
package com.jogamp.common.jvm;
+import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.net.URL;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.util.HashSet;
+import java.util.jar.JarFile;
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.JarUtil;
import com.jogamp.common.util.cache.TempJarCache;
import jogamp.common.Debug;
@@ -135,6 +140,31 @@ public class JNILibLoaderBase {
loaderAction = action;
}
+ public static final boolean addNativeJarLibs(Class<?> classFromJavaJar, String nativeJarBaseName) {
+ if(TempJarCache.isInitialized()) {
+ final String nativeJarName = nativeJarBaseName+"-natives-"+Platform.getOSAndArch()+".jar";
+ final ClassLoader cl = classFromJavaJar.getClassLoader();
+ try {
+ URL jarUrlRoot = JarUtil.getJarURLDirname( JarUtil.getJarURL( classFromJavaJar.getName(), cl ) );
+ if(DEBUG) {
+ System.err.println("addNativeJarLibs: "+nativeJarBaseName+": url-root "+jarUrlRoot);
+ }
+ URL nativeJarURL = JarUtil.getJarURL(jarUrlRoot, nativeJarName);
+ if(DEBUG) {
+ System.err.println("addNativeJarLibs: "+nativeJarBaseName+": nativeJarURL "+nativeJarURL);
+ }
+ JarFile nativeJar = JarUtil.getJarFile(nativeJarURL, cl);
+ if(DEBUG) {
+ System.err.println("addNativeJarLibs: "+nativeJarBaseName+": nativeJar "+nativeJar.getName());
+ }
+ return TempJarCache.addNativeLibs(classFromJavaJar, nativeJar);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+ return false;
+ }
+
protected static synchronized boolean loadLibrary(String libname, boolean ignoreError) {
if (loaderAction != null) {
return loaderAction.loadLibrary(libname, ignoreError);
diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java
index 3627513..38635e1 100644
--- a/src/java/com/jogamp/common/os/Platform.java
+++ b/src/java/com/jogamp/common/os/Platform.java
@@ -285,22 +285,19 @@ public class Platform {
public Object run() {
if(TempJarCache.initSingleton()) {
try {
- URL jarUrlRoot = JarUtil.getJarURLDirname(
+ final URL jarUrlRoot = JarUtil.getJarURLDirname(
JarUtil.getJarURL(Platform.class.getName(), cl) );
- System.err.println("gluegen-rt: url-root "+jarUrlRoot);
- URL nativeJarURL = JarUtil.getJarURL(jarUrlRoot, nativeJarName);
- System.err.println("gluegen-rt: nativeJarURL "+nativeJarURL);
- JarFile nativeJar = JarUtil.getJarFile(nativeJarURL, cl);
- System.err.println("gluegen-rt: nativeJar "+nativeJar.getName());
- TempJarCache.bootstrapNativeLib(libBaseName, nativeJar);
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- DynamicLibraryBundle.GlueJNILibLoader.loadLibrary(libBaseName, false);
- return null;
+ final URL nativeJarURL = JarUtil.getJarURL(jarUrlRoot, nativeJarName);
+ final JarFile nativeJar = JarUtil.getJarFile(nativeJarURL, cl);
+ TempJarCache.bootstrapNativeLib(Platform.class, libBaseName, nativeJar);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
}
- });
+ }
+ DynamicLibraryBundle.GlueJNILibLoader.loadLibrary(libBaseName, false);
+ return null;
+ }
+ });
}
/**
diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java
index 3cbd555..4f46ca8 100644
--- a/src/java/com/jogamp/common/util/JarUtil.java
+++ b/src/java/com/jogamp/common/util/JarUtil.java
@@ -55,6 +55,27 @@ public class JarUtil {
/**
* @param clazzBinName com.jogamp.common.util.cache.TempJarCache
* @param cl
+ * @return gluegen-rt.jar
+ * @throws IOException
+ * @see {@link IOUtil#getClassURL(String, ClassLoader)}
+ */
+ public static String getJarName(String clazzBinName, ClassLoader cl) throws IOException {
+ URL url = IOUtil.getClassURL(clazzBinName, cl);
+ if(null != url) {
+ String urlS = url.toExternalForm();
+ // from
+ // jar:file:/usr/local/projects/JOGL/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/util/cache/TempJarCache.class
+ // to
+ // gluegen-rt.jar
+ urlS = urlS.substring(0, urlS.lastIndexOf('!')); // exclude !/
+ return urlS.substring(urlS.lastIndexOf('/')+1); // just the jar name
+ }
+ return null;
+ }
+
+ /**
+ * @param clazzBinName com.jogamp.common.util.cache.TempJarCache
+ * @param cl
* @return jar:file:/usr/local/projects/JOGL/gluegen/build-x86_64/gluegen-rt.jar!/
* @throws IOException
* @see {@link IOUtil#getClassURL(String, ClassLoader)}
@@ -195,11 +216,11 @@ public class JarUtil {
* @return
* @throws IOException
*/
- public static int extract(File dest, Map<String, String> nativeLibMap,
- JarFile jarFile,
- boolean extractNativeLibraries,
- boolean extractClassFiles,
- boolean extractOtherFiles) throws IOException {
+ public static final int extract(File dest, Map<String, String> nativeLibMap,
+ JarFile jarFile,
+ boolean extractNativeLibraries,
+ boolean extractClassFiles,
+ boolean extractOtherFiles) throws IOException {
if (VERBOSE) {
System.err.println("extract: "+jarFile.getName()+" -> "+dest+
@@ -280,30 +301,25 @@ public class JarUtil {
* Validate the certificates for each native Lib in the jar file.
* Throws an IOException if any certificate is not valid.
* <pre>
- Certificate[] appletLauncherCerts = Something.class.getProtectionDomain().
- getCodeSource().getCertificates();
+ Certificate[] rootCerts = Something.class.getProtectionDomain().
+ getCodeSource().getCertificates();
</pre>
*/
- public static void validateCertificates(Certificate[] appletLauncherCerts, JarFile jarFile)
- throws IOException {
+ public static final void validateCertificates(Certificate[] rootCerts, JarFile jarFile)
+ throws IOException, SecurityException {
if (VERBOSE) {
- System.err.println("validateCertificates:");
+ System.err.println("validateCertificates: "+jarFile.getName());
+ }
+
+ if (rootCerts == null || rootCerts.length == 0) {
+ throw new IllegalArgumentException("Null certificates passed");
}
- byte[] buf = new byte[1000];
+ byte[] buf = new byte[1024];
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
- JarEntry entry = (JarEntry) entries.nextElement();
- String entryName = entry.getName();
-
- if (VERBOSE) {
- System.err.println("Validate JarEntry : " + entryName);
- }
-
- if (!checkNativeCertificates(appletLauncherCerts, jarFile, entry, buf)) {
- throw new IOException("Cannot validate certificate for " + entryName);
- }
+ validateCertificate(rootCerts, jarFile, entries.nextElement(), buf);
}
}
@@ -311,8 +327,12 @@ public class JarUtil {
* Check the certificates with the ones in the jar file
* (all must match).
*/
- private static boolean checkNativeCertificates(Certificate[] launchedCerts,
- JarFile jar, JarEntry entry, byte[] buf) throws IOException {
+ private static final void validateCertificate(Certificate[] rootCerts,
+ JarFile jar, JarEntry entry, byte[] buf) throws IOException, SecurityException {
+
+ if (VERBOSE) {
+ System.err.println("Validate JarEntry : " + entry.getName());
+ }
// API states that we must read all of the data from the entry's
// InputStream in order to be able to get its certificates
@@ -321,25 +341,23 @@ public class JarUtil {
while (is.read(buf) > 0) { }
is.close();
- if (launchedCerts == null || launchedCerts.length == 0) {
- throw new RuntimeException("Null certificates passed");
- }
-
// Get the certificates for the JAR entry
Certificate[] nativeCerts = entry.getCertificates();
if (nativeCerts == null || nativeCerts.length == 0) {
- return false;
+ throw new SecurityException("no certificate for " + entry.getName() + " in " + jar.getName());
}
int checked = 0;
- for (int i = 0; i < launchedCerts.length; i++) {
+ for (int i = 0; i < rootCerts.length; i++) {
for (int j = 0; j < nativeCerts.length; j++) {
- if (nativeCerts[j].equals(launchedCerts[i])){
+ if (nativeCerts[j].equals(rootCerts[i])){
checked++;
break;
}
}
}
- return (checked == launchedCerts.length);
+ if( checked != rootCerts.length ) {
+ throw new SecurityException("not all certificates match, only "+checked+" out of "+rootCerts.length+" for " + entry.getName() + " in " + jar.getName());
+ }
}
}
diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java
index dcc6651..7e90f7d 100644
--- a/src/java/com/jogamp/common/util/cache/TempJarCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java
@@ -34,6 +34,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.security.cert.Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -120,13 +121,17 @@ public class TempJarCache {
/**
* Adds native libraries, if not yet added.
*
+ * @param certClass if class is certified, the JarFile entries needs to have the same certificate
* @param jarFile
+ *
* @return
* @throws IOException
+ * @throws SecurityException
*/
- public static boolean addNativeLibs(JarFile jarFile) throws IOException {
+ public static final boolean addNativeLibs(Class<?> certClass, JarFile jarFile) throws IOException, SecurityException {
checkInitialized();
if(!nativeLibJars.contains(jarFile)) {
+ validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile,
true, false, false);
nativeLibJars.add(jarFile);
@@ -140,14 +145,18 @@ public class TempJarCache {
*
* TODO class access pending
* needs Classloader.defineClass(..) access, ie. own derivation - will do when needed ..
- *
+ *
+ * @param certClass if class is certified, the JarFile entries needs to have the same certificate
* @param jarFile
+ *
* @return
* @throws IOException
+ * @throws SecurityException
*/
- public static boolean addClasses(JarFile jarFile) throws IOException {
+ public static final boolean addClasses(Class<?> certClass, JarFile jarFile) throws IOException, SecurityException {
checkInitialized();
if(!classFileJars.contains(jarFile)) {
+ validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile,
false, true, false);
classFileJars.add(jarFile);
@@ -159,13 +168,17 @@ public class TempJarCache {
/**
* Adds native resources, if not yet added.
*
+ * @param certClass if class is certified, the JarFile entries needs to have the same certificate
* @param jarFile
+ *
* @return
* @throws IOException
+ * @throws SecurityException
*/
- public static boolean addResources(JarFile jarFile) throws IOException {
+ public static final boolean addResources(Class<?> certClass, JarFile jarFile) throws IOException, SecurityException {
checkInitialized();
if(!resourceFileJars.contains(jarFile)) {
+ validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile,
false, false, true);
resourceFileJars.add(jarFile);
@@ -180,12 +193,15 @@ public class TempJarCache {
*
* TODO class access pending
* needs Classloader.defineClass(..) access, ie. own derivation - will do when needed ..
- *
+ *
+ * @param certClass if class is certified, the JarFile entries needs to have the same certificate
* @param jarFile
+ *
* @return
* @throws IOException
+ * @throws SecurityException
*/
- public static boolean addAll(JarFile jarFile) throws IOException {
+ public static final boolean addAll(Class<?> certClass, JarFile jarFile) throws IOException, SecurityException {
checkInitialized();
if(!nativeLibJars.contains(jarFile) ||
!classFileJars.contains(jarFile) ||
@@ -193,6 +209,7 @@ public class TempJarCache {
final boolean extractNativeLibraries = !nativeLibJars.contains(jarFile);
final boolean extractClassFiles = !classFileJars.contains(jarFile);
final boolean extractOtherFiles = !resourceFileJars.contains(jarFile);
+ validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile,
extractNativeLibraries, extractClassFiles, extractOtherFiles);
if(extractNativeLibraries) {
@@ -209,7 +226,7 @@ public class TempJarCache {
return false;
}
- public static String findLibrary(String libName) {
+ public static final String findLibrary(String libName) {
checkInitialized();
// try with mapped library basename first
String path = nativeLibMap.get(libName);
@@ -240,7 +257,7 @@ public class TempJarCache {
return null;
} */
- public static String findResource(String name) {
+ public static final String findResource(String name) {
checkInitialized();
final File f = new File(tmpFileCache.getTempDir(), name);
if(f.exists()) {
@@ -252,12 +269,19 @@ public class TempJarCache {
/**
* Bootstrapping version extracting the JAR files root entry containing libBaseName,
* assuming it's a native library. This is used to get the 'gluegen-rt'
- * native library, hence bootstrapping.
+ * native library, hence bootstrapping.
+ *
+ * @param certClass if class is certified, the JarFile entries needs to have the same certificate
+ *
+ * @throws IOException
+ * @throws SecurityException
*/
- public static boolean bootstrapNativeLib(String libBaseName, JarFile jarFile) throws IOException {
+ public static final boolean bootstrapNativeLib(Class<?> certClass, String libBaseName, JarFile jarFile)
+ throws IOException, SecurityException {
checkInitialized();
if(!nativeLibJars.contains(jarFile) && !nativeLibMap.containsKey(libBaseName) ) {
- final Enumeration<JarEntry> entries = jarFile.entries();
+ validateCertificates(certClass, jarFile);
+ final Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
final JarEntry entry = (JarEntry) entries.nextElement();
final String entryName = entry.getName();
@@ -289,4 +313,19 @@ public class TempJarCache {
}
return false;
}
+
+ private static void validateCertificates(Class<?> certClass, JarFile jarFile) throws IOException, SecurityException {
+ if(null == certClass) {
+ throw new IllegalArgumentException("certClass is null");
+ }
+ final Certificate[] rootCerts =
+ certClass.getProtectionDomain().getCodeSource().getCertificates();
+ if( null != rootCerts && rootCerts.length>0 ) {
+ // Only validate the jarFile's certs with ours, if we have any.
+ // Otherwise we may run uncertified JARs (application).
+ // In case one tries to run uncertified JARs, the wrapping applet/JNLP
+ // SecurityManager will kick in and throw a SecurityException.
+ JarUtil.validateCertificates(rootCerts, jarFile);
+ }
+ }
}
diff --git a/src/junit/com/jogamp/common/util/TestTempJarCache.java b/src/junit/com/jogamp/common/util/TestTempJarCache.java
index fca839b..e1e47af 100644
--- a/src/junit/com/jogamp/common/util/TestTempJarCache.java
+++ b/src/junit/com/jogamp/common/util/TestTempJarCache.java
@@ -41,6 +41,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.jvm.JNILibLoaderBase;
import com.jogamp.common.os.NativeLibrary;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.cache.TempCacheReg;
@@ -161,7 +162,7 @@ public class TestTempJarCache {
Assert.assertTrue(TempCacheReg.isTempJarCacheUsed());
Assert.assertTrue(TempJarCache.isInitialized());
- TempJarCache.addAll(JarUtil.getJarFile(GlueGenVersion.class.getName(), getClass().getClassLoader()));
+ TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFile(GlueGenVersion.class.getName(), getClass().getClassLoader()));
File f0 = new File(TempJarCache.getTempFileCache().getTempDir(), "META-INF/MANIFEST.MF");
Assert.assertTrue(f0.exists());
@@ -179,7 +180,7 @@ public class TestTempJarCache {
}
@Test
- public void testTempJarCache02LoadNativeLibrary() throws IOException {
+ public void testTempJarCache02AddNativeLibs() throws IOException {
final String nativeJarName = "gluegen-rt-natives-"+Platform.getOSAndArch()+".jar";
final String libBaseName = "gluegen-rt";
final ClassLoader cl = getClass().getClassLoader();
@@ -190,7 +191,21 @@ public class TestTempJarCache {
URL nativeJarURL = JarUtil.getJarURL(jarUrlRoot, nativeJarName);
JarFile nativeJar = JarUtil.getJarFile(nativeJarURL, cl);
- TempJarCache.addNativeLibs(nativeJar);
+ TempJarCache.addNativeLibs(TempJarCache.class, nativeJar);
+ String libFullPath = TempJarCache.findLibrary(libBaseName);
+ Assert.assertNotNull(libFullPath);
+ Assert.assertEquals(libBaseName, NativeLibrary.isValidNativeLibraryName(libFullPath, true));
+ File f = new File(libFullPath);
+ Assert.assertTrue(f.exists());
+ }
+
+ @Test
+ public void testTempJarCache03AddNativeJarLibs() throws IOException {
+ final String libBaseName = "gluegen-rt";
+
+ JNILibLoaderBase.addNativeJarLibs(TempJarCache.class, libBaseName);
+ Assert.assertTrue(JNILibLoaderBase.isLoaded(libBaseName));
+
String libFullPath = TempJarCache.findLibrary(libBaseName);
Assert.assertNotNull(libFullPath);
Assert.assertEquals(libBaseName, NativeLibrary.isValidNativeLibraryName(libFullPath, true));