JDK v. 1.2 Security
Overview
JDK v. 1.2 security allows one to restrict read and write access to a subset of signers or locations. The runtime system organizes code into individual domains, each of which encloses a set of classes whose instances are granted the same set of permissions. Permissions are granted by an entry in a policy file.
Here's the source code for an applet named WriteFile that tries to create and to write to a file named writetest in the current directory. The applet shouldn't be able to create the file unless it has explicit permission in a policy file.
Type this command in your command window:
Type this command on a single line, without spaces in the URL.appletviewer http://java.sun.com/docs/books/tutorial/ security/tour1/example-1dot2/WriteFile.htmlYou should see a message about a security exception. This is the expected behavior; the system caught the applet trying to access a resource it doesn't have permission to access.
Policy File
A policy file is an ASCII text file and can be composed via a text editor or the graphical Policy Tool utility demonstrated in this section. The Policy Tool saves you typing and eliminates the need for you to know the required syntax of policy files, thus reducing errors.
You will use the Policy Tool to create a policy file, named mypolicy, in which you will add a policy entry that grants code from the directory where WriteFile.class is stored permission to write the writetest file. The steps are as follows:
- Start Policy Tool
- Grant the Required Permission
- Save the Policy File
The steps illustrate creating the policy file for a Windows system. The steps are exactly the same if you are working on a UNIX system. Where the text says to store the policy file in the C:\Test directory, you can store it in another directory.
Start Policy Tool
To start Policy Tool, simply type the following at the command line:policytoolThis brings up the Policy Tool window.
Whenever Policy Tool is started, it tries to fill in this window with policy information from what is sometimes referred to as the "user policy file". The user policy file is by default a file named .java.policy in your home directory. If Policy Tool cannot find the user policy file, it reports the situation and displays a blank Policy Tool window (that is, a window with headings and buttons but no data in it).
You can then proceed to either open whatever policy file you want to work on or create a new policy file.
The first time you run the Policy Tool, you will see the blank Policy Tool window, since a user policy file does not yet exist. You can immediately proceed to create a new policy file, as described in the next step.
Grant the Required Permission
To grant the WriteFile applet permission to create and to write to the writetest file, you must create a policy entry granting this permission. To do so, choose the Add Policy Entry button in the main Policy Tool window. This brings up the Policy Entry dialog boxA policy entry specifies one or more permissions for code from a particular code source - code from a particular location (URL), code signed by a particular entity, or both.
The CodeBase and the SignedBy text boxes are used to specify which code you want to grant the permission(s) you will be adding.
- A CodeBase value indicates the code source location; you grant the permission(s) to code from that location. An empty CodeBase entry signifies "any code" -- it doesn't matter where the code originates.
- A SignedBy value indicates the alias for a certificate stored in a keystore. The public key within that certificate is used to verify the digital signature on the code; you grant the permission(s) to code signed by the private key corresponding to the public key in the keystore entry specified by the alias. The SignedBy entry is optional; omitting it signifies "any signer" -- it doesn't matter whether the code is signed or by whom.
If you have both a CodeBase and a SignedBy entry, the permission(s) will be granted only to code that is both from the specified location and signed by the named alias.
To grant WriteFile the permission it needs, you can grant the permission to all code from the location (URL) where WriteFile.class is stored.
Type the following URL into the CodeBase text box of the Policy Entry dialog box:
(Note, this is a URL and thus must always have slashes, not backslashes.)http://java.sun.com/docs/books/tutorial/security/tour1/example-1dot2/Leave the SignedBy text box blank, since you aren't requiring the code to be signed. If you wanted to grant the permission to any code (.class file) not just from the directory specified previously but from the security directory and its subdirectories, you'd type the following URL into the CodeBase box:
http://java.sun.com/docs/books/tutorial/security/-You've specified where the code comes from (the CodeBase), and that the code does not have to be signed (since there's no SignedBy value). Now you are ready to grant permissions to that code.
Choose the Add Permission button to bring up the Permissions dialog box.
Do the following to grant code from the specified CodeBase permission to write (and thus also to create) the file named writetest.
Now the Permissions dialog box.
- Choose File Permission from the Permission drop-down list. The complete permission type name (java.io.FilePermission) now appears in the text box to the right of the drop-down list.
- Type the following in the text box to the right of the list labeled Target Name to specify the file named writetest:
writetest- Specify write access by choosing the write option from the Actions drop-down list.
Choose the OK button. The new permission appears in a line in the Policy Entry dialog.
Save the Policy File
To save the new policy file you've been creating, choose the Save As command from the File menu. This brings up the Save As dialog box.
The examples in this lesson and in the Quick Tour of Controlling Applications lesson assume that you stored the policy file in the Test directory on the C: drive.
Navigate the directory structure to get to that directory. Then type the file name mypolicy and choose the Save button. The policy file is now saved, and its name and path are shown in the text box labeled Policy File.
Exit Policy Tool by choosing the Exit command from the File menu.
See the Policy File Effects
Now that you have created the mypolicy policy file, you should be able to successfully execute the WriteFile applet to create and to write the file writetest, as shown in the following figure.Whenever you run an applet, or an application with a security manager, the policy files that are loaded and used by default are the ones specified in the "security properties file", which is located at one of the following:
UNIX: java.home/lib/security/java.security"Note that java.home indicates the directory into which the JRE was installed.The policy file locations are specified as the values of properties whose names are of the form
Here n indicates a number. You specify each such property value in a line of the following form:policy.url.nHere URL is a URL specification. For example, the default policy files, sometimes referred to as the system and user policy files, respectively, are defined in the security properties file aspolicy.url.n=URLIn the previous step you did not modify one of these policy files. You created a policy file named mypolicy. There are two possible ways you can have the mypolicy file be considered as part of the overall policy, in addition to the policy files specified in the security properties file. You can either specify the additional policy file in a property passed to the runtime system, as described in Approach 1, or add a line in the security properties file specifying the additional policy file, as discussed in Approach 2.policy.url.1=file:${java.home}/lib/security/java.policy policy.url.2=file:${user.home}/.java.policyOn a UNIX system, you must have DNS configured in order for the WriteFile program to be downloaded from the public web site as in the command executions shown below. You need to have dns in the list of lookup services for hosts in your /etc/nsswitch.conf file, as in
hosts: dns files nisYou also need a /etc/resolv.conf file with a list of nameservers. Consult your system administrator for more information.
Approach 1
You can use an appletviewer command-line argument, -J-Djava.security.policy, to specify a policy file that should be used in addition to the ones specified in the security properties file. To run the WriteFile applet with the mypolicy policy file included, type the following in the directory in which mypolicy is stored:appletviewer -J-Djava.security.policy=mypolicy http://java.sun.com/docs/books/tutorial/security/tour1/ example-1dot2/WriteFile.html
- This must be typed as a single line, with a space between mypolicy and the URL and no spaces in the URL. Multiple lines are used in the example just for legibility purposes.
- If this command line is longer than the maximum number of characters you are allowed to type on a single line, do the following. Create a text file containing the full command, and name the file with a .bat extension, for example, wf.bat. Then in your command window simply type the name of the .bat file instead of the command. This results in execution of the full command.
If the applet still reports an error, something is wrong in the policy file. Use the Policy Tool to open the mypolicy file (using File > Open) and check the policy entries you just created in the previous step. Change any typos or other errors.
To view or edit an existing policy entry, select the line for that entry in the main Policy Tool window, then choose the Edit Policy Entry button. Alternatively you can simply double-click the line for that entry.
This brings up the same type of Policy Entry dialog box as appears when you are adding a new policy entry after choosing the Add Policy Entry button, except in this case the dialog box is filled in with the existing policy entry information. To change the information, simply retype it (for the CodeBase and SignedBy values) or add, remove, or modify permissions.
Approach 2
You can specify a number of URLs (including ones of the form "http://") in policy.url.n properties in the security properties file, and all the designated policy files will get loaded.So one way to have our mypolicy file's policy entry considered by the appletviewer is to add an entry specifying that policy file in the security properties file.
If you are running your own copy of the JDK, you can easily edit your security properties file. If you are running a version shared with others, you may only be able to modify the system-wide security properties file if you have write access to it or if you ask your system administrator to modify the file when appropriate. However, it's probably not appropriate for you to make modifications to a system-wide policy file for this tutorial test. We suggest that you just read the following to see how it's done or that you install your own private version of the JDK to use for the tutorial lessons.
To modify the security properties file, open it in an editor suitable for editing an ASCII text file. Then add the following line after the line starting with policy.url.2:
Windows: policy.url.3=file:/C:/Test/mypolicy UNIX: policy.url.3=file:${user.home}/test/mypolicyOn a UNIX system you can alternatively explicitly specify your home directory, as in
policy.url.3=file:/home/susanj/test/mypolicyNow you should be able to successfully run the following:
Type this command on one line, without spaces in the URL.appletviewer http://java.sun.com/docs/books/tutorial/ security/tour1/example-1dot2/WriteFile.htmlAs with approach 1, if you still get a security exception, something is wrong in the policy file. Use the Policy Tool to check the policy entry you just created in the previous step.
Change any typos or other errors.
The mypolicy policy file is also used in the Quick Tour of Controlling Applications lesson. If you will not be doing that lesson, you may want to delete the line you just added in the security properties file (or comment it out), since you probably do not want the mypolicy file included when you are not running the tutorial lessons.
Observe Application Freedom
Let's demonstrate that a security manager is by default not installed for an application, and thus the application has full access to resources.Create a file named GetProps.java on your computer by either copying or downloading the GetProps.java source code.
The examples in this lesson assume that you put GetProps.java in the C:\Test directory if you're using a Windows system or in the ~/test directory on UNIX.
As you can see if you examine the source file, this program tries to get (read) the values of various properties, whose names are "os.name" , "java.version", "user.home", and "java.home".
Now compile and run GetProps.java. You should see output like the following:
C:\TEST>java GetProps About to get os.name property value The name of your operating system is: Windows 95 About to get java.version property value The version of the JVM you are running is: 1.2.2 About to get user.home property value Your user home directory is: C:\WINDOWS About to get java.home property value Your JRE installation directory is: C:\JDK1.2.2\JREThe application is allowed to access all the property values
Restrict Applications
A security manager is not automatically installed when an application is running. To apply the same security policy to an application found on the local file system as to downloaded applets, you can invoke the interpreter with the new -Djava.security.manager command line argument.To execute the GetProps application with the default security manager, type the following:
Here's the output from the program:java -Djava.security.manager GetPropsC:\TEST>java -Djava.security.manager GetProps About to get os.name property value The name of your operating system is: Windows 95 About to get java.version property value The version of the JVM you are running is: JDK 1.2.2 About to get user.home property value Caught exception java.security.AccessControlException: access denied (java.util.PropertyPermission user.home read)
Security-Sensitive Properties
The system policy file, loaded by default, grants all code permission to access some commonly useful properties such as "os.name" and "java.version". These properties are not security-sensitive, so granting such permissions does not pose a problem.The other properties GetProps tries to access, "user.home" and "java.home", are not among the properties for which the system policy file grants read permission. Thus as soon as GetProps attempts to access the first of these properties ("user.home"), the security manager prevents the access and reports an AccessControlException. This exception indicates that the policy currently in effect, which consists of entries in one or more policy files, doesn't allow permission to read the "user.home" property.
The System Policy File
The system policy file is by default located at:
Windows: java.home\lib\security\java.policy UNIX: java.home/lib/security/java.policyNote that java.home represents the value of the "java.home" property, which is a system property specifying the directory into which the JRE was installed. Thus if the JRE was installed in the directory named C:\jdk1.2.2\jre on Windows and /jdk1.2.2/jre on UNIX, the system policy file is located atWindows: C:\jdk1.2.2\jre\lib\security\java.policy UNIX: /jdk1.2.2/jre/lib/security/java.policyHere is a copy of the system policy file.
The instructions illustrate creating the policy file for a Windows system. The steps are exactly the same if you are working on a UNIX system, with the following differences.
- You retrieve the mypolicy file from the test directory in your home directory.
- For the CodeBase URL in the step for granting the required permissions, you can substitute file:${user.home}/test/ for file:/C:/Test/. Alternatively you could directly specify your home directory rather than referring to the "user.home" property, as in file:/home/susanj/test/.
Open the Policy File
Start Policy Tool by typing the following at the command line:policytoolThis brings up the Policy Tool window. To open the mypolicy policy file, use the Open command in the File menu. This will present you with an Open dialog, which you can use to navigate the directory structure until you get to the directory containing the policy file (that is, the C:\Test\ directory).
Choose the mypolicy file in that directory and then select the Open button.
This will fill in the Policy Tool window with information from the mypolicy policy file, including the policy file name and the CodeBase part of the policy entry. lesson.
Grant the Required Permissions
To grant the GetProps application permission to read the "user.home" and "java.home" property values, you must create a policy entry granting those permissions. Choose the Add Policy Entry button in the main Policy Tool window. This brings up the Policy Entry dialog box.Type the following file URL into the CodeBase text box to indicate that you are going to be granting a permission to code from the specified directory, which is the directory in which GetProps.class is stored.
(Note, this is a URL and thus must always have slashes, not backslashes.)file:/C:/Test/Leave the SignedBy text box blank, since you aren't requiring the code to be signed.
To add permission to read the "user.home" property value, choose the Add Permission button. This brings up the Permissions dialog box.
Do the following.
- Choose Property Permission from the Permission drop-down list. The complete permission type name (java.util.PropertyPermission) now appears in the text box to the right of the drop-down list.
- Type the following in the text box to the right of the list labeled Target Name to specify the "user.home" property:
user.home- Specify permission to read this property by selecting the read option from the Actions drop-down list.
To add permission to read the "java.home" property value, choose the Add Permission button again. In the Permissions dialog box, do the following:
Now the Permissions dialog box looks like the following.
- Choose Property Permission from the Permission drop-down list.
- Type the following in the text box to the right of the list labeled Target Name to specify the "java.home" property:
java.home- Specify permission to read this property by choosing the read option from the Actions drop-down list.
Choose the OK button. The new permission and the previously added permission appear in lines in the policy entry window, as shown in the following figure.
You are now done specifying this policy entry, so choose the Done button in the Policy Entry dialog. The Policy Tool window now includes a line representing the new policy entry, showing the CodeBase value.
Save the Policy File
To save the policy file, simply choose the Save command in the File menu.Then exit Policy Tool by choosing the Exit command from the File menu. Now that you have added the required policy entry to the mypolicy policy file, you should be able to successfully read the specified properties when you execute the GetProps application with a security manager.
As noted at the end of the Quick Tour of Controlling Applets lesson, whenever you run an applet, or an application with a security manager, the policy files that are loaded and used by default are the ones specified in the "security properties file", which is located at
Windows: java.home\lib\security\java.security UNIX: java.home/lib/security/java.security"Note that java.home indicates the directory into which the JRE was installed.There are two possible ways you can have the mypolicy file be considered as part of the overall policy, in addition to the policy files specified in the security properties file. You can either specify the additional policy file in a property passed to the runtime system, as described in Approach 1, or add a line in the security properties file specifying the additional policy file, as discussed in Approach 2.
Approach 1
You can use a -Djava.security.policy interpreter command line argument to specify a policy file that should be used in addition to the ones specified in the security properties file.Make sure that you are in the directory containing GetProps.class and mypolicy. Then you can run the GetProps application and pass the mypolicy policy file to the interpreter by typing the following command on one line:
java -Djava.security.manager -Djava.security.policy=mypolicy GetPropsThe program should report the values of the "user.home" and "java.home" properties.
If the application still reports an error, something is wrong in the policy file. Use the Policy Tool to check the policy entry you just created. Then fix any typos or other errors.
Approach 2
You can specify a number of URLs in policy.url.n properties in the security properties file, and all the designated policy files will get loaded. So one way to have your mypolicy file's policy entries considered by the java interpreter is to add an entry specifying that policy file in the security properties file.You created such an entry in the last part of the Quick Tour of Controlling Applets lesson. If your security properties file still has that entry, you're ready to run the application. Otherwise you need to add the entry. To do so, open the security properties file in an editor suitable for editing an ASCII text file. Then add the following line after the line containing policy.url.2: If you're on a Windows system, add
policy.url.3=file:/C:/Test/mypolicyIf you're on a UNIX system, add
On a UNIX system you can alternatively explicitly specify your home directory, as inpolicy.url.3=file:${user.home}/test/mypolicypolicy.url.3=file:/home/susanj/test/mypolicy
Run the Application
Now you should be able to successfully run the following.java -Djava.security.manager GetPropsAs with approach 1, if you still get a security exception, something is wrong in the policy file. Use the Policy Tool to check the policy entry you just created. Then fix any typos or other errors.
Before continuing, you may want to delete the line you just added in the security properties file (or comment it out), since you probably do not want the mypolicy file included when you are not running the tutorial lessons.
Digital Signatures
The basic idea in the use of digital signatures is as follows.
- You "sign" the document or code using one of your private keys, which you can generate by using keytool or security API methods. That is, you generate a digital signature for the document or code, using the jarsigner tool or API methods.
- You send to the other person, the "receiver," the document or code and the signature.
- You also supply the receiver with the public key corresponding to the private key used to generate the signature, if the receiver doesn't already have it.
- The receiver uses the public key to verify the authenticity of the signature and the integrity of the document/code.
A receiver needs to ensure that the public key itself is authentic before reliably using it to check the signature's authenticity. Therefore it is more typical to supply a certificate containing the public key rather than just the public key itself, as discussed in the next section.
Certificates
A certificate containsOne way for a recipient to check whether a certificate is valid is by verifying its digital signature, using its issuer's (signer's) public key. That key may itself be stored in another certificate whose signature can be verified by using the public key of that other certificate's issuer, and that key may also be stored in yet another certificate, and so on. You can stop checking when you reach a public key that you already trust and use it to verify the signature on the corresponding certificate.
- A public key.
- The "distinguished-name" information of the entity (person, company, or so on) whose certificate it is. This entity is referred to as the certificate subject, or owner. The distinguished-name information includes the following attributes (or a subset): the entity's name, organizational unit, organization, city or locality, state or province, and country code.
- A digital signature. A certificate is signed by one entity, the issuer, to vouch for the fact that the enclosed public key is the actual public key of another entity, the owner.
- The distinguished-name information for the signer (issuer).
If the recipient cannot establish such a trust chain (for example, because the required issuer certificates are not available), the certificate fingerprint(s) can be calculated, as may be done by the keytool -import or -printcert command. Each fingerprint is a relatively short number that uniquely and reliably identifies the certificate. (Technically, the fingerprint is a hash value of the certificate information, using a message digest function.) The recipient can call up the certificate owner and compare the fingerprints of the received certificate with those of the certificate that was sent. If the fingerprints are the same, the certificates are the same.
Thus you can ensure that a certificate was not modified in transit. One other potential uncertainty when working with certificates is the identity of the sender. Sometimes a certificate is self-signed, that is, signed using the private key corresponding to the public key in the certificate; the issuer is the same as the subject. This is okay if the receiver already knows and trusts the sender.
Otherwise the sender needs to obtain a certificate from a trusted third party, referred to as a certification authority (CA). To do so, you send a self-signed certificate signing request (CSR) to the CA. The CA verifies the signature on the CSR and your identity, perhaps by checking your driver's license or other information. The CA then vouches for your being the owner of the public key by issuing a certificate and signing it with its own (the CA's) private key. Anybody who trusts the issuing CA's public key can now verify the signature on the certificate. In many cases the issuing CA itself may have a certificate from a CA higher up in the CA hierarchy, leading to certificate chains.
Certificates of entities you trust are typically imported into your keystore as "trusted certificates." The public key in each such certificate may then be used to verify signatures generated using the corresponding private key. Such verifications can be done by
- the jarsigner tool (if the document/code and signature appear in a JAR file),
- API methods, or
- the runtime system, when a resource access is attempted and a policy file specifies that the resource access is allowed for the code attempting the access if its signature is authentic. The code's class file(s) and signature must be in a JAR file.
If you are sending signed code or documents to others, you need to supply them with the certificate containing the public key corresponding to the private key used to sign the code/document. The keytool -export command or API methods can export your certificate from your keystore to a file, which can then be sent to anyone needing it. A person who receives the certificate can import it into the keystore as a trusted certificate, using, for example, API methods or the keytool -import command.
If you use the jarsigner tool to generate a signature for a JAR file, the tool retrieves your certificate and its supporting certificate chain from your keystore. The tool then stores them, along with the signature, in the JAR file.
Keystores
Private keys and their associated public key certificates are stored in password-protected databases called keystores. A keystore can contain two types of entries: the trusted certificate entries discussed above, and key/certificate entries, each containing a private key and the corresponding public key certificate. Each entry in a keystore is identified by an alias.
A keystore owner can have multiple keys in the keystore, accessed via different aliases. An alias is typically named after a particular role in which the keystore owner uses the associated key. An alias may also identify the purpose of the key. For example, the alias signPersonalEmail might be used to identify a keystore entry whose private key is used for signing personal e-mail, and the alias signJarFiles might be used to identify an entry whose private key is used for signing JAR files.
The keytool tool can be used to
- Create private keys and their associated public key certificates
- Issue certificate requests, which you send to the appropriate certification authority
- Import certificate replies, obtained from the certification authority you contacted
- Import public key certificates belonging to other parties as trusted certificates
- Manage your keystore
API methods can also be used to access and to modify a keystore.
Tool and API Notes
Note the following regarding use of the tools and the API related to digital signatures.
- You can use the JDK Security API, tools, or a combination to generate keys and signatures and to import certificates. You can use these API or tool features to securely exchange documents with others.
- To use the tools for document exchange, the document(s) must be placed in a JAR (Java ARchive) file, which may be created by the jar tool. A JAR file is a good way of encapsulating multiple files in one spot. When a file is "signed", the resulting digital signature bytes need to be stored somewhere. When a JAR file is signed, the signature can go in the JAR file itself. This is what happens when you use the jarsigner tool to sign a JAR file.
- If you are creating applet code that you will sign, it needs to be placed in a JAR file. The same is true if you are creating application code that may be similarly restricted by running it with a security manager. The reason you need the JAR file is that when a policy file specifies that code signed by a particular entity is permitted one or more operations, such as specific file reads or writes, the code is expected to come from a signed JAR file. (The term "signed code" is an abbreviated way of saying "code in a class file that appears in a JAR file that was signed.")
- In order for the runtime system to check a code signature, the person/organization that will run the code first needs to import into their keystore a certificate authenticating the public key corresponding to the private key used to sign the code.
- In order for the jarsigner tool to verify the authenticity of a JAR file signature, the person/organization that received the JAR file first needs to import into their keystore a certificate authenticating the public key corresponding to the private key used to sign the code.
- At this time there are no APIs for certificate creation.
Use of the JDK Security API to Sign Documents
The Generating and Verifying Signatures lesson demonstrates the use of the JDK Security API with respect to signing documents. The lesson shows what one program, executed by the person who has the original document, would do toThen it shows an example of another program, executed by the receiver of the data, signature, and public key. It shows how the program could
- generate keys,
- generate a digital signature for the data using the private key, and
- export the public key and the signature to files.
The lesson also discusses and demonstrates possible alternative approaches and methods of supplying and importing keys, including in certificates.
- import the public key and
- verify the authenticity of the signature.
Use of the Tools to Sign Code or Documents
The Signing Code and Granting It Permissions lesson shows use of the tools by a code developer to put the code into a JAR file, sign it, and export the public key. Then it shows use of the tools by someone who will run the code or by a system administrator to import the signer's public key certificate and add an entry into a policy file granting the code permission for the resource accesses it needs.The Exchanging Files lesson shows use of the tools by one person to sign an important document, such as a contract, and export the public key certificate for the public key corresponding to the private key used to sign the contract. Then it shows how another person receiving the contract, the signature, and the public key certificate would use keytool to import the certificate and the jarsigner tool to verify the signature.
These two lessons have much in common. In both cases, the first two steps for the code or document sender are to
The next two steps are optional:
- Create a JAR file containing the document or class file, using the jar tool.
- Generate keys (if they don't already exist), using the keytool -genkey command.
The next two steps are required:
- Use the keytool -certreq command; then send the resulting certificate signing request to a certification authority (CA) such as VeriSign.
- Use the keytool -import command to import the CA's response.
In both cases, the receiver of the signed JAR file and the certificate should import the certificate as a trusted certificate, using the keytool -import command. The keytool will attempt to construct a trust chain from the certificate to be imported to an already trusted certificate in the keystore. If that fails, the keytool will display the certificate fingerprint and prompt you to verify it.
- Sign the JAR file, using the jarsigner tool and the private key generated in Step 2.
- Export the public key certificate, using the keytool -export command. Then supply the signed JAR file and the certificate to the receiver.
If what was sent was code, the receiver also needs to modify a policy file to permit the required resource accesses to code signed by the private key corresponding to the public key in the imported certificate. The Policy Tool can be used to do this.
If what was sent was one or more documents, the receiver needs to verify the authenticity of the JAR file signature, using the jarsigner tool.
When keytool is used to generate public/private key pairs, it creates a keystore entry containing a private key and a self-signed certificate for the public key. (That is, the certificate is signed using the corresponding private key.) This may be adequate if the people receiving your signed files already know and trust your identity.
However, a certificate is more likely to be trusted by others if it is signed by a certification authority (CA). To get a certificate signed by a CA, you first generate a certificate signing request (CSR), via a command such as the following:
Here alias is used to access the keystore entry containing the private key and the public key certificate, and csrFile specifies the name to be used for the CSR created by this command.keytool -certreq -alias alias -file csrFileYou then submit this file to a CA, such as VeriSign, Inc. The CA will authenticate you, the requestor ("subject"), usually off line, and then will sign and return a certificate authenticating your public key. That is, the CA vouches that you are the owner of the public key by signing the certificate. (In some cases, the CA will return a chain of certificates, each one authenticating the public key of the signer of the previous certificate in the chain.)
Importing the Response from the CA
If you submitted a certificate signing request (CSR) to a certification authority (CA), you need to replace the original self-signed certificate in your keystore with a certificate chain by importing the certificate (or chain of certificates) returned to you by the CA.
But first you need a "trusted certificate" entry in your keystore (or in the cacerts keystore file, described below) that authenticates the CA's public key. With such an entry the CA's signature can be verified. That is, the CA's signature chain the CA sends to you in response to your CSR, can be verified.
Importing a Certificate from a CA as a "Trusted Certificate"
Before you import the certificate reply from a CA, you need one or more "trusted certificates" in your keystore or in the cacerts file.
- If the certificate reply is a certificate chain, you just need the top certificate of the chain -- the "root" CA certificate authenticating that CA's public key.
- If the certificate reply is a single certificate, you need a certificate for the issuing CA (the one that signed it). If that certificate is not self-signed, you need a certificate for its signer, and so on, up to a self-signed "root" CA certificate.
The cacerts file represents a system-wide keystore with CA certificates. This file resides in the JRE security properties directory, java.home/lib/security, where java.home is the JRE installation directory.
The cacerts file currently ships with five VeriSign root CA certificates. If you sent your CSR to VeriSign, you won't need to import a VeriSign certificate as a trusted certificate in your keystore; you can go on to the next section to see how to import the certificate reply from the CA.
IMPORTANT: Verify Your cacerts File
Since you trust the CAs in the cacerts file as entities for signing and issuing certificates to other entities, you must manage the cacerts file carefully. The cacerts file should contain only certificates of the CAs you trust. It is your responsibility to verify the trusted root CA certificates bundled in the cacerts file and make your own trust decisions. To remove an untrusted CA certificate from the cacerts file, use the delete option of the keytool command. You can find the cacerts file in the JRE installation directory. Contact your system administrator if you do not have permission to edit this file.
A certificate from a CA is usually either self-signed or signed by another CA, in which case you also need a certificate authenticating that CA's public key. Suppose that company ABC, Inc., is a CA and that you obtain a file named ABCCA.cer, purportedly a self-signed certificate from ABC, authenticating that CA's public key.
To ensure that the certificate is valid:
keytool -printcertor
keytool -import commandand make sure that the displayed certificate fingerprint(s) match the expected ones. You can call the person who sent the certificate and compare the fingerprint(s) that you see with the ones that they show or that a secure public key repository shows. Only if the fingerprints are equal is it guaranteed that the certificate has not been replaced in transit with somebody else's (for example, an attacker's) certificate. If such an attack took place and you did not check the certificate before you imported it, you would end up trusting anything the attacker has signed.
If you trust that the certificate is valid, you can add it to your keystore via a command such as the following:
This command creates a "trusted certificate" entry in the keystore whose name is that specified in storefile. The entry contains the data from the file ABCCA.cer, and it is assigned the specified alias.keytool -import -alias alias -file ABCCA.cer -keystore storefile
Importing the Certificate Reply from the CA
Once you've imported the required trusted certificate(s), as described in the previous section, or they are already in your keystore or in the cacerts file, you can import the certificate reply and thereby replace your self-signed certificate with a certificate chain. This chain will be either the one returned by the CA in response to your request (if the CA reply is a chain) or one constructed (if the CA reply is a single certificate) by using the certificate reply and trusted certificates that are already available in the keystore or in the cacerts keystore file.
As an example, suppose that you sent your certificate signing request to VeriSign. You can then import the reply via the following, which assumes that the returned certificate is in the file specified by certReplyFile:
keytool -import -trustcacerts -keystore storefile -alias alias -file certReplyFileType this command on one line.
The certificate reply is validated by using trusted certificates from the keystore and optionally by using the certificates configured in the cacerts keystore file (if the -trustcacerts option is specified). Each certificate in the chain is verified, using the certificate at the next level higher in the chain. You need to trust only the top-level "root" CA certificate in the chain. If you do not already trust the top-level certificate, keytool will display the fingerprint of that certificate and ask you whether you want to trust it.
The new certificate chain of the specified (by alias) entry replaces the old certificate (or chain) associated with this entry. The old chain can be replaced only if a valid keypass, the password used to protect the private key of the entry, is supplied. If no password is provided and if the private key password is different from the keystore password, the user is prompted for it.
For more detailed information about generating CSRs and importing certificate replies, see the keytool documentation on the public java.sun.com web site:
Signing Code and Granting It Permissions
This lesson illustrates the use of the security-related tools ( keytool, jarsigner, and Policy Tool). It also shows use of the jar tool to place files in JAR (Java ARchive) files for subsequent signing by the jarsigner tool.
In this lesson you first execute steps to create an application, put it in a JAR file, sign the JAR file, and export the public key certificate corresponding to the private key used to sign the JAR file. For convenience, you pretend to be Susan Jones, and you supply information about her when you generate the keys.
Then you act as the recipient of the signed JAR file and the certificate. For convenience, you pretend to be Ray. You see how the signed application cannot normally read a file when it is run under a security manager. Then you use keytool to import the certificate into Ray's keystore in an entry aliased by susan, and the Policy Tool to create an entry in Ray's policy file to permit code signed by susan to read the specified file. Finally, you see how the application running under a security manager can now read the file, since it has been granted permission to do so.
For further information about digital signatures, certificates, keystores, and the tools, see the API and Tools Use for Secure Code and File Exchanges lesson.
You need to do everything in this lesson while working in the directory in which you store the sample application, but you should store the data file needed by the application in a different directory. All of the examples assume that you are working in the C:\Test directory, and that the data file is in the C:\TestData directory. If you are working on a UNIX system, substitute your own directory names.
Here are the steps:
Code Signer
The code signer takes the following steps:
- Download and Try the Sample Application.
- Create a JAR File Containing the Class File using the jar tool.
- Generate keys using the keytool -genkey command.
An optional step is to generate a certificate signing request (CSR) for the public key certificate, and import the response from the certification authority (CA). For simplicity (and since you are only pretending to be Susan Jones), this step is omitted.
- Sign the JAR File, using the jarsigner tool and the private key.
- Export the Public Key Certificate, using the keytool -export command. Then supply the signed JAR file and the certificate to the receiver Ray.
These steps are shown in the following figure.
Sample Application
The application used by this lesson is supplied for you.
Create a file named Count.java on your local computer by either copying or downloading the Count.java source code. The examples in this lesson assume that you place it in the C:\Test directory.
Now compile and then run the Count application to see what it does. You need to specify (as an argument) the path name of a file to be read. You can download and use this sample file named data or any other file you like.
For this lesson, put the data file in a directory other than the directory containing the Count application. The examples assume that you put the data file in the C:\TestData directory. Later in this lesson you will see how an application running under a security manager cannot read a file unless it has explicit permission to do so. However, an application can always read a file from the same directory (or a subdirectory); it does not need explicit permission.
A sample run is
C:\Test>java Count C:\TestData\data Counted 65 chars.
Create a JAR File Containing the Class File
Next, create a JAR file containing the Count.class file. Type the following in your command window:This creates a JAR file, Count.jar, and places the Count.class file inside it.jar cvf Count.jar Count.class
Generate Keys
If a code signer does not yet have a suitable private key for signing the code, the key must first be generated, along with a corresponding public key that can be used by the code receiver's runtime system to verify the signature.
Since this lesson assumes that you don't yet have such keys, you are going to create a keystore named susanstore and create an entry with a newly generated public/private key pair (with the public key in a certificate).
Now pretend that you are Susan Jones and that you work in company ABC's purchasing department. Type the following command in your command window to create a keystore named susanstore and to generate keys for Susan Jones:
keytool -genkey -alias signFiles -keypass kpi135 -keystore susanstore -storepass ab987c(Note: This must be typed as a single line.)
Subparts of the keytool Command
Let's look at what each of the keytool subparts mean.
- The command for generating keys is -genkey.
- The -alias signFiles subpart indicates the alias to be used in the future to refer to the keystore entry containing the keys that will be generated.
- The -keypass kpi135 subpart specifies a password for the private key about to be generated. This password will always need to be used in order to access the keystore entry containing that key. The entry doesn't have to have its own password; if you don't include a -keypass option, you will be prompted for the key password and given the option of letting it be the same as the keystore password.
- The -keystore susanstore subpart indicates the name (and optionally path) of the keystore you are creating or already using.
- The -storepass ab987c subpart indicates the keystore password. If you don't include a -storepass option, you will be prompted for the keystore password.
For security reasons you actually should not supply your key or keystore passwords on the command line, because they can be intercepted more easily that way. Instead you should leave off the -keypass and the -storepass options and type your passwords when you are prompted for them.
Distinguished-Name Information
If you use the preceding command, you will be prompted for your distinguished-name information. Following are the prompts; the bold indicates what you should type.
What is your first and last name? [Unknown]: Susan Jones What is the name of your organizational unit? [Unknown]: Purchasing What is the name of your organization? [Unknown]: ABC What is the name of your City or Locality? [Unknown]: Cupertino What is the name of your State or Province? [Unknown]: CA What is the two-letter country code for this unit? [Unknown]: US Is <CN=Susan Jones, OU=Purchasing, O=ABC, L=Cupertino, ST=CA, C=US> correct? [no]: yThe keytool command creates the keystore named susanstore (if it doesn't already exist) in the same directory in which the command is executed and assigns it the password ab987c. The command generates a public/private key pair for the entity whose distinguished name has a common name of Susan Jones and the organizational unit of Purchasing.
The command creates a self-signed certificate that includes the public key and the distinguished-name information. (The distinguised name you supply will be used as the "subject" field in the certificate.) This certificate will be valid for 90 days, the default validity period if you don't specify a -validity option. The certificate is associated with the private key in a keystore entry referred to by the alias signFiles. The private key is assigned the password kpi135.
Note: The command could be shorter if option defaults are accepted or you wish to be prompted for various values. Whenever you execute a keytool command, defaults are used for unspecified options that have default values, and you are prompted for any required values. For the genkey command, options with default values include alias (whose default is mykey), validity (90 days), and keystore (the file named .keystore in your home directory). Required values include dname, storepass, and keypass.
Sign the JAR File
Now you are ready to sign the JAR file. Type the following in your command window to sign the JAR file Count.jar, using the private key in the keystore entry aliased by signFiles, and to name the resulting signed JAR file sCount.jar:You will be prompted for the store password (ab987c) and the private key password (kpi135).jarsigner -keystore susanstore -signedjar sCount.jar Count.jar signFilesThe jarsigner tool extracts the certificate from the keystore entry whose alias is signFiles and attaches it to the generated signature of the signed JAR file.
Export the Public Key Certificate
You now have a signed JAR file sCount.jar. The runtime system of the code receiver (Ray) will need to authenticate the signature when the Count application in the signed JAR file tries to read a file and a policy file grants that permission to this signed code.In order for the runtime system to authenticate the signature, Ray's keystore needs to have the public key corresponding to the private key used to generate the signature. You supply this by sending Ray a copy of the certificate authenticating the public key. Copy that certificate from the keystore susanstore to a file named SusanJones.cer via the following:
You will be prompted for the store password (ab987c).keytool -export -keystore susanstore -alias signFiles -file SusanJones.cer
Steps for the Code Receiver
Now act as Ray, who receives the signed JAR file and the certificate file from Susan.
Observe the Restricted Application
The last part of the Quick Tour of Controlling Applications lesson shows how an application can be run under a security manager by invoking the interpreter with the new -Djava.security.manager command-line argument. But what if the application to be invoked resides inside a JAR file?One of the interpreter options is the -cp (for class path) option, whereby you specify a search path for application classes and resources. Thus, for example, to execute the Count application inside the sCount.jar JAR file, specifying the file C:\TestData\data as its argument, you could type the following while in the directory containing sCount.jar:
To execute the application with a security manager, simply add -Djava.security.manager, as injava -cp sCount.jar Count C:\TestData\dataWhen you run this command, you should get an exception.java -Djava.security.manager -cp sCount.jar Count C:\TestData\dataException in thread "main" java.security.AccessControlException: access denied (java.io.FilePermission C:\TestData\data read) at java.security.AccessControlContext.checkPermission(Compiled Code) at java.security.AccessController.checkPermission(Compiled Code) at java.lang.SecurityManager.checkPermission(Compiled Code) at java.lang.SecurityManager.checkRead(Compiled Code) at java.io.FileInputStream.(Compiled Code) at Count.main(Compiled Code) This AccessControlException is reporting that the application does not have permission to read the file C:\TestData\data. This exception is raised because an application running under a security manager cannot read a file or access other resources unless it has explicit permission to do so.
Import the Certificate as a Trusted Certificate
Before you can grant the signed code permission to read a specified file, you need to import Susan's certificate as a trusted certificate in your keystore.Suppose that you have received from Susan
- the signed JAR file sCount.jar, which contains the Count.class file, and
- the file SusanJones.cer, which contains the public key certificate for the public key corresponding to the private key used to sign the JAR file.
Even though you created these files and they haven't actually been transported anywhere, you can simulate being someone other than the creater and sender, Susan. Pretend that you are now Ray. Acting as Ray, you will create a keystore named raystore and will use it to import the certificate into an entry with an alias of susan.
A keystore is created whenever you use a keytool command specifying a keystore that doesn't yet exist. Thus we can create the raystore and import the certificate via a single keytool command. Do the following in your command window.
Since the keystore doesn't yet exist, it will be created, and you will be prompted for a keystore password; type whatever password you want.
- Go to the directory containing the public key certificate file SusanJones.cer. (You should actually already be there, since this lesson assumes that you stay in a single directory throughout.)
- Type the following command on one line:
keytool -import -alias susan -file SusanJones.cer -keystore raystoreThe keytool command will print out the certificate information and ask you to verify it, for example, by comparing the displayed certificate fingerprints with those obtained from another (trusted) source of information. (Each fingerprint is a relatively short number that uniquely and reliably identifies the certificate.) For example, in the real world you might call up Susan and ask her what the fingerprints should be. She can get the fingerprints of the SusanJones.cer file she created by executing the command
If the fingerprints she sees are the same as the ones reported to you by keytool, the certificate has not been modified in transit. In that case you let keytool proceed with placing a trusted certificate entry in the keystore. The entry contains the public key certificate data from the file SusanJones.cer and is assigned the alias susan.keytool -printcert -file SusanJones.cer
Set Up a Policy File to Grant the Required Permission
Next, you will use the Policy Tool to create a policy file named raypolicy and in it grant a permission to code from a signed JAR file.
The JAR file must have been signed using the private key corresponding to the public key imported into Ray's keystore (raystore) in the previous step. The certificate containing the public key is aliased by susan in the keystore. We will grant such code permission to read any file in the C:\TestData\ directory.
The steps are:
- Start the Policy Tool
- Specify the Keystore
- Add a Policy Entry with a SignedBy Alias
- Save the Policy File
Start Policy Tool
To start Policy Tool, simply type the following at the command line:policytoolThis brings up the Policy Tool window. Whenever Policy Tool is started, it tries to fill in this window with policy information from what is sometimes referred to as the "user policy file," which by default is a file named .java.policy in your home directory. If Policy Tool cannot find the user policy file, it reports the situation and displays a blank Policy Tool window (that is, a window with headings and buttons but no data in it, as shown in the following figure.
You will create and work on a policy file other than the user policy file, since the lessons of this trail don't expect modifications to be made to your official user policy file.
Assuming that you see the blank Policy Tool window (if not, select New in the File menu), you can immediately proceed to create a new policy file.
Specify the Keystore
For this lesson you will grant all code in JAR files signed by the alias susan read access to all files in the C:\TestData\ directory. You need to
- Specify the keystore containing the certificate information aliased by susan
- Create the policy entry granting the permission
The keystore is the one named raystore
To specify the keystore, choose the Change Keystore command in the Edit menu of the main Policy Tool window. This brings up a dialog box in which you can specify the keystore URL and the keystore type.
To specify the keystore named raystore in the Test directory on the C: drive, type the following file URL into the text box labeled New KeyStore URL
You can leave the text box labeled New KeyStore Type blank if the keystore type is the default one, as specified in the security properties file. Your keystore will be the default type, so leave the text box blank.file:/C:/Test/raystoreNote: The New KeyStore URL value is a URL and thus should always use slashes (never backslashes) as the directory separator.
When you are done specifying the keystore URL, choose OK. The text box labeled Keystore is now filled in with the URL:
Next, you need to specify the new policy entry.
Add a Policy Entry with a SignedBy Alias
To grant code signed by susan permission to read any files in the C:\TestData directory, you need to create a policy entry granting this permission. Note that "Code signed by susan" is an abbreviated way of saying "Code in a class file contained in a JAR file, where the JAR file was signed using the private key corresponding to the public key that appears in a keystore certificate in an entry aliased by susan."Choose the Add Policy Entry button in the main Policy Tool window. This brings up the Policy Entry dialog box:
Using this dialog box, type the following alias into the SignedBy text box:
susanLeave the CodeBase text box blank, to grant all code signed by susan the permission, no matter where it comes from.
Note: If you wanted to restrict the permission to just code signed by susan that comes from the C:\Test\ directory, you would type the following URL into the CodeBase text box:
file:/C:/Test/*To add the permission, choose the Add Permission button. This brings up the Permissions dialog box.
Do the following.
Now the Permissions dialog box looks like the following.
- Choose File Permission from the Permission drop-down list. The complete permission type name (java.io.FilePermission) now appears in the text box to the right of the drop-down list.
- Type the following in the text box to the right of the list labeled Target Name to specify all files in the C:\TestData\ directory:
C:\TestData\*- Specify read access by choosing the read option from the Actions drop-down list.
Choose the OK button. The new permission appears in a line in the Policy Entry dialog, as follows. Each backslash in the file path you typed has been replaced with two backslashes, for your convenience. Strings in a policy file are processed by a tokenizer that allows \ to be used as an escape character (for example, \n to indicate a new line), so the policy file requires two backslashes to indicate a single backslash. If you use single backslashes as your directory separators, Policy Tool automatically converts them to double backslashes for you.
You are now done specifying this policy entry, so choose the Done button in the Policy Entry dialog. The Policy Tool window now contains a line representing the policy entry, showing the SignedBy value, as shown in the following figure.
Save the Policy File
To save the new policy file you've been creating, choose the Save As command from the File menu. This brings up the Save As dialog box.
Navigate the directory structure to get to the directory in which to save the policy file: the Test directory on the C: drive. Type the file name
Then choose the Save button. The policy file is now saved, and its name and path are shown in the text box labeled Policy File, as shown in the following figure.raypolicyThen exit Policy Tool by selecting the Exit command from the File menu.
In the previous steps you created an entry in the raypolicy policy file granting code signed by susan permission to read files from the C:\TestData\ directory (or the testdata directory in your home directory if you're working on UNIX). Now you should be able to successfully execute the Count program to read and to count the characters in a file from the specified directory, even when you run the application with a security manager.
There are two possible ways you can have the raypolicy file be considered as part of the overall policy, in addition to the policy files specified in the security properties file. The first approach is to specify the additional policy file in a property passed to the runtime system. The second approach is to add a line in the security properties file specifying the additional policy file.
Approach 1
You can use a -Djava.security.policy command-line argument to specify a policy file that should be used in addition to or instead of the ones specified in the security properties file.To run the Count application and have the raypolicy policy file included, type the following while in the directory containing the sCount.jar and raypolicy files:
java -Djava.security.manager -Djava.security.policy=raypolicy -cp sCount.jar Count C:\TestData\dataNote: The command should be typed on a single line, with a space between raypolicy and -cp.
The program should report the number of characters in the specified file.
If it still reports an error, something is wrong in the policy file. Use the Policy Tool to check the permission you just created in the previous step, and change any typos or other errors.
Approach 2
You can specify a number of URLs -- including ones of the form "http://" -- in policy.url.n properties in the security properties file, and all the designated policy files will get loaded.So one way to have your raypolicy file's policy entries considered by the interpreter is to add an entry indicating that file in the security properties file.
If you are running your own copy of the JDK, you can easily edit your security properties file. If you are running a version shared with others, you may only be able to modify the system-wide security properties file if you have write access to it or if you ask your system administrator to modify the file when appropriate. However, it's probably not appropriate for you to make modifications to a system-wide policy file for this tutorial test; we suggest that you just read the following to see how it's done or that you install your own private version of the JDK to use for the tutorial lessons. The security properties file is located at
Windows: java.home\lib\security\java.security UNIX: java.home/lib/security/java.security"The java.home portion indicates the directory into which the JRE was installed.To modify the security properties file, open it in an editor suitable for editing an ASCII text file. Then add the following line after the line starting with policy.url.2:
Windows: policy.url.3=file:/C:/Test/raypolicy UNIX: policy.url.3=file:${user.home}/test/raypolicyOn a UNIX system you can alternatively explicitly specify your home directory, as in
Next, in your command window, go to the directory containing the sCount.jar file, that is, the C:\Test or ~/test directory. Type the following command on one line:policy.url.3=file:/home/susanj/test/raypolicyjava -Djava.security.manager -cp sCount.jar Count C:\TestData\dataAs with approach 1, if the program still reports an error, something is wrong with the policy file. Use the Policy Tool to check the permission you just created in the previous step, and change any typos or other errors. Before continuing, you may want to delete the line you just added in the security properties file (or comment it out), since you probably do not want the raypolicy file included when you are not running the tutorial lessons.
Exchanging Files
If you want to electronically send an important document, such as a contract, to someone else, it is a good idea to digitally "sign" the document, so that the recipient has a way of checking that the document indeed came from you and was not altered in transit.
This lesson illustrates the use of security-related tools for the exchange of an important document, in this case a contract. You first pretend that you are the contract sender, Stan Smith. This lesson shows the steps Stan would use to put the contract in a JAR file, sign it, and export the public key certificate for the public key corresponding to the private key used to sign the JAR file.
Then you pretend that you are Ruth, who has received the signed JAR file and the certificate. You'll use keytool to import the certificate into Ruth's keystore in an entry aliased by stan, and the jarsigner tool to verify the signature.
The commands executed in this lesson are assumed to all be done from within the same directory.
Here are the steps:
Contract Sender
The steps outlined here for the contract sender are basically the same as those listed for a code signer in the Signing Code and Granting It Permissions lesson. Here, however, you are pretending to be Stan Smith rather than Susan Jones and are storing a data file rather than a class file in the JAR file to be signed.The steps you take as the contract sender are as follows.
- Create a JAR File Containing the Contract, using the jar tool.
- Generate Keys (if they don't already exist), using the keytool -genkey command.
Optional Step: Generate a certificate signing request (CSR) for the public key certificate, and import the response from the certification authority. For simplicity and since you are only pretending to be Stan Smith, this step is omitted. See Generating a Certificate Signing Request (CSR) for a Public Key Certificate for more information.
- Sign the JAR File, using the jarsigner tool and the private key generated in step 2.
- Export the Public Key Certificate, using the keytool -export command. Then supply the signed JAR file and the certificate to the receiver, Ruth.
Create a JAR File Containing the Contract
The first thing you need is a contract file. You can download and use this very basic sample file named contract. Or you can use any other file you like. Just be sure to name the file contract so it will work with the commands specified in this lesson.
Once you've got a contract file, you can place it in a JAR file. In your command window type the following:
This command creates a JAR file named Contract.jar and places the contract file inside it.jar cvf Contract.jar contract
Generate Keys
Before signing the Contract.jar JAR file containing the contract file, you need to generate keys, if you don't already have suitable keys available. The private key is needed to sign the JAR file, and the corresponding public key is needed by the contract receiver to verify the signature.
This lesson assumes that you don't yet have such keys. You are going to create a keystore named stanstore and create an entry with a newly generated public/private key pair (with the public key in a certificate).
Now pretend that you are Stan Smith and that you work in the legal department of XYZ corporation. Type the following in your command window to create a keystore named stanstore and to generate keys for Stan Smith:
keytool -genkey -alias signLegal -keystore stanstoreYou will be prompted for the keystore password, your distinguished-name information, and the key password. Following are the prompts; the bold indicates what you should type.
Enter keystore password: balloon53 What is your first and last name? [Unknown]: Stan Smith What is the name of your organizational unit? [Unknown]: Legal What is the name of your organization? [Unknown]: XYZ What is the name of your City or Locality? [Unknown]: New York What is the name of your State or Province? [Unknown]: NY What is the two-letter country code for this unit? [Unknown]: US Is <CN=Stan Smith, OU=Legal, O=XYZ, L=New York, ST=NY, C=US> correct? [no]: y Enter key password for(RETURN if same as keystore password): cat876 The preceding keytool command creates the keystore named stanstore in the same directory in which the command is executed (assuming that the specified keystore doesn't already exist) and assigns it the password balloon53. The command generates a public/private key pair for the entity whose distinguished name has a common name of Stan Smith and an organizational unit of Legal.
The self-signed certificate created includes the public key and the distinguished-name information. (A self-signed certificate is one signed by the private key corresponding to the public key in the certificate.) This certificate will be valid for 90 days, the default validity period if you don't specify a -validity option. The certificate is associated with the private key in a keystore entry referred to by the alias signLegal. The private key is assigned the password cat876.
Sign the JAR File
Now you are ready to sign the JAR file.Type the following in your command window to sign the JAR file Contract.jar, using the private key in the keystore entry aliased by signLegal, and to name the resulting signed JAR file sContract.jar:
(Type all that on one line.)jarsigner -keystore stanstore -signedjar sContract.jar Contract.jar signLegalYou will be prompted for the store password (balloon53) and the private key password (cat876).
The jarsigner tool extracts the certificate from the keystore entry whose alias is signLegal and attaches it to the generated signature of the signed JAR file.
Export the Public Key Certificate
You now have a signed JAR file sContract.jar. Clients wanting to use the file will want to authenticate the signature. In order to do so, they need the public key corresponding to the private key used to generate the signature. You supply this by sending them a copy of the certificate containing the public key. Copy that certificate from the keystore stanstore to a file named StanSmith.cer via the following:You will be prompted for the store password (balloon53).keytool -export -keystore stanstore -alias signLegal -file StanSmith.cerGiven that certificate and the signed JAR file, a client can use the jarsigner tool to authenticate your signature, as you will see next.
Steps for the Contract Receiver
Now acting as Ruth, who receives the signed JAR file and the certificate file from Stan, perform the following steps, as shown in the figure.
- Import the Certificate as a Trusted Certificate using the keytool -import command.
- Verify the JAR File Signature, using the jarsigner tool.
Import the Certificate as a Trusted Certificate
Suppose that you are Ruth and have received from Stan Smith
- The signed JAR file sContract.jar containing a contract
- The file StanSmith.cer containing the public key certificate for the public key corresponding to the private key used to sign the JAR file
Before you can use the jarsigner tool to check the authenticity of the JAR file's signature, you need to import into your keystore the certificate from Stan.
Even though you (acting as Stan) created these files and they haven't actually been transported anywhere, you can simulate being someone other than the creater and sender, Stan. Acting as Ruth, type the following to create a keystore named ruthstore and import the certificate into an entry with an alias of stan.
Since the keystore doesn't yet exist, it will be created. You will be prompted for a keystore password; type whatever password you want.keytool -import -alias stan -file StanSmith.cer -keystore ruthstoreThe keytool will print out the certificate information and ask you to verify it, for example, by comparing the displayed certificate fingerprints with those obtained from another (trusted) source of information. (Each fingerprint is a relatively short number that uniquely and reliably identifies the certificate.) For example, in the real world you might call up Stan and ask him what the fingerprints should be. He can get the fingerprints of the StanSmith.cer file he created by executing the command
If the fingerprints he sees are the same as the ones reported to you by keytool, the certificate has not been modified in transit. In that case you let keytool proceed with placing a "trusted certificate" entry in the keystore. The entry contains the public key certificate data from the file StanSmith.cer and is assigned the alias stan.keytool -printcert -file StanSmith.cer
Verify the JAR File Signature
Now that you, acting as Ruth, have imported Stan's public key certificate into the ruthstore keystore as a "trusted certificate," you can use the jarsigner tool to verify the authenticity of the JAR file signature.When you verify a signed JAR file, you verify that the signature is valid and that the JAR file has not been tampered with. You can do this for the sContract.jar file via the following command:
You should see something like the following:jarsigner -verify -verbose -keystore ruthstore sContract.jarBe sure to run the command with the -verbose option to get enough information to ensure that183 Fri Jul 31 10:49:54 PDT 1998 META-INF/SIGNLEGAL.SF 1542 Fri Jul 31 10:49:54 PDT 1998 META-INF/SIGNLEGAL.DSA 0 Fri Jul 31 10:49:18 PDT 1998 META-INF/ smk 1147 Wed Jul 29 16:06:12 PDT 1998 contract s = signature was verified m = entry is listed in manifest k = at least one certificate was found in keystore i = at least one certificate was found in identity scope jar verified.
- the contract file is among the files in the JAR file that were signed and its signature was verified (that's what the s signifies), and
- the public key used to verify the signature is in the specified keystore and thus trusted by you (that's what the k signifies).
Generating and Verifying Signatures
This lesson walks you through the steps necessary to use the JDK Security API to generate a digital signature for data and to verify that a signature is authentic. This lesson is meant for developers who wish to incorporate security functionality into their programs, including cryptography services.
This lesson demonstrates the use of the JDK Security API with respect to signing documents. The lesson shows what one program, executed by the person who has the original document, would do to generate keys, generate a digital signature for the document using the private key, and export the public key and the signature to files.
Then it shows an example of another program, executed by the receiver of the document, signature, and public key. It shows how the program could import the public key and verify the authenticity of the signature. The lesson also discusses and demonstrates possible alternative approaches and methods of supplying and importing keys, including in certificates.
For further information about the concepts and terminology (digital signatures, certificates, keystores), see the API and Tools Use for Secure Code and File Exchanges lesson.
In this lesson you create two basic applications, one for the digital signature generation and the other for the verification. This is followed by a discussion and demonstration of potential enhancements. The lesson contains three sections.
- Generating a Digital Signature shows using the API to generate keys and a digital signature for data using the private key and to export the public key and the signature to files. The application gets the data file name from the command line.
- Verifying a Digital Signature shows using the API to import a public key and a signature that is alleged to be the signature of a specified data file and to verify the authenticity of the signature. The data, public key, and signature file names are specified on the command line.
- Weaknesses and Alternatives discusses potential weaknesses of the approach used by the basic programs. It then presents and demonstrates possible alternative approaches and methods of supplying and importing keys, including the use of files containing encoded key bytes and the use of certificates containing public keys.
Generating a Digital Signature
The GenSig program you are about to create will use the JDK Security API to generate keys and a digital signature for data using the private key and to export the public key and the signature to files. The application gets the data file name from the command line.The following steps create the GenSig sample program.
- Write program
- Generate Public and Private Keys
Generate a key pair public key(and private key). The private key is needed for signing the data. The public key will be used by the VerSig program for verifying the signature.
- Sign the Data
Get a Signature object and initialize it for signing. Supply it with the data to be signed, and generate the signature.
- Save the Signature and the Public Key in Files
Save the signature bytes in one file and the public key bytes in another.
- Compile and Run the Program
GenSig.java
Place it in a file called GenSig.java.import java.io.*; import java.security.*; // Gensig.java class GenSig { public static void main(String[] args) { /* Generate a DSA signature */ if (args.length != 1) { System.out.println("Usage: GenSig nameOfFileToSign"); } else try { // the rest of the code goes here } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } } }
Notes:
- The methods for signing data are in the java.security package, so the program imports everything from that package. The program also imports the java.io package, which contains the methods needed to input the file data to be signed.
- A single argument is expected, specifying the data file to be signed.
- The code written in subsequent steps will go between the try and the catch blocks.
Generate Public and Private Keys
In order to be able to create a digital signature, you need a private key. (Its corresponding public key will be needed in order to verify the authenticity of the signature.)
In some cases the key pair (private key and corresponding public key) are already available in files. In that case the program can import and use the private key for signing, as shown in Weaknesses and Alternatives.
In other cases the program needs to generate the key pair. A key pair is generated by using the KeyPairGenerator class.
In this example you will generate a public/private key pair for the Digital Signature Algorithm (DSA). You will generate keys with a 1024-bit length.
Generating a key pair requires several steps:
Create a Key Pair Generator
The first step is to get a key-pair generator object for generating keys for the DSA signature algorithm.
As with all engine classes, the way to get a KeyPairGenerator object for a particular type of algorithm is to call the getInstance static factory method on the KeyPairGenerator class. This method has two forms, both of which hava a String algorithm first argument; one form also has a String provider second argument.
A caller may thus optionally specify the name of a provider, which will guarantee that the implementation of the algorithm requested is from the named provider. The sample code of this lesson always specifies the default SUN provider built into the JDK.
Put the following statement after the
line in the file created in the previous step:else try {KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");Initialize the Key-Pair Generator
The next step is to initialize the key-pair generator. All key-pair generators share the concepts of a keysize and a source of randomness. The KeyPairGenerator class has an initialize method that takes these two types of arguments.
The keysize for a DSA key generator is the key length (in bits), which you will set to 1024.
The source of randomness must be an instance of the SecureRandom class. This example requests one that uses the SHA1PRNG pseudo-random-number generation algorithm, as provided by the built-in SUN provider. The example then passes this SecureRandom instance to the key-pair generator initialization method.
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); keyGen.initialize(1024, random);Note: The SecureRandom implementation attempts to completely randomize the internal state of the generator itself unless the caller follows the call to the getInstance method with a call to the setSeed method. So if you had a specific seed value that you wanted used, you would call the following prior to the initialize call:
random.setSeed(seed);Generate the Pair of Keys keys in PrivateKey and PublicKey objects.
KeyPair pair = keyGen.generateKeyPair(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic();
Sign the Data
Now that you have created a public key and a private key, you are ready to sign the data. In this example you will sign the data contained in a file. GenSig gets the file name from the command line. A digital signature is created (or verified) using an instance of the Signature class.
Signing data, generating a digital signature for that data, is done with the following steps.
Get a Signature Object: The following gets a Signature object for generating or verifying signatures using the DSA algorithm, the same algorithm for which the program generated keys in the previous step:
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");Note: When specifying the signature algorithm name, you should also include the name of the message digest algorithm used by the signature algorithm. SHA1withDSA is a way of specifying the DSA signature algorithm, using the SHA-1 message digest algorithm.
Initialize the Signature Object
Before a Signature object can be used for signing or verifying, it must be initialized. The initialization method for signing requires a private key. Use the private key placed into the PrivateKey object named priv in the previous step.
dsa.initSign(priv);Supply the Signature Object the Data to Be Signed This program will use the data from the file whose name is specified as the first (and only) command line argument. The program will read in the data a buffer at a time and will supply it to the Signature object by calling the update method.
FileInputStream fis = new FileInputStream(args[0]); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while (bufin.available() != 0) { len = bufin.read(buffer); dsa.update(buffer, 0, len); }; bufin.close();Generate the Signature
Once all of the data has been supplied to the Signature object, you can generate the digital signature of that data.
byte[] realSig = dsa.sign();
Save the Signature and the Public Key in Files
Now that you have generated a signature for some data, you need to save the signature bytes in one file and the public key bytes in another so you can send (via modem, floppy, mail, and so on) someone elseThe receiver can verify that the data came from you and was not modified in transit by running the VerSig program, which uses the public key to verify that the signature received is the true signature for the data received.
- the data for which the signature was generated,
- the signature, and
- the public key
Recall that the signature was placed in a byte array named realSig. You can save the signature bytes in a file named sig via the following.
The public key was placed in a PublicKey object named pub. You can get the encoded key bytes by calling the getEncoded method and then store the encoded bytes in a file. You can name the file whatever you want. If, for example, your name is Susan, you might name it something like suepk (for "Sue's public key"), as in the following:/* save the signature in a file */ FileOutputStream sigfos = new FileOutputStream("sig"); sigfos.write(realSig); sigfos.close();/* save the public key in a file */ byte[] key = pub.getEncoded(); FileOutputStream keyfos = new FileOutputStream("suepk"); keyfos.write(key); keyfos.close();
Compile and Run the Program
Here is the complete source code for the GenSig.java program, with some comments added. Compile and run it. Remember, you need to specify the name of a file to be signed, as in
java GenSig dataYou can download and use this sample file named data or any other file you like. The file will not be modified. It will be read so that a signature can be generated for it.
After executing the program, you should see the saved suepk (public key) and sig (signature) files.
Verifying a Digital Signature
If you have data for which a digital signature was generated, you can verify the authenticity of the signature. To do so, you need
- the data
- the signature
- the public key corresponding to the private key used to sign the data
In this example you write a VerSig program to verify the signature generated by the GenSig program. This demonstrates the steps required to verify the authenticity of an alleged signature.
VerSig imports a public key and a signature that is alleged to be the signature of a specified data file and then verifies the authenticity of the signature. The public key, signature, and data file names are specified on the command line.
The steps to create the VerSig sample program to import the files and to verify the signature are the following.
- Create the app
Create a text file named VerSig.java. Type in the initial program structure (import statements, class name, main method, and so on).
- Input and Convert the Encoded Public Key Bytes
Import the encoded public key bytes from the file specified as the first command line argument and convert them to a PublicKey.
- Input the Signature Bytes
Input the signature bytes from the file specified as the second command line argument.
- Verify the Signature
Get a Signature object and initialize it with the public key for verifying the signature. Supply it with the data whose signature is to be verified (from the file specified as the third command line argument), and verify the signature.
- Compile and Run the Program
VerSig.java
import java.io.*; import java.security.*; import java.security.spec.*; class VerSig { public static void main(String[] args) { /* Verify a DSA signature */ if (args.length != 3) { System.out.println("Usage: VerSig publickeyfile signaturefile datafile"); } else try { // the rest of the code goes here } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } } }
Input and Convert the Encoded Public Key Bytes
Next, VerSig needs to import the encoded public key bytes from the file specified as the first command line argument and to convert them to a PublicKey. A PublicKey is needed because that is what the Signature initVerify method requires in order to initialize the Signature object for verification.First, read in the encoded public key bytes.
Now the byte array encKey contains the encoded public key bytes.FileInputStream keyfis = new FileInputStream(args[0]); byte[] encKey = new byte[keyfis.available()]; keyfis.read(encKey); keyfis.close();You can use a KeyFactory class in order to instantiate a DSA public key from its encoding. The KeyFactory class provides conversions between opaque keys (of type Key) and key specifications, which are transparent representations of the underlying key material. With an opaque key you can obtain the algorithm name, format name, and encoded key bytes, but not the key material, which, for example, may consist of the key itself and the algorithm parameters used to calculate the key. (Note that PublicKey, because it extends Key, is itself a Key.)
So, first you need a key specification. You can obtain one via the following, assuming that the key was encoded according to the X.509 standard, which is the case, for example, if the key was generated with the built-in DSA key-pair generator supplied by the SUN provider:
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);Now you need a KeyFactory object to do the conversion. That object must be one that works with DSA keys.
KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN");Finally, you can use the KeyFactory object to generate a PublicKey from the key specification.
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Input the Signature Bytes
Next, input the signature bytes from the file specified as the second command line argument.Now the byte array sigToVerify contains the signature bytes.FileInputStream sigfis = new FileInputStream(args[1]); byte[] sigToVerify = new byte[sigfis.available()]; sigfis.read(sigToVerify); sigfis.close();
Verify the Signature
You've added code to the VerSig program to
You can now proceed to do the verification.
- Input the encoded key bytes and converted them to a PublicKey named pubKey
- Input the signature bytes into a byte array named sigToVerify
Initialize the Signature Object for Verification
As with signature generation, a signature is verified by using an instance of the Signature class. You need to create a Signature object that uses the same signature algorithm as was used to generate the signature. The algorithm used by the GenSig program was the SHA1withDSA algorithm from the SUN provider.
Next, you need to initialize the Signature object. The initialization method for verification requires the public key.Signature sig = Signature.getInstance("SHA1withDSA", "SUN");sig.initVerify(pubKey);Supply the Signature Object With the Data to be Verified You now need to supply the Signature object with the data for which a signature was generated. This data is in the file whose name was specified as the third command line argument. As you did when signing, read in the data one buffer at a time, and supply it to the Signature object by calling the update method.
FileInputStream datafis = new FileInputStream(args[2]); BufferedInputStream bufin = new BufferedInputStream(datafis); byte[] buffer = new byte[1024]; int len; while (bufin.available() != 0) { len = bufin.read(buffer); sig.update(buffer, 0, len); }; bufin.close();Verify the Signature
Once you have supplied all of the data to the Signature object, you can verify the digital signature of that data and report the result. Recall that the alleged signature was read into a byte array called sigToVerify.
boolean verifies = sig.verify(sigToVerify); System.out.println("signature verifies: " + verifies);The verifies value will be true if the alleged signature (sigToVerify) is the actual signature of the specified data file generated by the private key corresponding to the public key pubKey.
Compile and Run the Program
Here is the complete source code for the VerSig.java program, with some comments added.
Compile and run the program. Remember, you need to specify three arguments on the command line:
Since you will be testing the output of the GenSig program, the file names you should use are
- The name of the file containing the encoded public key bytes
- The name of the file containing the signature bytes
- The name of the data file (the one for which the signature was generated)
- suepk
- sig
- data
Here's a sample r