Skip Headers

Oracle® Security Developer Tools Reference 10g Release 3 (10.1.3) B25372-01 |
| Home | Solution Area | Contents | Index

Previous | 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:

- Oracle CMS Features and Benefits

- Setting Up Your Oracle CMS Environment

- Developing Applications with Oracle CMS

- "The Oracle CMS API"

## 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:

- System Requirements

- Setting the CLASSPATH Environment Variable

### 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:

- Using the `CMSContentInfo` classes, which are relatively easy to utilize

- Using one of the following classes:

  - `CMSInputStream`

  - `CMSOutputStream`

  - `CMSInputConnector`

  - `CMSOutputConnector`

  These classes provide the ability to read and write CMS objects in a single pass, eliminating the need to accumulate the input data before writing any output.

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:

- CMS Object Types

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

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

### 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 `CMSSignedDataContentInfo`. For example, to create the `CMSSignedDataContentInfo` object, pass the contentInfo object (the data that is to be signed):

       CMSSignedDataContentInfo 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();
       CMSContentInfo sigContentInfo = sigData.getEnclosed();
       if (sigData.getEnclosedContentType().equals(CMS.id_data))
           CMSDataContentInfo contentInfo = (CMSDataContentInfo)sigContentInfo;

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 `CMSEncryptedDataContentInfo`. 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();
       CMSEncryptedDataContentInfo enc =
           new CMSEncryptedDataContentInfo(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:

       CMSEncryptedDataContentInfo encdata =
           new CMSEncryptedDataContentInfo(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 CMSEncryptedDataContentInfo)
       {
           CMSEncryptedDataContentInfo encdata =
               (CMSEncryptedDataContentInfo) 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.setOriginatorInfo(originatorInfo);
       env.setUnprotectedAttribs(unprotectedAttributes);

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 `CMSDigestedDataOutputStream` 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 `CMSSignedDataOutputStream` 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 `CMSDSignedDataOutputStream` constructor.

##### 5.3.3.3.5 CMS id-encryptedData Objects

Setting the boolean parameter `writeEncryptedOutput` in the `CMSEncryptedDataOutputStream` 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, and 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, and 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 Security Developer Tools CMS Java API Reference