Code Signing
One of the most important uses of authentication technology is signing executable programs. If you download a program, you are naturally concerned about damage that a program can do. For example, the program could have been infected by a virus. If you know where the code comes from and that it has not been tampered with since it left its origin, then your comfort level will be a lot higher than without this knowledge. In fact, if the program was also written in the Java programming language, you can then use this information to make a rational decision about what privileges you will allow that program to have. You might want it to run just in a sandbox as a regular applet, or you might want to grant it a different set of rights and restrictions. For example, if you download a word processing program, you might want to grant it access to your printer and to files in a certain subdirectory. However, you might not want to give it the right to make network connections, so that the program can't try to send your files to a third party without your knowledge.
You now know how to implement this sophisticated scheme.
- Use authentication to verify where the code came from.
- Run the code with a security policy that enforces the permissions that you want to grant the program, depending on its origin.
JAR File Signing
In this section, we show you how to sign applets and web start applications for use with the Java Plug-in software. There are two scenarios:
- Delivery in an intranet.
- Delivery over the public Internet.
In the first scenario, a system administrator installs policy files and certificates on local machines. Whenever the Java Plug-in tool loads signed code, it consults the policy file for the permissions and the keystore for signatures. Installing the policies and certificates is straightforward and can be done once per desktop. End users can then run signed corporate code outside the sandbox. Whenever a new program is created or an existing one is updated, it must be signed and deployed on the web server. However, no desktops need to be touched as the programs evolve. We think this is a reasonable scenario that can be an attractive alternative to deploying corporate applications on every desktop.
In the second scenario, software vendors obtain certificates that are signed by CAs such as VeriSign. When an end user visits a web site that contains a signed applet, a pop-up dialog box identifies the software vendor and gives the end user two choices: to run the applet with full privileges or to confine it to the sandbox. We discuss this less desirable scenario in detail in the section "Software Developer Certificates" on page 827.
For the remainder of this section, we describe how you can build policy files that grant specific permissions to code from known sources. Building and deploying these policy files is not for casual end users. However, system administrators can carry out these tasks in preparation for distributing intranet programs.
Suppose ACME Software wants its users to run certain programs that require local file access, and it wants to deploy the programs through a browser, as applets or Web Start applications. Because these programs cannot run inside the sandbox, ACME Software needs to install policy files on employee machines.
As you saw earlier in this chapter, ACME could identify the programs by their code base. But that means that ACME would need to update the policy files each time the programs are moved to a different web server. Instead, ACME decides to sign the JAR files that contain the program code.
First, ACME generates a root certificate:
keytool -genkeypair -keystore acmesoft.certs -alias acmeroot
Of course, the keystore containing the private root key must be kept at a safe place. Therefore, we create a second keystore client.certs for the public certificates and add the public acmeroot certificate into it.
keytool -exportcert -keystore acmesoft.certs -alias acmeroot -file acmeroot.cer keytool -importcert -keystore client.certs -alias acmeroot -file acmeroot.cer
To make a signed JAR file, programmers add their class files to a JAR file in the usual way. For example,
javac FileReadApplet.java jar cvf FileReadApplet.jar *.class
Then a trusted person at ACME runs the jarsigner tool, specifying the JAR file and the alias of the private key:
jarsigner -keystore acmesoft.certs FileReadApplet.jar acmeroot
The signed applet is now ready to be deployed on a web server.
Next, let us turn to the client machine configuration. A policy file must be distributed to each client machine.
To reference a keystore, a policy file starts with the line
keystore "keystoreURL", "keystoreType";
The URL can be absolute or relative. Relative URLs are relative to the location of the policy file. The type is JKS if the keystore was generated by keytool. For example,
keystore "client.certs", "JKS";
Then grant clauses can have suffixes signedBy "alias", such as this one:
grant signedBy "acmeroot" { . . . };
Any signed code that can be verified with the public key associated with the alias is now granted the permissions inside the grant clause.
You can try out the code signing process with the applet in Listing 9-16. The applet tries to read from a local file. The default security policy only lets the applet read files from its code base and any subdirectories. Use appletviewer to run the applet and verify that you can view files from the code base directory, but not from other directories.
Now create a policy file applet.policy with the contents:
keystore "client.certs", "JKS"; grant signedBy "acmeroot" { permission java.lang.RuntimePermission "usePolicy"; permission java.io.FilePermission "/etc/*", "read"; };
The usePolicy permission overrides the default "all or nothing" permission for signed applets. Here, we say that any applets signed by acmeroot are allowed to read files in the /etc directory. (Windows users: Substitute another directory such as C:\Windows.)
Tell the applet viewer to use the policy file:
appletviewer -J-Djava.security.policy=applet.policy FileReadApplet.html
Now the applet can read files from the /etc directory, thus demonstrating that the signing mechanism works.
As a final test, you can run your applet inside the browser (see Figure 9-16). You need to copy the permission file and keystore inside the Java deployment directory. If you run UNIX or Linux, that directory is the .java/deployment subdirectory of your home directory. In Windows Vista, it is the C:\Users\yourLoginName\AppData\Sun\Java\Deployment directory. In the following, we refer to that directory as deploydir.
Figure 9-16 A signed applet can read local files
Copy applet.policy and client.certs to the deploydir/security directory. In that directory, rename applets.policy to java.policy. (Double-check that you are not wiping out an existing java.policy file. If there is one, add the applet.policy contents to it.)
Restart your browser and load the FileReadApplet.html. You should not be prompted to accept any certificate. Check that you can load any file in the /etc directory and the directory from which the applet was loaded, but not from other directories.
When you are done, remember to clean up your deploydir/security directory. Remove the files java.policy and client.certs. Restart your browser. If you load the applet again after cleaning up, you should no longer be able to read files from the local file system. Instead, you will be prompted for a certificate. We discuss security certificates in the next section.
Listing 9-16. FileReadApplet.java
1. import java.awt.*; 2. import java.awt.event.*; 3. import java.io.*; 4. import java.util.*; 5. import javax.swing.*; 6. 7. /** 8. * This applet can run "outside the sandbox" and read local files when it is given the right 9. * permissions. 10. * @version 1.11 2007-10-06 11. * @author Cay Horstmann 12. */ 13. public class FileReadApplet extends JApplet 14. { 15. public void init() 16. { 17. EventQueue.invokeLater(new Runnable() 18. { 19. public void run() 20. { 21. fileNameField = new JTextField(20); 22. JPanel panel = new JPanel(); 23. panel.add(new JLabel("File name:")); 24. panel.add(fileNameField); 25. JButton openButton = new JButton("Open"); 26. panel.add(openButton); 27. ActionListener listener = new ActionListener() 28. { 29. public void actionPerformed(ActionEvent event) 30. { 31. loadFile(fileNameField.getText()); 32. } 33. }; 34. fileNameField.addActionListener(listener); 35. openButton.addActionListener(listener); 36. 37. add(panel, "North"); 38. 39. fileText = new JTextArea(); 40. add(new JScrollPane(fileText), "Center"); 41. } 42. }); 43. } 44. 45. /** 46. * Loads the contents of a file into the text area. 47. * @param filename the file name 48. */ 49. public void loadFile(String filename) 50. { 51. try 52. { 53. fileText.setText(""); 54. Scanner in = new Scanner(new FileReader(filename)); 55. while (in.hasNextLine()) 56. fileText.append(in.nextLine() + "\n"); 57. in.close(); 58. } 59. catch (IOException e) 60. { 61. fileText.append(e + "\n"); 62. } 63. catch (SecurityException e) 64. { 65. fileText.append("I am sorry, but I cannot do that.\n"); 66. fileText.append(e + "\n"); 67. } 68. } 69. private JTextField fileNameField; 70. private JTextArea fileText; 71. }
Software Developer Certificates
Up to now, we discussed scenarios in which programs are delivered in an intranet and for which a system administrator configures a security policy that controls the privileges of the programs. However, that strategy only works with programs from known sources.
Suppose while surfing the Internet, you encounter a web site that offers to run an applet or web start application from an unfamiliar vendor, provided you grant it the permission to do so (see Figure 9-17). Such a program is signed with a software developer certificate that is issued by a CA. The pop-up dialog box identifies the software developer and the certificate issuer. You now have two choices:
- Run the program with full privileges.
- Confine the program to the sandbox. (The Cancel button in the dialog box is misleading. If you click that button, the applet is not canceled. Instead, it runs in the sandbox.)
Figure 9-17 Launching a signed applet
What facts do you have at your disposal that might influence your decision? Here is what you know:
- Thawte sold a certificate to the software developer.
- The program really was signed with that certificate, and it hasn't been modified in transit.
- The certificate really was signed by Thawte—it was verified by the public key in the local cacerts file.
Does that tell you whether the code is safe to run? Do you trust the vendor if all you know is the vendor name and the fact that Thawte sold them a software developer certificate? Presumably Thawte went to some degree of trouble to assure itself that ChemAxon Kft. is not an outright cracker. However, no certificate issuer carries out a comprehensive audit of the honesty and competence of software vendors.
In the situation of an unknown vendor, an end user is ill-equipped to make an intelligent decision whether to let this program run outside the sandbox, with all permissions of a local application. If the vendor is a well-known company, then the user can at least take the past track record of the company into account.
We don't like situations in which a program demands "give me all rights, or I won't run at all." Naive users are too often cowed into granting access that can put them in danger.
Would it help if each program explained what rights it needs and requested specific permission for those rights? Unfortunately, as you have seen, that can get pretty technical. It doesn't seem reasonable for an end user to have to ponder whether a program should really have the right to inspect the AWT event queue.
We remain unenthusiastic about software developer certificates. It would be better if applets and web start applications on the public Internet tried harder to stay within their respective sandboxes, and if those sandboxes were improved. The Web Start API that we discussed in Volume I, Chapter 10 is a step in the right direction.