The security-related enhancements and changes available in JDK1.1 are the following:
A new JavaSecurity API. See an overview and the beta documentation. This API includes:
- a powerful and flexible provider-based architecture.
- digital signatures to authenticate classes, images, sounds, and other types of data.
- message digests.
- key and certificate management (including an implementation of X.509v1 certificates).
- access control and permissions.
A new javakey (for Solaris) (for Windows) tool for
- managing a database of entities (people, companies, etc.), their public and private keys and certificates, and an indication as to which entities are "trusted".
- generating digital signatures for Java ARchive (JAR) files.
Changes to previously-existing security features. These changes, such as those listed below, will be documented in the Java Security FAQ available from our public Web site:
- Java Security Manager enhancements. This now includes
- support for digital signatures to authenticate classes, images, sounds and other types of data. The client (e.g., end user or system administrator) can use the javakey tool to declare certain entities to be trusted. The Security Manager utilized by the Applet Viewer allows any downloaded applets signed by a trusted entity to run with the same full rights as local applications. That is, such applets are not subject to the "sandbox" restrictions of the original Java security model. Later releases of JDK1.1 will provide greater granularity in the allowable trust levels.
- a new check to make sure that the Reflection API doesn't open any holes in the sandbox model.
- a number of sandbox model bug fixes.
- a number of new features in JDK 1.1 that potentially affect the sandbox model.
The JavaSecurity API is a new Java Core API, built around the
java.security package. JavaSecurity is designed to let developers
incorporate both low-level and high-level security functionality into
their Java applications. This includes digital signatures, data
encryption, key management, and access control.
The first release of JavaSecurity, available in JDK 1.1, contains a subset of this functionality, including APIs for:
JDK 1.1 also has facilities to sign and verify Java ARchives (JAR), which contain arbitrary data, including class files, images, sounds, etc. The JDK 1.1 Security Manager used, for example, by the Java Applet Viewer, is aware of these signatures, and, working in conjunction with the javakey tool, will grant special privileges to signed and trusted code. See JAR Files and Digital Signatures for more information.
Subsequent releases of JavaSecurity will include APIs for data encryption and key exchange as well as more sophisticated security policies. The encryption API will be an API for block, stream, symmetric, and asymmetric encryption, with support for multiple modes of operation and multiple encryption.
JavaSecurity is essentially an abstract layer, and introduces the notion of a Security Package Provider (SPP). An SPP is a package (or set of packages) providing a concrete implementation of a subset of JavaSecurity. JDK 1.1 comes standard with a default provider, the Sun Security Provider.
SPPs are explicitly installed in a Java environment, and configured according to the user's preferences. This is to allow end users of Java runtimes to be able to select the implementations of their choice for critical algorithms, if they so desire.
In JDK 1.1, high-level provider configuration
information appears in the java.security file. Registration
of an SPP can be done by specifying (in java.security) the Provider
subclass whose constructor sets the values of various properties that are
required for the JavaSecurity API to look up the algorithms or other
facilities implemented by the SPP. An SPP can also be registered
dynamically, via a call to the Security addProvider or
insertProviderAt method.
The Sun Security Provider
In JDK 1.1, there is one default provider, called Sun Security.
The sun.security.provider package includes:
Note: The sun.security.provider classes should
never be
accessed directly. They will be instantiated and used by the JavaSecurity
API if "SUN" is the requested service provider, or if no other service
provider is specified, since they provide the default implementation.
Applications should always call the JavaSecurity API
(java.security) interfaces.
Implementations of various classes that are useful when using
java.security are available in other sun.security
subpackages. This includes:
Unlike the JavaSecurity is built around several important
design principles:sun.security.provider package, the classes in the
other sun.security subpackages can be accessed directly.
Architecture and Design
Certain types of data relevant to JavaSecurity, such as
certificates, are often encoded in a variety of formats. In the case
of certificates, JavaSecurity defines a certificate interface, and a
mechanism to dynamically specify which classes to use to parse
certificates. In sun.security we include an X.509
certificate. Another provider may add a PGP or SDSI certificate parser.
The same mechanism is true of keys and of algorithms. That is, JavaSecurity defines an interface for each of these, and a mechanism to dynamically specify which classes to actually use for them.
X.509 and
PKCS#8.
The JavaSecurity API documentation for the JDK1.1 beta release appears in the following, in javadoc format:
If you develop Java applications and Java applets, you may want to use the Java code-signing features. Two sample reasons for using code-signing features are the following:
In order to be able to sign code, a developer must first take two basic steps:
After obtaining a private key and a certificate, an application may sign code
using them.
One new feature of JDK 1.1 is the introduction of Java ARchives
(or JAR files), which enable the packaging of class files, images, sounds,
and other digital data in a single file for faster and easier distribution.
A JAR file is an archive of files. JAR is defined to be ZIP+manifest, where
ZIP is the standard archiving format. JAR includes a manifest file, which
stores meta-information about the contents of the archive. The manifest is
an ASCII file, defined by the manifest spec.
A tool included with
JDK 1.1 allows developers to generate JAR files. This tool is called
jar. (See
Windows for the Windows
version.)
Another addition to JDK 1.1 is a tool to manage identities, to
generate and manage keys and certificates, and to sign and verify
JAR files. The tool,
javakey is a simple command-line driven
utility which uses a persistent database. (See Windows
for the Windows version.)
Signers are real-world entities which can both be authenticated and
can produce signatures. Thus signers have both a public key (for
authentication) and a
private key (for signing) associated with them. To create a signer involves
generating (or otherwise associating) a public/private key pair with a name,
and possibly associating a set of certificates with the public key.
We expect Java licensees to honor signatures generated using
javakey.
JAR Files and Digital Signatures
Digital Signatures for the Java
Platform
The Sun Security Provider for JavaSecurity is the default provider included in JDK 1.1. It implements the following classes:
javakey utility to sign and verify files, and to
manage trust.
The basic mechanism for obtaining an appropriate Signature object
is as follows: A user requests a Signature object by calling the
getSignature method in the Signature class, specifying a
signature algorithm (such as "DSA"), and, optionally, a provider. The
getSignature method finds a Signature subclass
that fits the algorithm and provider parameters supplied. If no
provider is specified, getSignature searches the
registered providers, in preference order, for one with a Signature
subclass implementing the specified algorithm. The provider preference
order is set in the java.security file (and possibly
modified when new providers are added dynamically). See configuration information.
The Key, Identity and IdentityScope classes are used for key, certificate, and trust management. Identities are reflections of real-world entities, such as persons, companies and organizations. They have keys, certificates, and trust levels (permissions) associated with them. There is a system IdentityDatabase, which holds system identities.
import java.security.Signature;
import java.security.NoSuchAlgorithmException;
public class SignFile {
Signature signature;
private void init(String algorithm)
throws NoSuchAlgorithmException{
signature = Signature.getSignature(algorithm);
}
}
generateKeyPair method on Signature. Let
us assume that we just obtained a DSA (Digital Signature Algorithm)
signature object, and that we would like to generate 1024-bit keys.
First, we must initialize the signature object for generation
of keys of 1024 bits:
signature.initGenerateKeyPair(1024);
Then we can generate the keys:
// seed is a byte array with some random bits from, say, the user.
// we use the random seed to generate the keys.
KeyPair kp = signature.generateKeyPair(seed);
The kp object now contains two keys: a public key and
the associated private key.
java.security classes can. As with key generation,
the Signature object must be initialized for signing before the
signing is actually done:
// initializing the signature object for signing signature.initSign(kp.getPrivate());This will initialize the signature with the private key. Signing is done on a set of bytes. The signing interface is stream-oriented, letting you specify what bytes are to be signed through the update method. There are two types of
update methods, one which works on byte arrays and one which
works on a single byte at a time. Here is an example of the use
of the latter, followed by a call to sign to
calculate and return the signature of all the data:
// signature is an initialized signature object
// fileToSign has the name of the file containing the data bytes
File file = new File(fileToSign);
FileInputStream fis = new FileInputStream(file);
while (fis.available() != 0) {
signature.update(fis.read());
}
byte[] realSignature = signature.sign();
Now suppose that we want to verify whether or not an
alleged signature is in fact the authentic signature of the data
associated with it.
In order to verify the signature, we must first initialize a
signature object for verification. To do so, we call
initVerify with the public key for the
identity whose signature is going to be verified. Assuming that
kp is the key pair for the identity,
kp.getPublicKey() is the public key:
// initialize the signature with the public key for verification
signature.initVerify(kp.getPublicKey());
Then we must read in the bytes of data associated with the alleged signature:
// fileToVerify has the name of the file containing the data bytes
File file = new File(fileToVerify);
FileInputStream fis = new FileInputStream(file);
while (fis.available() != 0) {
signature.update(fis.read());
}
Finally, we verify the authenticity of the alleged signature:
if (signature.verify(allegedSignature)) {
System.out.println("Signature checks out");
} else {
System.out.println("Signature does not check out.");
}