Oracle® Security Developer Tools Reference
10g Release 2 (10.1.2) B15975-01 |
|
Previous |
Next |
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:
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".
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. |
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. |
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:
In order to use Oracle CMS, your system must have the Java Development Kit (JDK) version 1.2.2 or higher.
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
To set the CLASSPATH
on Windows:
In your Windows Control Panel, select System.
In the System Properties dialog, select the Advanced tab.
Click Environment Variables.
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.
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;
Click OK.
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
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:
Constructing CMS Objects using the CMS***ContentInfo Classes
Constructing CMS Objects using the CMS***Stream and CMS***Connector Classes
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.
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.
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. |
Perform the following steps to construct a CMS object:
Create the object of the specified content type.
Initialize the object.
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.
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:
Create an instance of CMSDataContentInfo
using the constructor that takes a byte array, documentBytes, that contains the information:
CMSDataContentInfo exdata = new CMSDataContentInfo(byte[] documentBytes)
Write the data object to a file, for example data.p7m
:
exdata.output(new FileOutputStream("data.p7m"));
Note: You cannot create aCMSDataContentInfo 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.
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; // ..... }
To access the information stored in the CMS data object:
byte[] docBytes = exdata.getData();
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.
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);
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 tonull .
|
To read a receipt object:
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; // ..... }
Access the information stored in the receipt object:
ASN1ObjectID contentType = getReceiptContentType(); byte[] sciBytes = rcptdata.getSignedContentIdentifier() byte[] osvBytes = rcptdata.getOriginatorSignatureValue();
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. |
Take the following steps to create a CMS digested-data object.
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);
Write the CMS digested-data object to a file named data.p7m
.
dig.output(new FileOutputStream("data.p7m"));
The steps you need to read a CMS digested-data
object depend on whether you know the object's content type.
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; // ..... }
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;
To verify the integrity of the protected data, verify the digest:
digData.verify();
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();
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.
Follow these steps to create a CMS signed-data object:
Create an instance of CMSDigestedDataContentInfo
. For example, to create the CMSDigestedDataContentInfo
object contentInfo that is to be signed:
CMSDigestedDataContentInfo sig = new CMSSignedDataContentInfo(contentInfo);
Add signatures:
X509 signerCert = new X509(new FileInputStream("name")); PrivateKey signerKey = CryptoUtils.inputPrivateKey(new FileInputStream("name"));
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);
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);
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);
Add any Certificates and CRLs:
sig.addCertificate (....) sig.addCRL (...)
Write the CMS signed-data object to a file, for example data.p7m
:
sig.output(new FileOutputStream("data.p7m"));
The steps you need to read a CMS signed-data object depend on whether you know the object's content type.
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; // ..... }
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;
Verify the signature using the signer's public key certificate:
sigData.verify(signerCert);
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();
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);
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".
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.
To create an encrypted-data
object:
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);
Write the encrypted-data
object to a file, say data.p7m
:
enc.output(new FileOutputStream("data.p7m"));
The steps you need to read an encrypted-data
object depend on whether you know the object's content type.
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; // ..... }
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;
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);
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 |
To create an enveloped-data
object:
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);
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)
Set any optional arguments:
env.setAuthenticatedAttributes(authenticatedAttributes, CMS.md5); env.setOriginatorInfo(originatorInfo); env.setUnauthenticatedAttributes(unauthenticatedAttributes);
Write the CMS enveloped-data
object to a file, say data.p7m
:
enc.output(new FileOutputStream("data.p7m"));
The steps you need to read the object depend on whether you know the object's content type.
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; // ..... }
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();
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; // ... }
This mechanism supports the use of either IssuerAndSerialNo
or SubjectKeyIdentifier
as the recipient identifier.
Oracle CMS supports CMS3DESWrap and CMSRC2Wrap algorithms. Mixed mode wrapping is not supported; for example, 3DES keys cannot be RC2-wrapped.
Note: Using theOtherKeyAttribute could cause interoperability problems.
|
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(............);
The class CMSAuthenticatedDataContentInfo
represents an object of type id-ct-authData as defined by the constant CMS.id_ct_authData
.
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 |
|
|
Take the following steps to create an authenticated-data object:
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);
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)
Set any optional arguments:
auth.setAuthenticatedAttributes(authenticatedAttributes, CMS.md5); auth.setOriginatorInfo(originatorInfo); auth.setUnauthenticatedAttributes(unauthenticatedAttributes);
Write the CMS authenticated-data object to a file, say data.p7m
:
auth.output(new FileOutputStream("data.p7m"));
The steps you need to read the object depend on whether you know the object's content type:
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; // ..... }
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;
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)
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(...)
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.
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.
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 |
There are some limitations to CMS***Stream and CMS***Connector classes when processing objects:
They cannot verify the digest of a detached CMS id-digestedData
object.
They cannot verify the signature of a detached CMS id-signedData
object.
They cannot verify the MAC of a detached CMS id-ct-authData
object.
Caution: Always use the CMS**DataContentInfo classes when processing detached objects. |
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.
To construct an object:
Create a CMS***OutputStream class of the appropriate content type. All the relevant parameters are passed through the constructor.
Write the data being protected to the CMS***OutputStream created in step 1.
After all the data is written, close the CMS***OutputStream created in step 1 .
To read an object:
Create a CMS***InputStream class of the appropriate content type by passing the underlying input stream through the constructor.
Read the protected data from the CMS***InputStream created in step 1 using the read()
and read (byte[],...)
methods.
Invoke terminate()
after you have finished reading data from the CMS***InputStream created in step 1. This completes the reading of the object.
Invoke the appropriate methods to verify that the protected content is secure.
The getData()
method returns the data which can then be written to a CMS***OutputStream or CMS***OutputConnector.
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);
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.
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.
Setting the boolean parameter writeEncryptedOutput
in the CMSDigestedDataOutputStream
constructor to false enables you to create a detached encrypted-data
object.
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.
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);