Using Digital Signatures and Certificates in Java
Java Cryptography Architecture
For the purposes of digital signing of documents, verification of digital signatures, and handling digital certificates in the Java platform, the Java Cryptography Architecture (JCA) is used. JCA is a specification that gives the programmers a standard way to access cryptographic services, digital signatures, and digital certificates.
From an architectural point of view, JCA is designed to allow different implementations of various services from different software vendors. Such implementations of cryptographic services are called cryptographic service providers. Different software vendors implement different cryptographic service providers that support different sets of cryptographic algorithms. When working with JCA, the programmer specifies the names of the cryptographic service providers and the names of the cryptographic algorithms to be used. Algorithms are accessed by names and it is possible one and the same algorithm to have several implementations available in several different service providers.
The JCA specification establishes standards for the different types of cryptographic services and specifies the way to access the cryptographic algorithms. The implementation of the algorithms is not part of JCA and is left for the software vendors. Along with JDK 1.4 and any new version, Sun Microsystems distributes a standard implementation of JCA that is used as default if the programmer does not explicitly specify any other to use.
The JCA provides classes and interfaces for working with public and private keys, digital certificates, message signing, digital signatures verification, accessing protected keystores, and some other processes. These classes and interfaces are located in the standard packages java.security and java.security.cert. We will give a short description of the most important of them:
The Most Important Classes in JCA
java.security.KeyStore—gives access to protected keystores for certificates and passwords. The keystores are represented as set of entries and each entry has a unique name, called an alias. The KeyStore class has methods for loading keystore from a stream, storing a keystore to a stream, enumerating the entries in the keystore, extracting keys, certificates and certification chains, modifying entries in the keystore, and so forth. Two major formats for storing keystores are supported—PFX (according to the PKCS#12 standard) and JKS (Java Key Store format used by JDK internally). When we create objects of the class KeyStore, the format of the keystore should be given as a parameter. The possible values are "JKS" and "PKCS12". Objects stored in a keystore can be accessed by the alias but for accessing keys a password also is required.
java.security.PublicKey—represents a public key. It holds the key itself, its encoding format, and the algorithm destined to be used with this key.
java.security.PrivateKey—represents a private key. It holds the key itself, its encoding format, and the algorithm destined to be used with this key.
java.security.cert.Certificate—it is an abstract class for all classes that represent digital certificates. It contains a public key and information for its owner. For representing each particular type of certificates (for example X.509, PGP, and so forth), an appropriate derived class is used.
java.security.cert.X509Certificate—represents an X.509 v.3 certificate. It provides methods for accessing its attributes—owner (Subject), issuer, public key of the owner, period of validity, version, serial number, digital signature algorithm, digital signature, additional extensions, and so forth. All the information in an X509Certificate object is available for reading only.
java.security.Signature—provides functionality for digitally signing and verifying digital signatures. When we create an instance of the Signature class, we specify the name of the algorithm for digital signatures that will be used. Several different algorithms, such as SHA1withRSA, SHA1withDSA, MD5withRSA, and so on are supported. The algorithm name is usually obtained by combining the name of some hashing algorithm with the name of some encrypting algorithm. When signing messages, we use the initSign() methods that take the private key, update() that takes the message for signing, and sign() that signs the message and returns the calculated signature. When we verify digital signatures, we use the initVerify() methods that take the public key for the verification, update() that takes the signed message, and verify() that takes the signature for verification and returns if the signature verification is successful (if the signature corresponds to the given message and public key).
java.security.cert.CertificateFactory—provides functionality for loading certificates, certification chains, and CRL lists from a stream. The generateCertificate() method that is purposed for reading a certificate from a stream expects the certificate to be DER-encoded (according to the PKCS#7 standard) and to be in a binary or text format (Base64-encoded). For reading a certification chain, the generateCertPath() method can be used and the encoding for the chain can be specified. Acceptable are encodings such as PkiPath, that corresponds to the ASN.1 DER sequence of certificates, and PKCS7 that corresponds to the PKCS#7 SignedData object (usually, such objects are stored in files with the standard extension .P7B). It is important to take into account the fact that PKCS7 encoding does not preserve the order of the certificates and, due to this particularity, we cannot use it for storing and reading certification chains. In Java, the only standard encoding for staring certification chains is PkiPath.