Signed Applets contain a signature that users may use to verify the identity of the organization responsible for the Applet and confirm that it has not been modified since the signature was applied. A signed Applet from a “trusted” source may be automatically accepted by a browser, and a signed Applet from an “untrusted” source usually results in the appearance of a security warning that requires the end user to view the signature and decide whether or not to trust the Applet. If the signature is approved, the Applet is granted security rights roughly equivalent to an ordinary standalone program.
To obtain a signature from a trusted source, a fee must be paid to an independent certificate authority such as VeriSign, GoDaddy, and Comodo. For example, VeriSign charges $499 for an Applet signature that lasts one year. To avoid paying this fee, developers or organizations may choose to create their own signatures. This is known as self-signing an Applet.
In Implementation Assignment #1, we saw that an unsigned Applet is able to download contents from the same domain as the server hosting the Applet. For instance, we installed our Applets at www2.hawaii.edu
, and our Applets downloaded text files from other locations at www2.hawaii.edu
.
In Implementation Assignment #2, we would like our Applets to provide a method to download contents from any valid URL, not only URLs for the same domain that hosts our Applets. For example, the following code implements an Applet that downloads and displays the contents for a URL specified by the user.
/* * Copyright (c) 2011, Jade Cheng * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University of Hawaii nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Jade Cheng ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Jade Cheng BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class UnsignedApplet extends JApplet implements ActionListener { private static final long serialVersionUID = -4370650602318597069L; private JTextArea textArea; private JTextField textField; @Override public void init() { // Add a text field that provides the URL to download. this.textField = new JTextField("http://www2.hawaii.edu/~yucheng/home"); this.textField.addActionListener(this); // Add a button that downloads the content from the URL. final JButton button = new JButton("Download"); button.addActionListener(this); // Add a text area that displays the downloaded content. this.textArea = new JTextArea(); this.textArea.setEditable(false); this.textArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); this.textArea.setLineWrap(true); // Layout the Applet. final JPanel panel = new JPanel(); panel.setLayout(new BorderLayout(8, 8)); panel.add(this.textField, BorderLayout.CENTER); panel.add(button, BorderLayout.LINE_END); this.setLayout(new BorderLayout(8, 8)); this.add(panel, BorderLayout.PAGE_START); this.add(new JScrollPane(this.textArea), BorderLayout.CENTER); } public void actionPerformed(final ActionEvent event) { try { // Download and display the contents for the URL. final URL url = new URL(this.textField.getText()); final String contents = download(url.openStream()); this.textArea.setForeground(Color.BLACK); this.textArea.setText(contents); } catch (final Exception e) { // Display information about the exception. this.textArea.setForeground(Color.RED); this.textArea.setText(e.toString()); } } private static String download(final InputStream in) throws IOException { // Read all bytes from the stream and return the data as a string. final ByteArrayOutputStream out = new ByteArrayOutputStream(); int ch; while (-1 != (ch = in.read())) out.write(ch); return out.toString(); } }
The HTML file used to launch this Applet is shown below. To run the Applet, click on the file title or the Java icon.
<html> <head> <title>Unsigned Applet</title> </head> <body> <applet code="UnsignedApplet.class" width="640" height="480"> Your browser does not support Applets. </applet> </body> </html>
Deployed from UHUNIX, however, this Applet cannot download a URL from a foreign domain such as http://www.google.com
. Attempting to do so would result in the following error.
java.security.AccessControlException: access denied (java.net.SocketPermission www.google.com:80 connect,resolve)
The reason for this failure is that Java virtual machines run Applets under a more restrictive security environment than desktop applications.
By default, desktop applications are implicitly trusted. The designers of the JVM specification assumed that users start applications at their own initiative and can therefore take responsibility for the application’s behavior on their machine.
Applets, on the other hand, are started automatically by a browser after it downloads and displays a page. Users cannot be expected to know what Applets a page might contain before they download it and therefore cannot take responsibility for the Applet’s behavior on their machine. For this reason, Applets are considered to be untrusted by default.
Among other restrictions, an Applet cannot open a socket for a URL with a domain different from the one hosting the Applet. This is part of the security architecture that browsers employ to protect users’ computing resources from malicious or faulty Applets.
To give our Applets the ability to download from foreign hosts, and to avoid paying hefty fees to trusted certificate authorities, we will create self-signed Applets. Once this is done, browsers will grant our Applets additional security rights after users accept the untrusted certificate authorities (us).
When a browser first encounters an unsigned Applet, it displays a security warning, examples of which are shown below.
The warning indicates the Applet’s signature was not verified by a trusted authority. The user may deny the Applet the additional rights it has requested or allow the Applet to run with the elevated priviledges. If the user is interested, he may choose to view additional information about the digital signature.
If the user chooses to permanently accept the digital signature, corresponding information is stored on the client’s computer. The next time the user opens the page with the self-signed Applet, no warning message appears.
Different operating systems provide different methods to manage previously accepted digital signatures. On the Mac, these signatures are stored in the Keychain. On Windows, they are stored in the Java Control Panel.
Creating a self-signed Applet involves three steps:
creating a public/private key pair
creating a certificate for the key pair created in step one
associating the certificate with the JAR file that contains the Applet
keytool
is a utility provided by the JDK, and it can be used to create public/private key pairs. It prompts for a password and a number of parameters that are stored into the digital signature. The output of the program is a file in the current directory. This file, called a key-store file, contains the public/private key pair. The key-store can contain more than one key pair, and each one is given an alias that uniquely identifies it.
The following command demonstrates how to create key pairs using keytool
. If the file mykeystore
does not exist in the current directory, it is created. Otherwise, a new key pair with the alias myalias
is added to this file.
$ keytool -genkey -keystore mykeystore -alias myalias Enter keystore password: mypassword What is your first and last name? [Unknown]: yucheng What is the name of your organizational unit? [Unknown]: ics What is the name of your organization? [Unknown]: university of hawaii What is the name of your City or Locality? [Unknown]: honolulu What is the name of your State or Province? [Unknown]: hawaii What is the two-letter country code for this unit? [Unknown]: us Is CN=yucheng, OU=ics, O=university of hawaii, L=honolulu, ST=hawaii, C=us correct? [no]: yes Enter key password for <myalias> (RETURN if same as keystore password):
The next step in self-signing an Applet is to create a digital certificate, again with the keytool
program. The certificate is stored in the same key-store file that was created in step. The following example demonstrates how to create the certificate.
$ keytool -selfcert -keystore mykeystore -alias myalias Enter keystore password: mypassword
The last step in self-signing an Applet is to sign the desired Applet with the digital certificate created in step two. Only Applets contained in JARs can be signed, and signing a jar is accomplished using the jarsigner
tool provided by the JDK.
$ jarsigner -keystore mykeystore SignedApplet.jar myalias Enter keystore password: mypassword Warning: The signer certificate will expire within six months.
This creates a hash for each file in the JAR and signs them with the private key created in step one. These hashes, the public key, and the certificate are added to the META-INF
directory of the JAR file alongside the JAR’s manifest.
$ jar -tf SignedApplet.jar META-INF/MANIFEST.MF META-INF/MYKEY.SF META-INF/MYKEY.DSA META-INF/ SignedApplet.class
Once a JAR is signed, its contents cannot be changed. Otherwise, the hashes computed by the jarsigner
program will become invalid. In other words, we may find it useful to automate the steps that create and sign the JAR file because we need to repeat these steps every time something is modified in our code.
Using the same Java code as we presented earlier, we can create and sign a JAR file that allows the Applet to download contents from foreign hosts—assuming the user accepts the self-signed certificate when the browser launches the Applet.
<html> <head> <title>Signed Applet</title> </head> <body> <applet code="SignedApplet.class" archive="SignedApplet.jar" width="640" height="480"> Your browser does not support Applets. </applet> </body> </html>