diff options
author | andrew <devnull@localhost> | 2010-10-19 17:55:59 +0100 |
---|---|---|
committer | andrew <devnull@localhost> | 2010-10-19 17:55:59 +0100 |
commit | 7603e948d7a0a7eb2e72358cb4a40ae6779f95da (patch) | |
tree | c6441f7d14eafe8119d890cddd09b05b8f88c52a /netx/net/sourceforge/jnlp/security |
Initial import from IcedTea6.
2010-10-19 Andrew John Hughes <[email protected]>
* .hgignore,
* Makefile.am,
* acinclude.m4,
* autogen.sh,
* configure.ac,
* extra/net/sourceforge/jnlp/about/HTMLPanel.java,
* extra/net/sourceforge/jnlp/about/Main.java,
* extra/net/sourceforge/jnlp/about/resources/about.html,
* extra/net/sourceforge/jnlp/about/resources/applications.html,
* extra/net/sourceforge/jnlp/about/resources/notes.html,
* javac.in,
* javaws.desktop: Imported from IcedTea6.
* launcher/java.c,
* launcher/java.h,
* launcher/java_md.c,
* launcher/java_md.h,
* launcher/jli_util.h,
* launcher/jni.h,
* launcher/jvm.h,
* launcher/jvm_md.h,
* launcher/manifest_info.h,
* launcher/splashscreen.h,
* launcher/splashscreen_stubs.c,
* launcher/version_comp.h,
* launcher/wildcard.h: Imported from OpenJDK.
* netx/javaws.1,
* netx/javax/jnlp/BasicService.java,
* netx/javax/jnlp/ClipboardService.java,
* netx/javax/jnlp/DownloadService.java,
* netx/javax/jnlp/DownloadServiceListener.java,
* netx/javax/jnlp/ExtendedService.java,
* netx/javax/jnlp/ExtensionInstallerService.java,
* netx/javax/jnlp/FileContents.java,
* netx/javax/jnlp/FileOpenService.java,
* netx/javax/jnlp/FileSaveService.java,
* netx/javax/jnlp/JNLPRandomAccessFile.java,
* netx/javax/jnlp/PersistenceService.java,
* netx/javax/jnlp/PrintService.java,
* netx/javax/jnlp/ServiceManager.java,
* netx/javax/jnlp/ServiceManagerStub.java,
* netx/javax/jnlp/SingleInstanceListener.java,
* netx/javax/jnlp/SingleInstanceService.java,
* netx/javax/jnlp/UnavailableServiceException.java,
* netx/net/sourceforge/jnlp/AppletDesc.java,
* netx/net/sourceforge/jnlp/ApplicationDesc.java,
* netx/net/sourceforge/jnlp/AssociationDesc.java,
* netx/net/sourceforge/jnlp/ComponentDesc.java,
* netx/net/sourceforge/jnlp/DefaultLaunchHandler.java,
* netx/net/sourceforge/jnlp/ExtensionDesc.java,
* netx/net/sourceforge/jnlp/IconDesc.java,
* netx/net/sourceforge/jnlp/InformationDesc.java,
* netx/net/sourceforge/jnlp/InstallerDesc.java,
* netx/net/sourceforge/jnlp/JARDesc.java,
* netx/net/sourceforge/jnlp/JNLPFile.java,
* netx/net/sourceforge/jnlp/JNLPSplashScreen.java,
* netx/net/sourceforge/jnlp/JREDesc.java,
* netx/net/sourceforge/jnlp/LaunchException.java,
* netx/net/sourceforge/jnlp/LaunchHandler.java,
* netx/net/sourceforge/jnlp/Launcher.java,
* netx/net/sourceforge/jnlp/MenuDesc.java,
* netx/net/sourceforge/jnlp/NetxPanel.java,
* netx/net/sourceforge/jnlp/Node.java,
* netx/net/sourceforge/jnlp/PackageDesc.java,
* netx/net/sourceforge/jnlp/ParseException.java,
* netx/net/sourceforge/jnlp/Parser.java,
* netx/net/sourceforge/jnlp/PluginBridge.java,
* netx/net/sourceforge/jnlp/PropertyDesc.java,
* netx/net/sourceforge/jnlp/RelatedContentDesc.java,
* netx/net/sourceforge/jnlp/ResourcesDesc.java,
* netx/net/sourceforge/jnlp/SecurityDesc.java,
* netx/net/sourceforge/jnlp/ShortcutDesc.java,
* netx/net/sourceforge/jnlp/StreamEater.java,
* netx/net/sourceforge/jnlp/UpdateDesc.java,
* netx/net/sourceforge/jnlp/Version.java,
* netx/net/sourceforge/jnlp/cache/CacheEntry.java,
* netx/net/sourceforge/jnlp/cache/CacheUtil.java,
* netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java,
* netx/net/sourceforge/jnlp/cache/DownloadIndicator.java,
* netx/net/sourceforge/jnlp/cache/Resource.java,
* netx/net/sourceforge/jnlp/cache/ResourceTracker.java,
* netx/net/sourceforge/jnlp/cache/UpdatePolicy.java,
* netx/net/sourceforge/jnlp/cache/package.html,
* netx/net/sourceforge/jnlp/event/ApplicationEvent.java,
* netx/net/sourceforge/jnlp/event/ApplicationListener.java,
* netx/net/sourceforge/jnlp/event/DownloadEvent.java,
* netx/net/sourceforge/jnlp/event/DownloadListener.java,
* netx/net/sourceforge/jnlp/event/package.html,
* netx/net/sourceforge/jnlp/package.html,
* netx/net/sourceforge/jnlp/resources/Manifest.mf,
* netx/net/sourceforge/jnlp/resources/Messages.properties,
* netx/net/sourceforge/jnlp/resources/about.jnlp,
* netx/net/sourceforge/jnlp/resources/default.jnlp,
* netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java,
* netx/net/sourceforge/jnlp/runtime/AppletAudioClip.java,
* netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java,
* netx/net/sourceforge/jnlp/runtime/AppletInstance.java,
* netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java,
* netx/net/sourceforge/jnlp/runtime/Boot.java,
* netx/net/sourceforge/jnlp/runtime/Boot13.java,
* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java,
* netx/net/sourceforge/jnlp/runtime/JNLPPolicy.java,
* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java,
* netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java,
* netx/net/sourceforge/jnlp/runtime/package.html,
* netx/net/sourceforge/jnlp/security/AccessWarningPane.java,
* netx/net/sourceforge/jnlp/security/AppletWarningPane.java,
* netx/net/sourceforge/jnlp/security/CertVerifier.java,
* netx/net/sourceforge/jnlp/security/CertWarningPane.java,
* netx/net/sourceforge/jnlp/security/CertsInfoPane.java,
* netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java,
* netx/net/sourceforge/jnlp/security/MoreInfoPane.java,
* netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java,
* netx/net/sourceforge/jnlp/security/SecurityDialogPanel.java,
* netx/net/sourceforge/jnlp/security/SecurityUtil.java,
* netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java,
* netx/net/sourceforge/jnlp/security/SingleCertInfoPane.java,
* netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java,
* netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java,
* netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java,
* netx/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java,
* netx/net/sourceforge/jnlp/services/InstanceExistsException.java,
* netx/net/sourceforge/jnlp/services/ServiceUtil.java,
* netx/net/sourceforge/jnlp/services/SingleInstanceLock.java,
* netx/net/sourceforge/jnlp/services/XBasicService.java,
* netx/net/sourceforge/jnlp/services/XClipboardService.java,
* netx/net/sourceforge/jnlp/services/XDownloadService.java,
* netx/net/sourceforge/jnlp/services/XExtendedService.java,
* netx/net/sourceforge/jnlp/services/XExtensionInstallerService.java,
* netx/net/sourceforge/jnlp/services/XFileContents.java,
* netx/net/sourceforge/jnlp/services/XFileOpenService.java,
* netx/net/sourceforge/jnlp/services/XFileSaveService.java,
* netx/net/sourceforge/jnlp/services/XJNLPRandomAccessFile.java,
* netx/net/sourceforge/jnlp/services/XPersistenceService.java,
* netx/net/sourceforge/jnlp/services/XPrintService.java,
* netx/net/sourceforge/jnlp/services/XServiceManagerStub.java,
* netx/net/sourceforge/jnlp/services/XSingleInstanceService.java,
* netx/net/sourceforge/jnlp/services/package.html,
* netx/net/sourceforge/jnlp/tools/CharacterEncoder.java,
* netx/net/sourceforge/jnlp/tools/HexDumpEncoder.java,
* netx/net/sourceforge/jnlp/tools/JarRunner.java,
* netx/net/sourceforge/jnlp/tools/JarSigner.java,
* netx/net/sourceforge/jnlp/tools/JarSignerResources.java,
* netx/net/sourceforge/jnlp/tools/KeyStoreUtil.java,
* netx/net/sourceforge/jnlp/tools/KeyTool.java,
* netx/net/sourceforge/jnlp/util/FileUtils.java,
* netx/net/sourceforge/jnlp/util/PropertiesFile.java,
* netx/net/sourceforge/jnlp/util/Reflect.java,
* netx/net/sourceforge/jnlp/util/WeakList.java,
* netx/net/sourceforge/jnlp/util/XDesktopEntry.java,
* netx/net/sourceforge/nanoxml/XMLElement.java,
* netx/net/sourceforge/nanoxml/XMLParseException.java,
* plugin/icedteanp/IcedTeaJavaRequestProcessor.cc,
* plugin/icedteanp/IcedTeaJavaRequestProcessor.h,
* plugin/icedteanp/IcedTeaNPPlugin.cc,
* plugin/icedteanp/IcedTeaNPPlugin.h,
* plugin/icedteanp/IcedTeaPluginRequestProcessor.cc,
* plugin/icedteanp/IcedTeaPluginRequestProcessor.h,
* plugin/icedteanp/IcedTeaPluginUtils.cc,
* plugin/icedteanp/IcedTeaPluginUtils.h,
* plugin/icedteanp/IcedTeaRunnable.cc,
* plugin/icedteanp/IcedTeaRunnable.h,
* plugin/icedteanp/IcedTeaScriptablePluginObject.cc,
* plugin/icedteanp/IcedTeaScriptablePluginObject.h,
* plugin/icedteanp/java/netscape/javascript/JSException.java,
* plugin/icedteanp/java/netscape/javascript/JSObject.java,
* plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java,
* plugin/icedteanp/java/netscape/javascript/JSProxy.java,
* plugin/icedteanp/java/netscape/javascript/JSRunnable.java,
* plugin/icedteanp/java/netscape/javascript/JSUtil.java,
* plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java,
* plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java,
* plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java,
* plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java,
* plugin/icedteanp/java/sun/applet/JavaConsole.java,
* plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java,
* plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java,
* plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java,
* plugin/icedteanp/java/sun/applet/PluginAppletViewer.java,
* plugin/icedteanp/java/sun/applet/PluginCallRequest.java,
* plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java,
* plugin/icedteanp/java/sun/applet/PluginClassLoader.java,
* plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java,
* plugin/icedteanp/java/sun/applet/PluginCookieManager.java,
* plugin/icedteanp/java/sun/applet/PluginDebug.java,
* plugin/icedteanp/java/sun/applet/PluginException.java,
* plugin/icedteanp/java/sun/applet/PluginMain.java,
* plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java,
* plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java,
* plugin/icedteanp/java/sun/applet/PluginObjectStore.java,
* plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java,
* plugin/icedteanp/java/sun/applet/PluginProxySelector.java,
* plugin/icedteanp/java/sun/applet/PluginStreamHandler.java,
* plugin/icedteanp/java/sun/applet/RequestQueue.java,
* plugin/icedteanp/java/sun/applet/TestEnv.java,
* plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java,
* plugin/tests/LiveConnect/DummyObject.java,
* plugin/tests/LiveConnect/OverloadTestHelper1.java,
* plugin/tests/LiveConnect/OverloadTestHelper2.java,
* plugin/tests/LiveConnect/OverloadTestHelper3.java,
* plugin/tests/LiveConnect/PluginTest.java,
* plugin/tests/LiveConnect/build,
* plugin/tests/LiveConnect/common.js,
* plugin/tests/LiveConnect/index.html,
* plugin/tests/LiveConnect/jjs_eval_test.js,
* plugin/tests/LiveConnect/jjs_func_parameters_tests.js,
* plugin/tests/LiveConnect/jjs_func_rettype_tests.js,
* plugin/tests/LiveConnect/jjs_get_tests.js,
* plugin/tests/LiveConnect/jjs_set_tests.js,
* plugin/tests/LiveConnect/jsj_func_overload_tests.js,
* plugin/tests/LiveConnect/jsj_func_parameters_tests.js,
* plugin/tests/LiveConnect/jsj_func_rettype_tests.js,
* plugin/tests/LiveConnect/jsj_get_tests.js,
* plugin/tests/LiveConnect/jsj_set_tests.js,
* plugin/tests/LiveConnect/jsj_type_casting_tests.js,
* plugin/tests/LiveConnect/jsj_type_conversion_tests.js:
Initial import from IcedTea6.
* AUTHORS,
* COPYING
* INSTALL,
* NEWS,
* README: New documentation.
Diffstat (limited to 'netx/net/sourceforge/jnlp/security')
15 files changed, 3218 insertions, 0 deletions
diff --git a/netx/net/sourceforge/jnlp/security/AccessWarningPane.java b/netx/net/sourceforge/jnlp/security/AccessWarningPane.java new file mode 100644 index 0000000..5afbfff --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/AccessWarningPane.java @@ -0,0 +1,209 @@ +/* AccessWarningPane.java + Copyright (C) 2008 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.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.util.FileUtils; + +/** + * Provides a panel to show inside a SecurityWarningDialog. These dialogs are + * used to warn the user when either signed code (with or without signing + * issues) is going to be run, or when service permission (file, clipboard, + * printer, etc) is needed with unsigned code. + * + * @author <a href="mailto:[email protected]">Joshua Sumali</a> + */ +public class AccessWarningPane extends SecurityDialogPanel { + + JCheckBox alwaysAllow; + Object[] extras; + + public AccessWarningPane(SecurityWarningDialog x, CertVerifier certVerifier) { + super(x, certVerifier); + addComponents(); + } + + public AccessWarningPane(SecurityWarningDialog x, Object[] extras, CertVerifier certVerifier) { + super(x, certVerifier); + this.extras = extras; + addComponents(); + } + + /** + * Creates the actual GUI components, and adds it to this panel + */ + private void addComponents() { + SecurityWarningDialog.AccessType type = parent.getAccessType(); + JNLPFile file = parent.getFile(); + + String name = ""; + String publisher = ""; + String from = ""; + + //We don't worry about exceptions when trying to fill in + //these strings -- we just want to fill in as many as possible. + try { + name = file.getInformation().getTitle() != null ? file.getInformation().getTitle() : "<no associated certificate>"; + } catch (Exception e) { + } + + try { + publisher = file.getInformation().getVendor() != null ? file.getInformation().getVendor() : "<no associated certificate>"; + } catch (Exception e) { + } + + try { + from = !file.getInformation().getHomepage().toString().equals("") ? file.getInformation().getHomepage().toString() : file.getSourceLocation().getAuthority(); + } catch (Exception e) { + from = file.getSourceLocation().getAuthority(); + } + + //Top label + String topLabelText = ""; + switch (type) { + case READ_FILE: + if (extras != null && extras.length > 0 && extras[0] instanceof String) { + topLabelText = R("SFileReadAccess", FileUtils.displayablePath((String)extras[0])); + } else { + topLabelText = R("SFileReadAccess", R("AFileOnTheMachine")); + } + break; + case WRITE_FILE: + if (extras != null && extras.length > 0 && extras[0] instanceof String) { + topLabelText = R("SFileWriteAccess", FileUtils.displayablePath((String)extras[0])); + } else { + topLabelText = R("SFileWriteAccess", R("AFileOnTheMachine")); + } + break; + case CREATE_DESTKOP_SHORTCUT: + topLabelText = R("SDesktopShortcut"); + break; + case CLIPBOARD_READ: + topLabelText = R("SClipboardReadAccess"); + break; + case CLIPBOARD_WRITE: + topLabelText = R("SClipboardWriteAccess"); + break; + case PRINTER: + topLabelText = R("SPrinterAccess"); + break; + case NETWORK: + if (extras != null && extras.length >= 0) + topLabelText = R("SNetworkAccess", extras[0]); + else + topLabelText = R("SNetworkAccess", "(address here)"); + } + + ImageIcon icon = new ImageIcon((new sun.misc.Launcher()).getClassLoader().getResource("net/sourceforge/jnlp/resources/warning.png")); + JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, SwingConstants.LEFT); + topLabel.setFont(new Font(topLabel.getFont().toString(), + Font.BOLD, 12)); + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.setBackground(Color.WHITE); + topPanel.add(topLabel, BorderLayout.CENTER); + topPanel.setPreferredSize(new Dimension(450,100)); + topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //application info + JLabel nameLabel = new JLabel("Name: " + name); + nameLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + JLabel publisherLabel = new JLabel("Publisher: " + publisher); + publisherLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + JLabel fromLabel = new JLabel("From: " + from); + fromLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + + alwaysAllow = new JCheckBox("Always allow this action"); + alwaysAllow.setEnabled(false); + + JPanel infoPanel = new JPanel(new GridLayout(4,1)); + infoPanel.add(nameLabel); + infoPanel.add(publisherLabel); + infoPanel.add(fromLabel); + infoPanel.add(alwaysAllow); + infoPanel.setBorder(BorderFactory.createEmptyBorder(25,25,25,25)); + + //run and cancel buttons + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + JButton run = new JButton("Allow"); + JButton cancel = new JButton("Cancel"); + run.addActionListener(createSetValueListener(parent,0)); + run.addActionListener(new CheckBoxListener()); + cancel.addActionListener(createSetValueListener(parent, 1)); + initialFocusComponent = cancel; + buttonPanel.add(run); + buttonPanel.add(cancel); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //all of the above + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(topPanel); + add(infoPanel); + add(buttonPanel); + + } + + + private class CheckBoxListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + if (alwaysAllow != null && alwaysAllow.isSelected()) { + // TODO: somehow tell the ApplicationInstance + // to stop asking for permission + } + } + } + +} diff --git a/netx/net/sourceforge/jnlp/security/AppletWarningPane.java b/netx/net/sourceforge/jnlp/security/AppletWarningPane.java new file mode 100644 index 0000000..8bd14ef --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/AppletWarningPane.java @@ -0,0 +1,115 @@ +/* AppletWarningPane.java + Copyright (C) 2008 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.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; + + +public class AppletWarningPane extends SecurityDialogPanel { + + public AppletWarningPane(SecurityWarningDialog x, CertVerifier certVerifier) { + super(x, certVerifier); + addComponents(); + } + + protected void addComponents() { + + //Top label + String topLabelText = "While support for verifying signed code" + + " has not been implemented yet, some applets will not run " + + "properly under the default restricted security level."; + String bottomLabelText = "Do you want to run this applet under the " + + "restricted security level? (clicking No will run this applet " + + "without any security checking, and should only be done if you " + + "trust the applet!)"; + + JLabel topLabel = new JLabel(htmlWrap(topLabelText)); + topLabel.setFont(new Font(topLabel.getFont().toString(), + Font.BOLD, 12)); + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.setBackground(Color.WHITE); + topPanel.add(topLabel, BorderLayout.CENTER); + topPanel.setPreferredSize(new Dimension(400,80)); + topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + JLabel bottomLabel = new JLabel(htmlWrap(bottomLabelText)); + JPanel infoPanel = new JPanel(new BorderLayout()); + infoPanel.add(bottomLabel, BorderLayout.CENTER); + infoPanel.setPreferredSize(new Dimension(400,80)); + infoPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //run and cancel buttons + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + JButton yes = new JButton("Yes"); + JButton no = new JButton("No"); + JButton cancel = new JButton("Cancel"); + int buttonWidth = cancel.getMinimumSize().width; + int buttonHeight = cancel.getMinimumSize().height; + Dimension d = new Dimension(buttonWidth, buttonHeight); + yes.setPreferredSize(d); + no.setPreferredSize(d); + cancel.setPreferredSize(d); + yes.addActionListener(createSetValueListener(parent, 0)); + no.addActionListener(createSetValueListener(parent, 1)); + cancel.addActionListener(createSetValueListener(parent, 2)); + initialFocusComponent = cancel; + buttonPanel.add(yes); + buttonPanel.add(no); + buttonPanel.add(cancel); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //all of the above + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(topPanel); + add(infoPanel); + add(buttonPanel); + + } + +} diff --git a/netx/net/sourceforge/jnlp/security/CertVerifier.java b/netx/net/sourceforge/jnlp/security/CertVerifier.java new file mode 100644 index 0000000..cef69c3 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/CertVerifier.java @@ -0,0 +1,92 @@ +/* CertVerifier.java + Copyright (C) 2009 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.security.cert.Certificate; +import java.util.ArrayList; + +/** + * An interface that provides various details about a certificate + */ + +public interface CertVerifier { + + /** + * Return if the publisher is already trusted + */ + public boolean getAlreadyTrustPublisher(); + + /** + * Return if the root is in CA certs + */ + public boolean getRootInCacerts(); + + /** + * Return if there are signing issues with the certificate(s) being veried + */ + public boolean hasSigningIssues(); + + /** + * Return if there are no signing issues with this cert (!hasSigningIssues()) + */ + public boolean noSigningIssues(); + + /** + * 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 The CertPath + */ + public ArrayList<CertPath> getCerts(); + + /** + * Returns the application's publisher's certificate. + */ + public abstract Certificate getPublisher(); + + /** + * Returns the application's root's certificate. This + * may return the same certificate as getPublisher() in + * the event that the application is self signed. + */ + public abstract Certificate getRoot(); +} diff --git a/netx/net/sourceforge/jnlp/security/CertWarningPane.java b/netx/net/sourceforge/jnlp/security/CertWarningPane.java new file mode 100644 index 0000000..59559c4 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/CertWarningPane.java @@ -0,0 +1,254 @@ +/* CertWarningPane.java + Copyright (C) 2008 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.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.PluginBridge; +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.tools.KeyTool; + +/** + * Provides the panel for using inside a SecurityWarningDialog. These dialogs are + * used to warn the user when either signed code (with or without signing + * issues) is going to be run, or when service permission (file, clipboard, + * printer, etc) is needed with unsigned code. + * + * @author <a href="mailto:[email protected]">Joshua Sumali</a> + */ +public class CertWarningPane extends SecurityDialogPanel { + + JCheckBox alwaysTrust; + CertVerifier certVerifier; + + public CertWarningPane(SecurityWarningDialog x, CertVerifier certVerifier) { + super(x, certVerifier); + this.certVerifier = certVerifier; + addComponents(); + } + + /** + * Creates the actual GUI components, and adds it to this panel + */ + private void addComponents() { + SecurityWarningDialog.AccessType type = parent.getAccessType(); + JNLPFile file = parent.getFile(); + Certificate c = parent.getJarSigner().getPublisher(); + + String name = ""; + String publisher = ""; + String from = ""; + + //We don't worry about exceptions when trying to fill in + //these strings -- we just want to fill in as many as possible. + try { + if ((certVerifier instanceof HttpsCertVerifier) && + (c instanceof X509Certificate)) + name = SecurityUtil.getCN(((X509Certificate)c) + .getSubjectX500Principal().getName()); + else if (file instanceof PluginBridge) + name = file.getTitle(); + else + name = file.getInformation().getTitle(); + } catch (Exception e) { + } + + try { + if (c instanceof X509Certificate) { + publisher = SecurityUtil.getCN(((X509Certificate)c) + .getSubjectX500Principal().getName()); + } + } catch (Exception e) { + } + + try { + if (file instanceof PluginBridge) + from = file.getCodeBase().getHost(); + else + from = file.getInformation().getHomepage().toString(); + } catch (Exception e) { + } + + //Top label + String topLabelText = ""; + String propertyName = ""; + if (certVerifier instanceof HttpsCertVerifier) + { + topLabelText = "The website's certificate cannot be verified. " + + "Do you want to continue?"; + propertyName = "OptionPane.warningIcon"; + } + else + switch (type) { + case VERIFIED: + topLabelText = R("SSigVerified"); + propertyName = "OptionPane.informationIcon"; + break; + case UNVERIFIED: + topLabelText = R("SSigUnverified"); + propertyName = "OptionPane.warningIcon"; + break; + case SIGNING_ERROR: + topLabelText = R("SSignatureError"); + propertyName = "OptionPane.warningIcon"; + break; + } + ImageIcon icon = new ImageIcon((new sun.misc.Launcher()) + .getClassLoader().getResource("net/sourceforge/jnlp/resources/warning.png")); + JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, SwingConstants.LEFT); + topLabel.setFont(new Font(topLabel.getFont().toString(), + Font.BOLD, 12)); + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.setBackground(Color.WHITE); + topPanel.add(topLabel, BorderLayout.CENTER); + topPanel.setPreferredSize(new Dimension(400,60)); + topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //application info + JLabel nameLabel = new JLabel("Name: " + name); + nameLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + JLabel publisherLabel = new JLabel("Publisher: " + publisher); + publisherLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + JLabel fromLabel = new JLabel("From: " + from); + fromLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + + alwaysTrust = new JCheckBox( + "Always trust content from this publisher"); + alwaysTrust.setEnabled(true); + + JPanel infoPanel = new JPanel(new GridLayout(4,1)); + infoPanel.add(nameLabel); + infoPanel.add(publisherLabel); + + if (!(certVerifier instanceof HttpsCertVerifier)) + infoPanel.add(fromLabel); + + infoPanel.add(alwaysTrust); + infoPanel.setBorder(BorderFactory.createEmptyBorder(25,25,25,25)); + + //run and cancel buttons + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + JButton run = new JButton("Run"); + JButton cancel = new JButton("Cancel"); + int buttonWidth = Math.max(run.getMinimumSize().width, + cancel.getMinimumSize().width); + int buttonHeight = run.getMinimumSize().height; + Dimension d = new Dimension(buttonWidth, buttonHeight); + run.setPreferredSize(d); + cancel.setPreferredSize(d); + run.addActionListener(createSetValueListener(parent, 0)); + run.addActionListener(new CheckBoxListener()); + cancel.addActionListener(createSetValueListener(parent, 1)); + initialFocusComponent = cancel; + buttonPanel.add(run); + buttonPanel.add(cancel); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //all of the above + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(topPanel); + add(infoPanel); + add(buttonPanel); + + JLabel bottomLabel; + JButton moreInfo = new JButton("More information..."); + moreInfo.addActionListener(new MoreInfoButtonListener()); + + if (parent.getJarSigner().getRootInCacerts()) + bottomLabel = new JLabel(htmlWrap(R("STrustedSource"))); + else + bottomLabel = new JLabel(htmlWrap(R("SUntrustedSource"))); + + JPanel bottomPanel = new JPanel(); + bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS)); + bottomPanel.add(bottomLabel); + bottomPanel.add(moreInfo); + bottomPanel.setPreferredSize(new Dimension(500,100)); + bottomPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + add(bottomPanel); + + } + + private class MoreInfoButtonListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + SecurityWarningDialog.showMoreInfoDialog(parent.getJarSigner(), + parent); + } + } + + /** + * Updates the user's KeyStore of trusted Certificates. + */ + private class CheckBoxListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + if (alwaysTrust != null && alwaysTrust.isSelected()) { + try { + KeyTool kt = new KeyTool(); + Certificate c = parent.getJarSigner().getPublisher(); + kt.importCert(c); + if (JNLPRuntime.isDebug()) { + System.out.println("certificate is now permanently trusted"); + } + } catch (Exception ex) { + //TODO: Let NetX show a dialog here notifying user + //about being unable to add cert to keystore + } + } + } + } + +} diff --git a/netx/net/sourceforge/jnlp/security/CertsInfoPane.java b/netx/net/sourceforge/jnlp/security/CertsInfoPane.java new file mode 100644 index 0000000..85afd1b --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/CertsInfoPane.java @@ -0,0 +1,341 @@ +/* CertsInfoPane.java + Copyright (C) 2008 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.util.ArrayList; +import java.util.Date; +import java.security.cert.CertPath; +import java.security.cert.X509Certificate; +import java.security.MessageDigest; +import java.math.BigInteger; +import javax.security.auth.x500.X500Principal; +import sun.security.x509.*; +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.table.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeSelectionModel; + +import net.sourceforge.jnlp.tools.*; + +/** + * Provides the panel for the Certificate Info dialog. This dialog displays data from + * X509Certificate(s) used in jar signing. + * + * @author <a href="mailto:[email protected]">Joshua Sumali</a> + */ +public class CertsInfoPane extends SecurityDialogPanel { + + private ArrayList<CertPath> certs; + private JList list; + protected JTree tree; + private JTable table; + private JTextArea output; + private ListSelectionModel listSelectionModel; + private ListSelectionModel tableSelectionModel; + protected String[] certNames; + private String[] columnNames = { "Field", "Value" }; + protected ArrayList<String[][]> certsData; + + public CertsInfoPane(SecurityWarningDialog x, CertVerifier certVerifier) { + super(x, certVerifier); + addComponents(); + } + + /** + * Builds the JTree out of CertPaths. + */ + void buildTree() { + certs = parent.getJarSigner().getCerts(); + //for now, we're only going to display the first signer, even though + //jars can be signed by multiple people. + CertPath firstPath = certs.get(0); + X509Certificate firstCert = + ((X509Certificate)firstPath.getCertificates().get(0)); + String subjectString = + SecurityUtil.getCN(firstCert.getSubjectX500Principal().getName()); + String issuerString = + SecurityUtil.getCN(firstCert.getIssuerX500Principal().getName()); + + DefaultMutableTreeNode top = + new DefaultMutableTreeNode(subjectString + + " (" + issuerString + ")"); + + //not self signed + if (!firstCert.getSubjectDN().equals(firstCert.getIssuerDN()) + && (firstPath.getCertificates().size() > 1)) { + X509Certificate secondCert = + ((X509Certificate)firstPath.getCertificates().get(1)); + subjectString = + SecurityUtil.getCN(secondCert.getSubjectX500Principal().getName()); + issuerString = + SecurityUtil.getCN(secondCert.getIssuerX500Principal().getName()); + top.add(new DefaultMutableTreeNode(subjectString + + " (" + issuerString + ")")); + } + + tree = new JTree(top); + tree.getSelectionModel().setSelectionMode + (TreeSelectionModel.SINGLE_TREE_SELECTION); + tree.addTreeSelectionListener(new TreeSelectionHandler()); + } + + /** + * Fills in certsNames, certsData with data from the certificates. + */ + protected void populateTable() { + certNames = new String[certs.get(0).getCertificates().size()]; + certsData = new ArrayList<String[][]>(); + + for (int i = 0; i < certs.get(0).getCertificates().size(); i++) { + + X509Certificate c = (X509Certificate) certs.get(0).getCertificates().get(i); + certsData.add(parseCert(c)); + certNames[i] = SecurityUtil.getCN(c.getSubjectX500Principal().getName()) + + " (" + SecurityUtil.getCN(c.getIssuerX500Principal().getName()) + ")"; + } + } + + protected String[][] parseCert(X509Certificate c) { + + String version = ""+c.getVersion(); + String serialNumber = c.getSerialNumber().toString(); + String signatureAlg = c.getSigAlgName(); + String issuer = c.getIssuerX500Principal().toString(); + String validity = new CertificateValidity(c.getNotBefore(), + c.getNotAfter()).toString(); + String subject = c.getSubjectX500Principal().toString(); + + //convert our signature into a nice human-readable form. + HexDumpEncoder encoder = new HexDumpEncoder(); + String signature = encoder.encodeBuffer(c.getSignature()); + + String md5Hash = ""; + String sha1Hash = ""; + try { + MessageDigest digest = MessageDigest.getInstance("MD5"); + digest.update(c.getEncoded()); + md5Hash = makeFingerprint(digest.digest()); + + digest = MessageDigest.getInstance("SHA-1"); + digest.update(c.getEncoded()); + sha1Hash = makeFingerprint(digest.digest()); + } catch (Exception e) { + //fail quietly + } + + String[][] cert = { {"Version", version}, + {"Serial", serialNumber}, + {"Signature Algorithm", signatureAlg}, + {"Issuer", issuer}, + {"Validity", validity}, + {"Subject", subject}, + {"Signature", signature}, + {"MD5 Fingerprint", md5Hash}, + {"SHA1 Fingerprint", sha1Hash} + }; + return cert; + } + + /** + * Constructs the GUI components of this panel + */ + protected void addComponents() { + buildTree(); + populateTable(); + /** + //List of Certs + list = new JList(certNames); + list.setSelectedIndex(0); //assuming there's at least 1 cert + listSelectionModel = list.getSelectionModel(); + listSelectionModel.addListSelectionListener(new ListSelectionHandler()); + JScrollPane listPane = new JScrollPane(list); + */ + JScrollPane listPane = new JScrollPane(tree); + + //Table of field-value pairs + DefaultTableModel tableModel = new DefaultTableModel(certsData.get(0), + columnNames); + table = new JTable(tableModel); + table.getTableHeader().setReorderingAllowed(false); + tableSelectionModel = table.getSelectionModel(); + tableSelectionModel.addListSelectionListener(new TableSelectionHandler()); + table.setFillsViewportHeight(true); + JScrollPane tablePane = new JScrollPane(table); + tablePane.setPreferredSize(new Dimension(500,200)); + + //Text area to display the larger values + output = new JTextArea(); + output.setEditable(false); + JScrollPane outputPane = new JScrollPane(output, + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + outputPane.setPreferredSize(new Dimension(500,200)); + + //split pane of the field-value pairs and textbox + JSplitPane rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, + tablePane, outputPane); + rightSplitPane.setDividerLocation(0.50); + rightSplitPane.setResizeWeight(0.50); + + JSplitPane mainPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + listPane, rightSplitPane); + mainPane.setDividerLocation(0.30); + mainPane.setResizeWeight(0.30); + + JPanel buttonPane = new JPanel(new BorderLayout()); + JButton close = new JButton("Close"); + JButton copyToClipboard = new JButton("Copy to Clipboard"); + close.addActionListener(createSetValueListener(parent, 0)); + copyToClipboard.addActionListener(new CopyToClipboardHandler()); + buttonPane.add(close, BorderLayout.EAST); + buttonPane.add(copyToClipboard, BorderLayout.WEST); + buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + + add(mainPane, BorderLayout.CENTER); + add(buttonPane, BorderLayout.SOUTH); + } + + /** + * Copies the currently selected certificate to the system Clipboard. + */ + private class CopyToClipboardHandler implements ActionListener { + public void actionPerformed(ActionEvent e) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + int certIndex = 0; + DefaultMutableTreeNode node = (DefaultMutableTreeNode) + tree.getLastSelectedPathComponent(); + if (node == null) return; + if (node.isRoot()) + certIndex = 0; + else if (node.isLeaf()) + certIndex = 1; + + String[][] cert = certsData.get(certIndex); + int rows = cert.length; + int cols = cert[0].length; + + String certString = ""; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + certString += cert[i][j]; + certString += " "; + } + certString += "\n"; + } + + clipboard.setContents(new StringSelection(certString), null); + } + } + + /** + * Updates the JTable when the JTree selection has changed. + */ + protected class TreeSelectionHandler implements TreeSelectionListener { + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) + tree.getLastSelectedPathComponent(); + + if (node == null) return; + if (node.isRoot()) { + table.setModel(new DefaultTableModel(certsData.get(0), + columnNames)); + } else if (node.isLeaf()) { + table.setModel(new DefaultTableModel(certsData.get(1), + columnNames)); + } + } + } + + /** + * Updates the JTable when the selection on the list has changed. + */ + private class ListSelectionHandler implements ListSelectionListener { + public void valueChanged(ListSelectionEvent e) { + ListSelectionModel lsm = (ListSelectionModel) e.getSource(); + + int minIndex = lsm.getMinSelectionIndex(); + int maxIndex = lsm.getMaxSelectionIndex(); + + for (int i = minIndex; i <= maxIndex; i++) { + if (lsm.isSelectedIndex(i)) { + table.setModel(new DefaultTableModel(certsData.get(i), + columnNames)); + } + } + } + } + + /** + * Updates the JTextArea output when the selection on the JTable + * has changed. + */ + private class TableSelectionHandler implements ListSelectionListener { + public void valueChanged(ListSelectionEvent e) { + ListSelectionModel lsm = (ListSelectionModel) e.getSource(); + + int minIndex = lsm.getMinSelectionIndex(); + int maxIndex = lsm.getMaxSelectionIndex(); + + for (int i = minIndex; i <= maxIndex; i++) { + if (lsm.isSelectedIndex(i)) { + output.setText((String) table.getValueAt(i,1)); + } + } + } + } + + /** + * Makes a human readable hash fingerprint. + * For example: 11:22:33:44:AA:BB:CC:DD:EE:FF. + */ + private String makeFingerprint(byte[] hash) { + String fingerprint = ""; + for (int i = 0; i < hash.length; i++) { + if (!fingerprint.equals("")) + fingerprint += ":"; + fingerprint += Integer.toHexString( + ((hash[i] & 0xFF)|0x100)).substring(1,3); + } + return fingerprint.toUpperCase(); + } +} diff --git a/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java b/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java new file mode 100644 index 0000000..ca2fc08 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java @@ -0,0 +1,238 @@ +/* HttpsCertVerifier.java + Copyright (C) 2009 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.io.IOException; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.tools.KeyTool; +import sun.security.util.DerValue; +import sun.security.util.HostnameChecker; +import sun.security.x509.X500Name; + +public class HttpsCertVerifier implements CertVerifier { + + private VariableX509TrustManager tm; + private X509Certificate[] chain; + private String authType; + private String hostName; + private boolean isTrusted; + private boolean hostMatched; + private ArrayList<String> details = new ArrayList<String>(); + + public HttpsCertVerifier(VariableX509TrustManager tm, + X509Certificate[] chain, String authType, + boolean isTrusted, boolean hostMatched, + String hostName) { + this.tm = tm; + this.chain = chain; + this.authType = authType; + this.hostName = hostName; + this.isTrusted = isTrusted; + this.hostMatched = hostMatched; + } + + public boolean getAlreadyTrustPublisher() { + return isTrusted; + } + + public ArrayList<CertPath> getCerts() { + + ArrayList<X509Certificate> list = new ArrayList<X509Certificate>(); + for (int i=0; i < chain.length; i++) + list.add(chain[i]); + + ArrayList<CertPath> certPaths = new ArrayList<CertPath>(); + + try { + certPaths.add(CertificateFactory.getInstance("X.509").generateCertPath(list)); + } catch (CertificateException ce) { + ce.printStackTrace(); + + // carry on + } + + return certPaths; + } + + public ArrayList<String> getDetails() { + + boolean hasExpiredCert=false; + boolean hasExpiringCert=false; + boolean notYetValidCert=false; + boolean isUntrusted=false; + boolean CNMisMatch = !hostMatched; + + if (! getAlreadyTrustPublisher()) + isUntrusted = true; + + for (int i=0; i < chain.length; i++) + { + X509Certificate cert = chain[i]; + + long now = System.currentTimeMillis(); + long SIX_MONTHS = 180*24*60*60*1000L; + long notAfter = cert.getNotAfter().getTime(); + if (notAfter < now) { + hasExpiredCert = true; + } else if (notAfter < now + SIX_MONTHS) { + hasExpiringCert = true; + } + + try { + cert.checkValidity(); + } catch (CertificateNotYetValidException cnyve) { + notYetValidCert = true; + } catch (CertificateExpiredException cee) { + hasExpiredCert = true; + } + } + + String altNames = getNamesForCert(chain[0]); + + if (isUntrusted || hasExpiredCert || hasExpiringCert || notYetValidCert || CNMisMatch) { + if (isUntrusted) + addToDetails(R("SUntrustedCertificate")); + if (hasExpiredCert) + addToDetails(R("SHasExpiredCert")); + if (hasExpiringCert) + addToDetails(R("SHasExpiringCert")); + if (notYetValidCert) + addToDetails(R("SNotYetValidCert")); + if (CNMisMatch) + addToDetails(R("SCNMisMatch", altNames, this.hostName)); + } + + + return details; + } + + private String getNamesForCert(X509Certificate c) { + + String names = ""; + + + // We use the specification from + // http://java.sun.com/j2se/1.5.0/docs/api/java/security/cert/X509Certificate.html#getSubjectAlternativeNames() + // to determine the type of address + int ALTNAME_DNS = 2; + int ALTNAME_IP = 7; + + try { + Collection<List<?>> subjAltNames = c.getSubjectAlternativeNames(); + X500Name subjectName = HostnameChecker.getSubjectX500Name(c); + DerValue derValue = subjectName.findMostSpecificAttribute + (X500Name.commonName_oid); + names += derValue.getAsString(); + + if (subjAltNames != null) { + for (List<?> next : subjAltNames) { + if ( ((Integer)next.get(0)).intValue() == ALTNAME_IP || + ((Integer)next.get(0)).intValue() == ALTNAME_DNS + ) { + names += ", " + (String)next.get(1); + } + } + } + + if (subjAltNames != null) + names = names.substring(2); // remove proceeding ", " + + } catch (CertificateParsingException cpe) { + cpe.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + + return names; + } + + private void addToDetails(String detail) { + if (!details.contains(detail)) + details.add(detail); + } + + private static String R(String key) { + return JNLPRuntime.getMessage(key); + } + + private static String R(String key, String arg1, String arg2) { + return JNLPRuntime.getMessage(key, new Object[] { arg1, arg2 }); + } + + public Certificate getPublisher() { + if (chain.length > 0) + return (Certificate)chain[0]; + return null; + } + + public Certificate getRoot() { + if (chain.length > 0) + return (Certificate)chain[chain.length - 1]; + return null; + } + + public boolean getRootInCacerts() { + try { + KeyTool kt = new KeyTool(); + return kt.checkCacertsForCertificate(getRoot()); + } catch (Exception e) { + } + return false; + } + + public boolean hasSigningIssues() { + return false; + } + + public boolean noSigningIssues() { + return false; + } + +} diff --git a/netx/net/sourceforge/jnlp/security/MoreInfoPane.java b/netx/net/sourceforge/jnlp/security/MoreInfoPane.java new file mode 100644 index 0000000..729eb1c --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/MoreInfoPane.java @@ -0,0 +1,110 @@ +/* MoreInfoPane.java + Copyright (C) 2008 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.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +/** + * Provides the panel for the More Info dialog. This dialog shows details about an + * application's signing status. + * + * @author <a href="mailto:[email protected]">Joshua Sumali</a> + */ +public class MoreInfoPane extends SecurityDialogPanel { + + public MoreInfoPane(SecurityWarningDialog x, CertVerifier certVerifier) { + super(x, certVerifier); + addComponents(); + } + + /** + * Constructs the GUI components of this panel + */ + private void addComponents() { + ArrayList<String> details = certVerifier.getDetails(); + + int numLabels = details.size(); + JPanel errorPanel = new JPanel(new GridLayout(numLabels,1)); + errorPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + errorPanel.setPreferredSize(new Dimension(400, 70*(numLabels))); + + for (int i = 0; i < numLabels; i++) { + ImageIcon icon = null; + if (details.get(i).equals(R("STrustedCertificate"))) + icon = new ImageIcon((new sun.misc.Launcher()) + .getClassLoader().getResource("net/sourceforge/jnlp/resources/info-small.png")); + else + icon = new ImageIcon((new sun.misc.Launcher()) + .getClassLoader().getResource("net/sourceforge/jnlp/resources/warning-small.png")); + + errorPanel.add(new JLabel(htmlWrap(details.get(i)), icon, SwingConstants.LEFT)); + } + + JPanel buttonsPanel = new JPanel(new BorderLayout()); + JButton certDetails = new JButton("Certificate Details"); + certDetails.addActionListener(new CertInfoButtonListener()); + JButton close = new JButton("Close"); + close.addActionListener(createSetValueListener(parent, 0)); + buttonsPanel.add(certDetails, BorderLayout.WEST); + buttonsPanel.add(close, BorderLayout.EAST); + buttonsPanel.setBorder(BorderFactory.createEmptyBorder(15,15,15,15)); + + add(errorPanel, BorderLayout.NORTH); + add(buttonsPanel, BorderLayout.SOUTH); + + } + + private class CertInfoButtonListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + SecurityWarningDialog.showCertInfoDialog(parent.getJarSigner(), + parent); + } + } +} diff --git a/netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java b/netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java new file mode 100644 index 0000000..7210a89 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/NotAllSignedWarningPane.java @@ -0,0 +1,120 @@ +/* NotAllSignedWarningPane.java + Copyright (C) 2008 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.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import net.sourceforge.jnlp.JNLPFile; + + +public class NotAllSignedWarningPane extends SecurityDialogPanel { + + public NotAllSignedWarningPane(SecurityWarningDialog x) { + super(x); + addComponents(); + } + + /** + * Creates the actual GUI components, and adds it to this panel + */ + private void addComponents() { + JNLPFile file = parent.getFile(); + + String topLabelText = "Only parts of this application code are signed."; + String infoLabelText = "This application contains both signed and" + + " unsigned code. While signed code is safe if you trust the " + + "provider, unsigned code may imply code outside of the trusted " + + "provider's control."; + String questionLabelText = "Do you wish to proceed and run this " + + "application anyway?"; + + ImageIcon icon = new ImageIcon((new sun.misc.Launcher()).getClassLoader().getResource("net/sourceforge/jnlp/resources/warning.png")); + JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, SwingConstants.LEFT); + topLabel.setFont(new Font(topLabel.getFont().toString(), + Font.BOLD, 12)); + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.setBackground(Color.WHITE); + topPanel.add(topLabel, BorderLayout.CENTER); + topPanel.setPreferredSize(new Dimension(500,80)); + topPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + JLabel infoLabel = new JLabel(htmlWrap(infoLabelText)); + JPanel infoPanel = new JPanel(new BorderLayout()); + infoPanel.add(infoLabel, BorderLayout.CENTER); + infoPanel.setPreferredSize(new Dimension(500,100)); + infoPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + JLabel questionLabel = new JLabel(htmlWrap(questionLabelText)); + JPanel questionPanel = new JPanel(new BorderLayout()); + questionPanel.add(questionLabel, BorderLayout.CENTER); + questionPanel.setPreferredSize(new Dimension(500,100)); + questionPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //run and cancel buttons + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + JButton run = new JButton("Proceed"); + JButton cancel = new JButton("Cancel"); + run.addActionListener(createSetValueListener(parent,0)); + cancel.addActionListener(createSetValueListener(parent, 1)); + initialFocusComponent = cancel; + buttonPanel.add(run); + buttonPanel.add(cancel); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + //all of the above + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(topPanel); + add(infoPanel); + add(questionPanel); + add(buttonPanel); + + } +} diff --git a/netx/net/sourceforge/jnlp/security/SecurityDialogPanel.java b/netx/net/sourceforge/jnlp/security/SecurityDialogPanel.java new file mode 100644 index 0000000..f3b8ee8 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SecurityDialogPanel.java @@ -0,0 +1,134 @@ + /* SecurityDialogPanel.java + Copyright (C) 2008-2010 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.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JComponent; +import javax.swing.JPanel; + + +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +/** + * Provides a JPanel for use in JNLP warning dialogs. + */ +public abstract class SecurityDialogPanel extends JPanel { + + protected SecurityWarningDialog parent; + + JComponent initialFocusComponent = null; + + CertVerifier certVerifier = null; + + public SecurityDialogPanel(SecurityWarningDialog dialog, CertVerifier certVerifier){ + this.parent = dialog; + this.certVerifier = certVerifier; + this.setLayout(new BorderLayout()); + } + + public SecurityDialogPanel(SecurityWarningDialog dialog) { + this.parent = dialog; + this.setLayout(new BorderLayout()); + } + + /* + * String translation functions + */ + + protected static String R(String key) { + return JNLPRuntime.getMessage(key); + } + + protected static String R(String key, Object param) { + return JNLPRuntime.getMessage(key, new Object[] {param}); + } + + /** + * Needed to get word wrap working in JLabels. + */ + protected String htmlWrap (String s) { + return "<html>"+s+"</html>"; + } + + /** + * Create an ActionListener suitable for use with buttons. When this {@link ActionListener} + * is invoked, it will set the value of the {@link SecurityWarningDialog} and then dispossed. + * + * @param buttonIndex the index of the button. By convention 0 = Yes. 1 = No, 2 = Cancel + * @return + */ + protected ActionListener createSetValueListener(SecurityWarningDialog dialog, int buttonIndex) { + return new SetValueHandler(dialog, buttonIndex); + } + + @Override + public void setVisible(boolean aFlag) { + super.setVisible(aFlag); + requestFocusOnDefaultButton(); + } + + public void requestFocusOnDefaultButton() { + if (initialFocusComponent != null) { + initialFocusComponent.requestFocusInWindow(); + } + } + + /** + * Creates a handler that sets a dialog's value and then disposes it when activated + * + */ + private class SetValueHandler implements ActionListener { + + Integer buttonIndex; + SecurityWarningDialog dialog; + + public SetValueHandler(SecurityWarningDialog dialog, int buttonIndex) { + this.dialog = dialog; + this.buttonIndex = buttonIndex; + } + + @Override + public void actionPerformed(ActionEvent e) { + dialog.setValue(buttonIndex); + dialog.dispose(); + } + } +} diff --git a/netx/net/sourceforge/jnlp/security/SecurityUtil.java b/netx/net/sourceforge/jnlp/security/SecurityUtil.java new file mode 100644 index 0000000..2a63a21 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SecurityUtil.java @@ -0,0 +1,285 @@ +/* SecurityUtil.java + Copyright (C) 2008 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.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.security.KeyStore; + +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +public class SecurityUtil { + + private static final char[] password = "changeit".toCharArray(); + + public static String getTrustedCertsFilename() throws Exception{ + + String homeDir = JNLPRuntime.HOME_DIR; + + if (homeDir == null) { + throw new Exception("Could not access home directory"); + } else { + return JNLPRuntime.CERTIFICATES_FILE; + } + } + + public static char[] getTrustedCertsPassword() { + return password; + } + + /** + * Extracts the CN field from a Certificate principal string. Or, if it + * can't find that, return the principal unmodified. + * + * This is a simple (and hence 'wrong') version. See + * http://www.ietf.org/rfc/rfc2253.txt for all the gory details. + */ + public static String getCN(String principal) { + + /* + * FIXME Incomplete + * + * This does not implement RFC 2253 completely + * + * Issues: + * - rfc2253 talks about utf8, java uses utf16. + * - theoretically, java should have dealt with all byte encodings + * so we shouldnt even see cases like \FF + * - if the above is wrong, then we need to deal with cases like + * \FF\FF + */ + + int start = principal.indexOf("CN="); + if (start == -1) { + return principal; + } + + StringBuilder commonName = new StringBuilder(); + + boolean inQuotes = false; + boolean escaped = false; + + /* + * bit 0 = high order bit. bit 1 = low order bit + */ + char[] hexBits = null; + + for (int i = start + 3; i < principal.length(); i++) { + char ch = principal.charAt(i); + switch (ch) { + case '"': + if (escaped) { + commonName.append(ch); + escaped = false; + } else { + inQuotes = !inQuotes; + } + break; + + case '\\': + if (escaped) { + commonName.append(ch); + escaped = false; + } else { + escaped = true; + } + break; + + case ',': + /* fall through */ + case ';': + /* fall through */ + case '+': + if (escaped || inQuotes) { + commonName.append(ch); + if (escaped) { + escaped = false; + } + } else { + return commonName.toString(); + } + break; + + default: + if (escaped && isHexDigit(ch)) { + hexBits = new char[2]; + hexBits[0] = ch; + } else if (hexBits != null) { + if (!isHexDigit(ch)) { + /* error parsing */ + return ""; + } + hexBits[1] = ch; + commonName.append((char) Integer.parseInt(new String(hexBits), 16)); + hexBits = null; + } else { + commonName.append(ch); + } + escaped = false; + } + } + + return commonName.toString(); + + } + + private static boolean isHexDigit(char ch) { + return ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')); + } + + /** + * Checks the user's home directory to see if the trusted.certs file exists. + * If it does not exist, it tries to create an empty keystore. + * @return true if the trusted.certs file exists or a new trusted.certs + * was created successfully, otherwise false. + */ + public static boolean checkTrustedCertsFile() throws Exception { + + File certFile = new File(getTrustedCertsFilename()); + + //file does not exist + if (!certFile.isFile()) { + File dir = certFile.getAbsoluteFile().getParentFile(); + boolean madeDir = false; + if (!dir.isDirectory()) { + madeDir = dir.mkdirs(); + } + + //made directory, or directory exists + if (madeDir || dir.isDirectory()) { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, password); + FileOutputStream fos = new FileOutputStream(certFile); + ks.store(fos, password); + fos.close(); + return true; + } else { + return false; + } + } else { + return true; + } + } + + /** + * Returns the keystore associated with the user's trusted.certs file, + * or null otherwise. + */ + public static KeyStore getUserKeyStore() throws Exception { + + KeyStore ks = null; + FileInputStream fis = null; + + if (checkTrustedCertsFile()) { + + try { + File file = new File(getTrustedCertsFilename()); + if (file.exists()) { + fis = new FileInputStream(file); + ks = KeyStore.getInstance("JKS"); + ks.load(fis, password); + } + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + if (fis != null) + fis.close(); + } + } + return ks; + } + + /** + * Returns the keystore associated with the JDK cacerts file, + * or null otherwise. + */ + public static KeyStore getCacertsKeyStore() throws Exception { + + KeyStore caks = null; + FileInputStream fis = null; + + try { + File file = new File(System.getProperty("java.home") + + "/lib/security/cacerts"); + if (file.exists()) { + fis = new FileInputStream(file); + caks = KeyStore.getInstance("JKS"); + caks.load(fis, null); + } + } catch (Exception e) { + caks = null; + } finally { + if (fis != null) + fis.close(); + } + + return caks; + } + + /** + * Returns the keystore associated with the system certs file, + * or null otherwise. + */ + public static KeyStore getSystemCertStore() throws Exception { + + KeyStore caks = null; + FileInputStream fis = null; + + try { + File file = new File(System.getProperty("javax.net.ssl.trustStore")); + String type = System.getProperty("javax.net.ssl.trustStoreType"); + //String provider = "SUN"; + char[] password = System.getProperty( + "javax.net.ssl.trustStorePassword").toCharArray(); + if (file.exists()) { + fis = new FileInputStream(file); + caks = KeyStore.getInstance(type); + caks.load(fis, password); + } + } catch (Exception e) { + caks = null; + } finally { + if (fis != null) + fis.close(); + } + + return caks; + } +} diff --git a/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java b/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java new file mode 100644 index 0000000..14f5fe0 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java @@ -0,0 +1,474 @@ +/* SecurityWarningDialog.java + Copyright (C) 2008 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 net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +import java.awt.*; + +import javax.swing.*; + +import java.awt.event.*; + +import java.security.cert.X509Certificate; + +/** + * Provides methods for showing security warning dialogs + * for a wide range of JNLP security issues. + * + * @author <a href="mailto:[email protected]">Joshua Sumali</a> + */ +public class SecurityWarningDialog extends JDialog { + + /** Types of dialogs we can create */ + public static enum DialogType { + CERT_WARNING, + MORE_INFO, + CERT_INFO, + SINGLE_CERT_INFO, + ACCESS_WARNING, + NOTALLSIGNED_WARNING, + APPLET_WARNING + } + + /** The types of access which may need user permission. */ + public static enum AccessType { + READ_FILE, + WRITE_FILE, + CREATE_DESTKOP_SHORTCUT, + CLIPBOARD_READ, + CLIPBOARD_WRITE, + PRINTER, + NETWORK, + VERIFIED, + UNVERIFIED, + NOTALLSIGNED, + SIGNING_ERROR + } + + /** The type of dialog we want to show */ + private DialogType dialogType; + + /** The type of access that this dialog is for */ + private AccessType accessType; + + private SecurityDialogPanel panel; + + /** The application file associated with this security warning */ + private JNLPFile file; + + private CertVerifier certVerifier; + + private X509Certificate cert; + + /** An optional String array that's only necessary when a dialog + * label requires some parameters (e.g. showing which address an application + * is trying to connect to). + */ + private Object[] extras; + + /** Whether or not this object has been fully initialized */ + private boolean initialized = false; + + /** + * the return value of this dialog. result: 0 = Yes, 1 = No, 2 = Cancel, + * null = Window closed. + */ + private Object value; + + public SecurityWarningDialog(DialogType dialogType, AccessType accessType, + JNLPFile file) { + super(); + this.dialogType = dialogType; + this.accessType = accessType; + this.file = file; + this.certVerifier = null; + initialized = true; + initDialog(); + } + + public SecurityWarningDialog(DialogType dialogType, AccessType accessType, + JNLPFile file, CertVerifier jarSigner) { + super(); + this.dialogType = dialogType; + this.accessType = accessType; + this.file = file; + this.certVerifier = jarSigner; + initialized = true; + initDialog(); + } + + public SecurityWarningDialog(DialogType dialogType, AccessType accessType, + CertVerifier certVerifier) { + super(); + this.dialogType = dialogType; + this.accessType = accessType; + this.file = null; + this.certVerifier = certVerifier; + initialized = true; + initDialog(); + } + + public SecurityWarningDialog(DialogType dialogType, AccessType accessType, + JNLPFile file, Object[] extras) { + super(); + this.dialogType = dialogType; + this.accessType = accessType; + this.file = file; + this.certVerifier = null; + initialized = true; + this.extras = extras; + initDialog(); + } + + //for displaying a single certificate + public SecurityWarningDialog(DialogType dialogType, X509Certificate c) { + super(); + this.dialogType = dialogType; + this.accessType = null; + this.file = null; + this.certVerifier = null; + this.cert = c; + initialized = true; + initDialog(); + } + + /** + * Returns if this dialog has been fully initialized yet. + * @return true if this dialog has been initialized, and false otherwise. + */ + public boolean isInitialized(){ + return initialized; + } + + /** + * Shows a warning dialog for different types of system access (i.e. file + * open/save, clipboard read/write, printing, etc). + * + * @param accessType the type of system access requested. + * @param file the jnlp file associated with the requesting application. + * @return true if permission was granted by the user, false otherwise. + */ + public static boolean showAccessWarningDialog(AccessType accessType, + JNLPFile file) { + return showAccessWarningDialog(accessType, file, null); + } + + /** + * Shows a warning dialog for different types of system access (i.e. file + * open/save, clipboard read/write, printing, etc). + * + * @param accessType the type of system access requested. + * @param file the jnlp file associated with the requesting application. + * @param extras an optional array of Strings (typically) that gets + * passed to the dialog labels. + * @return true if permission was granted by the user, false otherwise. + */ + public static boolean showAccessWarningDialog(AccessType accessType, + JNLPFile file, Object[] extras) { + SecurityWarningDialog dialog = new SecurityWarningDialog( + DialogType.ACCESS_WARNING, accessType, file, extras); + dialog.setVisible(true); + dialog.dispose(); + + Object selectedValue = dialog.getValue(); + if (selectedValue == null) { + return false; + } else if (selectedValue instanceof Integer) { + if (((Integer)selectedValue).intValue() == 0) + return true; + else + return false; + } else { + return false; + } + } + + /** + * Shows a warning dialog for when the main application jars are signed, + * but extensions aren't + * + * @return true if permission was granted by the user, false otherwise. + */ + public static boolean showNotAllSignedWarningDialog(JNLPFile file) { + SecurityWarningDialog dialog = new SecurityWarningDialog( + DialogType.NOTALLSIGNED_WARNING, AccessType.NOTALLSIGNED, file, (new Object[0])); + dialog.setVisible(true); + dialog.dispose(); + + Object selectedValue = dialog.getValue(); + if (selectedValue == null) { + return false; + } else if (selectedValue instanceof Integer) { + if (((Integer)selectedValue).intValue() == 0) + return true; + else + return false; + } else { + return false; + } + } + + /** + * Shows a security warning dialog according to the specified type of + * access. If <code>type</code> is one of AccessType.VERIFIED or + * AccessType.UNVERIFIED, extra details will be available with regards + * to code signing and signing certificates. + * + * @param accessType the type of warning dialog to show + * @param file the JNLPFile associated with this warning + * @param jarSigner the JarSigner used to verify this application + */ + public static boolean showCertWarningDialog(AccessType accessType, + JNLPFile file, CertVerifier jarSigner) { + SecurityWarningDialog dialog = + new SecurityWarningDialog(DialogType.CERT_WARNING, accessType, file, + jarSigner); + dialog.setVisible(true); + dialog.dispose(); + + Object selectedValue = dialog.getValue(); + if (selectedValue == null) { + return false; + } else if (selectedValue instanceof Integer) { + if (((Integer)selectedValue).intValue() == 0) + return true; + else + return false; + } else { + return false; + } + } + + /** + * Shows more information regarding jar code signing + * + * @param jarSigner the JarSigner used to verify this application + * @param parent the parent option pane + */ + public static void showMoreInfoDialog( + CertVerifier jarSigner, SecurityWarningDialog parent) { + + SecurityWarningDialog dialog = + new SecurityWarningDialog(DialogType.MORE_INFO, null, null, + jarSigner); + dialog.setVisible(true); + dialog.dispose(); + } + + /** + * Displays CertPath information in a readable table format. + * + * @param certs the certificates used in signing. + */ + public static void showCertInfoDialog(CertVerifier jarSigner, + SecurityWarningDialog parent) { + SecurityWarningDialog dialog = new SecurityWarningDialog(DialogType.CERT_INFO, + null, null, jarSigner); + dialog.setLocationRelativeTo(parent); + dialog.setVisible(true); + dialog.dispose(); + } + + /** + * Displays a single certificate's information. + * + * @param c + * @param optionPane + */ + public static void showSingleCertInfoDialog(X509Certificate c, + JDialog parent) { + SecurityWarningDialog dialog = new SecurityWarningDialog(DialogType.SINGLE_CERT_INFO, c); + dialog.setLocationRelativeTo(parent); + dialog.setVisible(true); + dialog.dispose(); + } + + public static int showAppletWarning() { + SecurityWarningDialog dialog = new SecurityWarningDialog(DialogType.APPLET_WARNING, + null, null, (CertVerifier) null); + dialog.setVisible(true); + dialog.dispose(); + + Object selectedValue = dialog.getValue(); + + //result 0 = Yes, 1 = No, 2 = Cancel + if (selectedValue == null) { + return 2; + } else if (selectedValue instanceof Integer) { + return ((Integer)selectedValue).intValue(); + } else { + return 2; + } + } + + private void initDialog() { + setSystemLookAndFeel(); + + String dialogTitle = ""; + if (dialogType == DialogType.CERT_WARNING) + dialogTitle = "Warning - Security"; + else if (dialogType == DialogType.MORE_INFO) + dialogTitle = "More Information"; + else if (dialogType == DialogType.CERT_INFO) + dialogTitle = "Details - Certificate"; + else if (dialogType == DialogType.ACCESS_WARNING) + dialogTitle = "Security Warning"; + else if (dialogType == DialogType.APPLET_WARNING) + dialogTitle = "Applet Warning"; + else if (dialogType == DialogType.NOTALLSIGNED_WARNING) + dialogTitle = "Security Warning"; + + setTitle(dialogTitle); + setModal(true); + + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + installPanel(); + + pack(); + + WindowAdapter adapter = new WindowAdapter() { + private boolean gotFocus = false; + @Override + public void windowClosing(WindowEvent we) { + setValue(null); + } + @Override + public void windowGainedFocus(WindowEvent we) { + // Once window gets focus, set initial focus + if (!gotFocus) { + selectDefaultButton(); + gotFocus = true; + } + } + @Override + public void windowOpened(WindowEvent e) { + if (e.getSource() instanceof SecurityWarningDialog) { + SecurityWarningDialog dialog = (SecurityWarningDialog) e.getSource(); + dialog.setResizable(true); + centerDialog(dialog); + dialog.setValue(null); + } + } + }; + addWindowListener(adapter); + addWindowFocusListener(adapter); + + } + + public AccessType getAccessType() { + return accessType; + } + + public JNLPFile getFile() { + return file; + } + + public CertVerifier getJarSigner() { + return certVerifier; + } + + public X509Certificate getCert() { + return cert; + } + + /** + * Adds the appropriate JPanel to this Dialog, based on {@link DialogType}. + */ + private void installPanel() { + + if (dialogType == DialogType.CERT_WARNING) + panel = new CertWarningPane(this, this.certVerifier); + else if (dialogType == DialogType.MORE_INFO) + panel = new MoreInfoPane(this, this.certVerifier); + else if (dialogType == DialogType.CERT_INFO) + panel = new CertsInfoPane(this, this.certVerifier); + else if (dialogType == DialogType.SINGLE_CERT_INFO) + panel = new SingleCertInfoPane(this, this.certVerifier); + else if (dialogType == DialogType.ACCESS_WARNING) + panel = new AccessWarningPane(this, extras, this.certVerifier); + else if (dialogType == DialogType.APPLET_WARNING) + panel = new AppletWarningPane(this, this.certVerifier); + else if (dialogType == DialogType.NOTALLSIGNED_WARNING) + panel = new NotAllSignedWarningPane(this); + + add(panel, BorderLayout.CENTER); + } + + private static void centerDialog(JDialog dialog) { + Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension dialogSize = dialog.getSize(); + + dialog.setLocation((screen.width - dialogSize.width)/2, + (screen.height - dialogSize.height)/2); + } + + private void selectDefaultButton() { + if (panel == null) { + System.out.println("initial value panel is null"); + } + panel.requestFocusOnDefaultButton(); + } + + protected void setValue(Object value) { + if (JNLPRuntime.isDebug()) { + System.out.println("Setting value:" + value); + } + this.value = value; + } + + protected Object getValue() { + if (JNLPRuntime.isDebug()) { + System.out.println("Returning value:" + value); + } + return value; + } + + /** + * Updates the look and feel of the window to be the system look and feel + */ + protected void setSystemLookAndFeel() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + //don't worry if we can't. + } + } +} diff --git a/netx/net/sourceforge/jnlp/security/SingleCertInfoPane.java b/netx/net/sourceforge/jnlp/security/SingleCertInfoPane.java new file mode 100644 index 0000000..59b8ab8 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/SingleCertInfoPane.java @@ -0,0 +1,77 @@ +/* SingleCertInfoPane.java + Copyright (C) 2008 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.X509Certificate; +import java.util.ArrayList; + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeSelectionModel; + + +public class SingleCertInfoPane extends CertsInfoPane { + + public SingleCertInfoPane(SecurityWarningDialog x, CertVerifier certVerifier) { + super(x, certVerifier); + } + + protected void buildTree() { + X509Certificate cert = parent.getCert(); + String subjectString = + SecurityUtil.getCN(cert.getSubjectX500Principal().getName()); + String issuerString = + SecurityUtil.getCN(cert.getIssuerX500Principal().getName()); + + DefaultMutableTreeNode top = new DefaultMutableTreeNode(subjectString + + " (" + issuerString + ")"); + + tree = new JTree(top); + tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + tree.addTreeSelectionListener(new TreeSelectionHandler()); + } + + protected void populateTable() { + X509Certificate c = parent.getCert(); + certNames = new String[1]; + certsData = new ArrayList<String[][]>(); + certsData.add(parseCert(c)); + certNames[0] = SecurityUtil.getCN(c.getSubjectX500Principal().getName()) + + " (" + SecurityUtil.getCN(c.getIssuerX500Principal().getName()) + ")"; + } +} diff --git a/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java b/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java new file mode 100644 index 0000000..d5ad6da --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java @@ -0,0 +1,314 @@ +/* VariableX509TrustManager.java + Copyright (C) 2009 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.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import sun.security.util.HostnameChecker; +import sun.security.validator.ValidatorException; + +import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; + +/** + * This class implements an X509 Trust Manager. The certificates it trusts are + * "variable", in the sense that it can dynamically, and temporarily support + * different certificates that are not in the keystore. + */ + +public class VariableX509TrustManager extends X509ExtendedTrustManager { + + KeyStore userKeyStore = null; + KeyStore caKeyStore = null; + + X509TrustManager userTrustManager = null; + X509TrustManager caTrustManager = null; + + ArrayList<Certificate> temporarilyTrusted = new ArrayList<Certificate>(); + ArrayList<Certificate> temporarilyUntrusted = new ArrayList<Certificate>(); + + static VariableX509TrustManager instance = null; + + /** + * Constructor initializes the system, user and custom stores + */ + public VariableX509TrustManager() { + + try { + userKeyStore = SecurityUtil.getUserKeyStore(); + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("SunX509", "SunJSSE"); + tmFactory.init(userKeyStore); + + // tm factory initialized, now get the managers so we can assign the X509 one + TrustManager[] trustManagers = tmFactory.getTrustManagers(); + + for (int i=0; i < trustManagers.length; i++) { + if (trustManagers[i] instanceof X509TrustManager) { + userTrustManager = (X509TrustManager) trustManagers[i]; + } + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + caKeyStore = SecurityUtil.getCacertsKeyStore(); + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("SunX509", "SunJSSE"); + tmFactory.init(caKeyStore); + + // tm factory initialized, now get the managers so we can extract the X509 one + TrustManager[] trustManagers = tmFactory.getTrustManagers(); + + for (int i=0; i < trustManagers.length; i++) { + if (trustManagers[i] instanceof X509TrustManager) { + caTrustManager = (X509TrustManager) trustManagers[i]; + } + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Check if client is trusted (no support for custom here, only system/user) + */ + public void checkClientTrusted(X509Certificate[] chain, String authType, + String hostName, String algorithm) + throws CertificateException { + // First try catrustmanager, then try usertrustmanager + try { + caTrustManager.checkClientTrusted(chain, authType); + } catch (Exception caex) { + try { + userTrustManager.checkClientTrusted(chain, authType); + } catch (Exception userex) { + // Do nothing here. This trust manager is intended to be used + // only in the plugin instance vm, which does not act as a + // server + } + } + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + checkClientTrusted(chain, authType, null, null); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType, + String hostName, String algorithm) + throws CertificateException { + checkServerTrusted(chain, authType, hostName, false); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + checkServerTrusted(chain, authType, null, null); + } + + /** + * Check if the server is trusted + * + * @param chain The cert chain + * @param authType The auth type algorithm + * @param checkOnly Whether to "check only" i.e. no user prompt, or to prompt for permission + */ + public synchronized void checkServerTrusted(X509Certificate[] chain, + String authType, String hostName, + boolean checkOnly) throws CertificateException { + CertificateException ce = null; + boolean trusted = true; + boolean CNMatched = true; + + try { + checkAllManagers(chain, authType); + } catch (CertificateException e) { + trusted = false; + ce = e; + } + + // If the certificate is not explicitly trusted, we + // need to prompt the user + if (!isExplicitlyTrusted(chain, authType)) { + + try { + HostnameChecker checker = HostnameChecker + .getInstance(HostnameChecker.TYPE_TLS); + + checker.match(hostName, chain[0]); // only need to match @ 0 for + // CN + + } catch (CertificateException e) { + CNMatched = false; + ce = e; + } + } + + if (!trusted || !CNMatched) { + if (checkOnly) { + throw ce; + } else { + if (!isTemporarilyUntrusted(chain[0])) { + boolean b = askUser(chain, authType, trusted, CNMatched, hostName); + + if (b) { + temporarilyTrust(chain[0]); + } else { + temporarilyUntrust(chain[0]); + } + } + + checkAllManagers(chain, authType); + } + } + } + + /** + * Check system, user and custom trust manager + */ + private void checkAllManagers(X509Certificate[] chain, String authType) throws CertificateException { + // First try catrustmanager, then try usertrustmanager, and finally, check temp trusted certs + try { + caTrustManager.checkServerTrusted(chain, authType); + } catch (ValidatorException caex) { + try { + userTrustManager.checkServerTrusted(chain, authType); + } catch (ValidatorException uex) { + if (!temporarilyTrusted.contains(chain[0])) + throw (CertificateException) uex; + } + } + } + + /** + * Return if the user explicitly trusted this i.e. in userTrustManager or temporarilyTrusted + */ + private boolean isExplicitlyTrusted(X509Certificate[] chain, String authType) { + boolean explicitlyTrusted = false; + + try { + userTrustManager.checkServerTrusted(chain, authType); + explicitlyTrusted = true; + } catch (ValidatorException uex) { + if (temporarilyTrusted.contains(chain[0])) + explicitlyTrusted = true; + } catch (CertificateException ce) { + // do nothing, this means that the cert is not explicitly trusted + } + + return explicitlyTrusted; + + } + + public X509Certificate[] getAcceptedIssuers() { + // delegate to default + return caTrustManager.getAcceptedIssuers(); + } + + /** + * Temporarily untrust the given cert - do not ask the user to trust this + * certificate again + * + * @param c The certificate to trust + */ + private void temporarilyUntrust(Certificate c) { + temporarilyUntrusted.add(c); + } + + /** + * Was this certificate explicitly untrusted by user? + * + * @param c the certificate + * @return true if the user was presented with this certificate and chose + * not to trust it + */ + private boolean isTemporarilyUntrusted(Certificate c) { + if (temporarilyUntrusted.contains(c)) { + return true; + } + return false; + } + + /** + * Temporarily trust the given cert (runtime) + * + * @param c The certificate to trust + */ + private void temporarilyTrust(Certificate c) { + temporarilyTrusted.add(c); + } + + /** + * Ask user if the certificate should be trusted + * + * @param chain The certificate chain + * @param authType The authentication algorithm + * @return user's response + */ + private boolean askUser(X509Certificate[] chain, String authType, + boolean isTrusted, boolean hostMatched, + String hostName) { + return SecurityWarningDialog.showCertWarningDialog( + SecurityWarningDialog.AccessType.UNVERIFIED, null, + new HttpsCertVerifier(this, chain, authType, + isTrusted, hostMatched, + hostName)); + } + + /** + * Return an instance of this singleton + * + * @return The instance + */ + public static VariableX509TrustManager getInstance() { + if (instance == null) + instance = new VariableX509TrustManager(); + + return instance; + } +} diff --git a/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java new file mode 100644 index 0000000..69b98b4 --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java @@ -0,0 +1,335 @@ +/* CertificatePane.java + Copyright (C) 2008 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.viewer; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Enumeration; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; + +import net.sourceforge.jnlp.security.SecurityUtil; +import net.sourceforge.jnlp.security.SecurityWarningDialog; +import net.sourceforge.jnlp.tools.KeyTool; + +public class CertificatePane extends JPanel { + + /** + * The certificates stored in the user's trusted.certs file. + */ + private ArrayList<X509Certificate> certs = null; + + /** + * "Issued To" and "Issued By" string pairs for certs. + */ + private String[][] issuedToAndBy = null; + private final String[] columnNames = { "Issued To", "Issued By" }; + + private JTable table; + + private JDialog parent; + + private JComponent defaultFocusComponent = null; + + /** + * The KeyStore associated with the user's trusted.certs file. + */ + private KeyStore keyStore = null; + + public CertificatePane(JDialog parent) { + super(); + this.parent = parent; + initializeKeyStore(); + addComponents(); + } + + /** + * Reads the user's trusted.cacerts keystore. + */ + private void initializeKeyStore() { + try { + keyStore = SecurityUtil.getUserKeyStore(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + //create the GUI here. + protected void addComponents() { + readKeyStore(); + + JPanel main = new JPanel(new BorderLayout()); + + JPanel tablePanel = new JPanel(new BorderLayout()); + + //Table + DefaultTableModel tableModel + = new DefaultTableModel(issuedToAndBy, columnNames); + table = new JTable(tableModel); + table.getTableHeader().setReorderingAllowed(false); + table.setFillsViewportHeight(true); + JScrollPane tablePane = new JScrollPane(table); + tablePane.setPreferredSize(new Dimension(500,200)); + tablePane.setSize(new Dimension(500,200)); + tablePane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); + + JTabbedPane tabbedPane = new JTabbedPane(); + tabbedPane.addTab("User", tablePane); + JPanel buttonPanel = new JPanel(new FlowLayout()); + + String[] buttonNames = {"Import", "Export", "Remove", "Details"}; + char[] buttonMnemonics = { KeyEvent.VK_I, + KeyEvent.VK_E, + KeyEvent.VK_M, + KeyEvent.VK_D}; + ActionListener[] listeners = { new ImportButtonListener(), + new ExportButtonListener(), + new RemoveButtonListener(), + new DetailsButtonListener() }; + JButton button; + + //get the max width + int maxWidth = 0; + for (int i = 0; i < buttonNames.length; i++) { + button = new JButton(buttonNames[i]); + maxWidth = Math.max(maxWidth, button.getMinimumSize().width); + } + + for (int i = 0; i < buttonNames.length; i++) { + button = new JButton(buttonNames[i]); + button.setMnemonic(buttonMnemonics[i]); + button.addActionListener(listeners[i]); + button.setSize(maxWidth, button.getSize().height); + buttonPanel.add(button); + } + + tablePanel.add(tabbedPane, BorderLayout.CENTER); + tablePanel.add(buttonPanel, BorderLayout.SOUTH); + + JPanel closePanel = new JPanel(new BorderLayout()); + closePanel.setBorder(BorderFactory.createEmptyBorder(7,7,7,7)); + JButton closeButton = new JButton("Close"); + closeButton.addActionListener(new CloseButtonListener()); + defaultFocusComponent = closeButton; + closePanel.add(closeButton, BorderLayout.EAST); + + main.add(tablePanel, BorderLayout.CENTER); + main.add(closePanel, BorderLayout.SOUTH); + + add(main); + + } + + /** + * Read in the optionPane's keystore to issuedToAndBy. + */ + private void readKeyStore() { + + Enumeration<String> aliases = null; + certs = new ArrayList<X509Certificate>(); + try { + + //Get all of the X509Certificates and put them into an ArrayList + aliases = keyStore.aliases(); + while (aliases.hasMoreElements()) { + Certificate c = keyStore.getCertificate(aliases.nextElement()); + if (c instanceof X509Certificate) + certs.add((X509Certificate)c); + } + + //get the publisher and root information + issuedToAndBy = new String[certs.size()][2]; + for (int i = 0; i < certs.size(); i++) { + X509Certificate c = certs.get(i); + issuedToAndBy[i][0] = + SecurityUtil.getCN(c.getSubjectX500Principal().getName()); + issuedToAndBy[i][1] = + SecurityUtil.getCN(c.getIssuerX500Principal().getName()); + } + } catch (Exception e) { + //TODO + } + } + + /** + * Re-reads the certs file and repopulates the JTable. This is typically + * called after a certificate was deleted from the keystore. + */ + private void repopulateTable() { + initializeKeyStore(); + readKeyStore(); + DefaultTableModel tableModel + = new DefaultTableModel(issuedToAndBy, columnNames); + + table.setModel(tableModel); + repaint(); + } + + public void focusOnDefaultButton() { + if (defaultFocusComponent != null) { + defaultFocusComponent.requestFocusInWindow(); + } + } + + private class ImportButtonListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + + JFileChooser chooser = new JFileChooser(); + int returnVal = chooser.showOpenDialog(parent); + if(returnVal == JFileChooser.APPROVE_OPTION) { + try { + KeyTool kt = new KeyTool(); + kt.importCert(chooser.getSelectedFile()); + repopulateTable(); + } catch (Exception ex) { + // TODO: handle exception + ex.printStackTrace(); + } + } + } + } + + private class ExportButtonListener implements ActionListener { + public void actionPerformed(ActionEvent e) { + //For now, let's just export in -rfc mode as keytool does. + //we'll write to a file the exported certificate. + + + try { + int selectedRow = table.getSelectedRow(); + if (selectedRow != -1) { + JFileChooser chooser = new JFileChooser(); + int returnVal = chooser.showOpenDialog(parent); + if(returnVal == JFileChooser.APPROVE_OPTION) { + String alias = keyStore.getCertificateAlias(certs + .get(selectedRow)); + if (alias != null) { + Certificate c = keyStore.getCertificate(alias); + PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath()); + KeyTool.dumpCert(c, ps); + repopulateTable(); + } + } + } + } catch (Exception ex) { + // TODO + ex.printStackTrace(); + } + } + } + + private class RemoveButtonListener implements ActionListener { + + /** + * Removes a certificate from the keyStore and writes changes to disk. + */ + public void actionPerformed(ActionEvent e) { + + try { + int selectedRow = table.getSelectedRow(); + + if (selectedRow != -1){ + String alias = keyStore.getCertificateAlias(certs.get(selectedRow)); + if (alias != null) { + + int i = JOptionPane.showConfirmDialog(parent, + "Are you sure you want to remove the selected certificate?", + "Confirmation - Remove Certificate?", + JOptionPane.YES_NO_OPTION); + if (i == 0) { + keyStore.deleteEntry(alias); + FileOutputStream fos = new FileOutputStream( + SecurityUtil.getTrustedCertsFilename()); + keyStore.store(fos, SecurityUtil.getTrustedCertsPassword()); + fos.close(); + } + } + repopulateTable(); + } + } catch (Exception ex) { + // TODO + ex.printStackTrace(); + } + + } + } + + private class DetailsButtonListener implements ActionListener { + + /** + * Shows the details of a trusted certificate. + */ + public void actionPerformed(ActionEvent e) { + + int selectedRow = table.getSelectedRow(); + if (selectedRow != -1 && selectedRow >= 0) { + X509Certificate c = certs.get(selectedRow); + SecurityWarningDialog.showSingleCertInfoDialog(c, parent); + } + } + } + + private class CloseButtonListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + parent.dispose(); + } + } + +} diff --git a/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java b/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java new file mode 100644 index 0000000..403472c --- /dev/null +++ b/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java @@ -0,0 +1,120 @@ +/* CertificateViewer.java + Copyright (C) 2008 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.viewer; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JDialog; +import javax.swing.UIManager; + +public class CertificateViewer extends JDialog { + + private boolean initialized = false; + private static final String dialogTitle = "Certificates"; + + CertificatePane panel; + + public CertificateViewer() { + super((Frame)null, dialogTitle, true); + + Container contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + + panel = new CertificatePane(this); + + add(panel); + + pack(); + + WindowAdapter adapter = new WindowAdapter() { + private boolean gotFocus = false; + + public void windowGainedFocus(WindowEvent we) { + // Once window gets focus, set initial focus + if (!gotFocus) { + panel.focusOnDefaultButton(); + gotFocus = true; + } + } + }; + addWindowFocusListener(adapter); + + initialized = true; + } + + public boolean isInitialized(){ + return initialized; + } + + private void centerDialog() { + Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension dialogSize = getSize(); + + setLocation((screen.width - dialogSize.width)/2, + (screen.height - dialogSize.height)/2); + } + + + public static void showCertificateViewer() throws Exception { + setSystemLookAndFeel(); + + CertificateViewer cv = new CertificateViewer(); + cv.setResizable(true); + cv.centerDialog(); + cv.setVisible(true); + cv.dispose(); + } + + private static void setSystemLookAndFeel() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + // don't worry if we can't. + } + } + + public static void main(String[] args) throws Exception { + CertificateViewer.showCertificateViewer(); + } +} |