public class SignedData extends SignedDataStream implements Content
SignedData.
Each CMS content type is associated with a specific object identifier, derived from PKCS#7:
pkcs-7 OBJECT IDENTIFIER ::=
{ iso(1) member-body(2) US(840) rsadsi(113549)
pkcs(1) 7 }
The object identifier for the SignedData content type is
defined as:
signedData OBJECT IDENTIFIER ::= { pkcs-7 2 }
which corresponds to the OID string "1.2.840.1.113549.1.7.2".
The CMS Cryptographic Message Syntax
(RFC 2630) specifies the SignedData
content type for providing a syntax for building digital signatures. Content
of any type may be signed by any number of signers in parallel. For each
signer, a message digest is computed on the content (and any additional
authenticating information) with a signer-specific message-digest algorithm.
Subsequently, again for each signer, the corresponding message digest from the
previous step is encrypted with the particular signer´s private key and
- together with some signer-specific information - collected into a
SignerInfo value. Finally all created SignerInfo values
are collected together with the content for forming a SignedData
structure.
This class implements the SignedData structure resulting from
the last step described above. The SignedData type is defined
as ASN.1 SEQUENCE type containing the following components (see RFC 2630):
SignedData ::= SEQUENCE {
version CMSVersion,
digestAlgorithms DigestAlgorithmIdentifiers,
encapContentInfo EncapsulatedContentInfo,
certificates [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
signerInfos SignerInfos }
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
CertificateSet ::= SET OF CertificateChoices
CertificateChoices ::= CHOICE {
certificate Certificate, -- See X.509
extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete
attrCert [1] IMPLICIT AttributeCertificate } -- See X.509 & X9.57
}
CertificateRevocationLists ::= SET OF CertificateList
SignerInfos ::= SET OF SignerInfo
The digestAlgorithms field contains the object identifiers of
the message digest algorithms used by the several signers for digesting the
content that is supplied in the contentInfo field. The
optional certificates field shall contain certificate chains
for all the signers of the signerInfos field; also attribute
certificates maybe included. The optional crls field may supply
information about the revocation status of the certificates specified in the
certificates field.
And finally, the signerInfos field collects per-signer
information for all parciticipated signers including the signer-specific digital
signatures of the content.
If there are no signers on the content, the signed-data content type may be used for disseminating certificates and certificate-revocation lists.
Verifying some received signature(s) is done according to the signature algorithm used (rsaEncryption or DSA).
For more information consult the RSA RFC 2630.
When creating a SignedData object for the content to be signed by using
the SignedData(byte[] content, int mode)
constructor, the transimission mode has to be specified. You may use an alternative
constructor for additionally
specifying the content type of the inherent EncapsulatedContentInfo; default is
id-data. If the mode is set to SignedData.IMPLICIT the content data will be included
in the SignedData message to be transmitted, but it will be not included
if the mode is set to SignedData.EXPLICIT. However, in both cases the content data
has to be supplied when creating the SignedData object, because it is
needed for the digest computation:
byte[] data = ...; SignedData signed_data = new SignedData(data, SignedData.IMPLICIT);respectively
SignedData signed_data = new SignedData(data, SignedData.EXPLICIT);In contrast to the stream-variant of the CMS SignedData type (implemented by the
SignedDataStream class),
where explicit and implicit mode require a different proceeding, both cases may be
handled in the same way, when using the non-stream variant. In this way, the
steps of creating a SignedData object and preparing it for transmission
can be summarized in the following way (to simplify matters, we will assume not to include
certificate revocation lists):
SignedData object thereby supplying the content data
to be signed and specifying the transmission mode to be used (either
SignedData.IMPLICIT or SignedData.EXPLICIT):
byte[] data = ...;
int mode = ...;
SignedData signed_data = new SignedData(data, mode);
setCertificates method. The certificates are supplied
as array of X509Certificates
an shall contain chains from a known top-level CA to all the signers in the
SignerInfo field:
signed_data.setCertificates(certificates);
SignerInfo
object, optionally supply it with attributes, and add it to the SignedData structure
by calling the addSignerInfo method:
SignerInfo signer1 = ...;
signed_data.addSignerInfo(signer1);
SignerInfo signer2 = ...;
signed_data.addSignerInfo(signer2);
...
You alternatively may collectively add all signers by utilizing the
setSignerInfos method.
toASN1Object method, the latter by using the getEncoded method:
ASN1Object obj = signed_data.toASN1Object();
respectively
byte[] encoding = signed_data.getEncoded();
You alternatively may use a proper writeTo method of the parent
SignedDataStream class for immediately
encoding this SignedData object to an output stream. When using writeTo in
implicit mode, you additionally have the possibility of specifying a particular blockSize
for forcing an indefinite constructed encoding of the inherent content data bytes, instead of
of the default definite primitive encoding, e.g:
0x24 0x80
0x04 0x02 0x01 0xAB
0x04 0x02 0x23 0x7F
0x04 0x01 0xCA
0x00 0x00
instead of:
0x04 0x05 0x01 0xAB 0x23 0x7F 0xCA
for encoding the five data bytes 0x01 0xAB 0x23 0x7F 0xCA. The indefinte
constrcuted encoding scheme may be preferable when intending to be compatible to the
encoding practice of some particular application (for instance some versions of
Netscape Navigator).
Unlike the procedure of newly creating a SignedData object to be transmitted, even when
using this non-stream implementation of the SignedData content type, it
has to be distinguished between IMPLICIT and EXPLICIT mode when parsing a received
SignedData message. When operating in IMPLICIT mode, the content data is included in
the received SignedData object, and so the parsing immediately may be
performed when creating a SignedData object from the - already decoded -
SignedData ASN1Object by calling the SignedData(ASN1Object obj)
constructor. On the other side, when
the content data has been transmitted outside the SignedData message (EXPLICIT mode), the
SignedData(byte[] content, AlgorithmID[] hashAlgorithms) constructor
has be to used for initializing the new SignedData object with content data and
hash algorithms to be used for digest computation; and the decoding has to be performed
explicitly by calling the decode method.
The initialization is necessary for computing the digests on the content data for the
digest algorithms of all participated signers. Later, during signature verification the
digest value computaion is finished and the results are used for checking the signatures
with the signer´s public keys.
All further steps are the same for implicit and explicit mode, and so the proceeding
necessary for parsing a received SignedData message and verifying the signatures
may be summarized as follows:
ASN1Object obj = DerCoder.decode(received_message);
SignedData(ASN1Object obj)
constructor for creating a SignedData object and implicitly parsing the
the supplied ASN.1 structure:
SignedData signedData = new SignedData(obj);
On the other hand, if the ASN1Object resulting from step 1 above represents an
explicit SignedData object, use the
SignedData(byte[] content, AlgorithmID[] hashAlgorithms)
constructor for initializing a new SignedData object with content data and
digest algorithms for hash computation, and subsequently explicitly perform
the decoding by means of the decode
method (assuming that two hash algorithms are used: SHA and MD5):
AlgorithmID[] algIDs = { AlgorithmID.sha1, AlgorithmID.md5 };
SignedData signedData = new SignedData(content_data, algIDs);
signedData.decode(obj);
// get the signer infos
SignerInfo[] signerInfos_ = signed_data.getSignerInfos();
// verify the signatures
for (int i=0; i < signerInfos_.length; i++) {
try {
// verify the signature for SignerInfo at index i
X509Certificate signer_cert = signed_data.verify(i);
// if the signature is OK the certificate of the signer is returned
System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
} catch (SignatureException ex) {
// if the signature is not OK a SignatureException is thrown
System.out.println("Signature ERROR from signer: "+signed_data.getCertificate(signerInfos_[i].getIssuerAndSerialNumber()).getSubjectDN());
}
}
byte[] data = signedData.getContent();
SignedDataStream class should be used.Content,
ContentInfo,
SignerInfo,
SignedDataStreamblockSize_, certSet_, contentType_, crls_, EXPLICIT, IMPLICIT, inputStream_, mode_, securityProvider_, signerInfos_, thisObject_, version_| Modifier | Constructor and Description |
|---|---|
protected |
SignedData()
Default constructor for dynamic object creation in ContentInfo.
|
|
SignedData(ASN1Object obj)
Creates a CMS
SignedData from an ASN1Object. |
|
SignedData(byte[] content,
AlgorithmID[] hashAlgorithms)
Creates a new SignedData from a byte array holding the content that
has been transmitted by other means, and an array specifying the hash
algorithms to be used for digesting.
|
|
SignedData(byte[] content,
int mode)
Creates a SignedData object from a byte array containing the content data to be signed.
|
|
SignedData(byte[] content,
ObjectID contentType,
int mode)
Creates a SignedData object from a byte array containing the content data to be signed.
|
|
SignedData(java.io.InputStream is)
Creates a new SignedData where the DER encoded data
is read from the given InputStream.
|
|
SignedData(ObjectID contentType)
Creates a new SignedData object without any content.
|
| Modifier and Type | Method and Description |
|---|---|
void |
addSignerInfo(SignerInfo signerInfo)
Adds a SignerInfo object to this SignedData.
|
void |
decode(ASN1Object obj)
Decodes the SignedData supplied as ASN1Object.
|
void |
decode(java.io.InputStream is)
Reads and decodes the SignedData from a DerInputStream.
|
byte[] |
getContent()
Returns the content.
|
byte[] |
getEncoded()
Returns the DER encoding of this SignedData object as byte array.
|
java.io.InputStream |
getInputStream()
Returns an InputStream from which the contents of this object can be read.
|
void |
setInputStream(java.io.InputStream is)
Sets the InputStream which holds the content to sign.
|
protected void |
setupMessageDigests()
Sets up the message digests for hash computation.
|
protected ASN1Object |
toASN1Object(int blockSize)
Returns this SignedData as ASN1Object.
|
java.lang.String |
toString(boolean detailed)
Returns a string giving some - if requested - detailed information
about this
SignedData object. |
getAttributeCertificates, getBlockSize, getCertificate, getCertificates, getCertificateSet, getContentType, getCRLs, getDigestAlgorithms, getEncapsulatedContentType, getMessageDigest, getMode, getSignedDigest, getSignerInfos, getVersion, getX509Certificates, notifyEOF, setBlockSize, setCertificates, setCertificateSet, setCRLs, setMessageDigest, setSignerInfos, toASN1Object, toString, verify, verify, verify, verifyAndValidate, verifyAndValidate, writeTo, writeToclone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitgetBlockSize, getContentType, setBlockSize, toASN1Objectprotected SignedData()
public SignedData(ObjectID contentType)
contentType - the contentType of the datapublic SignedData(java.io.InputStream is)
throws CMSParsingException,
java.io.IOException
is - the InputStream holding a DER encoded CMS SignedData objectjava.io.IOException - if an I/O error occurs during reading from the InputStreamCMSParsingException - if an error occurs while parsing the objectpublic SignedData(byte[] content,
int mode)
content - the content data to be signedmode - IMPLICIT if the message shall be included in the DER encoding,
EXPLICIT otherwisepublic SignedData(byte[] content,
ObjectID contentType,
int mode)
Use this constructor for signing content having any other type than CMS (PKCS#7) id-data.
In such cases typically the given byte array will supply the DER encoding of a
particular content object to be signed. The PKIX Time Stamp protocol, for instance,
defines a TSTInfo structure to be signed by using a CMS SignedData object. Assuming a
Java class implementing the TSTInfo type it may be prepared for being
signed with the SignedData type in a way similar to:
TSTInfo tstInfo = ...; ... // encode the TSTInfo byte[] encodedTSTInfo = DerCoder.encode(tstInfo.toASN1Object()); // now sign the TSTInfo: ObjectID oid = ObjectID.tstInfo; int mode = SignedData.IMPLICIT; SignedData signedData = new SignedDataStream(enodedTSTInfo, oid, mode); ...
content - the content data to be signedcontentType - the contentType for the inherent EncapsulatedContentInfomode - IMPLICIT if the message shall be included in the DER encoding,
EXPLICIT otherwisepublic SignedData(ASN1Object obj) throws CMSParsingException
SignedData from an ASN1Object.
Do not use this constructor for supplying the content value
to be signed. This constructor may be used by the recipient for parsing an
already exisiting SignedData object, supplied as ASN1Object
that may have been created by calling
toASN1Object.
Use the SignedData(byte[] content, int mode)
or SignedData(byte[] content,
ObjectID contentType, int mode) constructors for supplying the content value
to be signed when creating a SignedData object.
This constructor only shall be used for parsing an ASN1Object that represents
a SignedData object with included content data bytes (implicit mode).
To initialize a SignedData object for parsing an explicit SignedData message where the
content data is not included, use the
SignedData(byte[] content, AlgorithmID[] hashAlgorithms)
constructor, and perform the decoding explicitly by calling the
decode method.
obj - the CMS SignedData as ASN1Object representing an implicit SignedData objectCMSParsingException - if a parsing error occurspublic SignedData(byte[] content,
AlgorithmID[] hashAlgorithms)
throws java.security.NoSuchAlgorithmException
Do not use this constructor for supplying the content value
to be signed. This constructor may be used by the recipient for initializing
the digest computation for an already existing explicit SignedData message
where the content data is not included. In contrast to
the equivalent constructor of the parent SignedDataStream class, this constructor not only initializes
the digest computation, but also already computes the digests for all supplied
digest algorithms. Later, during signature verification these digest values have
to be compared against the hash values resulting from decrypting the encrypted
digests with the signer´s public keys.
For subsequently performing the decoding
of the received explicit SignedData object, use the decode
method:
// the received explicit SignedData structure as ASN1Object: ASN1Object = DerCoder.decode(received_message); //initialize - and perform - digest computaion: SignedData signedData = new SignedData(content_data, hashAlgorithms); //parse the received SignedData ASN1Object signedData.decode(obj);
A sender shall use the SignedData(byte[] content, int mode)
constructor for supplying the content value to be signed when creating a
SignedData object.
For parsing an implicit SignedData message, use the SignedData(ASN1Object obj) constructor.
content - the content transmitted by other meanshashAlgorithms - the hash algorithms used by the participated signers for digesting the
content datajava.security.NoSuchAlgorithmException - if any of the supplied hash algorithms is not supportedpublic void addSignerInfo(SignerInfo signerInfo) throws java.security.NoSuchAlgorithmException
Unlike the same-name method in the SignedDataStream super class this
method already performs the digest computation for the given SignerInfo.
addSignerInfo in class SignedDataStreamsignerInfo - the SignerInfo to addjava.security.NoSuchAlgorithmException - if there is no implementation for the message digest algorithm
specified in the signerInfoSignerInfoprotected void setupMessageDigests()
throws java.security.NoSuchAlgorithmException
java.security.NoSuchAlgorithmException - if any of the participated digest algorithms
is not supportedpublic void decode(ASN1Object obj) throws CMSParsingException
SignedData(byte[] content, AlgorithmID[] hashAlgorithms)
constructor for initializing it for hash computation:
// the received explicit SignedData structure as ASN1Object: ASN1Object = DerCoder.decode(received_message); //initialize - and perform - digest computaion: SignedData signedData = new SignedData(content_data, hashAlgorithms); //parse the received SignedData ASN1Object signedData.decode(obj);
decode in interface Contentobj - the CMS SignedData as ASN1ObjectCMSParsingException - if an error occurs while parsing the objectpublic void decode(java.io.InputStream is)
throws java.io.IOException,
CMSParsingException
DerInputStream,
internally a DerInputStream is created before parsing the data.
This method provides an alternative to the decoding
method where the SignedData to be decoded is given as ASN1Object.
decode in interface ContentStreamdecode in class SignedDataStreamis - the InputStream holding a DER encoded CMS SignedData objectjava.io.IOException - if an I/O error occurs during reading from the InputStreamCMSParsingException - if an error occurs while parsing the objectpublic void setInputStream(java.io.InputStream is)
SignedDataStream parent class.setInputStream in class SignedDataStreamis - InputSteam holding the content to signpublic java.io.InputStream getInputStream()
This method only overrides the corresponding getInputStream method
of the parent SignedDataStream
class for returning the content of this SignedData object. There should be
no real necessity for using this method since the content data bytes immediately
can be obtained by the getContent method.
However, in contrast to the equivalent getInputStream method of the
parent SignedDataStream class, this method may be called arbitrarly often;
it only returns a ByteArrayInputStream that is initialized with the content content bytes.
getInputStream in class SignedDataStreamSignedData objectpublic byte[] getContent()
protected ASN1Object toASN1Object(int blockSize) throws CMSException
If blockSize is set to a positive value the ASN1Object returned
by this method is prepared for forcing an indefinite constructed encoding of the inherent content
data bytes, instead of the default definite primitive encoding, e.g:
0x24 0x80
0x04 0x02 0x01 0xAB
0x04 0x02 0x23 0x7F
0x04 0x01 0xCA
0x00 0x00
instead of:
0x04 0x05 0x01 0xAB 0x23 0x7F 0xCAfor encoding the five data bytes
0x01 0xAB 0x23 0x7F 0xCA. The indefinte
constrcuted encoding scheme may be preferable when intending to be compatible to the
encoding practice of some particular application (for instance some versions of
Netscape Navigator).
The inherent data is encoded by means of the primitive definite method when the
blockSize value is not positive.toASN1Object in class SignedDataStreamblockSize - the block size defining the encoding scheme - and specifying the
length of each primitive encoded octet string component, if positiveCMSException - if the ASN1Object could not be createdpublic byte[] getEncoded()
throws CMSException
writeTo(OutputStream os, int blockSize) method
of the parent SignedDataStream class.CMSException - if an encoding error occurspublic java.lang.String toString(boolean detailed)
SignedData object.toString in interface ContentStreamtoString in class SignedDataStreamdetailed - - whether or not to give detailed information