Putting the Java cryptography architecture to work
Snezana is a researcher at Belgrade's Institute Mihailo Pupin and can be contacted at [email protected]. Zoran is director of the Belgrade University Computing Center.
Most systems use passwords as a verification of claimed identity. However, conventional passwords have disadvantages. For one thing, they can easily be shared among users or become easy targets for eavesdropping. Another way for proving identity is by the use of digital certificates, also known as "digital IDs." The most widely accepted format for digital certificates is defined by the ITU-T X.509 International Standard, enabling certificates to be read or written by any application complying with X.509. In short, X.509 is a Standard that makes it possible to identify someone on the Internet.
Authentication methods specified on X.509 are based upon public-key cryptosystems. For users to trust the authentication procedure, the procedure needs to get the other user's public key from a source that it trusts. The source, called a "certification authority" (CA), uses the public-key algorithm to certify the public key, producing a certificate. Because certificates are unforgeable, they can be published by being placed in the Directory, without the need for the latter to make special efforts to protect them.
As shown in Listing One(a), in addition to the public key of the certificate owner, digital certificates contain the following:
- Serial number of the certificate.
- Digital signature of the issuer.
- Owner's name.
- Expiration date of the public key.
- Name of the issuer (the CA that issued the Digital ID).
- Extensions that provide some additional information.
Digital certificates are signed with the CA's private key. The protocol used by applications to obtain the certificate from the Directory is the Directory Access Protocol (DAP), specified in ITU-T Recommendation X.519.
Standards-compliant applications that use the authentication framework need to specify the protocol exchanges that must be performed to achieve authentication based upon the authentication information obtained from the Directory. In this article, we present an application based on the authentication protocol given in the Comité Européen de Normalisation (CEN) Standard for medical information systemsCEN ENV 13729 "Health InformaticsSecure User Identification: Strong Authentication Using Microprocessor Cards" (see Figure 1). In this protocol, a reply attack (sending of old messages) is prevented by the entity that requires authentication through sending a generated random number on which the entity that proves identity creates a digital signature. X.509 supports one-way authentication, where only one party proves identity, and two-way authentication, which is mutual identification. The Standard also describes three-way authentication, which involves one additional data transfer. In our application, one-way authentication is applied (two-way could be applied analogously).
We use Java Crypto API for the realization of authentication in a distributed system, where clients access servers in the system via a central server. All certificates are generated centrally on demand and imported in a central repositorythe keystore. Certificates are signed with the "CA" key; that is, a private key that belongs to a central server. Certificates and private key files are sent to clients before authentication begins. Clients import certificates and private keys into a local keystore using the AppletImportCertificates applet (available electronically; see "Resource Center," page 5). This application has been tested using Tomcat 4.1 and Netscape 6 with a Java 1.3.0_1 plugin. Before running the application, a read/write permissions must be added to the java.policy file on directory javaPlugIn_home/java/lib/security.
The application comprises several applets and one servlet:
- AppletGenerateCAKeys, which generates a private key for creating a digital signature on all certificates in the system.
- AppletGenerateCertificates, which generates a certificate for a user whose name is in X500 format and places it in a keystore with a given alias and password. It also generates the files "certFile" + X500Name and "privKey" + X500 Name, which are sent to a client offline (Figure 2).
- AppletImportCertificate, which creates the .keystore file on the client side and imports the obtained certificate and private key (Figure 3).
- AppletLogin, which sends an access request and generates a digital signature on RND using a local keystore (Figure 4).
- LoginServlet, which sends RND and verifies the signature using the keystore.
In our application, access control is achieved using certificate extensions that contain a ROLE belonging to a certificate owner. Each extension is identified by an Object Identifier, which, according to ASN.1, is a string of integer values assigned by the Registration Authority; see Listing One(b).
Java Cryptography Architecture
The first version of Java Crypto Architecture (JCA), contained in JDK1.1, included an API for a digital signature and message digest. Version 1.2 was the first to include an infrastructure supporting X.509 v3 certificates.
JCA is a provider-based framework that provides a particular functionality (Message Digest, Digital Signing) and is independent of algorithms, and there exist providers that implement algorithms.
The infrastructure supporting X.509 certificates involves these services:
- Key management (introduced in JDK1.1).
- Generation and verification of digital signature (introduced in JDK1.1).
- Keystore management (introduced in JDK1.2).
Keys in JCA can have a "transparent" or an "opaque" representation. The opaque representation has three characteristics: an algorithm, coded form, and format. The most important attribute of the opaque representation is its coded form that permits, when necessary, the keys to be used out of JVM; for example, when the keys are sent to some other party. Contrary to this, the most important characteristic of the transparent representation is the possibility of access to single parts of a key. In our application, we have used the opaque representation of keys only.
The algorithm in the opaque representation of a key denotes an algorithm (such as DSA and RSA) in which a given key is used together with the hash function algorithm (for example, MD5withRSA or SHA1withRSA).
A format is the format in which keys are coded (X.509 for a public key and PKCS#8 for a private key, for example). The name of ASN.1 data type for a public key is SubjectPublicKeyInfo, and this data type is defined in the X.509 Standard. The SubjectPublicKeyInfo is defined in the X.509 Standard in ASN.1 terms, as in Listing Two.
Similar to this, the ASN.1 data type that represents private keys is named "PrivateKeyInfo" and defined in the PKCS#8 Standard. PKCS#8 denotes a Standard whose full name is "Private Key Information Syntax Standard" (see http://www.rsa.com/). In Listing Three, Attribute is a data type consisting of an attribute type (given as an OBJECT IDENTIFIER) and one or more values. Certificates are generated by creating first the class X509CertInfo and then all the attributes of a certificate; see Listing Four. After that, a CA private key is used to create a digital signature on a certificate.
The keystore database can be used to manage the repository of keys and certificates. Several different actual implementations may exist, each of them being characterized by a particular type. At present, there also exists keytool, a keystore management tool that is started from the command line. There is also a built-in default implementation provided by Sun. According to this implementation, a keystore is a file of JKS format. In Sun's implementation, passwords are used to protect each private key as well as the entire keystore.
Keystore type determines the format of information contained in the keystore as well as the algorithms used for protecting private keys and the keystore itself. Different keystore implementations are not compatible. "JKS," a default keystore type (implemented by Sun), is specified in the line keystore.type=jks, from the file java_home/jre/lib/java.security. If some other keystore implementation is used, the type of that implementation ("pkcs12," for instance) should be entered into this file.
A KeyStore class represents a collection of keys and certificates. There are two types of entry:
- Key Entry contains sensitive information. Keys are stored in a protected format to prevent unauthorized access. Typically, a key stored in this entry is a private key or a private key with a chain of certificates corresponding to a public key. Private keys and the string of certificates associated to them are used for the authentication of the entity to which the keystore also belongs.
- Trusted Certificate Entry contains the certificate of a public key that belongs to some other entity. It is referred to as a trusted certificate because the keystore owner trusts that the public key in the certificate really belongs to the identity presenting itself as the certificate owner. This type of entry performs the authentication of other parties.
Each entry in the keystore is identified by an "alias" string. In case of a private key and an associated chain of certificates, the alias distinguishes between the different methods an identity can use for authentication purposes. For example, an entity may authenticate itself using various CA. Listings Five(a) and Five(b) illustrate the JKS data format
Conclusion
The Java Cryptography Architecture 1.2 and later support X.509 certificates. A DSA algorithm with 1024-bit key length is implemented in a default provider. Moreover, Java supports keystore, an in-memory collection of keys and certificates (http://java.sun.com/j2se/1.4.2/docs/api/java/ security/KeyStore.html). In this article, we've implemented X.509 authentication according to the CEN ENV 13729 Standard. Although authentication protocols appear simple, the choice of a protocol is important, because protocol steps may interfere with some auxiliary relations satisfied by symmetric or asymmetric cryptosystems.
DDJ
Certificate ::= SIGNED {SEQUENCE{ version [0] Version DEFAULT v1, serialNumber CertificateSerialNumber, signature AlgorithmIdentifier, issuer Name, validity Validity, subject name, subjectPublicKeyInfo SubjectPublicKeyInfo, issuerUniqueIdentifier [1] IMPLICIT UniqueIdentifier OPTIONAL, subjectUniqueIdentifier [2] IMPLICIT UniqueIdentifier OPTIONAL, extensions [3] Extensions OPTIONAL }} Validity ::= SEQUENCE { notBefore Time, notAfter Time }(b)
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension Extension ::= SEQUENCE { extnId OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING -- DER coded value }Back to article
Listing Two
SubjectPublicKeyInfo ::= SEQUENCE { Algorithm AlgorithmIdentifier, SubjectPublicKey BIT STRING } AlgorithmIdentifier : := SEQUENCE { Algorithm OBJECT IDENTIFIER, Parameters ANY DEFINED BY algorithm OPTIONAL }Back to article
Listing Three
PrivateKeyInfo ::= SEQUENCE { Version Version, PrivateKeyAlgorithm PrivateAlgorithmIdentifier, PrivateKey PrivateKey, Attributes [0] IMPLICIT Attributes OPTIONAL } Version ::= INTEGER PrivateKeyAlgorithm ::= AlgorithmIdentifier PrivateKey ::= OCTET STRING Attributes ::= SET OF AttributeBack to article
Listing Four
X509CertInfo certinfo = new X509CertInfo(); CertificateVersion cv = new CertificateVersion(CertificateVersion.V3); ... etc certinfo.set(certinfo.VERSION,cv); ... etc X509CertImpl cert = new X509CertImpl(certinfo);Back to article
Listing Five (a)
Magic number (big-endian integer), Version of this file format (big-endian integer), Count (big-endian integer), followed by "count" instances of either: { tag=1 (big-endian integer), alias (UTF string) timestamp encrypted private-key info according to PKCS #8 (integer length followed by encoding) cert chain (integer count, then certs; for each cert, integer length followed by encoding) }(b)
{ tag=2 (big-endian integer) alias (UTF string) timestamp cert (integer length followed by encoding) } ended by a keyed SHA1 hash (bytes only) of { password + whitener + preceding body }Back to article