home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

Book Home Java Security Search this book

Appendix B. Identity-Based Key Management

In Java 1.1, the primary tool that was used for key management was javakey, which is based heavily on the Identity and IdentityScope classes. The keytool utility that comes with 1.2[1] is a better way to implement key management, and the KeyStore class on which keytool is based is definitely more flexible than the classes on which javakey is based. In addition, the javakey database uses some classes and interfaces that have been deprecated in 1.2--primarily the java.security.Certificate interface.

[1]1.2 is now Java 2.

Nonetheless, for developers who are still using 1.1, a key management system based upon the Identity and IdentityScope classes is the only possible solution. In this appendix, we'll show how these classes can be used for key management. All of the techniques we'll discuss in this appendix have a complementary technique in key management with the KeyStore class. In addition, the Identity and IdentityScope classes have been deprecated in 1.2, so you should really move to the keystore implementation as soon as possible.

B.1. Identities

You probably noticed in Chapter 10, "Keys and Certificates" that none of the key classes had any notion of whom the key belonged to. Keys are really just an arbitrary-appearing series of bytes. The set of classes we'll examine now deal with the notion of identity: the entity to which a key belongs. An identity can represent an individual or a corporation (or anything else that can possess a public or a private key).

B.1.1. The Identity Class

First we'll look at the primary class used to encapsulate an entity that has a public key, the Identity class (java.security.Identity):

public abstract class Identity implements Principal, Serializable figure

Implement an identity--an entity that has a public key. In 1.1, this class is abstract.

An identity object holds only a public key; private keys are held in a different type of object (the signer object, which we'll look at a little later). Hence, identity objects represent the entities in the world who have sent you their public keys in order for you to verify their identity.

An identity contains five pieces of information:

  • A name--the name of the identity; this satisfies the Principal interface that the identity implements.

  • A public key.

  • An optional information string describing the identity.

  • An optional identity scope. Identities can be aggregated into a collection, which is called an identity scope.

  • A list of certificates that vouch for the identity.

Note that the default implementation of an identity object carries with it no notion of trustworthiness. You're free to add that feature to your own identity class.

B.1.1.1. Using the identity class

If you want to use an identity object, you have the following methods at your disposal:

public final String getName() figure

Return the name of the identity.

public final IdentityScope getScope() figure

Return the identity scope to which the identity belongs.

public PublicKey getPublicKey() figure

Return the public key associated with the identity.

public void setPublicKey(PublicKey key) throws KeyManagementException figure

Set the public key associated with the identity to the given public key. This replaces any previous public key as well as any previous certificates associated with this identity. If the public key is already associated with another identity in the identity scope to which this identity belongs, a KeyManagementException is thrown. The implementation of this method in the base class does not actually check the identity scope to see if the key already exists in another identity; it's up to the concrete subclass to provide this functionality.

public String getInfo() figure

Return the information string associated with the identity.

public void setInfo(String info) figure

Set the information string in the identity, replacing any existing information string.

public void addCertificate(java.security.Certificate certificate) figure

Add the given certificate to the list of certificates in the identity. If the identity has a public key and that public key does not match the public key in the certificate, a KeyManagementException is thrown. If the identity does not have a public key, the public key in the certificate becomes the public key for the identity. Like the setPublicKey() method, this should generate a KeyManagementException if this conflicts with another key in the identity scope, but the implementation in the base class doesn't automatically provide that.

public void removeCertificate(java.security.Certificate certificate) figure

Remove the given certificate from the list of certificates in the identity. If the given certificate isn't in the identity's list of certificates, no exception is thrown.

public java.security.Certificate[] certificates() figure

Return a copy of the array of certificates held in the identity. The array itself is a copy of what is held by the object, but the certificate objects themselves are not.

public final boolean equals(Object id) figure

Test if the given identity is equal to the current object. Identities are considered equal if they are in the same scope and have the same name. Otherwise, they are considered equal if the identityEquals() method returns true. By default, identities in different scopes are considered equal by the identityEquals() method if they have the same name and the same public key.

There are two ways to obtain an identity object--via the getIdentity() method of the IdentityScope class or by implementing and constructing an instance of your own subclass of the Identity class.

B.1.1.2. Implementing an Identity class

An application that wants to work with identities will typically provide its own identity class. A typical implementation of the Identity class is trivial:

Class Definition

public class XYZIdentity extends Identity {
	public XYZIdentity(String name)	throws KeyManagementException {
		super(name);
	}
}

Because all of the methods in the Identity class are fully implemented, our class need only construct itself. Here are the constructors in the Identity class that we have the option of calling:

protected Identity() figure

Construct an unnamed identity. This constructor is not designed to be used directly; it is provided for use by object serialization only.

public Identity(String name) figure

Construct an identity object that does not belong to an identity scope.

public Identity(String name, IdentityScope scope) throws KeyManagementException figure

Construct an identity object that belongs to the given scope. A KeyManagementException is thrown if the given name already exists in the identity scope.

We've chosen in this example only to implement the second of these constructors.

Other than the constructor, we are not required to implement any methods in our class. If you are implementing an identity within an identity scope, there are methods that you'll need to override in order to get the expected semantics.

Our identity class has one other option available to it, and that is the ability to determine when two identities will compare as equal (via the equals() method). The equals() method itself is final, and it will claim that two identities are equal if they exist in the same scope and have the same name. If either of those tests fails, however, the equals() method relies on the following method to check for equality:

protected boolean identityEquals(Identity id)

Test for equality between the given identity and this identity. The default behavior for this method is to return true if the identities have the same name and the same key.

If your identity class has other information, you may want to override this method to take that other information into account.

B.1.1.3. The Identity class and the security manager

The identity class uses the checkSecurityAccess() method of the security manager to prevent many of its operations from being performed by untrusted classes. Table B-1 lists the methods of the Identity class that make this check and the argument they pass to the checkSecurityAccess() method.

Table B-1. Methods in the Identity Class that Call the Security Manager

Method

Argument

Class Definition

setPublicKey()

Class Definition

set.public.key

Class Definition

setInfo()

Class Definition

set.info

Class Definition

addCertificate()

Class Definition

add.certificate

Class Definition

removeCertificate()

Class Definition

remove.certificate

Class Definition

toString()

Class Definition

print

The argument to the checkSecurityAccess() method is constructed from four pieces of information: the name of the class that is providing the implementation of the identity class, the string listed in the table above, the name of the particular identity in question (that is, the string returned by the getName() method), and the name of the class that implements the identity scope to which the identity belongs (if any).

In common implementations of the security manager, this string is ignored and trusted classes are typically able to work with identities, while untrusted classes are not.

B.1.2. Signers

An identity has a public key, which can be used to verify the digital signature of something signed by the identity. In order to create a digital signature, we need a private key. An identity that carries with it a private key is modeled by the Signer class (java.security.Signer):

public abstract class Signer extends Identity figure

A class to model an entity that has both a public key and a private key. Since this is a subclass of the Identity class, the public key comes from the implementation of that class, and a signer class needs only to be concerned with the private key.

The Signer class is fully implemented even though it is declared as abstract; an implementation of the Signer class need not implement any methods.

B.1.2.1. Using the Signer class

A signer is used just like an identity, with these additional methods:

public PrivateKey getPrivateKey() figure

Return the private key of the signer.

public final void setKeyPair(KeyPair pair) figure

Set both the public and private key of the signer. Since public and private keys must match in order to be used, this class requires that in order to set the private key, the public key must be set at the same time. If only one key is present in the key pair, an InvalidParameterException is thrown. The act of setting the public key might generate a KeyManagementException (a subclass of KeyException, which this method throws).

Except for these two operations, a signer is identical to an identity.

B.1.2.2. Implementing a signer

Signers are trivial to implement, given that none of their methods are abstract. Hence, it is simply a matter of calling the appropriate constructor:

Class Definition

public class XYZSigner extends Signer {
	public XYZSigner(String name) throws KeyManagementException {
		super(name);
	}
}

Note an unfortunate problem here: if you've added additional logic to your identity subclass, your signer subclass cannot use that logic. Your own signer subclass must extend Java's Signer class, not your own identity subclass.

B.1.2.3. Signers and the security manager

In addition to the security checks that will be made as part of the methods of the Identity class, the signer class calls the checkSecurityAccess() method of the security manager in the following cases with the strings in Table B-2.

Table B-2. Methods of the Signer Class That Call the Security Manager

Method

Parameter

Class Definition

getPrivateKey()

Class Definition

get.private.key

Class Definition

setKeyPair()

Class Definition

set.private.keypair

As with the Identity class, the actual string passed to the security manager is preceded with the name of the class, and the name of the identity is appended to the class along with the name of the identity's scope.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.







??????????????@Mail.ru