Skip Headers
Oracle® Security Developer Tools Reference
10g Release 2 (10.1.2)
B15975-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

5 Oracle CMS

This chapter describes key features and benefits of Oracle CMS and explains how to set up and use Oracle CMS.

This chapter contains these topics:

5.1 Oracle CMS Features and Benefits

The Oracle CMS SDK is a pure Java API with an extensive set of tools for reading and writing CMS objects, sample programs, and supporting tools for developing secure message envelopes.

Oracle CMS implements the IETF Cryptographic Message Syntax specified in RFC-2630. A link to this document is available in Appendix A, "References".

5.1.1 Content Types

Oracle CMS supports all the content types specified in RFC-2630, as shown in Table 5-1:

Table 5-1 Content Types Supported by Oracle CMS

Type Identifier
data 1.2.840.113549.1.7.1
signed-data 1.2.840.113549.1.7.2
enveloped-data 1.2.840.113549.1.7.3
digested-data 1.2.840.113549.1.7.5
encrypted-data 1.2.840.113549.1.7.6
authenticated-data 1.2.840.113549.1.9.16.1.2

Oracle CMS is a full implementation of RFC-2630 with the following exceptions:

  • There is no support for Attribute Certificates

  • There is no support for Key Agreement RecipientInfo

Oracle CMS supports the following Enhanced Security Services for S/MIME content type specified in RFC-2634:

Type Identifier
receipt 1.2.840.113549.1.9.16.1.2

A link to this document is available in Appendix A, "References".

The following IETF PKIX TimeStamp Protocol content type corresponding to RFC 3161 is supported:

Type Identifier
TSTInfo 1.2.840.113549.1.9.16.1.4


Note:

Oracle CMS will not process a content type other than the ones specified earlier.

5.1.2 Differences Between Oracle CMS and PKCS #7 Version 1.5

Oracle CMS is based on PKCS #7 v 1.5 but differs in the following ways:

  • The enveloped-data contains an optional OriginatorInfo

  • The SignerIdentifier in the signed-data SignerInfo is a choice of IssuerAndSerialNo or SubjectKeyIdentifier


Note:

You must keep these differences in mind if you require interoperability with PKCS#7 implementations.

5.2 Setting Up Your Oracle CMS Environment

The Oracle Security Developer Tools are installed with Oracle Application Server in ORACLE_HOME. This section describes how to set up your environment for Oracle CMS. It contains the following:

5.2.1 System Requirements

In order to use Oracle CMS, your system must have the Java Development Kit (JDK) version 1.2.2 or higher.

5.2.2 Setting the CLASSPATH Environment Variable

Your CLASSPATH environment variable must contain the full path and file names to all of the required jar and class files. Make sure the following items are included in your CLASSPATH:

  • the osdt_core.jar file

  • the osdt_cert.jar file

  • the osdt_cms.jar file

5.2.2.1 Setting the CLASSPATH on Windows

To set the CLASSPATH on Windows:

  1. In your Windows Control Panel, select System.

  2. In the System Properties dialog, select the Advanced tab.

  3. Click Environment Variables.

  4. In the User Variables section, click New to add a CLASSPATH environment variable for your user profile. If a CLASSPATH environment variable already exists, select it and click Edit.

  5. Add the full path and file names for all the required jar and class files to the CLASSPATH.

    For example, your CLASSPATH might look like this:

    %CLASSPATH%;C:\ORACLE_HOME\jlib\osdt_core.jar;
    C:\ORACLE_HOME\jlib\osdt_cert.jar;
    C:\ORACLE_HOME\jlib\osdt_cms.jar;
    
    
  6. Click OK.

5.2.2.2 Setting the CLASSPATH on UNIX

To set your CLASSPATH on UNIX, set your CLASSPATH environment variable to include the full path and file name of all of the required jar and class files. For example:

setenv CLASSPATH $CLASSPATH:$ORACLE_HOME/jlib/osdt_core.jar:\
$ORACLE_HOME/jlib/osdt_cert.jar:\
$ORACLE_HOME/jlib/osdt_cms.jar

5.3 Developing Applications with Oracle CMS

There are two approaches to reading and writing CMS objects with the oracle.security.crypto.cms package:

The Oracle CMS API enables you to build nested (wrapped) CMS objects with no limit on the number of wrappings.

This section contains these topics:

5.3.1 CMS Object Types

Application developers should be aware of some specific CMS object types which are discussed in subsequent sections.

A detached object applies to data and receipt content types. For these types, a detached object is one where the protected content is absent.

A degenerate object is a certificate-only signed-data object and is defined only for the signed-data content type. It refers to the case where the signed-data object has no signers. It is normally used to store certificates and is associated with file extensions p7b and p7c.

An external signature is defined only for the signed-data content type. It is essentially a detached signed-data object; that is, the signed-data object has one or more signers but the content that was signed is not present in the signed-data object.

5.3.2 Constructing CMS Objects using the CMS***ContentInfo Classes

Table 5-2 lists the classes which make up the CMS***ContentInfo classes.

Table 5-2 CMS***ContentInfo Classes

Class Content Type
CMSDataContentInfo CMS.id_data
ESSReceipt CMS.id_ct_receipt (RFC-2634 receipt)
CMSDigestedDataContentInfo CMS.id_digestedData
CMSSignedDataContentInfo CMS.id_signedData
CMSEncryptedDataContentInfo CMS.id_encryptedData
CMSEnvelopedDataContentInfo CMS.id_envelopedData
CMSAuthenticateDataContentInfo CMS.id_ct_authData

You can use these classes to:

  • Read and write objects of the appropriate content type

  • Construct and process detached objects

  • Create nested objects

A detailed discussion of CMS***ContentInfo classes follows.

5.3.2.1 Abstract Base Class CMSContentInfo

CMSContentInfo is an abstract class representing a fundamental CMS object. Table 5-2 lists the subclasses of CMSContentInfo.

Some of the useful methods of this abstract class are described in Table 5-3.

Table 5-3 Useful Methods of CMSContentInfo

Method Description
contentTypeName (oracle.security.crypto.asn1.ASN1ObjectID contentType) Returns the content type of the object as a string.
getContentType() Returns the content type of the object as an object identifier (OID).
input(java.io.InputStream is) Initializes this object by reading a BER encoding from the specified input stream.
inputInstance(java.io.InputStream is) Creates a new CMSContentInfo object by reading a BER encoding from the specified input stream.
isDegenerate() Indicates if the object is degenerate.
isDetached() Indicates if the object is detached.
output(java.io.OutputStream os) Writes the encoding of the object to the given output stream.

5.3.2.1.1 Constructing a CMS Object

Perform the following steps to construct a CMS object:

  1. Create the object of the specified content type.

  2. Initialize the object.

  3. Call the output(..) method to write the object encoding.

If you are reading in an existing CMSContentInfo, but you do not know the concrete type in advance, use inputInstance(). To create a new object, use one of the constructors of the concrete subclass with which you are working. To read in one of a known concrete type, use the no-args constructor and then invoke the input() method.

5.3.2.1.2 Reading a CMS Object

Perform the following steps to read an object:

  1. Call CMSContentInfo.inputInstance(..) to read in the object.

  2. Call getContentType() to determine its content type.

  3. You can now invoke the content type-specific operations.

5.3.2.2 The CMSDataContentInfo Class

The class CMSDataContentInfo represents an object of type id-data as defined by the constant CMS.id_data, and is intended to refer to arbitrary octet strings whose interpretation is left up to the application.

A useful method of this class is:

byte[] getData()

which returns the data stored in the data object.

To create a CMS data object:

  1. Create an instance of CMSDataContentInfo using the constructor that takes a byte array, documentBytes, that contains the information:

    CMSDataContentInfo exdata =
        new CMSDataContentInfo(byte[] documentBytes)
    
    
  2. Write the data object to a file, for example data.p7m:

    exdata.output(new FileOutputStream("data.p7m"));
    
    

Note:

You cannot create a CMSDataContentInfo object that contains null content.

The steps you use when reading a CMS data object depend on whether you know the object's content type.

  1. Open a connection to the file using FileInputStream.

    If you know that the object stored in the file data.p7m is of content type id-data:

    CMSDataContentInfo exdata =
        new CMSDataContentInfo(new FileInputStream("data.p7m"));
    
    

    However, if you do not know the content type in advance, check the type prior to reading:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof CMSDataContentInfo)
    {
       CMSDataContentInfo exdata =  (CMSDataContentInfo) cmsdata;
       // .....
    }
    
    
  2. To access the information stored in the CMS data object:

    byte[] docBytes = exdata.getData();
    
    

5.3.2.3 The ESSReceipt Class

Class ESSReceipt represents an object of type id-ct-receipt as defined by the constant CMS.id_ct_receipt, and refers to an RFC-2634 receipt.

Table 5-4 lists some useful methods of this class.

Table 5-4 Useful Methods of ESSReceipt

Method Description
byte[] getOriginatorSignatureValue() Returns the signature value of the message that triggered the generation of this receipt.
ASN1ObjectID getReceiptContentType() Returns the content type of the message that triggered the generation of this receipt.
byte[] getReceiptData() Returns the encoded receipt.
byte[] getSignedContentIdentifier() Returns the signed content identifier of the message that triggered the generation of this receipt.
void inputContent(InputStream is) Initialize this object by reading the BER encoding from the specified input stream.

Take the following steps to create a CMS receipt object.

  1. Create an instance of ESSReceipt using the constructor that takes a content type identifier, a byte array containing the signed content identifier and a byte array containing the originator signature value:

    ESSReceipt rcpt =
        new ESSReceipt(contentType, signedContentIdentifier,
        originatorSignatureValue);
    
    
  2. Write the receipt object to a file, for example data.p7m:

    rcpt.output(new FileOutputStream("data.p7m"));
    

Note:

When you create an ESSReceipt object, do not leave any input parameters set to null.

To read a receipt object:

  1. Open a connection to the file using FileInputStream.

    If you know that the object stored in the file data.p7m is of content type id-ct-receipt:

    ESSReceipt rcptdata = new ESSReceipt(new FileInputStream("data.p7m"));
    
    

    Otherwise, if the content type is unknown:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof ESSReceipt)
    {
        ESSReceipt rcptdata =  (ESSReceipt) cmsdata;
        // .....
    }
    
    
  2. Access the information stored in the receipt object:

    ASN1ObjectID contentType = getReceiptContentType();
    byte[] sciBytes = rcptdata.getSignedContentIdentifier()
    byte[] osvBytes = rcptdata.getOriginatorSignatureValue();
    

5.3.2.4 The CMSDigestedDataContentInfo Class

The class CMSDigestedDataContentInfo represents an object of type id-digestedData as defined by the constant CMS.id_digestedData.

Table 5-5 lists some of the useful methods of this class.

Table 5-5 Useful Methods of CMSDigestedDataContentInfo

Method Description
byte[] getDigest() Returns the message digest value.
AlgorithmIdentifier getDigestAlgID() Returns the message digest algorithm ID.
CMSContentInfo getEnclosed() Returns the digested content.
ASN1ObjectID getEnclosedContentType() Returns the content type of the digested content.
ASN1Integer getVersion() Returns the version number of this object.
isDetached() Indicates if this object is detached.
void setEnclosed(CMSContentInfo content) Sets the encapsulated content, that is, the object that was originally digested.
void writeDetached(boolean writeDetached) Indicates if the object that is being digested should be omitted when creating the CMSDigestedDataContentInfo object.

5.3.2.4.1 Constructing a CMS Digested-data Object

Take the following steps to create a CMS digested-data object.

  1. Create an instance of CMSDigestedDataContentInfo using the constructor that takes the object to be digested and the digest algorithm identifier. For example, if contentInfo is a CMSDataContentInfo object and MD5 is the digest algorithm:

    CMSDigestedDataContentInfo dig =
        new CMSDigestedDataContentInfo(contentInfo, CMS.md5);
    
    
  2. Write the CMS digested-data object to a file named data.p7m.

    dig.output(new FileOutputStream("data.p7m"));
    
    
5.3.2.4.2 Reading a CMS Digested-data Object

The steps you need to read a CMS digested-data object depend on whether you know the object's content type.

  1. Open a connection to the data.p7m file using FileInputStream.

    If you know that the object stored in the file is of content type id-digestedData:

    CMSDigestedDataContentInfo digdata =
        new CMSDigestedDataContentInfo(new FileInputStream("data.p7m"));
    
    

    However, if you do not know the content type in advance:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof CMSDigestedDataContentInfo)
    {
        CMSDigestedDataContentInfo digdata =
            (CMSDigestedDataContentInfo) cmsdata;
        // .....
    }
    
    
  2. To access the information stored in the CMS digested-data object:

    int version = digdata.getVersion().intValue();
    AlgorithmIdentifier digestAlgID = digdata.getDigestAlgID();
    byte[] digestValue = digdata.getDigest();
    CMSContentInfo digContentInfo = digData.getEnclosed()
    if (digData.getEnclosedContentType().equals(CMS.id_data))
        CMSDataContentInfo contentInfo = (CMSDataContentInfo)digContentInfo;
    
    
  3. To verify the integrity of the protected data, verify the digest:

    digData.verify();
    
    
5.3.2.4.3 Detached digested-data Objects

When working with a detached object, the object that is digested is not a part of the resulting CMS digested-data structure. To generate a detached object, call the writeDetached (true | false) method. For example:

dig.writeDetached(true);

While you can read in a detached CMS digested-data object as shown earlier, the digest verification will fail because the original object that was digested is not present. To resolve this, call the setEnclosed (CMScontentInfo) method to set the digestedContent:

digdata.setEnclosed(CMScontentInfo object);

followed by digest verification:

digdata.verify();

5.3.2.5 The CMSSignedDataContentInfo Class

The class CMSSignedDataContentInfo represents an object of type id-signedData as defined by the constant CMS.id_signedData.

Oracle CMS supports a choice of IssuerAndSerialNo or SubjectKeyIdentifier for use as the SignerIdentifier. For interoperability with PKCS #7 and S/MIME, however, the IssuerAndSerialNo must be used as the SignerIdentifier.

Table 5-6 lists some useful methods of this class:

Table 5-6 Useful Methods of CMSSignedDataContentInfo

Method Description
void addCertificate(X509 cert) Appends the given certificate to the list of certificates which will be included with this signed data object.
void addCRL(CRL crl) Appends the given CRL to the list of CRLs which will be included with this signed data object.
void addSignature(AttributeSet authenticatedAttributes, PrivateKey signerKey, X509 signerCert, AlgorithmIdentifier digestAlgID, AlgorithmIdentifier digestEncryptionAlgID, AttributeSet unauthenticatedAttributes) Adds a signature using the IssuerAndSerialNumber as the SignerIdentifier, that is, a Version1 CMSSignerInfo.
void addSignature(AttributeSet authenticatedAttributes, PrivateKey signerKey, X509 signerCert, AlgorithmIdentifier digestAlgID, AlgorithmIdentifier digestEncryptionAlgID, AttributeSet unauthenticatedAttributes, boolean useSPKI64) Adds a signature using the SubjectKeyIdentifier as the SignerIdentifier; that is, a Version3 CMSSignerInfo.
void addSignerInfo(X509 signerCert, CMSSignerInfo signerInfo) Adds a CMSSignerInfo to the list of signers.
Vector getCertificates() Returns the list of certificates included with this signed data object.
Vector getCRLs() Returns the list of CRLs included with this signed data object.
CMSContentInfo getEnclosed() Returns the signed document.
ASN1ObjectID getEnclosedContentType() Returns the content type of the document which was signed.
CMSSignerInfo getSignerInfo(signerCert) Returns the CMSSignerInfo corresponding to the certificate.
ASN1Integer getVersion() Returns the version number of this object.
boolean isDegenerate() IIndicates if this is a degenerate CMSSignedDataContentInfo object (that is, has no SignerInfo structures)
boolean isDetached() Indicates if this is a detached object.
boolean isExternalSignature() Checks for the presence of external signatures.
void setEnclosed(CMSContentInfo content) Sets the content which was signed.
Enumeration signers() Returns the signatures on this signed data object in the form of an enumeration, each element of which is an instance of CMSSignerInfo.
void verify(CertificateTrustPolicy trustPolicy) Returns normally if this CMS signed data object contains at least one valid signature, according to the given trust policy.
void verify(CertificateTrustPolicy   trustPolicy,CMSContentInfo contentInfo) Returns normally if this signed data object contains at least one valid signature, according to the given trust policy.
void verifySignature(X509 signerCert) Returns successfully if this signed data object contains a signature which is validated by the given certificate.
void verifySignature(X509 signerCert,   CMSContentInfo contentInfo) Returns successfully if this signed data object contains a signature which is validated by the given certificate and data.
void writeExternalSignature(boolean createExternalSignature) Indicates if an external signature must be created.

Oracle CMS supports the RSA and DSA signature algorithms.

5.3.2.5.1 Constructing a CMS Signed-data Object

Follow these steps to create a CMS signed-data object:

  1. Create an instance of CMSDigestedDataContentInfo. For example, to create the CMSDigestedDataContentInfo object contentInfo that is to be signed:

    CMSDigestedDataContentInfo sig =
        new CMSSignedDataContentInfo(contentInfo);
    
    
  2. Add signatures:

    X509 signerCert = new X509(new FileInputStream("name"));
    PrivateKey signerKey =
        CryptoUtils.inputPrivateKey(new FileInputStream("name"));
    
    
    1. To add a signature using the IssuerAndSerialNo as the SignerIdentifier, MD5 digests and RSA Signature Algorithm:

      sig.addSignature(null, signerKey, signerCert, CMS.md5,
          CMS.rsaEncryption, null);
      
      
    2. To add a signature using the 64 bit SubjectKeyIdentifier as the SignerIdentifier, SHA-1 digests and DSS Signature Algorithm:

      sig.addSignature(null, signerKey, signerCert, CMS.sha_1,
          CMS.dsaWithSHA, null, true);
      
      
    3. To add a signature using the 160 bit SubjectKeyIdentifier as the SignerIdentifier, SHA-1 digests and RSA Signature Algorithm:

      sig.addSignature(null, signerKey, signerCert, CMS.sha_1,
          CMS.rsaEncryption, null, false);
      
      
  3. Add any Certificates and CRLs:

    sig.addCertificate (....)
    sig.addCRL (...)
    
    
  4. Write the CMS signed-data object to a file, for example data.p7m:

    sig.output(new FileOutputStream("data.p7m"));
    
    
5.3.2.5.2 Reading a CMS Signed-data Object

The steps you need to read a CMS signed-data object depend on whether you know the object's content type.

  1. Open a connection to the data.p7m file using FileInputStream.

    If you know that the object stored in the file is of content type id-signedData:

    CMSSignedDataContentInfo sigdata =
        new CMSSignedDataContentInfo(new FileInputStream("data.p7m"));
    
    

    However, if you do not know the content type in advance:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof CMSSignedDataContentInfo)
    {
        CMSSignedDataContentInfo sigdata =
            (CMSSignedDataContentInfo) cmsdata;
        // .....
    }
    
    
  2. Access the information stored in the CMS signed-data object:

    int version = sigdata.getVersion().intValue();
    CMSContentInfo sigContentInfo = sigData.getEnclosed()
    Vector certs = sigdata.getCertificates();
    Vector crls = sigData.getCRLs();
    Enumeration e = sigData.signers();
    if (digData.getEnclosedContentType().equals(CMS.id_data))
        CMSDataContentInfo contentInfo = (CMSDataContentInfo)digContentInfo;
    
    
  3. Verify the signature using the signer's public key certificate:

    sigData.verify(signerCert);
    
    
  4. To get more information about the signer:

    CMSSignerInfo sigInfo = sigdata.getSignerInfo(signerCert);
    byte[] signatureValue = sigInfo.getEncryptedDigest();
    AlgorithmIdentifier digest = sigInfo.getDigestAlgID();
    AlgorithmIdentifier signature = sigInfo.getDigestEncryptionAlgID();
    AttributeSet signedAttributes = sigInfo.getAuthenticatedAttributes();
    AttributeSet unsignedAttributes = sigInfo.getUnauthenticatedAttributes();
    
    
5.3.2.5.3 External Signatures (Detached Objects)

For a detached object, the signed object is not part of the resulting CMS signed-data structure. To generate a detached object, call the writeExternalSignature() method:

sig.writeExternalSignature(true);

While you can read in a detached CMS signed-data object as shown in "Reading a CMS Signed-data Object", the signature verification will fail because the original object that was signed is not present. Call the setEnclosed (..) method to set the signed content:

sigdata.setEnclosed(contentInfo);

followed by signature verification:

sigdata.verify(signerCert);

5.3.2.5.4 Certificates/CRL-Only Objects

These are essentially CMSSignedDataContentInfo objects with attached certificates, or CRLs, or both, but without any signatures. To generate a Certificate/CRL-only object:

CMSSignedDataContentInfo sigdata = 
    new CMSSignedDataContentInfo(new CMSDataContentInfo(new byte[0]));
sigData.addCertificate (...);
sigData.addCRL( ...);
sigData.output(..);

You can read in a Certificate/CRL-only signed-data object as shown in "Reading a CMS Signed-data Object".

5.3.2.6 The CMSEncryptedDataContentInfo Class

The class CMSEncryptedDataContentInfo represents an object of type id-encryptedData as defined by the constant CMS.id_encryptedData.

Table 5-7 lists some useful methods of this class.

Table 5-7 Useful Methods of CMSEncryptedDataContentInfo

Method Description
AlgorithmIdentifier getContentEncryptionAlgID() Returns the content encryption algorithm
CMSContentInfo getEnclosed(SymmetricKey decryptionKey) Returns the decrypted content
ASN1ObjectID getEnclosedContentType() Returns the content type of the encrypted content
byte[] getEncryptedContent() Returns the encrypted content
AttributeSet getUnprotectedAttributes() Returns the set of unprotected attributes
ASN1Integer getVersion() Returns the version number
boolean isDetached() Indicates if this is a detached CMS object
void setEncryptedContent(byte[] encryptedContent) Sets the encrypted content
void setUnprotectedAttributes   (oracle.security.crypto.cert.AttributeSet unprotectedAttributes) Sets the unprotected attributes
void writeDetached   (boolean writeDetachedObject) Indicates if the encryptedContent will be a part of the EncryptedContentInfo structure in this object's output encoding

You can use any of the ciphers supported by the Oracle Security Engine to perform the encryption operation, including RC2, DES, Triple-DES, AES, and so on.

5.3.2.6.1 Constructing a CMS Encrypted-data Object

To create an encrypted-data object:

  1. Create an instance of CMSEncrytedDataContentInfo. For example, if contentInfo is a CMSDataContentInfo object and the cipher is Triple-DES in CBC mode:

    SymmetricKey contentEncryptionKey =
        SymmetricKeyGenerator.getInstance(CMS.des_ede3_cbc).generateKey();
    CMSEncrytedDataContentInfo enc =
        new CMSEncrytedDataContentInfo(contentInfo, contentEncryptionKey,
            CMS.des_ede3_cbc);
    
    
  2. Write the encrypted-data object to a file, say data.p7m:

    enc.output(new FileOutputStream("data.p7m"));
    
    
5.3.2.6.2 Reading a CMS Encrypted-data Object

The steps you need to read an encrypted-data object depend on whether you know the object's content type.

  1. Open a connection to the data.p7m file using FileInputStream.

    If you know that the object stored in the file data.p7m is of content type id-encryptedData:

    CMSEncrytedDataContentInfo encdata =
        new CMSEncrytedDataContentInfo(new FileInputStream("data.p7m"));
    
    

    However, if you do not know the content type in advance:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof CMSEncrytedDataContentInfo)
    {
        CMSEncrytedDataContentInfo encdata =
            (CMSEncrytedDataContentInfo) cmsdata;
        // .....
    }
    
    
  2. To access the information stored in the CMS encrypted-data object:

    int version = encdata.getVersion().intValue();
    AlgorithmIdentifier encAlgID = encdata.getContentEncryptionAlgID();
    byte[] encValue = encdata.getEncryptedContent();
    CMSContentInfo encContentInfo =
        encdata.getEnclosed(ContentEncryptionKey);  //Decrypt the Content
    if (encData.getEnclosedContentType().equals(CMS.id_data))
       CMSDataContentInfo contentInfo = (CMSDataContentInfo)encContentInfo;
    
    
5.3.2.6.3 Detached encrypted-data CMS Objects

If it is a detached object, the encrypted object is not a part of the resulting CMS encrypted-data structure. To generate a detached object, call the writeDetached (..) method:

enc.writeDetached(true);

While you can read in a detached CMS encrypted-data object as shown in "Reading a CMS Encrypted-data Object", the content decryption will fail because the original object that was encrypted is not present. Call the setEncryptedContent (..) method to set the encryptedContent:

encData.setEncryptedContent(enc.getEncryptedContent());

followed by content decryption:

encdata.getEnclosed(ContentEncryptionKey);

5.3.2.7 The CMSEnvelopedDataContentInfo Class

The class CMSEnvelopedDataContentInfo represents an object of type id-envelopedData as defined by the constant CMS.id_envelopedData.

Table 5-8 lists some useful methods of this class:

Table 5-8 Useful Methods of CMSEnvelopedDataContentInfo

Method Description
void addRecipient(AlgorithmIdentifier keyEncryptionAlgID, SymmetricKey keyEncryptionKey, byte[] keyIdentifier, Date keyDate, ASN1Sequence otherKeyAttribute) Adds a recipient using the key encryption (wrap) key exchange mechanism.
void addRecipient(CMSRecipientInfoSpec ris) Adds a recipient using the key exchange mechanism specification
void addRecipient(X509 recipientCert, AlgorithmIdentifier keyEncryptionAlgID) Adds a recipient using the key transport (IssuerAndSerialNo) key exchange mechanism
void addRecipient(X509 recipientCert, AlgorithmIdentifier keyEncryptionAlgID, boolean useSPKI64) Adds a recipient the key transport (SubjectKeyIdentifier) key exchange mechanism
AlgorithmIdentifier getContentEncryptionAlgID() Returns the content encryption algorithm
CMSContentInfo getEnclosed(PrivateKeyprivateKey, X509 recipientCert) Returns the enclosed content after decryption using Key Transport RecipientInfo
CMSContentInfo getEnclosed(SymmetricKey symmetricKey, byte[] keyIdentifier) Returns the enclosed content after decryption using Key Encryption RecipientInfo
CMSContentInfo getEnclosed(SymmetricKey symmetricKey, byte[] keyIdentifier,Date keyDate) Returns the enclosed content after decryption
ASN1ObjectID getEnclosedContentType() Returns the content type of the encrypted content
byte[] getEncryptedContent() Returns the enclosed content which is encrypted
OriginatorInfo getOriginatorInfo() Returns the OriginatorInfo
AttributeSet getUnprotectedAttribs() Returns the unprotected attributes
ASN1Integer getVersion() Returns the version number
boolean isDetached() Indicates if the encrypted content is not present
Enumeration recipients() Returns the list of message recipients
void setEnclosed(byte[] encryptedContent) Sets the Encrypted Content
void setOriginatorInfo(OriginatorInfo   origInfo) Sets the OriginatorInfo
void setUnprotectedAttribs   (oracle.security.crypto.cert.AttributeSet unprotectedAttributes) Sets the unprotected attributes
void writeDetached(boolean writeDetached) Indicates if the encrypted content must be omitted from this object's output encoding

5.3.2.7.1 Constructing a CMS Enveloped-data Object

To create an enveloped-data object:

  1. Create an instance of CMSEnvelopedDataContentInfo. For example, if contentInfo is a CMSDataContentInfo object and the cipher is Triple-DES in CBC mode:

    CMSEnvelopedDataContentInfo env = 
        new CMSEnvelopedDataContentInfo(contentInfo, CMS.des_ede3_cbc);
    
    
    
  2. Add recipients, keeping in mind the recipient's key management technique.

    • If the recipient uses the key encryption (wrap) key management mechanism:

      env.addRecipient(keyEncryptionAlgID, keyEncryptionKey,
          keyIdentifier, keyDate, otherKeyAttribute);
      
      
    • If the recipient key exchange mechanism was specified using a CMSRecipientInfoSpec object:

      env.addRecipient(ris)
      
      
    • If the recipient uses the key transport (IssuerAndSerialNo recipient identifier) key management mechanism:

      env.addRecipient(recipientCert, CMS.rsaEncryption);
      
      
    • If the recipient uses the key transport (64-bit SubjectKeyIdentifier recipient identifier) key management mechanism:

      env.addRecipient(recipientCert, CMS.rsaEncryption, true)
      
      
    • If the recipient uses the key transport (160-bit SubjectKeyIdentifier recipient identifier) key management mechanism:

      env.addRecipient(recipientCert, CMS.rsaEncryption, false)
      
      
  3. Set any optional arguments:

    env.setAuthenticatedAttributes(authenticatedAttributes, CMS.md5);
    env.setOriginatorInfo(originatorInfo);
    env.setUnauthenticatedAttributes(unauthenticatedAttributes);
    
    
  4. Write the CMS enveloped-data object to a file, say data.p7m:

    enc.output(new FileOutputStream("data.p7m"));
    
    
5.3.2.7.2 Reading a CMS Enveloped-data Object

The steps you need to read the object depend on whether you know the object's content type.

  1. Open a connection to the data.p7m file using FileInputStream. If you know that the object stored in the file is of content type id-envelopedData:

    CMSEnvelopedDataContentInfo envdata =
        new CMSEnvelopedDataContentInfo(new FileInputStream("data.p7m"));
    
    

    However, if you do not know the content type in advance:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof CMSEnvelopedDataContentInfo)
    {
        CMSEnvelopedDataContentInfo envdata =
            (CMSEnvelopedDataContentInfo) cmsdata;
        // 
        .....
    }
    
    
  2. To access the information stored in the enveloped-data object:

    int version = envdata.getVersion().intValue();
    AlgorithmIdentifier encAlgID = envdata.getContentEncryptionAlgID();
    ASN1ObjectID contentType = env.getEnclosedContentType();
    byte[] encryptedContent = env.getEncryptedContent();
    OriginatorInfo origInfo = env.getOriginatorInfo();
    AttributeSet unprotected = env.getUnprotectedAttribs();
    
    
  3. Decrypt the content depending on the recipient information:

    CMSContentInfo envContentInfo =
        env.getEnclosed(privateKey, recipientCert);
    
    

    or

    CMSContentInfo envContentInfo =
        env.getEnclosed(symmetricKey, keyIdentifier);
    
    

    or

    CMSContentInfo envContentInfo =
        env.getEnclosed(symmetricKey, keyIdentifier, keyDate)
    if (envContentInfo instanceof CMSDataContentInfo)
    {
        CMSDataContentInfo contentInfo = (CMSDataContentInfo) envContentInfo;
        // ...
    }
    
    
5.3.2.7.3 Key Transport Key Exchange Mechanism

This mechanism supports the use of either IssuerAndSerialNo or SubjectKeyIdentifier as the recipient identifier.

5.3.2.7.4 Key Agreement Key Exchange Mechanism

This mechanism is not currently supported.

5.3.2.7.5 Key Encryption (Wrap) Key Exchange Mechanism

Oracle CMS supports CMS3DESWrap and CMSRC2Wrap algorithms. Mixed mode wrapping is not supported; for example, 3DES keys cannot be RC2-wrapped.


Note:

Using the OtherKeyAttribute could cause interoperability problems.

5.3.2.7.6 Detached Enveloped-data CMS Object

If working with a detached object, note that the enveloped object is not part of the resulting CMS enveloped-data structure. Call the writeDetached (..) method to generate a detached object:

env.writeDetached(true);

While you can read in a detached enveloped-data object as shown in "Reading a CMS Enveloped-data Object", the content decryption will fail because the original, enveloped object is not present. Call the setEnclosed (..) method to set the enveloped content:

envdata.setEnclosed(env.getEncryptedContent());

followed by content decryption:

envdata.getEnclosed(............);

5.3.2.8 The CMSAuthenticatedDataContentInfo Class

The class CMSAuthenticatedDataContentInfo represents an object of type id-ct-authData as defined by the constant CMS.id_ct_authData.


Note:

Oracle CMS supports HMAC with SHA-1 Message Authentication Code (MAC) Algorithm.

Table 5-9 lists some useful methods of this class.

Table 5-9 Useful Methods of CMSAuthenticatedDataContentInfo

Method Description
void addRecipient(AlgorithmIdentifier keyEncryptionAlgID, SymmetricKey keyEncryptionKey, byte[] keyIdentifier, java.util.Date keyDate, ASN1Sequence otherKeyAttribute) Adds a recipient using the key wrap key exchange mechanism
void addRecipient(CMSRecipientInfoSpec ris) Adds a recipient using the specified key exchange mechanism
void addRecipient(X509 recipientCert, AlgorithmIdentifier keyEncryptionAlgID) Adds a recipient using the key transport key exchange mechanism using the IssuerAndSerialNo as the recipient identifier
void addRecipient(X509 recipientCert, AlgorithmIdentifier keyEncryptionAlgID, boolean useSPKI64) Adds a recipient using the key transport key exchange mechanism using the SubjectKeyIdentifier as the recipient identifier
AttributeSet getAuthenticatedAttributes() Returns the Authenticated Attributes
AlgorithmIdentifier getDigestAlgID() Returns the digest algorithm
CMSContentInfo getEnclosed() Returns the authenticated content
ASN1ObjectID getEnclosedContentType() Returns the content type of the enclosed content
byte[] getMAC() Returns the message authentication code
AlgorithmIdentifier getMACAlgID() Returns the MAC algorithm used for authentication
OriginatorInfo getOriginatorInfo() Returns the Originator information
AttributeSet getUnauthenticatedAttributes() Returns the Unauthenticated Attributes
ASN1Integer getVersion() Returns the version number
boolean isDetached() Indicates if this object is detached
java.util.Enumeration recipients() Returns the list of message recipients
void setAuthenticatedAttributes(AttributeSet authenticatedAttributes, AlgorithmIdentifier digestAlgorithm) Sets the Authenticated attributes
void setEnclosed(CMSContentInfo content) Sets the authenticated content
void setOriginatorInfo(OriginatorInfo originatorInfo) Sets the OriginatorInfo
void setUnauthenticatedAttributes(AttributeSet unauthenticatedAttributes) Sets the unauthenticated attributes
void verifyMAC(PrivateKey privateKey, X509 recipientCert) Returns the enclosed content after decryption
void verifyMAC(SymmetricKey symmetricKey, byte[] keyIdentifier) Returns the enclosed content after decryption
void verifyMAC(SymmetricKey symmetricKey, byte[] keyIdentifier) Date keyDate) Returns the enclosed content after decryption
void verifyMAC(SymmetricKey symmetricKey, byte[] keyIdentifier, Date keyDate, ASN1Sequence otherKeyAttribute) Returns the enclosed content after decryption
void writeDetached(boolean writeDetachedObject) Indicates if the authenticated content must be omitted from this object's output encoding



5.3.2.8.1 Constructing a CMS Authenticated-data Object

Take the following steps to create an authenticated-data object:

  1. Create an instance of CMSAuthenticatedDataContentInfo. For example, if contentInfo is a CMSDataContentInfo object, Triple-DES HMAC key and HMAC with SHA-1 MAC algorithm:

    SymmetricKey contentEncryptionKey =
        SymmetricKeyGenerator.getInstance(CMS.des_ede3_cbc).generateKey();
    CMSAuthenticatedDataContentInfo auth = 
        new CMSAuthenticatedDataContentInfo(contentInfo, 
    contentEncryptionKey, CMS.hmac_SHA_1);
    
    
  2. Add recipients, keeping in mind the recipient's key management technique.

    • If the recipient uses the key encryption (wrap) key management mechanism:

      auth.addRecipient(keyEncryptionAlgID, keyEncryptionKey, keyIdentifier,
          keyDate, otherKeyAttribute);
      
      
    • If the recipient key exchange mechanism was specified using a CMSRecipientInfoSpec object:

      auth.addRecipient(ris)
      
      
    • If the recipient uses the key transport (IssuerAndSerialNo recipient identifier) key management mechanism:

      auth.addRecipient(recipientCert, CMS.rsaEncryption);
      
      
    • If the recipient uses the key transport (64-bit SubjectKeyIdentifier recipient identifier) key management mechanism:

      auth.addRecipient(recipientCert, CMS.rsaEncryption, true)
      
      
    • If the recipient uses the key transport (160-bit SubjectKeyIdentifier recipient identifier) key management mechanism:

      auth.addRecipient(recipientCert, CMS.rsaEncryption, false)
      
      
  3. Set any optional arguments:

    auth.setAuthenticatedAttributes(authenticatedAttributes, CMS.md5);
    auth.setOriginatorInfo(originatorInfo);
    auth.setUnauthenticatedAttributes(unauthenticatedAttributes);
    
    
  4. Write the CMS authenticated-data object to a file, say data.p7m:

    auth.output(new FileOutputStream("data.p7m"));
    
    
5.3.2.8.2 Reading a CMS Authenticated-data Object

The steps you need to read the object depend on whether you know the object's content type:

  1. Open a connection to the data.p7m file using FileInputStream. If you know that the object stored in the file is of content type id-ct-authData:

    CMSAuthenticatedDataContentInfo authdata =
        new CMSAuthenticatedDataContentInfo(new FileInputStream("data.p7m"));
    
    

    However, if you do not know the content type in advance:

    CMSContentInfo cmsdata =
        CMSContentInfo.inputInstance(new FileInputStream("data.p7m"));
    if (cmsdata instanceof  CMSAuthenticatedDataContentInfo)
    {
    CMSAuthenticatedDataContentInfo authdata = 
                                 (CMSAuthenticatedDataContentInfo) cmsdata;
       // .....
    }
    
    
  2. To access the information stored in the CMS authenticated-data object:

    int version = authdata.getVersion().intValue();
    AlgorithmIdentifier macAlgID = authdata.getMACAlgID();
    byte[] macValue = authdata.getMAC();
    CMSContentInfo authContentInfo = authdata.getEnclosed();
    if (authData.getEnclosedContentType().equals(CMS.id_data))
        CMSDataContentInfo contentInfo = (CMSDataContentInfo)authContentInfo;
    
    
  3. Verify the MAC depending on the recipient information:

    authdata.verifyMAC(recipientPrivateKey, recipientCert);
    
    

    or

    authdata.verifyMAC(symmetricKey, keyIdentifier)
    
    

    or

    authdata.verifyMAC(symmetricKey, keyIdentifier, keyDate)
    
    

    or

    authdata.verifyMAC(symmetricKey, keyIdentifier, keyDate,
        otherKeyAttribute)
    
    
5.3.2.8.3 Detached Authenticated-data CMS Objects

While you can read in a detached authenticated-data object as shown earlier, the MAC verification will fail because the original object that was authenticated is not present. To resolve this, call the setEnclosed (..) method to set the authenticated content:

authdata.setEnclosed(contentInfo);

followed by MAC verification using the appropriate key exchange mechanism:

authdata.verifyMAC(...)

5.3.2.9 Wrapped (Triple or more) CMSContentInfo Objects

To wrap a CMSContentInfo object in another CMSContentInfo object, you simply pass an initialized CMSContentInfo object to the enclosing CMSContentInfo object through its constructor. Call the output (..) method of the enclosing outermost CMSContentInfo object to generate the nested object.

5.3.2.9.1 Reading a Nested (Wrapped) CMS Object

The approach to reading a nested object depends on whether you know the outermost content type in advance.

If you do not know the outermost content type in advance, call the static method:

CMSContentInfo.inputInstance( ... )

If you do know the outermost content type in advance, call the appropriate constructor:

new CMS***DataContentInfo( .... )

Then, recursively call the getEnclosed(..) method to extract the next inner object.

5.3.3 Constructing CMS Objects using the CMS***Stream and CMS***Connector Classes

The CMS**DataContentInfo classes provide the same functionality as the CMS***Stream classes. The primary advantage of the CMS***Stream classes over the CMS**DataContentInfo classes is that CMS objects can be created or read in one pass without having to accumulate all the necessary information.

Table 5-10 lists the content types of the CMS***Stream classes:

Table 5-10 The CMS***Stream Classes

Class Content Type
CMSDigestedDataInputStream, CMSDigestedDataOutputStream CMS.id_digestedData
CMSSignedDataInputStream, CMSSignedDataOutputStream CMS.id_signedData
CMSEncryptedDataInputStream, CMSEncryptedDataOutputStream CMS.id_encryptedData
CMSEnvelopedDataInputStream, CMSEnvelopedDataOutputStream CMS.id_envelopedData
CMSAuthenticatedDataInputStream, CMSAuthenticatedDataOutputStream CMS.id_ct_authData

Table 5-11 lists the content types of the CMS***Connector classes:

Table 5-11 The CMS***Connector Classes

Class Content Type
CMSDigestedDataInputConnector, CMSDigestedDataOutputConnector CMS.id_digestedData
CMSSignedDataInputConnector, CMSSignedDataOutputConnector CMS.id_signedData
CMSEncryptedDataInputConnector, CMSEncryptedDataOutputConnector CMS.id_encryptedData
CMSEnvelopedDataInputConnector, CMSEnvelopedDataOutputConnector CMS.id_envelopedData
CMSAuthenticatedDataInputConnector, CMSAuthenticatedDataOutputConnector CMS.id_ct_authData

5.3.3.1 Limitations of the CMS***Stream and CMS***Connector Classes

There are some limitations to CMS***Stream and CMS***Connector classes when processing objects:

  1. They cannot verify the digest of a detached CMS id-digestedData object.

  2. They cannot verify the signature of a detached CMS id-signedData object.

  3. They cannot verify the MAC of a detached CMS id-ct-authData object.


Caution:

Always use the CMS**DataContentInfo classes when processing detached objects.

5.3.3.2 Difference between CMS***Stream and CMS***Connector Classes

The CMS***OutputStream class is an output stream filter which wraps the data written to it within a CMS (RFC-2630) ContentInfo structure, whose BER encoding is then written to the underlying output stream. The CMS***OutputConnector class is an output stream filter which likewise wraps the data written to it within a CMS (RFC-2630) ContentInfo structure, except that only the values octets of the Content field of the ContentInfo structure (minus the explicit [0] tag) are written to the underlying output stream.

The CMS***InputStream class is an input stream filter which reads in a BER encoding of a CMS (RFC-2630) ContentInfo structure from the underlying output stream. The CMS***InputConnector class is an input stream filter that expects the underlying input stream to be positioned at the start of the value octets of the Content field of the ContentInfo structure (after the explicit [0] tag).

CMS***Connectors are useful in creating and reading nested objects.

5.3.3.3 Using the CMS***OutputStream and CMS***InputStream Classes

To construct an object:

  1. Create a CMS***OutputStream class of the appropriate content type. All the relevant parameters are passed through the constructor.

  2. Write the data being protected to the CMS***OutputStream created in step 1.

  3. After all the data is written, close the CMS***OutputStream created in step 1 .

To read an object:

  1. Create a CMS***InputStream class of the appropriate content type by passing the underlying input stream through the constructor.

  2. Read the protected data from the CMS***InputStream created in step 1 using the read() and read (byte[],...) methods.

  3. Invoke terminate() after you have finished reading data from the CMS***InputStream created in step 1. This completes the reading of the object.

  4. Invoke the appropriate methods to verify that the protected content is secure.

5.3.3.3.1 CMS id-data Object

The getData() method returns the data which can then be written to a CMS***OutputStream or CMS***OutputConnector.

5.3.3.3.2 CMS id-ct-receipt Object

The getReceiptData() method returns the encoded receipt which can then be written to a CMS***OutputStream or CMS***OutputConnector.

To read ESSReceipt data from the input stream:

byte[] rcptData = in.read(...);
ESSReceipt er = new ESSReceipt();
er.inputContent(rcptData);
5.3.3.3.3 CMS id-digestedData Object

You will not be able to verify the digest of a detached digested-data object. Setting the boolean parameter writeEContentInfo in the CMSSignedDataOutputStream constructor to false enables you to create a detached digested-data object.

5.3.3.3.4 CMS id-signedData Object

You will not be able to verify the signature of a detached signed-data object.

The CMSSignerInfoSpec class stores signer-specific information. For every signature you want to add, you will need to create a corresponding CMSSignerInfoSpec object which is then passed to the constructor.

Setting the boolean parameter createExternalSignatures in the CMSEncryptedDataOutputStream constructor to true enables you to create a detached signed-data object or external signatures.

To create a Certificate/CRL only object, do not pass any signer information to the CMSDigestedDataOutputStream constructor.

5.3.3.3.5 CMS id-encryptedData Objects

Setting the boolean parameter writeEncryptedOutput in the CMSDigestedDataOutputStream constructor to false enables you to create a detached encrypted-data object.

5.3.3.3.6 CMS id-envelopedData Objects

The CMSRecipientInfoSpec class stores recipient-specific information. For every recipient you want to add, you will need to create a corresponding CMSRecipientInfoSpec object which is then passed to the constructor.

Setting the boolean parameter writeContent in the CMSEnvelopedDataOutputStream constructor to false enables you to create a detached enveloped-data object.

Key Transport Key Exchange Mechanism

Use the CMSKeyTransRecipientInfoSpec class to store recipient information that uses the key transport key management mechanism.

Key Agreement Key Exchange Mechanism

This mechanism is not supported at this time.

Key Encryption (wrap) Key Exchange Mechanism

Use the CMSKEKRecipientInfoSpec class to store recipient information that uses the key wrap key management mechanism.

5.3.3.3.7 CMS id-ct-authData Objects

You will not be able to verify the MAC of a detached authenticated-data object.

Setting the boolean parameter detachEncapContent in the CMSAuthenticatedDataOutputStream constructor to true enables you to create a detached authenticated-data object.

5.3.3.4 Wrapping (Triple or more) CMS***Connector Objects

You use CMS***OutputConnectors to create nested objects.

Use the following code to create signed, enveloped, digested, or encrypted data and write it to the file nested.p7m:

// nested.p7m <--- FileOutputStream <--- CMSSignedDataOutputConnector
//     <--- CMSEnvelopedDataOutputConnector <---
//         <----  CMSDigestedDataOutputConnector <---
//             <----  CMSEncryptedDataOutputConnector <---
//                 <---- write the data (byte[] data)

FileOutputStream fos = new FileOutputStream("nested.p7m");
CMSSignedDataOutputConnector conn1 = 
    new CMSSignedDataOutputConnector(fos, .....);
CMSEnvelopedDataOutputConnector conn2 = 
    new CMSEnvelopedDataOutputConnector(conn1, ...);
CMSDigestedDataOutputConnector conn3 = 
    new CMSDigestedDataOutputConnector(conn2, ...);
CMSEncryptedDataOutputConnector conn4 = 
    new CMSEncryptedDataOutputConnector(conn3, ...);
OutputStream os = conn4.getOutputStream();
os.write(data);
os.close();

To read signed, enveloped, digested, or encrypted data stored in file nested.p7m:

// nested.p7m ---> FileInputStream ---> CMSSignedDataInputConnector -
//     ---> CMSEnvelopedDataInputConnector ---
//         -----> CMSDigestedDataInputConnector ---
//             ----> CMSEncryptedDataInputConnector ---
//                 ---> read the data (byte[] data)

FileInputStream fos = new FileInputStream("nested.p7m");
CMSSignedDataInputConnector conn1 =
    new CMSSignedDataInputConnector(fos, .....);
CMSEnvelopedDataInputConnector conn2 =
    new CMSEnvelopedDataInputConnector(conn1, ...);
CMSDigestedDataInputConnector conn3 =
    new CMSDigestedDataInputConnector(conn2, ...);
CMSEncryptedDataInputConnector conn4 =
    new CMSEncryptedDataInputConnector(conn3, ...);
InputStream is = conn4.getInputStream();
is.read(data);

5.4 The Oracle CMS API

The Oracle CMS API Reference (Javadoc) is available at:

Oracle CMS Java API Reference