aboutsummaryrefslogtreecommitdiffstats
path: root/netx/net
diff options
context:
space:
mode:
authorDanesh Dadachanji <[email protected]>2012-10-22 11:02:38 -0400
committerDanesh Dadachanji <[email protected]>2012-10-22 11:02:38 -0400
commite150560769232e18fa516609933649dab002f358 (patch)
tree661e1b4d3c9d101447bc952e541e8f054c1d96be /netx/net
parent229e52bca7c9298d3a0889fe1bc6f9107b32639a (diff)
Major rework of JarCertVerifier certificate management.
This is a long-planned rework of JarCertVerifier, allowing it to handle multiple certificates. The algorithms used to verify jars with multiple certificates vary between JNLPs and Applets.
Diffstat (limited to 'netx/net')
-rw-r--r--netx/net/sourceforge/jnlp/resources/Messages.properties3
-rw-r--r--netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java135
-rw-r--r--netx/net/sourceforge/jnlp/security/AppVerifier.java91
-rw-r--r--netx/net/sourceforge/jnlp/security/CertVerifier.java30
-rw-r--r--netx/net/sourceforge/jnlp/security/CertWarningPane.java4
-rw-r--r--netx/net/sourceforge/jnlp/security/CertsInfoPane.java2
-rw-r--r--netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java28
-rw-r--r--netx/net/sourceforge/jnlp/security/JNLPAppVerifier.java143
-rw-r--r--netx/net/sourceforge/jnlp/security/MoreInfoPane.java4
-rw-r--r--netx/net/sourceforge/jnlp/security/PluginAppVerifier.java224
-rw-r--r--netx/net/sourceforge/jnlp/tools/CertInformation.java292
-rw-r--r--netx/net/sourceforge/jnlp/tools/JarCertVerifier.java650
12 files changed, 1198 insertions, 408 deletions
diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties
index 1f3a1e5..4010837 100644
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties
@@ -82,7 +82,7 @@ LSignedAppJarUsingUnsignedJar=Signed application using unsigned jars.
LSignedAppJarUsingUnsignedJarInfo=The main application jar is signed, but some of the jars it is using aren't.
LSignedJNLPFileDidNotMatch=The signed JNLP file did not match the launching JNLP file.
LNoSecInstance=Error: No security instance for {0}. The application may have trouble continuing
-LCertFoundIn={0} found in cacerts ({1})
+LCertFoundIn={0} found in cacerts ({1})
LSingleInstanceExists=Another instance of this applet already exists and only one may be run at the same time.
JNotApplet=File is not an applet.
@@ -227,7 +227,6 @@ SJNLPFileIsNotSigned=This application contains a digital signature in which the
SBadKeyUsage=Resources contain entries whose signer certificate's KeyUsage extension doesn't allow code signing.
SBadExtendedKeyUsage=Resources contain entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.
SBadNetscapeCertType=Resources contain entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.
-SHasUnsignedEntry=Resources contain unsigned entries which have not been integrity-checked.
SHasExpiredCert=The digital signature has expired.
SHasExpiringCert=Resources contain entries whose signer certificate will expire within six months.
SNotYetValidCert=Resources contain entries whose signer certificate is not yet valid.
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
index 523d9bd..94d93a4 100644
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
@@ -79,8 +79,10 @@ import net.sourceforge.jnlp.cache.CacheUtil;
import net.sourceforge.jnlp.cache.IllegalResourceDescriptorException;
import net.sourceforge.jnlp.cache.ResourceTracker;
import net.sourceforge.jnlp.cache.UpdatePolicy;
+import net.sourceforge.jnlp.security.AppVerifier;
+import net.sourceforge.jnlp.security.JNLPAppVerifier;
+import net.sourceforge.jnlp.security.PluginAppVerifier;
import net.sourceforge.jnlp.security.SecurityDialogs;
-import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
import net.sourceforge.jnlp.tools.JarCertVerifier;
import net.sourceforge.jnlp.util.FileUtils;
import sun.misc.JarIndex;
@@ -153,14 +155,8 @@ public class JNLPClassLoader extends URLClassLoader {
/** all jars not yet part of classloader or active */
private List<JARDesc> available = new ArrayList<JARDesc>();
- /** all of the jar files that were verified */
- private ArrayList<String> verifiedJars = null;
-
- /** all of the jar files that were not verified */
- private ArrayList<String> unverifiedJars = null;
-
/** the jar cert verifier tool to verify our jars */
- private JarCertVerifier jcv = null;
+ private final JarCertVerifier jcv;
private boolean signing = false;
@@ -223,6 +219,16 @@ public class JNLPClassLoader extends URLClassLoader {
this.mainClass = mainName;
+ AppVerifier verifier;
+
+ if (file instanceof PluginBridge && !((PluginBridge)file).useJNLPHref()) {
+ verifier = new PluginAppVerifier();
+ } else {
+ verifier = new JNLPAppVerifier();
+ }
+
+ jcv = new JarCertVerifier(verifier);
+
// initialize extensions
initializeExtensions();
@@ -604,10 +610,8 @@ public class JNLPClassLoader extends URLClassLoader {
if (JNLPRuntime.isVerifying()) {
- JarCertVerifier jcv;
-
try {
- jcv = verifyJars(initialJars);
+ jcv.add(initialJars, tracker);
} catch (Exception e) {
//we caught an Exception from the JarCertVerifier class.
//Note: one of these exceptions could be from not being able
@@ -618,7 +622,7 @@ public class JNLPClassLoader extends URLClassLoader {
}
//Case when at least one jar has some signing
- if (jcv.anyJarsSigned() && jcv.isFullySignedByASingleCert()) {
+ if (jcv.isFullySigned()) {
signing = true;
if (!jcv.allJarsSigned() &&
@@ -650,10 +654,10 @@ public class JNLPClassLoader extends URLClassLoader {
// If main jar was found, but a signed JNLP file was not located
if (!isSignedJNLP && foundMainJar)
file.setSignedJNLPAsMissing();
-
+
//user does not trust this publisher
- if (!jcv.getAlreadyTrustPublisher() && !jcv.isTriviallySigned()) {
- checkTrustWithUser(jcv);
+ if (!jcv.isTriviallySigned()) {
+ checkTrustWithUser();
} else {
/**
* If the user trusts this publisher (i.e. the publisher's certificate
@@ -864,7 +868,6 @@ public class JNLPClassLoader extends URLClassLoader {
private void verifySignedJNLP(JARDesc jarDesc, JarFile jarFile)
throws LaunchException {
- JarCertVerifier signer = new JarCertVerifier();
List<JARDesc> desc = new ArrayList<JARDesc>();
desc.add(jarDesc);
@@ -875,9 +878,9 @@ public class JNLPClassLoader extends URLClassLoader {
InputStreamReader jnlpReader = null;
try {
- signer.verifyJars(desc, tracker);
-
- if (signer.allJarsSigned()) { // If the jar is signed
+ // NOTE: verification should have happened by now. In other words,
+ // calling jcv.verifyJars(desc, tracker) here should have no affect.
+ if (jcv.isFullySigned()) {
Enumeration<JarEntry> entries = jarFile.entries();
JarEntry je;
@@ -961,7 +964,7 @@ public class JNLPClassLoader extends URLClassLoader {
/*
* After this exception is caught, it is escaped. If an exception is
* thrown while handling the jar file, (mainly for
- * JarCertVerifier.verifyJars) it assumes the jar file is unsigned and
+ * JarCertVerifier.add) it assumes the jar file is unsigned and
* skip the check for a signed JNLP file
*/
@@ -991,28 +994,18 @@ public class JNLPClassLoader extends URLClassLoader {
e.printStackTrace(System.err);
}
}
-
- private void checkTrustWithUser(JarCertVerifier jcv) throws LaunchException {
+
+ /**
+ * Prompt the user for trust on all the signers that require approval.
+ * @throws LaunchException if the user does not approve every dialog prompt.
+ */
+ private void checkTrustWithUser() throws LaunchException {
if (JNLPRuntime.isTrustAll()){
return;
}
- if (!jcv.getRootInCacerts()) { //root cert is not in cacerts
- boolean b = SecurityDialogs.showCertWarningDialog(
- AccessType.UNVERIFIED, file, jcv);
- if (!b)
- throw new LaunchException(null, null, R("LSFatal"),
- R("LCLaunching"), R("LNotVerified"), "");
- } else if (jcv.getRootInCacerts()) { //root cert is in cacerts
- boolean b = false;
- if (jcv.noSigningIssues())
- b = SecurityDialogs.showCertWarningDialog(
- AccessType.VERIFIED, file, jcv);
- else if (!jcv.noSigningIssues())
- b = SecurityDialogs.showCertWarningDialog(
- AccessType.SIGNING_ERROR, file, jcv);
- if (!b)
- throw new LaunchException(null, null, R("LSFatal"),
- R("LCLaunching"), R("LCancelOnUserRequest"), "");
+
+ if (jcv.isFullySigned() && !jcv.getAlreadyTrustPublisher()) {
+ jcv.checkTrustWithUser(file);
}
}
@@ -1226,15 +1219,25 @@ public class JNLPClassLoader extends URLClassLoader {
continue;
}
- JarCertVerifier signer = new JarCertVerifier();
- List<JARDesc> jars = new ArrayList<JARDesc>();
- JARDesc jarDesc = new JARDesc(new File(extractedJarLocation).toURL(), null, null, false, false, false, false);
- jars.add(jarDesc);
tracker.addResource(new File(extractedJarLocation).toURL(), null, null, null);
- signer.verifyJars(jars, tracker);
- if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) {
- checkTrustWithUser(signer);
+ URL codebase = file.getCodeBase();
+ if (codebase == null) {
+ //FIXME: codebase should be the codebase of the Main Jar not
+ //the location. Although, it still works in the current state.
+ codebase = file.getResources().getMainJAR().getLocation();
+ }
+
+ SecurityDesc jarSecurity = null;
+ if (jcv.isFullySigned()) {
+ // Already trust application, nested jar should be given
+ jarSecurity = new SecurityDesc(file,
+ SecurityDesc.ALL_PERMISSIONS,
+ codebase.getHost());
+ } else {
+ jarSecurity = new SecurityDesc(file,
+ SecurityDesc.SANDBOX_PERMISSIONS,
+ codebase.getHost());
}
try {
@@ -1244,25 +1247,6 @@ public class JNLPClassLoader extends URLClassLoader {
CachedJarFileCallback.getInstance().addMapping(fakeRemote, fileURL);
addURL(fakeRemote);
- SecurityDesc jarSecurity = file.getSecurity();
-
- if (file instanceof PluginBridge) {
-
- URL codebase = null;
-
- if (file.getCodeBase() != null) {
- codebase = file.getCodeBase();
- } else {
- //Fixme: codebase should be the codebase of the Main Jar not
- //the location. Although, it still works in the current state.
- codebase = file.getResources().getMainJAR().getLocation();
- }
-
- jarSecurity = new SecurityDesc(file,
- SecurityDesc.ALL_PERMISSIONS,
- codebase.getHost());
- }
-
jarLocationSecurityMap.put(fakeRemote, jarSecurity);
} catch (MalformedURLException mfue) {
@@ -1475,18 +1459,6 @@ public class JNLPClassLoader extends URLClassLoader {
}
/**
- * Verifies code signing of jars to be used.
- *
- * @param jars the jars to be verified.
- */
- private JarCertVerifier verifyJars(List<JARDesc> jars) throws Exception {
-
- jcv = new JarCertVerifier();
- jcv.verifyJars(jars, tracker);
- return jcv;
- }
-
- /**
* Find the loaded class in this loader or any of its extension loaders.
*/
protected Class findLoadedClassAll(String name) {
@@ -1642,7 +1614,6 @@ public class JNLPClassLoader extends URLClassLoader {
// Verify if needed
- final JarCertVerifier signer = new JarCertVerifier();
final List<JARDesc> jars = new ArrayList<JARDesc>();
jars.add(desc);
@@ -1654,14 +1625,12 @@ public class JNLPClassLoader extends URLClassLoader {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
- signer.verifyJars(jars, tracker);
+ jcv.add(jars, tracker);
- if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) {
- checkTrustWithUser(signer);
- }
+ checkTrustWithUser();
final SecurityDesc security;
- if (signer.anyJarsSigned()) {
+ if (jcv.isFullySigned()) {
security = new SecurityDesc(file,
SecurityDesc.ALL_PERMISSIONS,
file.getCodeBase().getHost());
diff --git a/netx/net/sourceforge/jnlp/security/AppVerifier.java b/netx/net/sourceforge/jnlp/security/AppVerifier.java
new file mode 100644
index 0000000..2fc1ec0
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/security/AppVerifier.java
@@ -0,0 +1,91 @@
+/* AppVerifier.java
+ Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+*/
+
+package net.sourceforge.jnlp.security;
+
+import java.security.cert.CertPath;
+import java.util.HashMap;
+
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.LaunchException;
+import net.sourceforge.jnlp.tools.CertInformation;
+import net.sourceforge.jnlp.tools.JarCertVerifier;
+
+/**
+ * An interface that provides various details about an app's signers.
+ */
+public interface AppVerifier {
+
+ /**
+ * Checks if the app has already found trust in its publisher(s).
+ * @param certs The certs to search through and their cert information
+ * @param signedJars A map of all the jars of this app and the number of
+ * signed entries each one has.
+ * @return True if the app trusts its publishers.
+ */
+ public boolean hasAlreadyTrustedPublisher(
+ HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars);
+
+ /**
+ * Checks if the app has signer(s) whose certs along their chains are in CA certs.
+ * @param certs The certs to search through and their cert information
+ * @param signedJars A map of all the jars of this app and the number of
+ * signed entries each one has.
+ * @return True if the app has a root in the CA certs store.
+ */
+ public boolean hasRootInCacerts(HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars);
+
+ /**
+ * Checks if the app's jars are covered by the provided certificates, enough
+ * to consider the app fully signed.
+ * @param certs Any possible signer and their respective information regarding this app.
+ * @param signedJars A map of all the jars of this app and the number of
+ * signed entries each one has.
+ * @return
+ */
+ public boolean isFullySigned(HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars);
+
+ /**
+ * Prompt the user with requests for trusting the certificates used by this app
+ * @throws LaunchException
+ */
+ public void checkTrustWithUser(JarCertVerifier jcv, JNLPFile file)
+ throws LaunchException;
+}
diff --git a/netx/net/sourceforge/jnlp/security/CertVerifier.java b/netx/net/sourceforge/jnlp/security/CertVerifier.java
index 842a865..7769884 100644
--- a/netx/net/sourceforge/jnlp/security/CertVerifier.java
+++ b/netx/net/sourceforge/jnlp/security/CertVerifier.java
@@ -1,5 +1,5 @@
/* CertVerifier.java
- Copyright (C) 2009 Red Hat, Inc.
+ Copyright (C) 2012 Red Hat, Inc.
This file is part of IcedTea.
@@ -39,10 +39,10 @@ package net.sourceforge.jnlp.security;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
-import java.util.ArrayList;
+import java.util.List;
/**
- * An interface that provides various details about a certificate
+ * An interface that provides various details about certificates of an app.
*/
public interface CertVerifier {
@@ -58,36 +58,30 @@ public interface CertVerifier {
public boolean getRootInCacerts();
/**
- * Return if there are signing issues with the certificate(s) being veried
+ * Return if there are signing issues with the certificate being verified
*/
- public boolean hasSigningIssues();
+ public boolean hasSigningIssues(CertPath certPath);
/**
- * Return if there are no signing issues with this cert (!hasSigningIssues())
+ * Get the details regarding issue with this certificate
*/
- public boolean noSigningIssues();
+ public List<String> getDetails(CertPath certPath);
/**
- * Get the details regarding issue(s) with this certificate
- */
- public ArrayList<String> getDetails();
-
- /**
- * Return a valid certificate path to this certificate(s) being verified
+ * Return a valid certificate path to this certificate being verified
* @return The CertPath
*/
- public CertPath getCertPath();
+ public CertPath getCertPath(CertPath certPath);
/**
* Returns the application's publisher's certificate.
*/
- public abstract Certificate getPublisher();
+ public abstract Certificate getPublisher(CertPath certPath);
/**
* Returns the application's root's certificate. This
- * may return the same certificate as getPublisher() in
+ * may return the same certificate as getPublisher(CertPath certPath) in
* the event that the application is self signed.
*/
- public abstract Certificate getRoot();
-
+ public abstract Certificate getRoot(CertPath certPath);
}
diff --git a/netx/net/sourceforge/jnlp/security/CertWarningPane.java b/netx/net/sourceforge/jnlp/security/CertWarningPane.java
index eedd86e..fff814c 100644
--- a/netx/net/sourceforge/jnlp/security/CertWarningPane.java
+++ b/netx/net/sourceforge/jnlp/security/CertWarningPane.java
@@ -96,7 +96,7 @@ public class CertWarningPane extends SecurityDialogPanel {
private void addComponents() {
AccessType type = parent.getAccessType();
JNLPFile file = parent.getFile();
- Certificate c = parent.getCertVerifier().getPublisher();
+ Certificate c = parent.getCertVerifier().getPublisher(null);
String name = "";
String publisher = "";
@@ -253,7 +253,7 @@ public class CertWarningPane extends SecurityDialogPanel {
if (alwaysTrust != null && alwaysTrust.isSelected()) {
try {
KeyStore ks = KeyStores.getKeyStore(Level.USER, Type.CERTS);
- X509Certificate c = (X509Certificate) parent.getCertVerifier().getPublisher();
+ X509Certificate c = (X509Certificate) parent.getCertVerifier().getPublisher(null);
CertificateUtils.addToKeyStore(c, ks);
File keyStoreFile = new File(KeyStores.getKeyStoreLocation(Level.USER, Type.CERTS));
if (!keyStoreFile.isFile()) {
diff --git a/netx/net/sourceforge/jnlp/security/CertsInfoPane.java b/netx/net/sourceforge/jnlp/security/CertsInfoPane.java
index c4f7c67..d22a590 100644
--- a/netx/net/sourceforge/jnlp/security/CertsInfoPane.java
+++ b/netx/net/sourceforge/jnlp/security/CertsInfoPane.java
@@ -84,7 +84,7 @@ public class CertsInfoPane extends SecurityDialogPanel {
* Builds the JTree out of CertPaths.
*/
void buildTree() {
- certPath = parent.getCertVerifier().getCertPath();
+ certPath = parent.getCertVerifier().getCertPath(null);
X509Certificate firstCert =
((X509Certificate) certPath.getCertificates().get(0));
String subjectString =
diff --git a/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java b/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java
index 8490cf8..edd5899 100644
--- a/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java
+++ b/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java
@@ -80,7 +80,14 @@ public class HttpsCertVerifier implements CertVerifier {
return isTrusted;
}
- public CertPath getCertPath() {
+
+ /* XXX: Most of these methods have a CertPath param that should be passed
+ * from the UI dialogs. However, this is not implemented yet so most of
+ * the params are ignored.
+ */
+
+ @Override
+ public CertPath getCertPath(CertPath certPath) { // Parameter ignored.
ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
for (int i = 0; i < chain.length; i++)
@@ -99,7 +106,8 @@ public class HttpsCertVerifier implements CertVerifier {
return certPaths.get(0);
}
- public ArrayList<String> getDetails() {
+ @Override
+ public List<String> getDetails(CertPath certPath) { // Parameter ignored.
boolean hasExpiredCert = false;
boolean hasExpiringCert = false;
@@ -192,13 +200,15 @@ public class HttpsCertVerifier implements CertVerifier {
details.add(detail);
}
- public Certificate getPublisher() {
+ @Override
+ public Certificate getPublisher(CertPath certPath) { // Paramater ignored.
if (chain.length > 0)
return (Certificate) chain[0];
return null;
}
- public Certificate getRoot() {
+ @Override
+ public Certificate getRoot(CertPath certPath) { // Parameter ignored.
if (chain.length > 0)
return (Certificate) chain[chain.length - 1];
return null;
@@ -207,18 +217,14 @@ public class HttpsCertVerifier implements CertVerifier {
public boolean getRootInCacerts() {
try {
KeyStore[] caCertsKeyStores = KeyStores.getCAKeyStores();
- return CertificateUtils.inKeyStores((X509Certificate) getRoot(), caCertsKeyStores);
+ return CertificateUtils.inKeyStores((X509Certificate) getRoot(null), caCertsKeyStores);
} catch (Exception e) {
}
return false;
}
- public boolean hasSigningIssues() {
- return false;
- }
-
- public boolean noSigningIssues() {
+ @Override
+ public boolean hasSigningIssues(CertPath certPath) {
return false;
}
-
}
diff --git a/netx/net/sourceforge/jnlp/security/JNLPAppVerifier.java b/netx/net/sourceforge/jnlp/security/JNLPAppVerifier.java
new file mode 100644
index 0000000..9dcfaf5
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/security/JNLPAppVerifier.java
@@ -0,0 +1,143 @@
+/* JNLPAppVerifier.java
+ Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+package net.sourceforge.jnlp.security;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.security.cert.CertPath;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.LaunchException;
+import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
+import net.sourceforge.jnlp.tools.CertInformation;
+import net.sourceforge.jnlp.tools.JarCertVerifier;
+
+public class JNLPAppVerifier implements AppVerifier {
+
+ @Override
+ public boolean hasAlreadyTrustedPublisher(
+ HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars) {
+ int sumOfSignableEntries = JarCertVerifier.getTotalJarEntries(signedJars);
+ for (CertInformation certInfo : certs.values()) {
+ Map<String, Integer> certSignedJars = certInfo.getSignedJars();
+
+ if (JarCertVerifier.getTotalJarEntries(certSignedJars) == sumOfSignableEntries
+ && certInfo.isPublisherAlreadyTrusted()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean hasRootInCacerts(HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars) {
+ int sumOfSignableEntries = JarCertVerifier.getTotalJarEntries(signedJars);
+ for (CertInformation certInfo : certs.values()) {
+ Map<String, Integer> certSignedJars = certInfo.getSignedJars();
+
+ if (JarCertVerifier.getTotalJarEntries(certSignedJars) == sumOfSignableEntries
+ && certInfo.isRootInCacerts()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isFullySigned(HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars) {
+ int sumOfSignableEntries = JarCertVerifier.getTotalJarEntries(signedJars);
+ for (CertPath cPath : certs.keySet()) {
+ // If this cert has signed everything, return true
+ if (hasCompletelySignedApp(certs.get(cPath), sumOfSignableEntries)) {
+ return true;
+ }
+ }
+
+ // No cert found that signed all entries. Return false.
+ return false;
+ }
+
+ @Override
+ public void checkTrustWithUser(JarCertVerifier jcv, JNLPFile file)
+ throws LaunchException {
+
+ int sumOfSignableEntries = JarCertVerifier.getTotalJarEntries(jcv.getJarSignableEntries());
+ for (CertPath cPath : jcv.getCertsList()) {
+ jcv.setCurrentlyUsedCertPath(cPath);
+ CertInformation info = jcv.getCertInformation(cPath);
+ if (hasCompletelySignedApp(info, sumOfSignableEntries)) {
+ if (info.isPublisherAlreadyTrusted()) {
+ return;
+ }
+
+ AccessType dialogType;
+ if (info.isRootInCacerts() && !info.hasSigningIssues()) {
+ dialogType = AccessType.VERIFIED;
+ } else if (info.isRootInCacerts()) {
+ dialogType = AccessType.SIGNING_ERROR;
+ } else {
+ dialogType = AccessType.UNVERIFIED;
+ }
+
+ boolean wasApproved = SecurityDialogs.showCertWarningDialog(
+ dialogType, file, jcv);
+ if (wasApproved) {
+ return;
+ }
+ }
+ }
+
+ throw new LaunchException(null, null, R("LSFatal"), R("LCLaunching"),
+ R("LCancelOnUserRequest"), "");
+ }
+
+ /**
+ * Find out if the CertPath with the given info has fully signed the app.
+ * @param info The information regarding the CertPath in question
+ * @param sumOfSignableEntries The total number of signable entries in the app.
+ * @return True if the signer has fully signed this app.
+ */
+ public boolean hasCompletelySignedApp(CertInformation info, int sumOfSignableEntries) {
+ return JarCertVerifier.getTotalJarEntries(info.getSignedJars()) == sumOfSignableEntries;
+ }
+}
diff --git a/netx/net/sourceforge/jnlp/security/MoreInfoPane.java b/netx/net/sourceforge/jnlp/security/MoreInfoPane.java
index 3276ea2..1ccd302 100644
--- a/netx/net/sourceforge/jnlp/security/MoreInfoPane.java
+++ b/netx/net/sourceforge/jnlp/security/MoreInfoPane.java
@@ -44,7 +44,7 @@ import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.util.ArrayList;
+import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
@@ -73,7 +73,7 @@ public class MoreInfoPane extends SecurityDialogPanel {
* Constructs the GUI components of this panel
*/
private void addComponents() {
- ArrayList<String> details = certVerifier.getDetails();
+ List<String> details = certVerifier.getDetails(null);
// Show signed JNLP warning if the signed main jar does not have a
// signed JNLP file and the launching JNLP file contains special properties
diff --git a/netx/net/sourceforge/jnlp/security/PluginAppVerifier.java b/netx/net/sourceforge/jnlp/security/PluginAppVerifier.java
new file mode 100644
index 0000000..a8589d8
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/security/PluginAppVerifier.java
@@ -0,0 +1,224 @@
+/* PluginAppVerifier.java
+ Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+package net.sourceforge.jnlp.security;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.security.cert.CertPath;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.LaunchException;
+import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
+import net.sourceforge.jnlp.tools.CertInformation;
+import net.sourceforge.jnlp.tools.JarCertVerifier;
+
+public class PluginAppVerifier implements AppVerifier {
+
+ @Override
+ public boolean hasAlreadyTrustedPublisher(
+ HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars) {
+
+ boolean allPublishersTrusted = true;
+
+ for(String jarName : signedJars.keySet()) {
+ int numbSignableEntries = signedJars.get(jarName);
+ boolean publisherTrusted = false;
+
+ for (CertInformation certInfo : certs.values()) {
+ if(certInfo.isSignerOfJar(jarName)
+ && numbSignableEntries == certInfo.getNumJarEntriesSigned(jarName)
+ && certInfo.isPublisherAlreadyTrusted()) {
+ publisherTrusted = true;
+ break;
+ }
+ }
+
+ allPublishersTrusted &= publisherTrusted;
+ }
+ return allPublishersTrusted;
+ }
+
+ @Override
+ public boolean hasRootInCacerts(HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars) {
+
+ boolean allRootCAsTrusted = true;
+
+ for(String jarName : signedJars.keySet()) {
+ int numbSignableEntries = signedJars.get(jarName);
+ boolean rootCATrusted = false;
+
+ for (CertInformation certInfo : certs.values()) {
+ if(certInfo.isSignerOfJar(jarName)
+ && numbSignableEntries == certInfo.getNumJarEntriesSigned(jarName)
+ && certInfo.isRootInCacerts()) {
+ rootCATrusted = true;
+ break;
+ }
+ }
+
+ allRootCAsTrusted &= rootCATrusted;
+ }
+ return allRootCAsTrusted;
+ }
+
+ @Override
+ public boolean isFullySigned(HashMap<CertPath, CertInformation> certs,
+ HashMap<String, Integer> signedJars) {
+
+ boolean isFullySigned = true;
+
+ for(String jarName : signedJars.keySet()) {
+ int numbSignableEntries = signedJars.get(jarName);
+ boolean isSigned = false;
+
+ for (CertInformation certInfo : certs.values()) {
+ if(certInfo.isSignerOfJar(jarName)
+ && numbSignableEntries == certInfo.getNumJarEntriesSigned(jarName)) {
+ isSigned = true;
+ break;
+ }
+ }
+
+ isFullySigned &= isSigned;
+ }
+
+ return isFullySigned;
+ }
+
+ @Override
+ public void checkTrustWithUser(JarCertVerifier jcv, JNLPFile file)
+ throws LaunchException {
+ ArrayList<CertPath> certPaths = buildCertPathsList(jcv);
+ ArrayList<CertPath> alreadyApprovedByUser = new ArrayList<CertPath>();
+ for (String jarName : jcv.getJarSignableEntries().keySet()) {
+ boolean trustFoundOrApproved = false;
+ for (CertPath cPathApproved : alreadyApprovedByUser) {
+ jcv.setCurrentlyUsedCertPath(cPathApproved);
+ CertInformation info = jcv.getCertInformation(cPathApproved);
+ if (info.isSignerOfJar(jarName)
+ && alreadyApprovedByUser.contains(cPathApproved)) {
+ trustFoundOrApproved = true;
+ break;
+ }
+ }
+
+ if (trustFoundOrApproved) {
+ continue;
+ }
+
+ for (CertPath cPath : certPaths) {
+ jcv.setCurrentlyUsedCertPath(cPath);
+ CertInformation info = jcv.getCertInformation(cPath);
+ if (info.isSignerOfJar(jarName)) {
+ if (info.isPublisherAlreadyTrusted()) {
+ trustFoundOrApproved = true;
+ alreadyApprovedByUser.add(cPath);
+ break;
+ }
+
+ AccessType dialogType;
+ if (info.isRootInCacerts() && !info.hasSigningIssues()) {
+ dialogType = AccessType.VERIFIED;
+ } else if (info.isRootInCacerts()) {
+ dialogType = AccessType.SIGNING_ERROR;
+ } else {
+ dialogType = AccessType.UNVERIFIED;
+ }
+
+ boolean wasApproved = SecurityDialogs.showCertWarningDialog(
+ dialogType, file, jcv);
+ if (wasApproved) {
+ alreadyApprovedByUser.add(cPath);
+ trustFoundOrApproved = true;
+ break;
+ }
+ }
+ }
+ if (!trustFoundOrApproved) {
+ throw new LaunchException(null, null, R("LSFatal"),
+ R("LCLaunching"), R("LCancelOnUserRequest"), "");
+ }
+ }
+ }
+
+ /**
+ * Build a list of all the CertPaths that were detected in the provided
+ * JCV, placing them in the most trusted possible order.
+ * @param jcv The verifier containing the CertPaths to examine.
+ * @return A list of CertPaths sorted in the following order: Signers with
+ * 1. Already trusted publishers
+ * 2. Roots in the CA store and have no signing issues
+ * 3. Roots in the CA store but have signing issues
+ * 4. Everything else
+ */
+ public ArrayList<CertPath> buildCertPathsList(JarCertVerifier jcv) {
+ ArrayList<CertPath> certPathsList = jcv.getCertsList();
+ ArrayList<CertPath> returnList = new ArrayList<CertPath>();
+
+ for (CertPath cPath : certPathsList) {
+ if (!returnList.contains(cPath)
+ && jcv.getCertInformation(cPath).isPublisherAlreadyTrusted())
+ returnList.add(cPath);
+ }
+
+ for (CertPath cPath : certPathsList) {
+ if (!returnList.contains(cPath)
+ && jcv.getCertInformation(cPath).isRootInCacerts()
+ && !jcv.getCertInformation(cPath).hasSigningIssues())
+ returnList.add(cPath);
+ }
+
+ for (CertPath cPath : certPathsList) {
+ if (!returnList.contains(cPath)
+ && jcv.getCertInformation(cPath).isRootInCacerts()
+ && jcv.getCertInformation(cPath).hasSigningIssues())
+ returnList.add(cPath);
+ }
+
+ for (CertPath cPath : certPathsList) {
+ if (!returnList.contains(cPath))
+ returnList.add(cPath);
+ }
+
+ return returnList;
+ }
+}
diff --git a/netx/net/sourceforge/jnlp/tools/CertInformation.java b/netx/net/sourceforge/jnlp/tools/CertInformation.java
new file mode 100644
index 0000000..6d6d27e
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/tools/CertInformation.java
@@ -0,0 +1,292 @@
+/* CertInformation.java
+ Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+package net.sourceforge.jnlp.tools;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+
+/**
+ * Maintains information about a CertPath that has signed at least one of the
+ * entries provided by a jar of the app.
+ */
+public class CertInformation {
+
+ private boolean hasExpiredCert = false;
+ private boolean hasExpiringCert = false;
+
+ private boolean isNotYetValidCert = false;
+
+ /* Code signer properties of the certificate. */
+ private boolean hasBadKeyUsage = false;
+ private boolean hasBadExtendedKeyUsage = false;
+ private boolean hasBadNetscapeCertType = false;
+
+ private boolean alreadyTrustPublisher = false;
+ private boolean rootInCacerts = false;
+
+ static enum Detail {
+ TRUSTED (R("STrustedCertificate")),
+ UNTRUSTED (R("SUntrustedCertificate")),
+ RUN_WITHOUT_RESTRICTIONS(R("SRunWithoutRestrictions")),
+ EXPIRED (R("SHasExpiredCert")),
+ EXPIRING (R("SHasExpiringCert")),
+ NOT_YET_VALID (R("SNotYetValidCert")),
+ BAD_KEY_USAGE (R("SBadKeyUsage")),
+ BAT_EXTENDED_KEY_USAGE (R("SBadExtendedKeyUsage")),
+ BAD_NETSCAPE_CERT_TYPE (R("SBadNetscapeCertType"));
+
+ private final String message;
+ Detail(String issue) {
+ message = issue;
+ }
+
+ public String message() {
+ return message;
+ }
+ }
+
+ private EnumSet<Detail> details = EnumSet.noneOf(Detail.class);
+
+ /** The jars and their number of entries this cert has signed. */
+ private HashMap<String, Integer> signedJars = new HashMap<String, Integer>();
+
+ /**
+ * Return if there are signing issues with this certificate.
+ * @return true if there are any issues with expiry, validity or bad key usage.
+ */
+ public boolean hasSigningIssues() {
+ return hasExpiredCert || isNotYetValidCert || hasBadKeyUsage
+ || hasBadExtendedKeyUsage || hasBadNetscapeCertType;
+ }
+
+ /**
+ * Return whether or not the publisher is already trusted.
+ *
+ * @return True if the publisher is trusted already.
+ */
+ public boolean isPublisherAlreadyTrusted() {
+ return alreadyTrustPublisher;
+ }
+
+ /**
+ * Set whether or not the publisher is already trusted.
+ *
+ */
+ public void setAlreadyTrustPublisher() {
+ alreadyTrustPublisher = true;
+ }
+
+ /**
+ * Return whether or not the root is in the list of trusted CA certificates.
+ *
+ * @return True if the root is in the list of CA certificates.
+ */
+ public boolean isRootInCacerts() {
+ return rootInCacerts;
+ }
+
+ /**
+ * Set that this cert's root CA is to be trusted.
+ */
+ public void setRootInCacerts() {
+ rootInCacerts = true;
+ details.add(Detail.TRUSTED);
+ }
+
+ /**
+ * Resets any trust of the root and publisher. Also removes unnecessary
+ * details from the list of issues.
+ */
+ public void resetForReverification() {
+ alreadyTrustPublisher = false;
+ rootInCacerts = false;
+ removeFromDetails(Detail.UNTRUSTED);
+ removeFromDetails(Detail.TRUSTED);
+ }
+ /**
+ * Check if this cert is the signer of a jar.
+ * @param jarName The absolute path of the jar this certificate has signed.
+ * @return true if this cert has signed the jar found at jarName.
+ */
+ public boolean isSignerOfJar(String jarName) {
+ return signedJars.containsKey(jarName);
+ }
+
+ /**
+ * Add a jar to the list of jars this certificate has signed along with the
+ * number of entries it has signed in the jar.
+ *
+ * @param jarName The absolute path of the jar this certificate has signed.
+ * @param signedEntriesCount The number of entries this cert has signed in jarName.
+ */
+ public void setNumJarEntriesSigned(String jarName, int signedEntriesCount) {
+ if (signedJars.containsKey(jarName)) {
+ if (JNLPRuntime.isDebug())
+ System.err.println("WARNING: A jar that has already been "
+ + "verified is being yet again verified: " + jarName);
+ } else {
+ signedJars.put(jarName, signedEntriesCount);
+ }
+ }
+
+ /**
+ * Find the number of entries this cert has signed in the specified jar.
+ * @param jarName The absolute path of the jar this certificate has signed.
+ * @return The number of entries this cert has signed in jarName.
+ */
+ public int getNumJarEntriesSigned(String jarName) {
+ return signedJars.get(jarName);
+ }
+
+ /**
+ * Get all the jars this cert has signed along with the number of entries
+ * in each jar.
+ * @return
+ */
+ public Map<String, Integer> getSignedJars() {
+ return signedJars;
+ }
+
+ /**
+ * Get the details regarding issue(s) with this certificate.
+ *
+ * @return A list of all the details/issues with this app.
+ */
+ public List<String> getDetailsAsStrings() {
+ List<String> detailsToStr = new ArrayList<String>();
+ for (Detail issue : details) {
+ detailsToStr.add(issue.message());
+ }
+ return detailsToStr;
+ }
+
+ /**
+ * Remove an issue from the list of details of issues with this certificate.
+ * List is unchanged if detail was not present.
+ *
+ * @param detail The issue to be removed regarding this certificate.
+ */
+ private void removeFromDetails(Detail detail) {
+ details.remove(detail);
+ }
+
+ /**
+ * Set that this cert is expired and add this issue to the list of details.
+ */
+ public void setHasExpiredCert() {
+ hasExpiredCert = true;
+ details.add(Detail.RUN_WITHOUT_RESTRICTIONS);
+ details.add(Detail.EXPIRED);
+ }
+
+ /**
+ * Set that this cert is expiring within 6 months and add this issue to
+ * the list of details.
+ */
+ public void setHasExpiringCert() {
+ hasExpiringCert = true;
+ details.add(Detail.RUN_WITHOUT_RESTRICTIONS);
+ details.add(Detail.EXPIRING);
+ }
+
+ /**
+ * Get whether or not this cert will expire within 6 months.
+ * @return true if the cert will be expired after 6 months.
+ */
+ public boolean hasExpiringCert() {
+ return hasExpiringCert;
+ }
+
+ /**
+ * Set that this cert is not yet valid
+ * and add this issue to the list of details.
+ */
+ public void setNotYetValidCert() {
+ isNotYetValidCert = true;
+ details.add(Detail.RUN_WITHOUT_RESTRICTIONS);
+ details.add(Detail.NOT_YET_VALID);
+ }
+
+
+ /**
+ * Set that this cert has bad key usage
+ * and add this issue to the list of details.
+ */
+ public void setBadKeyUsage() {
+ hasBadKeyUsage = true;
+ details.add(Detail.RUN_WITHOUT_RESTRICTIONS);
+ details.add(Detail.BAD_KEY_USAGE);
+ }
+
+
+ /**
+ * Set that this cert has bad extended key usage
+ * and add this issue to the list of details.
+ */
+ public void setBadExtendedKeyUsage() {
+ hasBadExtendedKeyUsage = true;
+ details.add(Detail.RUN_WITHOUT_RESTRICTIONS);
+ details.add(Detail.BAT_EXTENDED_KEY_USAGE);
+ }
+
+
+ /**
+ * Set that this cert has a bad netscape cert type
+ * and add this issue to the list of details.
+ */
+ public void setBadNetscapeCertType() {
+ hasBadNetscapeCertType = true;
+ details.add(Detail.RUN_WITHOUT_RESTRICTIONS);
+ details.add(Detail.BAD_NETSCAPE_CERT_TYPE);
+ }
+
+ /**
+ * Set that this cert and all of its CAs are untrusted so far.
+ */
+ public void setUntrusted() {
+ details.add(Detail.UNTRUSTED);
+
+ }
+}
diff --git a/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java b/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java
index 520880a..01426f3 100644
--- a/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java
+++ b/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java
@@ -25,25 +25,41 @@
package net.sourceforge.jnlp.tools;
-import static net.sourceforge.jnlp.runtime.Translator.R;
-
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.CodeSigner;
+import java.security.KeyStore;
+import java.security.cert.CertPath;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
-import java.security.cert.CertPath;
-import java.security.*;
-import sun.security.x509.*;
-import sun.security.util.*;
-
-import net.sourceforge.jnlp.*;
-import net.sourceforge.jnlp.cache.*;
-import net.sourceforge.jnlp.security.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import net.sourceforge.jnlp.JARDesc;
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.LaunchException;
+import net.sourceforge.jnlp.cache.ResourceTracker;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.security.AppVerifier;
+import net.sourceforge.jnlp.security.CertVerifier;
+import net.sourceforge.jnlp.security.CertificateUtils;
+import net.sourceforge.jnlp.security.KeyStores;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerValue;
+import sun.security.x509.NetscapeCertTypeExtension;
/**
- * <p>The jar certificate verifier utility.
- *
+ * <p>
+ * The jar certificate verifier utility.
+ *
* @author Roland Schemers
* @author Jan Luehe
*/
@@ -55,53 +71,39 @@ public class JarCertVerifier implements CertVerifier {
// prefix for new signature-related files in META-INF directory
private static final String SIG_PREFIX = META_INF + "SIG-";
- private static final long SIX_MONTHS = 180 * 24 * 60 * 60 * 1000L; //milliseconds
+ private static final long SIX_MONTHS = 180 * 24 * 60 * 60 * 1000L; // milliseconds
- static enum verifyResult {
+ static enum VerifyResult {
UNSIGNED, SIGNED_OK, SIGNED_NOT_OK
}
- // signer's certificate chain (when composing)
- X509Certificate[] certChain;
+ /** All of the jar files that were verified for signing */
+ private ArrayList<String> verifiedJars = new ArrayList<String>();
+
+ /** All of the jar files that were not verified */
+ private ArrayList<String> unverifiedJars = new ArrayList<String>();
- boolean verbose = false; // verbose output when signing/verifying
- boolean showcerts = false; // show certs when verifying
+ /** The certificates used for jar verification linked to their respective information */
+ private HashMap<CertPath, CertInformation> certs = new HashMap<CertPath, CertInformation>();
- private boolean hasExpiredCert = false;
- private boolean hasExpiringCert = false;
- private boolean notYetValidCert = false;
+ /** Temporary cert path hack to be used to keep track of which one a UI dialog is using */
+ private CertPath currentlyUsed;
- private boolean badKeyUsage = false;
- private boolean badExtendedKeyUsage = false;
- private boolean badNetscapeCertType = false;
+ /** Absolute location to jars and the number of entries which are possibly signable */
+ private HashMap<String, Integer> jarSignableEntries = new HashMap<String, Integer>();
- private boolean alreadyTrustPublisher = false;
- private boolean rootInCacerts = false;
+ /** The application verifier to use by this instance */
+ private AppVerifier appVerifier;
/**
- * The single certPath used in this JarSiging. We're only keeping
- * track of one here, since in practice there's only one signer
- * for a JNLP Application.
+ * Create a new jar certificate verifier utility that uses the provided verifier for its strategy pattern.
+ *
+ * @param verifier
+ * The application verifier to be used by the new instance.
*/
- private CertPath certPath = null;
-
- private boolean noSigningIssues = true;
-
- private boolean anyJarsSigned = false;
-
- /** all of the jar files that were verified */
- private ArrayList<String> verifiedJars = null;
-
- /** all of the jar files that were not verified */
- private ArrayList<String> unverifiedJars = null;
-
- /** the certificates used for jar verification */
- private HashMap<CertPath, Integer> certs = new HashMap<CertPath, Integer>();
-
- /** details of this signing */
- private ArrayList<String> details = new ArrayList<String>();
-
- private int totalSignableEntries = 0;
+ public JarCertVerifier(AppVerifier verifier) {
+ appVerifier = verifier;
+ }
/** Whether a signable entry was found within jars (jars with content more than just META-INF/*) */
private boolean triviallySigned = false;
@@ -113,88 +115,107 @@ public class JarCertVerifier implements CertVerifier {
return triviallySigned;
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#getAlreadyTrustPublisher()
- */
public boolean getAlreadyTrustPublisher() {
- return alreadyTrustPublisher;
+ boolean allPublishersTrusted = appVerifier.hasAlreadyTrustedPublisher(
+ certs, jarSignableEntries);
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("App already has trusted publisher: "
+ + allPublishersTrusted);
+ }
+ return allPublishersTrusted;
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#getRootInCacerts()
- */
public boolean getRootInCacerts() {
- return rootInCacerts;
- }
-
- public CertPath getCertPath() {
- return certPath;
+ boolean allRootCAsTrusted = appVerifier.hasRootInCacerts(certs,
+ jarSignableEntries);
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("App has trusted root CA: " + allRootCAsTrusted);
+ }
+ return allRootCAsTrusted;
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#hasSigningIssues()
- */
- public boolean hasSigningIssues() {
- return hasExpiredCert || notYetValidCert || badKeyUsage
- || badExtendedKeyUsage || badNetscapeCertType;
+ public CertPath getCertPath(CertPath cPath) { // Parameter ignored.
+ return currentlyUsed;
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#noSigningIssues()
- */
- public boolean noSigningIssues() {
- return noSigningIssues;
+ public boolean hasSigningIssues(CertPath certPath) {
+ return certs.get(certPath).hasSigningIssues();
}
- public boolean anyJarsSigned() {
- return anyJarsSigned;
+ public List<String> getDetails(CertPath certPath) {
+ if (certPath != null) {
+ currentlyUsed = certPath;
+ }
+ return certs.get(currentlyUsed).getDetailsAsStrings();
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#getDetails()
+ /**
+ * Get a list of the cert paths of all signers across the app.
+ *
+ * @return ArrayList of CertPath vars representing each of the signers present on any jar.
*/
- public ArrayList<String> getDetails() {
- return details;
+ public ArrayList<CertPath> getCertsList() {
+ return new ArrayList<CertPath>(certs.keySet());
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#getCerts()
+ /**
+ * Find the information the specified cert path has with respect to this application.
+ *
+ * @return All the information the path has with this app.
*/
- public ArrayList<CertPath> getCerts() {
- return new ArrayList<CertPath>(certs.keySet());
+ public CertInformation getCertInformation(CertPath cPath) {
+ return certs.get(cPath);
}
/**
- * Returns whether or not all entries have a common signer.
- *
- * It is possible to create jars where only some entries are signed. In
- * such cases, we should not prompt the user to accept anything, as the whole
- * application must be treated as unsigned. This method should be called by a
- * caller before it is about to ask the user to accept a cert and determine
- * whether the application is trusted or not.
- *
- * @return Whether or not all entries have a common signer
+ * Returns whether or not the app is considered completely signed.
+ *
+ * An app using a JNLP is considered signed if all of the entries of its jars are signed by at least one common signer.
+ *
+ * An applet on the other hand only needs to have each individual jar be fully signed by a signer. The signers can differ between jars.
+ *
+ * @return Whether or not the app is considered signed.
*/
- public boolean isFullySignedByASingleCert() {
-
+ // FIXME: Change javadoc once applets do not need entire jars signed.
+ public boolean isFullySigned() {
if (triviallySigned)
return true;
-
- for (CertPath cPath : certs.keySet()) {
- // If this cert has signed everything, return true
- if (certs.get(cPath) == totalSignableEntries)
- return true;
+ boolean fullySigned = appVerifier.isFullySigned(certs,
+ jarSignableEntries);
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("App already has trusted publisher: "
+ + fullySigned);
}
-
- // No cert found that signed all entries. Return false.
- return false;
+ return fullySigned;
}
- public void verifyJars(List<JARDesc> jars, ResourceTracker tracker)
+ /**
+ * Update the verifier to consider new jars when verifying.
+ *
+ * @param jars
+ * List of new jars to be verified.
+ * @param tracker
+ * Resource tracker used to obtain the the jars from cache
+ * @throws Exception
+ * Caused by issues with obtaining the jars' entries or interacting with the tracker.
+ */
+ public void add(List<JARDesc> jars, ResourceTracker tracker)
throws Exception {
+ verifyJars(jars, tracker);
+ }
- verifiedJars = new ArrayList<String>();
- unverifiedJars = new ArrayList<String>();
+ /**
+ * Verify the jars provided and update the state of this instance to match the new information.
+ *
+ * @param jars
+ * List of new jars to be verified.
+ * @param tracker
+ * Resource tracker used to obtain the the jars from cache
+ * @throws Exception
+ * Caused by issues with obtaining the jars' entries or interacting with the tracker.
+ */
+ private void verifyJars(List<JARDesc> jars, ResourceTracker tracker)
+ throws Exception {
for (JARDesc jar : jars) {
@@ -209,17 +230,22 @@ public class JarCertVerifier implements CertVerifier {
}
String localFile = jarFile.getAbsolutePath();
- verifyResult result = verifyJar(localFile);
+ if (verifiedJars.contains(localFile)
+ || unverifiedJars.contains(localFile)) {
+ continue;
+ }
+
+ VerifyResult result = verifyJar(localFile);
triviallySigned = false;
- if (result == verifyResult.UNSIGNED) {
+ if (result == VerifyResult.UNSIGNED) {
unverifiedJars.add(localFile);
- } else if (result == verifyResult.SIGNED_NOT_OK) {
- noSigningIssues = false;
+ } else if (result == VerifyResult.SIGNED_NOT_OK) {
verifiedJars.add(localFile);
- } else if (result == verifyResult.SIGNED_OK) {
+ } else if (result == VerifyResult.SIGNED_OK) {
verifiedJars.add(localFile);
- triviallySigned = totalSignableEntries <= 0 && certs.size() <= 0;
+ triviallySigned = getTotalJarEntries(jarSignableEntries) <= 0
+ && certs.size() <= 0;
}
} catch (Exception e) {
// We may catch exceptions from using verifyJar()
@@ -228,26 +254,20 @@ public class JarCertVerifier implements CertVerifier {
}
}
- //we really only want the first certPath
- for (CertPath cPath : certs.keySet()) {
-
- if (certs.get(cPath) != totalSignableEntries)
- continue;
- else
- certPath = cPath;
-
- // check if the certs added above are in the trusted path
- checkTrustedCerts();
-
- if (alreadyTrustPublisher || rootInCacerts)
- break;
- }
-
+ for (CertPath certPath : certs.keySet())
+ checkTrustedCerts(certPath);
}
- private verifyResult verifyJar(String jarName) throws Exception {
- boolean anySigned = false;
- boolean hasUnsignedEntry = false;
+ /**
+ * Checks through all the jar entries of jarName for signers, storing all the common ones in the certs hash map.
+ *
+ * @param jarName
+ * The absolute path to the jar file.
+ * @return The return of {@link JarCertVerifier#verifyJarEntryCerts} using the entries found in the jar located at jarName.
+ * @throws Exception
+ * Will be thrown if there are any problems with the jar.
+ */
+ private VerifyResult verifyJar(String jarName) throws Exception {
JarFile jarFile = null;
try {
@@ -262,10 +282,9 @@ public class JarCertVerifier implements CertVerifier {
InputStream is = jarFile.getInputStream(je);
try {
- int n;
- while ((n = is.read(buffer, 0, buffer.length)) != -1) {
+ while (is.read(buffer, 0, buffer.length) != -1) {
// we just read. this will throw a SecurityException
- // if a signature/digest check fails.
+ // if a signature/digest check fails.
}
} finally {
if (is != null) {
@@ -273,95 +292,9 @@ public class JarCertVerifier implements CertVerifier {
}
}
}
+ return verifyJarEntryCerts(jarName, jarFile.getManifest() != null,
+ entriesVec);
- if (jarFile.getManifest() != null) {
- if (verbose)
- System.out.println();
-
- long now = System.currentTimeMillis();
-
- for (JarEntry je : entriesVec) {
- String name = je.getName();
- CodeSigner[] signers = je.getCodeSigners();
- boolean isSigned = (signers != null);
- anySigned |= isSigned;
-
- boolean shouldHaveSignature = !je.isDirectory()
- && !isMetaInfFile(name);
-
- hasUnsignedEntry |= shouldHaveSignature && !isSigned;
-
- if (shouldHaveSignature)
- totalSignableEntries++;
-
- if (shouldHaveSignature && isSigned) {
- for (int i = 0; i < signers.length; i++) {
- CertPath certPath = signers[i].getSignerCertPath();
- if (!certs.containsKey(certPath))
- certs.put(certPath, 1);
- else
- certs.put(certPath, certs.get(certPath) + 1);
-
- Certificate cert = signers[i].getSignerCertPath()
- .getCertificates().get(0);
- if (cert instanceof X509Certificate) {
- checkCertUsage((X509Certificate) cert, null);
- if (!showcerts) {
- long notBefore = ((X509Certificate) cert)
- .getNotBefore().getTime();
- long notAfter = ((X509Certificate) cert)
- .getNotAfter().getTime();
-
- if (now < notBefore) {
- notYetValidCert = true;
- }
-
- if (notAfter < now) {
- hasExpiredCert = true;
- } else if (notAfter < now + SIX_MONTHS) {
- hasExpiringCert = true;
- }
- }
- }
- }
- }
- } //while e has more elements
- } else { //if man not null
-
- // Else increment totalEntries by 1 so that unsigned jars with
- // no manifests can't sneak in
- totalSignableEntries++;
- }
-
- //Alert the user if any of the following are true.
- if (!anySigned) {
- return verifyResult.UNSIGNED;
- } else {
- anyJarsSigned = true;
-
- //warnings
- if (hasUnsignedEntry || hasExpiredCert || hasExpiringCert ||
- badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
- notYetValidCert) {
-
- addToDetails(R("SRunWithoutRestrictions"));
-
- if (badKeyUsage)
- addToDetails(R("SBadKeyUsage"));
- if (badExtendedKeyUsage)
- addToDetails(R("SBadExtendedKeyUsage"));
- if (badNetscapeCertType)
- addToDetails(R("SBadNetscapeCertType"));
- if (hasUnsignedEntry)
- addToDetails(R("SHasUnsignedEntry"));
- if (hasExpiredCert)
- addToDetails(R("SHasExpiredCert"));
- if (hasExpiringCert)
- addToDetails(R("SHasExpiringCert"));
- if (notYetValidCert)
- addToDetails(R("SNotYetValidCert"));
- }
- }
} catch (Exception e) {
e.printStackTrace();
throw e;
@@ -370,51 +303,175 @@ public class JarCertVerifier implements CertVerifier {
jarFile.close();
}
}
-
- //anySigned does not guarantee that all files were signed.
- return (anySigned && !(hasUnsignedEntry || hasExpiredCert
- || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || notYetValidCert)) ? verifyResult.SIGNED_OK : verifyResult.SIGNED_NOT_OK;
}
/**
- * Checks the user's trusted.certs file and the cacerts file to see
- * if a publisher's and/or CA's certificate exists there.
+ * Checks through all the jar entries for signers, storing all the common ones in the certs hash map.
+ *
+ * @param jarName
+ * The absolute path to the jar file.
+ * @param jarHasManifest
+ * Whether or not the associated jar has a manifest.
+ * @param entries
+ * The list of entries in the associated jar.
+ * @return If there is at least one signable entry that is not signed by a common signer, return UNSIGNED. Otherwise every signable entry is signed by at least one common signer. If the signer has no issues, return SIGNED_OK. If there are any signing issues, return SIGNED_NOT_OK.
+ * @throws Exception
+ * Will be thrown if there are issues with entries.
*/
- private void checkTrustedCerts() throws Exception {
- if (certPath != null) {
- try {
- X509Certificate publisher = (X509Certificate) getPublisher();
- KeyStore[] certKeyStores = KeyStores.getCertKeyStores();
- alreadyTrustPublisher = CertificateUtils.inKeyStores(publisher, certKeyStores);
- X509Certificate root = (X509Certificate) getRoot();
- KeyStore[] caKeyStores = KeyStores.getCAKeyStores();
- // Check entire cert path for a trusted CA
- for (Certificate c : certPath.getCertificates()) {
- if ((rootInCacerts = CertificateUtils.inKeyStores(
- (X509Certificate) c, caKeyStores))) {
- break;
+ VerifyResult verifyJarEntryCerts(String jarName, boolean jarHasManifest,
+ Vector<JarEntry> entries) throws Exception {
+ // Contains number of entries the cert with this CertPath has signed.
+ HashMap<CertPath, Integer> jarSignCount = new HashMap<CertPath, Integer>();
+ int numSignableEntriesInJar = 0;
+
+ // Record current time just before checking the jar begins.
+ long now = System.currentTimeMillis();
+ if (jarHasManifest) {
+
+ for (JarEntry je : entries) {
+ String name = je.getName();
+ CodeSigner[] signers = je.getCodeSigners();
+ boolean isSigned = (signers != null);
+
+ boolean shouldHaveSignature = !je.isDirectory()
+ && !isMetaInfFile(name);
+
+ if (shouldHaveSignature) {
+ numSignableEntriesInJar++;
+ }
+
+ if (shouldHaveSignature && isSigned) {
+ for (int i = 0; i < signers.length; i++) {
+ CertPath certPath = signers[i].getSignerCertPath();
+
+ if (!jarSignCount.containsKey(certPath))
+ jarSignCount.put(certPath, 1);
+ else
+ jarSignCount.put(certPath,
+ jarSignCount.get(certPath) + 1);
}
}
- } catch (Exception e) {
- // TODO: Warn user about not being able to
- // look through their cacerts/trusted.certs
- // file depending on exception.
- throw e;
+ } // while e has more elements
+ } else { // if manifest is null
+
+ // Else increment total entries by 1 so that unsigned jars with
+ // no manifests can't sneak in
+ numSignableEntriesInJar++;
+ }
+
+ jarSignableEntries.put(jarName, numSignableEntriesInJar);
+
+ // Find all signers that have signed every signable entry in this jar.
+ boolean allEntriesSignedBySingleCert = false;
+ for (CertPath certPath : jarSignCount.keySet()) {
+ if (jarSignCount.get(certPath) == numSignableEntriesInJar) {
+ allEntriesSignedBySingleCert = true;
+
+ boolean wasPreviouslyVerified = certs.containsKey(certPath);
+ if (!wasPreviouslyVerified)
+ certs.put(certPath, new CertInformation());
+
+ CertInformation certInfo = certs.get(certPath);
+ if (wasPreviouslyVerified)
+ certInfo.resetForReverification();
+
+ certInfo.setNumJarEntriesSigned(jarName,
+ numSignableEntriesInJar);
+
+ Certificate cert = certPath.getCertificates().get(0);
+ if (cert instanceof X509Certificate) {
+ checkCertUsage(certPath, (X509Certificate) cert, null);
+ long notBefore = ((X509Certificate) cert).getNotBefore().getTime();
+ long notAfter = ((X509Certificate) cert).getNotAfter().getTime();
+ if (now < notBefore) {
+ certInfo.setNotYetValidCert();
+ }
+
+ if (notAfter < now) {
+ certInfo.setHasExpiredCert();
+ } else if (notAfter < now + SIX_MONTHS) {
+ certInfo.setHasExpiringCert();
+ }
+ }
+ }
+ }
+
+ // Every signable entry of this jar needs to be signed by at least
+ // one signer for the jar to be considered successfully signed.
+ VerifyResult result = null;
+ if (allEntriesSignedBySingleCert) {
+
+ // We need to find at least one signer without any issues.
+ for (CertPath entryCertPath : jarSignCount.keySet()) {
+ if (certs.containsKey(entryCertPath)
+ && !hasSigningIssues(entryCertPath)) {
+ result = VerifyResult.SIGNED_OK;
+ break;
+ }
}
+ if (result == null) {
+ // All signers had issues
+ result = VerifyResult.SIGNED_NOT_OK;
+ }
+ } else {
+ result = VerifyResult.UNSIGNED;
+ }
- if (!rootInCacerts)
- addToDetails(R("SUntrustedCertificate"));
- else
- addToDetails(R("STrustedCertificate"));
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Jar found at " + jarName
+ + "has been verified as " + result);
}
+ return result;
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#getPublisher()
+ /**
+ * Checks the user's trusted.certs file and the cacerts file to see if a
+ * publisher's and/or CA's certificate exists there.
+ *
+ * @param certPath
+ * The cert path of the signer being checked for trust.
*/
- public Certificate getPublisher() {
- if (certPath != null) {
- List<? extends Certificate> certList = certPath.getCertificates();
+ private void checkTrustedCerts(CertPath certPath) throws Exception {
+ CertInformation info = certs.get(certPath);
+ try {
+ X509Certificate publisher = (X509Certificate) getPublisher(certPath);
+ KeyStore[] certKeyStores = KeyStores.getCertKeyStores();
+ if (CertificateUtils.inKeyStores(publisher, certKeyStores))
+ info.setAlreadyTrustPublisher();
+ KeyStore[] caKeyStores = KeyStores.getCAKeyStores();
+ // Check entire cert path for a trusted CA
+ for (Certificate c : certPath.getCertificates()) {
+ if (CertificateUtils.inKeyStores((X509Certificate) c,
+ caKeyStores)) {
+ info.setRootInCacerts();
+ return;
+ }
+ }
+ } catch (Exception e) {
+ // TODO: Warn user about not being able to
+ // look through their cacerts/trusted.certs
+ // file depending on exception.
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("WARNING: Unable to read through cert store files.");
+ }
+ throw e;
+ }
+
+ // Otherwise a parent cert was not found to be trusted.
+ info.setUntrusted();
+ }
+
+ public void setCurrentlyUsedCertPath(CertPath cPath) {
+ currentlyUsed = cPath;
+ }
+
+ public Certificate getPublisher(CertPath cPath) {
+ if (cPath != null) {
+ currentlyUsed = cPath;
+ }
+ if (currentlyUsed != null) {
+ List<? extends Certificate> certList = currentlyUsed
+ .getCertificates();
if (certList.size() > 0) {
return certList.get(0);
} else {
@@ -425,12 +482,13 @@ public class JarCertVerifier implements CertVerifier {
}
}
- /* (non-Javadoc)
- * @see net.sourceforge.jnlp.tools.CertVerifier2#getRoot()
- */
- public Certificate getRoot() {
- if (certPath != null) {
- List<? extends Certificate> certList = certPath.getCertificates();
+ public Certificate getRoot(CertPath cPath) {
+ if (cPath != null) {
+ currentlyUsed = cPath;
+ }
+ if (currentlyUsed != null) {
+ List<? extends Certificate> certList = currentlyUsed
+ .getCertificates();
if (certList.size() > 0) {
return certList.get(certList.size() - 1);
} else {
@@ -441,20 +499,10 @@ public class JarCertVerifier implements CertVerifier {
}
}
- private void addToDetails(String detail) {
- if (!details.contains(detail))
- details.add(detail);
- }
-
/**
* Returns whether a file is in META-INF, and thus does not require signing.
- *
- * Signature-related files under META-INF include:
- * . META-INF/MANIFEST.MF
- * . META-INF/SIG-*
- * . META-INF/*.SF
- * . META-INF/*.DSA
- * . META-INF/*.RSA
+ *
+ * Signature-related files under META-INF include: . META-INF/MANIFEST.MF . META-INF/SIG-* . META-INF/*.SF . META-INF/*.DSA . META-INF/*.RSA
*/
static boolean isMetaInfFile(String name) {
String ucName = name.toUpperCase();
@@ -463,15 +511,19 @@ public class JarCertVerifier implements CertVerifier {
/**
* Check if userCert is designed to be a code signer
- * @param userCert the certificate to be examined
- * @param bad 3 booleans to show if the KeyUsage, ExtendedKeyUsage,
- * NetscapeCertType has codeSigning flag turned on.
- * If null, the class field badKeyUsage, badExtendedKeyUsage,
+ *
+ * @param userCert
+ * the certificate to be examined
+ * @param bad
+ * 3 booleans to show if the KeyUsage, ExtendedKeyUsage,
+ * NetscapeCertType has codeSigning flag turned on. If null,
+ * the class field badKeyUsage, badExtendedKeyUsage,
* badNetscapeCertType will be set.
- *
- * Required for verifyJar()
+ *
+ * Required for verifyJar()
*/
- void checkCertUsage(X509Certificate userCert, boolean[] bad) {
+ void checkCertUsage(CertPath certPath, X509Certificate userCert,
+ boolean[] bad) {
// Can act as a signer?
// 1. if KeyUsage, then [0] should be true
@@ -489,7 +541,7 @@ public class JarCertVerifier implements CertVerifier {
if (bad != null) {
bad[0] = true;
} else {
- badKeyUsage = true;
+ certs.get(certPath).setBadKeyUsage();
}
}
}
@@ -502,7 +554,7 @@ public class JarCertVerifier implements CertVerifier {
if (bad != null) {
bad[1] = true;
} else {
- badExtendedKeyUsage = true;
+ certs.get(certPath).setBadExtendedKeyUsage();
}
}
}
@@ -512,24 +564,24 @@ public class JarCertVerifier implements CertVerifier {
try {
// OID_NETSCAPE_CERT_TYPE
- byte[] netscapeEx = userCert.getExtensionValue
- ("2.16.840.1.113730.1.1");
+ byte[] netscapeEx = userCert
+ .getExtensionValue("2.16.840.1.113730.1.1");
if (netscapeEx != null) {
DerInputStream in = new DerInputStream(netscapeEx);
byte[] encoded = in.getOctetString();
encoded = new DerValue(encoded).getUnalignedBitString()
.toByteArray();
- NetscapeCertTypeExtension extn =
- new NetscapeCertTypeExtension(encoded);
+ NetscapeCertTypeExtension extn = new NetscapeCertTypeExtension(
+ encoded);
- Boolean val = (Boolean) extn.get(
- NetscapeCertTypeExtension.OBJECT_SIGNING);
+ Boolean val = (Boolean) extn
+ .get(NetscapeCertTypeExtension.OBJECT_SIGNING);
if (!val) {
if (bad != null) {
bad[2] = true;
} else {
- badNetscapeCertType = true;
+ certs.get(certPath).setBadNetscapeCertType();
}
}
}
@@ -540,11 +592,31 @@ public class JarCertVerifier implements CertVerifier {
/**
* Returns if all jars are signed.
- *
+ *
* @return True if all jars are signed, false if there are one or more unsigned jars
*/
public boolean allJarsSigned() {
return this.unverifiedJars.size() == 0;
}
+ public void checkTrustWithUser(JNLPFile file) throws LaunchException {
+ appVerifier.checkTrustWithUser(this, file);
+ }
+
+ public Map<String, Integer> getJarSignableEntries() {
+ return Collections.unmodifiableMap(jarSignableEntries);
+ }
+
+ /**
+ * Get the total number of entries in the provided map.
+ *
+ * @return The number of entries.
+ */
+ public static int getTotalJarEntries(Map<String, Integer> map) {
+ int sum = 0;
+ for (int value : map.values()) {
+ sum += value;
+ }
+ return sum;
+ }
}