com.dstc.security.smime
Class SMIMESignature

java.lang.Object
  |
  +--com.dstc.security.smime.SMIMESignature

public class SMIMESignature
extends Object

A class for signing and verification of MIME messages according to RFC 2633 "S/MIME Version 3 Message Specification".

This class can be used in both signing and verification modes, depending on whether initSign() or initVerify() is called.

Both "clear signing" and "opaque signing" are supported. Clear signing results in a multipart MIME message, the first part of which is the message to be signed and the second its signature as a CMS SignedData encoding. Opaque signing results in a CMS SignedData encoding which encapsulates both the signature and the message that is signed. Clear signing has the advantage that a non-S/MIME MIME client can read the message that is signed, but may be corrupted by some (older) mail transport agents so that verification becomes impossible. Opaque signing results in unambiguosly verifiable messages but are not readable to non-S/MIME MIME clients.

Both RSA and DSA public key algorithms are supported, as specified in RFC 2633. The SHA-1 message digest algorithm is supported (and recommended) in conjunction with both RSA and DSA. For the RSA case, the MD5 message 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.

S/MIME supports inclusion of arbitrary "attributes" in the signing process. Only signing with attributes is supported, but verification of messages signed with and without attributes are both supported. The SigningTime attribute is automatically included in every signed message.

Example usage:

    /////// signing ///////

    // a JavaMail MimeMessage, appropriately constructed
    // including MIME headers (see JavaMail API for details)
    MimeMessage msg = ....

    // 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 an SMIMESignature 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
    SMIMESignature sig = new SMIMESignature();
    sig.initSign("SHA-1", joePrivateKey, 
                 new X509Certificate[]{joeCert, intermediateCACert};

    // Sets the MimeMessage to sign
    sig.setMessage(msg);

    // Signs it
    MimeMessage signed = sig.sign();

    // Sends it off to all the recipients 
    // eg. using javax.mail.Transport.send(msg);
    // (See JavaMail API for details)

    /////// verification ///////

    // A recipient instantiates a MimeMessage
    // from it (See JavaMail API for details)
    MimeMessage 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 an SMIMESignature 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.
    SMIMESignature sig = new SMIMESignature();
    sig.initVerify(trustedCerts, null);

    // Sets the message to verify
    sig.setMessage(fromJoe)

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

    // ... and retrieves the original message
    MimeMessage msg = res.getMessage();
 

See Also:
VerificationResult, SignedData, Attribute

Constructor Summary
SMIMESignature()
          Default constructor
 
Method Summary
 void initSign(String digestAlgName, PrivateKey priv, X509Certificate[] certChain, boolean opaque)
          Initializes for signing one or more MimeMessages with a supplied private key and certificate chain, a digest algorithm and an indication of whether 'clear signing' or 'opaque signing' is required.
 void initVerify(Vector trusted, Vector certStore)
          Initializes for verifying one or more MimeMessages with a Vector of trusted certificates (trust anchors) and an optional certificate store for certification path construction.
 void setMessage(MimeMessage origMsg)
          Sets the message to be signed or verified.
 MimeMessage sign()
          Signs the previously set MimeMessage, and if successful returns a MimeMessage encapsulating a representation of the signed message.
 VerificationResult verify()
          Verifies the previously set MimeMessage, and if successful returns a VerificationResult.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SMIMESignature

public SMIMESignature()
Default constructor
Method Detail

initSign

public void initSign(String digestAlgName,
                     PrivateKey priv,
                     X509Certificate[] certChain,
                     boolean opaque)
              throws SMIMEException
Initializes for signing one or more MimeMessages with a supplied private key and certificate chain, a digest algorithm and an indication of whether 'clear signing' or 'opaque signing' is required.

The certificate chain must start with the user certificate, and must be at least length 1. The user certificate must have its key usage set for signing, if a key usage extension exists. Current practice is to include all the certificates in the chain up to (but not including) the root certificate (if intermediate CA certificates are not included, a verifier will need a supplementary certificate store or repository in order to perform certificate path validation).

The parameter opaque must be set to true for "opaque signing" and false for "clear signing". Supported digest algorithms are "MD5" and "SHA-1" (recommended).

Parameters:
priv - private key to sign messages with
certChain - certificate chain associated with priv, with the user certificate being the first entry
opaque - true for opaque signing and false for clear signing

initVerify

public void initVerify(Vector trusted,
                       Vector certStore)
                throws SMIMEException
Initializes for verifying one or more MimeMessages with a Vector of trusted certificates (trust anchors) and an optional certificate store for certification path construction.

A certificate store will be required for certificate path validation if the certificates carried in the message itself is insufficient for that to happen (for instance, if intermediate CA certificates are not carried).

Parameters:
trusted - Vector of trusted X509Certificates
certStore - Vector of X509Certificates representing a supplementary storage for certificates useful in certificate path building.

setMessage

public void setMessage(MimeMessage origMsg)
                throws IOException,
                       MessagingException,
                       SMIMEException
Sets the message to be signed or verified. A copy of the passed-in MimeMessage is made (using the MimeMessage copy constructor in JavaMail 1.2) and subsequently modified in the signing or verification process. The passed-in message is unmodified.
Parameters:
origMsg - MimeMessage to be signed or verified.

sign

public MimeMessage sign()
                 throws SMIMEException,
                        IOException,
                        MessagingException
Signs the previously set MimeMessage, and if successful returns a MimeMessage encapsulating a representation of the signed message.

After this call, the SMIMESignature is returned to the state it was in after the previous initSign() call, and is ready to sign more messages.

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

Returns:
a MimeMessage representing the signed message

verify

public VerificationResult verify()
                          throws SMIMEException,
                                 MessagingException,
                                 IOException
Verifies the previously set MimeMessage, and if successful returns a VerificationResult. The verified message and signer and signing information can be obtained from the returned object.

After this call, the SMIMESignature is returned to the state it was in after the previous initVerify() call, and is ready to verify more messages.

NB: If the previously set MimeMessage does not represent a signed message, an SMIMEException will be thrown.

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

Returns:
a VerificationResult representing the result of verifying a signed message.