com.dstc.security.cms
Class CMSSignature

java.lang.Object
  |
  +--com.dstc.security.cms.CMSSignature

public class CMSSignature
extends Object

A class for signing data according to RFC 2630 "Cryptographic Message Syntax" and for verifying data signed according to that specification.

Both RSA and DSA public key algorithms are supported. The message digest algorithm SHA-1 is supported (and recommended) for both RSA and DSA. For RSA, the MD5 digest algorithm is also supported. A signer must possess both the private key and the accompanying X.509 certificate, and preferably the whole certificate chain up to but not including the root CA certificate. The certificate (sub)chain that is used to initialize an SMIMESignature instance for signing is carried in the signed message.

In this release, verification of multiply-signed data is supported but signing already signed data is not.

The data to be signed can be encapsulated (or not) in the CMS signed data, and may be itself signed or encrypted data.

CMS supports inclusion of arbitrary "attributes" in the signing process. Signing with attributes is enabled by default with the attributes content type, message digest and signing time included. Signing without attributes is also supported and is enabled by setting the system property jcsi.cms.nosignedatts to true. Verification of data signed with and without attributes are both supported.

Example usage:

    //////// Signing ///////////

    // Some data to be signed, available as an InputStream
    InputStream data = ....

    // Wrap with a CMSTypedDataInputStream
    CMSTypedDataInputStream cis = new CMSTypedDataInputStream(data);

    // a private key for a signer "Joe"
    PrivateKey joePrivateKey = ...

    // the corresponding chain of X.509 certificates for "Joe"
    X509Certicate joeCert = ....
    X509Certicate intermediateCACert = ....
    X509Certicate rootCACert = ....

    // Initializes a CMSSignature for signing by "Joe"
    // with "SHA-1" as the message digest algorithm
    // and the certificate chain up to but not including the root CA
    // certificate.
    // NB: The chain must begin with the end-user certificate
    CMSSignature sig = new CMSSignature();
    sig.initSign(joePrivateKey,
                 new X509Certificate[]{joeCert, intermediateCACert},
                 "SHA-1";
                                                
    // Sets the data to sign with encapsulation
    sig.setDataToBeSigned(cis, true);

    // Sign it
    CMSTypedDataInputStream signed = sig.sign();

    // Read signed data from stream
    ....

    //////// Verification ////////

    // A verifying party obtains the signed data and instantiates it
    // as an InputStream
    InputStream fromJoe = .......

    // Obtains a trustedCerts Vector including "Joe"'s root CA cert.
    // The root CA cert is obtained out-of-bands, eg. from the CA
    // itself
    Vector trustedCerts = ...

    // Initializes a CMSSignature instance for verification
    // with the trustedCerts. and a null cert store
    // NB: A non-null cert store is required if there are "missing"
    // intermediate CA certs, eg. if "Joe" had only included his
    // end-user certificate in the signing process.
    CMSSignature sig = new CMSSignature();
    sig.initVerify(trustedCerts, null);

    // Sets the data to verify
    sig.setDataToBeVerified(fromJoe)

    // ... verifies it
    VerificationResult res = sig.verify();

    // ... obtains the data that was signed as an InputStream
    CMSTypedDataInputStream verified = res.getVerified();

    // ... and reads data from the stream
    .........
                                                      
 

See Also:
CMSTypedDataInputStream, VerificationResult, SignedData, SMIMESignature

Constructor Summary
CMSSignature()
          Default constructor
 
Method Summary
 void initSign(PrivateKey priv, X509Certificate[] certChain, String digestAlg)
          Initializes for signing of one or more pieces of data with a PrivateKey, its associated certificate chain and a digest algorithm.
 void initVerify(Vector trusted, Vector store)
          Initializes for verification of one or more CMS signed data instances with a Vector of trusted certificates (trust anchors) and, optionally, a supplementary certificate store.
 void setDataToBeSigned(CMSTypedDataInputStream in, boolean encapContent)
          Supplies the data to be signed in the form of a CMSTypedDataInputStream from which it can be read, together with an indication of whether it should be encapsulated in the subsequently generated CMS signed data.
 void setDataToBeVerified(InputStream in)
          Supplies the CMS signed data for verification as an InputStream from which it can be read.
 void setDataToBeVerified(InputStream in, InputStream msg)
          Supplies the CMS signed data for verification as an InputStream from which it can be read together with an InputStream for the signed content.
 CMSTypedDataInputStream sign()
          Signs the previously supplied data and returns a CMSTypedDataInputStream from which the CMS signed data can be read.
 VerificationResult verify()
          Verifies the previously supplied CMS signed data and returns a VerificationResult.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

CMSSignature

public CMSSignature()
Default constructor
Method Detail

initVerify

public void initVerify(Vector trusted,
                       Vector store)
                throws CMSException
Initializes for verification of one or more CMS signed data instances with a Vector of trusted certificates (trust anchors) and, optionally, a supplementary certificate store.

The trusted certificates are typically root CA certificates (but may include non-root certificates) which the user trusts explicitly. The optional certificate store is used in certificate path validation when intermediate CA certificates (or even user certificates) are not carried in the signed data.

Parameters:
trusted - non-null list of trust anchors
store - optional (may be null) certificate store for certificate path validation

initSign

public void initSign(PrivateKey priv,
                     X509Certificate[] certChain,
                     String digestAlg)
              throws CMSException
Initializes for signing of one or more pieces of data with a PrivateKey, its associated certificate chain and a digest algorithm.

The private key must be either an RSA or a DSA PrivateKey. The certificate chain must begin with the user (or end-entity) certificate and must be of length at least 1. The user certificate must be such that it allows signing. The certificate chain that is included will be carried in the CMS signed data that is subsequently generated. Current practice is to include the chain up to (but not including) a root certificate. If the private key algorithm is "RSA", the supplied digest algorithm must be either "SHA" or "MD5". If it is "DSA" the supplied digest algorithm must be "SHA"

Parameters:
priv - User private key used for signing
certChain - Associated certificate chain beginning with the user certificate and one length at least 1
digestAlg - Message digest algorithm

setDataToBeSigned

public void setDataToBeSigned(CMSTypedDataInputStream in,
                              boolean encapContent)
                       throws CMSException
Supplies the data to be signed in the form of a CMSTypedDataInputStream from which it can be read, together with an indication of whether it should be encapsulated in the subsequently generated CMS signed data.

The data to be signed can itself be CMS signed or encrypted data (for instance, obtained from an encrypt() to CMSCipher), thereby allowing arbitrarily nested CMS data.

If the data to be signed is not encapsulated, it must be transferred separately to the verifying partythe verifying party.

Parameters:
in - data to be signed
encapContent - true if content is to be encapsulated in the CMS signed data to be generated and false otherwise.

setDataToBeVerified

public void setDataToBeVerified(InputStream in)
                         throws CMSException
Supplies the CMS signed data for verification as an InputStream from which it can be read.

The supplied enveloped data is expected to have the signed content encapsulated. Otherwise, a CMSException will be thrown during verification. It is usually known from the context whether content is encapsulated. If there is no encapsulation, the two-parameter setDataToBeVerified() method needs to be called instead.

Parameters:
in - InputStream from which the CMS signed data to verify is to be read

setDataToBeVerified

public void setDataToBeVerified(InputStream in,
                                InputStream msg)
                         throws CMSException
Supplies the CMS signed data for verification as an InputStream from which it can be read together with an InputStream for the signed content.

This method is to be called when the CMS signed data does not have encapsulated content, requiring it to be supplied separately. It is usually known from the context whether content is encapsulated or not. If the content is encapsulated the separately supplied content will be ignored during verification.

Parameters:
in - InputStream from which the CMS signed data to verify can be read
msg - InputStream from which the content to verify against can be read

verify

public VerificationResult verify()
                          throws CMSException,
                                 IOException
Verifies the previously supplied CMS signed data and returns a VerificationResult.

In JCSI's default mode of operation, verification is successful if an instance of VerificationResult is returned as a result of this call. Data that is read from the InputStream associated with this VerificationResult can be considered "verified". However, the signature verification process is such that the data purported to be signed will have had to have been read and buffered so that it can be subsequently returned, with obvious memory implications if the amount of data signed is large.

In order to support one-pass processing without data buffering for memory-sensitive applications, JCSI supports a second mode of operation (enabled by setting the system property jcsi.cms.delayverify=true) in which actual verification is delayed until reading till end-of-file from the InputStream obtained by getVerified() followed by a call to getCMSSignedData(). In other words, data read from the InputStream is not "verified" and must be treated with care until the above described sequence completes successfully.

After this call, the state is reset to what it was in right after the last call to initVerify().


sign

public CMSTypedDataInputStream sign()
                             throws CMSException,
                                    IOException
Signs the previously supplied data and returns a CMSTypedDataInputStream from which the CMS signed data can be read.

By default, signed attributes (message digest, content type and signing time) will be included in the CMS signed data. If signed attributes are required not to be sent (for compatibilty with older or incomplete implementations) the system property jcsi.cms.nosignedatts must be set to true.

NB: Actual signing is triggered by the caller of read() on the returned InputStream, to avoid having to buffer the message to be signed. Therefore, the actual signing time will lie between the first call to read() and when eof is reached.

After this call, the state is reset to what it was in right after the last call to initSign().