JavaSecurity Overview and Reference

Security in JDK 1.1

The JavaSecurity API and Digital Signatures


Draft 1.2 -- Last updated January 10, 1997


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 new javakey (for Solaris) (for Windows) tool for
  • 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:

  • JavaSecurity: the Java Security API

    Introduction

    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:

    Digital Signatures
    Digital signature algorithms, such as DSA or MD5 with RSA. The functionality includes generating public/private key pairs as well as signing and verifying arbitrary digital data.

    Message Digests
    Cryptographically secure message digests, such as MD2, MD5, or SHA. These algorithms, also called one-way hash algorithms, are useful as "digital fingerprints" of documents and are frequently used in digital signatures, and other applications that need unique identifiers for digital data.

    Key Management
    A set of abstractions for managing principals (entities such as individual users or groups), their keys, and their certificates. It allows applications to design their own key management system, and to interoperate with other systems at a high level.

    Access Control Lists
    A set of abstractions for managing principals and their access permissions. A high-level overview is available. This facility will be expanded in subsequent releases.
    JDK 1.1 includes a command-line utility for managing keys and certificates and for digitally signing files. See the javakey reference page for Solaris or the javakey reference page for Windows for more information.

    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.

    Security Package Providers

    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 sun.security.provider package, the classes in the other sun.security subpackages can be accessed directly.

    Architecture and Design

    JavaSecurity is built around several important design principles:

    Implementation and Format Independence
    JavaSecurity provides interfaces to various algorithms, such as DSA, MD5, and SHA. It does this while making it possible for applications to request an algorithm without regard to implementation details. For example, JDK 1.1 includes the Sun Security Provider, which implements DSA entirely in Java. Another implementation could be done in hardware, or written in another language, transparent to the application.

    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.

    Interoperability Across Implementations
    This feature is a byproduct of JavaSecurity's implementation independence. A simple example of this is that keys generated by any implementation of a given algorithm (within common parameter bounds, if applicable) should work with any other similar implementation. To achieve this, JavaSecurity defines standard encoding rules, based on existing international standards such as X.509 and PKCS#8.

    Implementation-Specific Security
    JavaSecurity takes advantage of Java's type system to allow its implementations to design their own security policies while adhering to a set of common semantics.

    JavaSecurity API Documentation

    The JavaSecurity API documentation for the JDK1.1 beta release appears in the following, in javadoc format:


    Code Signing in Java

    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:

    The JDK 1.1 Security Manager (used, for example, by the Java Applet Viewer, is aware of signatures, and, working in conjunction with the javakey tool (which is used to sign code and specify who is trusted), will grant special privileges to signed and trusted applet code.

    In order to be able to sign code, a developer must first take two basic steps:

    1. Generate a private/public key pair, and
    2. Obtain a certificate attesting to the authenticity of the public key (so parties verifying your signature using your public key are confident that the public key they are provided is authentic).

    After obtaining a private key and a certificate, an application may sign code using them.

    JAR Files and Digital Signatures

    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.)

    Managing Identities, Keys and Certificates

    This involves associating identity names with keys, and keys with certificates, as well as associating names and trust levels.

    Creating, adding, and removing identities and signers.

    Identities are real-world entities that can be authenticated using a public key that is associated with them. To create an identity means to associate a name with one or more certificates (all of which are for the same public key).

    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.

    Associating trust with certain identities.

    In JDK 1.1, certain identities will be declared by the client (such as the end user or system administrator) to be trusted. This will mean that code signed by trusted identities will have system code status. In later releases, we will provide greater granularity in the trust levels that we allow.

    Signing JAR files

    This involves generating a signature for a given Signer and including that signature in a given JAR file. A Signed JAR file includes at least one signature file, in addition to the manifest file. There is one signature file per signer.

    We expect Java licensees to honor signatures generated using javakey.


    Digital Signatures for the Java Platform

    Digital Signature API

    JavaSecurity provides a digital signature API (Application Programming Interface) and SPI (Service Provider Interface). The API classes for digital signatures are called the "Digital Signature Classes", and consist of:
    Signature
    Defines the API as well as the SPI to signature functionality.
    Provider
    Represents an implementor of JavaSecurity, which may provide digital signature or message digest implementations, as well as its own key management classes.
    Security
    Manages providers, and centralizes all security properties and common security methods.
    Key
    A generic key, such as a DSA public or private key.
    PublicKey
    A Key subclass for public keys.
    PrivateKey
    A Key subclass for private keys.
    DSAKey
    An interface to a DSA public or private key.
    DSAPublicKey
    An interface to a DSA public key. This interface extends the DSAKey interface.
    KeyPair
    A simple holder for a key pair (a public key and a private key).
    KeyParams
    An interface to algorithm-specific key parameters.
    DSAParams
    An interface for DSA-specific key parameters. This interface extends the KeyParams interface.
    Certificate
    An interface of abstract methods for managing an identity certificate. An identity certificate is a guarantee by a principal that a public key is that of another principal. (A principal represents an entity such as an individual user or a group.)
    Identity
    An object representing a real-world object such as a person, company, or organization that can be authenticated using a public key.
    Signer
    An Identity that can also sign code.
    IdentityScope
    A scope for identities, containing unique (withing the scope) Identity objects of all kinds, including Signers.

    The Sun Security Provider for JavaSecurity is the default provider included in JDK 1.1. It implements the following classes:

    DSA
    An implementation of the Digital Signature Algorithm (NIST fips 186).
    DSAPublicKey
    A public key for DSA.
    DSAPrivateKey
    A private key for DSA.
    MD5
    An implementation of the MD5 message digest algorithm.
    SHA
    An implementation of the Secure Hash Algorithm (SHA) message digest algorithm (NIST fip 180 as superseded by fip 180-1).
    SystemIdentity
    A basic implementation of Identity.
    SystemSigner
    A basic implementation of Signer.
    IdentityDatabase
    A basic implementation of IdentityScope.
    Main
    The javakey utility to sign and verify files, and to manage trust.
    X509Key
    A public key encoded using the X.509/DER rules.
    X509Cert
    A certificate encoded using the X.509/DER rules.

    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.

    Application Programming Interface - Example

    Overview

    The JavaSecurity API gives developers the ability to generate and verify digital signatures. Digital signatures are used to guarantee the origin and integrity of digital data. The Digital Signature classes share two of the fundamental designs in the JavaSecurity API: implementation independence and flexible key management. Implementation independence means that a developer can request a particular algorithm and the system will return a suitable implementation. Key management flexibility means that keys can be handled either by the system, or by the application, as appropriate.

    Obtaining a Signature Object

    The Signature class is the developer's interface to all signature functionality for a given algorithm. It can sign, verify a signature, or generate keys for that algorithm. There are two ways to request a Signature object: either by specifying the algorithm desired, or by specifying the algorithm and a provider for that algorithm. (See Algorithm Names for information about algorithm names.) Here is an example of requesting a particular algorithm:
    
    import java.security.Signature;
    import java.security.NoSuchAlgorithmException;
    
    public class SignFile {
        Signature signature;
    
        private void init(String algorithm) 
        throws NoSuchAlgorithmException{
            signature = Signature.getSignature(algorithm);
        }
    }
    
    

    Generating Keys

    Keys required for signing digital data can be generated through the 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.

    Signing Digital Data

    We now have a DSA key pair, and a signature object. A future version of this document will show how to get a key pair for a given identity. Note that the application developer cannot get access to the private key object -- only 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();
    
    

    Verifying a Signature

    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.");
    	}
    

    Please send feedback to java-security@java.sun.com