The Security class (java.security.Security) is responsible for managing the set of provider classes that a Java program can use, and forms the last link in the architecture of the security provider. This class is final, and all its methods are static (except for its constructor, which is private). Like the System and Math classes, then, the Security class can never be created or subclassed; it exists simply to provide a placeholder for methods that deal with the java.security package.
Earlier, we explained how to add entries to the java.security file to add new providers to the security architecture. The same feat can be accomplished programmatically via these methods of the Security class:
Add a new provider into the list of providers. The provider is added to the end of the internal array of providers.
Add a new provider into the internal array of providers. The provider is added at the specified position; other providers have their index changed if necessary to make room for this provider. Position counting begins at 1.
The notion that these classes are kept in an indexed array is important; when the Security class is asked to provide a particular algorithm for an operation, the array is searched sequentially for a provider that can provide the requested algorithm for the requested operation.
As an example, let's use a modification of the XYZProvider class that we outlined earlier. This class comes with a set of classes to perform generation of key pairs, and it can generate key pairs according to two algorithms: DSA and XYZ. The XYZProvider class, according to an entry added to the java.security file, has been added at position 2. Additionally, let's say that our Java program has installed an additional provider class at position 3 called the FooProvider that can generate key pairs and digital signatures according to a single algorithm known as Foo. This leaves us with the set of provider classes listed in Table 8-3.
Sun Provider |
XYZ Provider |
Foo Provider |
---|---|---|
Class DefinitionSignature Engines DSA |
Class DefinitionSignature Engines XYZ DSA |
Class DefinitionSignature Engines Foo |
Class DefinitionMessage Digest Engines MD5 |
Class DefinitionMessage Digest Engines XYZ SHA |
Class DefinitionMessage Digest Engines None |
Class DefinitionKey Pair Engines DSA |
Class DefinitionKey Pair Engines XYZ DSA |
Class DefinitionKey Pair Engines Foo |
Now when our Java program needs to generate a key pair, the security provider is consulted as to which classes will implement the key pair generation we want. If we need to generate a DSA key, the security provider returns to us a class associated with the Sun provider class, since the Sun provider, at position 1, is the first class that says that it can perform DSA key generation. If we had reversed the order of indices in the java.security file so that the Sun provider was at position 2 and the XYZ provider was at position 1, a class associated with the XYZ provider would have been returned instead. Similarly, when we request a Foo key pair, a class associated with the Foo provider is returned to us, regardless of what index it occurs at, since that is the only provider class that knows how to perform Foo key generation.
Remember that this is a two-step process. The security class receives a string (like KeyPairGenerator.DSA) and locates a class that provides that service (such as sun.security.provider.Sun). The Sun class, as a provider class, does not actually know how to generate keys (or do anything else)--it only knows what classes in the Sun security package know how to generate keys. Then the security class must ask the provider itself for the name of the class that actually implements the desired operation. That process is handled by an internal method of the Security class--we'll use that method implicitly over the next few chapters when we retrieve objects that implement a particular engine and algorithm. Before we do that, though, we'll finish looking at the interface of the Security class.
There are a number of other methods in the Security class that provide basic information about the configuration of the security provider.
Remove the named provider from the list of provider classes. The remaining providers move up in the array of providers if necessary. If the named provider is not in the list, this method silently returns (i.e., no exception is thrown).
Return a copy of the array of providers on which the Security class operates. Note that this is a copy of the array; reordering its elements has no effect on the Security class.
Return the provider with the given name. If the named provider is not in the list held by the Security class, this method returns null.
Get the property of the Security class with the associated key. The properties held in the Security class are the properties that were read from the java.security file. In typical usage, one of the properties is security.provider.1 (as well as any other providers listed in the java.security file). Note, however, that properties of this sort may not reflect the actual order of the provider classes: when the addProvider(), insertProviderAt(), and removeProvider() methods are called, the order of the providers changes. These changes are not reflected in the internal property list.
The java.security file has a number of other properties within it; these other properties may also be retrieved via this method.
Set the property of the security class with the associated key.
Search all the providers for a property in the form Alg.propName.algName and return the first match it finds. For example, if a provider had set the Alg.NativeImplementation.XYZ property to the string "false," a call to getAlgorithmName("XYZ","NativeImplementation") returns the string "false" (which is why earlier we used a string value in the provider class).
Here's a simple example, then, of how to see a list of all the security providers in a particular virtual machine:
public class ExamineSecurity { public static void main(String args[]) { try { Provider p[] = Security.getProviders(); for (int i = 0; i < p.length; i++) { System.out.println(p[i]); for (Enumeration e = p[i].keys(); e.hasMoreElements();) System.out.println("\t" + e.nextElement()); } } catch (Exception e) { System.out.println(e); } } }
If we run this program with the 1.2 Sun security provider, we get this output:
SUN version 1.2 Alg.Alias.MessageDigest.SHA Alg.Alias.Signature.SHAwithDSA Alg.Alias.Signature.1.3.14.3.2.13 Alg.Alias.Signature.OID.1.2.840.10040.4.3 Alg.Alias.Signature.SHA-1/DSA Alg.Alias.Signature.DSS Alg.Alias.Signature.SHA1withDSA Alg.Alias.Signature.OID.1.3.14.3.2.13 AlgorithmParameters.DSA KeyFactory.DSA Alg.Alias.Signature.1.2.840.10040.4.3 Alg.Alias.MessageDigest.SHA1 AlgorithmParameterGenerator.DSA Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1 MessageDigest.MD5 Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1 MessageDigest.SHA-1 Alg.Alias.KeyPairGenerator.OID.1.3.14.3.2.12 Signature.DSA Alg.Alias.KeyPairGenerator.1.3.14.3.2.12 Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1 Alg.Alias.Signature.1.3.14.3.2.27 Alg.Alias.Signature.SHA/DSA KeyPairGenerator.DSA Alg.Alias.Signature.SHA1/DSA Alg.Alias.Signature.OID.1.3.14.3.2.27 Alg.Alias.AlgorithmParameters.1.3.14.3.2.12 KeyStore.JKS CertificateFactory.X509 Alg.Alias.CertificateFactory.X.509 SecureRandom.SHA1PRNG
Two things are readily apparent from this example. First, the strings that contain only an engine name and an algorithm implement the expected operations that we listed in Table 8-1. Second, as we mentioned in the section on the Provider class, security providers often leverage the fact that the Provider class is a subclass of the Properties class to provide properties that may make sense only to other classes that are part of the provider package. Hence, the signature algorithm 1.3.14.3.2.13 may make sense to one of the classes in the Sun security provider, but it is not a string that will necessarily make sense to other developers. In fact, those aliases--including the ones that are prefaced by OID--do have meanings within the cryptography standards world, but for our purposes we'll stick with the standard algorithm names that we listed earlier.
All the public methods of the Security class call the checkSecurityAccess() method of the security manager. This gives the security manager the opportunity to intervene before an untrusted class affects the security policy of the virtual machine.
Recall that the checkSecurityAccess() method accepts a single string parameter. In the case of the methods in the Security class, the call that is made looks like this:
public static Provider getProvider(String name) { SecurityManager sec = System.getSecurityManager(); if (sec != null) sec.checkSecurityAccess("java"); ... continue to find the provider ... }
The string parameter that is sent to the checkSecurityAccess() method has changed between releases of Java; the various methods and the strings they pass to the security manager are listed in Table 8-4.
Method |
1.2 Parameter |
1.1 Parameter |
---|---|---|
Class DefinitioninsertProviderAt() |
Class DefinitioninsertProvider. + provider.getName() |
Class Definitionjava |
Class DefinitionremoveProvider() |
Class DefinitionremoveProvider. + provider.getName() |
Class Definitionjava |
Class DefinitiongetProviders() |
-- not called -- |
Class Definitionjava |
Class DefinitiongetProvider() |
-- not called -- |
Class Definitionjava |
Class DefinitiongetProperty() |
Class DefinitiongetProperty. + key |
Class Definitionjava |
Class DefinitionsetProperty() |
Class DefinitionsetProperty. + key |
Class Definitionjava |
In typical usage in 1.1, the security manager ignores this string altogether and simply allows all trusted classes to call these methods and prevents all untrusted classes from calling these methods. In 1.2, the security manager constructs a security permission for the given name and calls the access controller to see if the given permission has been granted.
Copyright © 2001 O'Reilly & Associates. All rights reserved.