iaik.cms
Class SignedDataStream

java.lang.Object
  extended by iaik.cms.SignedDataStream
All Implemented Interfaces:
EncodeListener, ContentStream, EOFListener, java.util.EventListener
Direct Known Subclasses:
SignedData, SignedDataInOutStream, SMimeSigned

public class SignedDataStream
extends java.lang.Object
implements ContentStream, EOFListener, EncodeListener

This class represents the stream-implementation of the CMS content type 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.113549.1.7.2".

The Cryptographic Message Syntax (CMS) (RFC 5652) 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 signature is computed on the content (and any additional authenticating information) and -- together with some signer-specific information -- collected into a SignerInfo object. Finally all created SignerInfo objects 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 5652):

 SignedData ::= SEQUENCE {
   version CMSVersion,
   digestAlgorithms DigestAlgorithmIdentifiers,
   encapContentInfo EncapsulatedContentInfo,
   certificates [0] IMPLICIT CertificateSet OPTIONAL,
   crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
   signerInfos SignerInfos }

 
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
CertificateSet ::= SET OF CertificateChoices CertificateChoices ::= CHOICE { certificate Certificate, extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete v2AttrCert [2] IMPLICIT AttributeCertificateV2, other [3] IMPLICIT OtherCertificateFormat } OtherCertificateFormat ::= SEQUENCE { otherCertFormat OBJECT IDENTIFIER, otherCert ANY DEFINED BY otherCertFormat }
RevocationInfoChoices ::= SET OF RevocationInfoChoice RevocationInfoChoice ::= CHOICE { crl CertificateList, other [1] IMPLICIT OtherRevocationInfoFormat } OtherRevocationInfoFormat ::= SEQUENCE { otherRevInfoFormat OBJECT IDENTIFIER, otherRevInfo ANY DEFINED BY otherRevInfoFormat }
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; attribute certificates or other certificates maybe included. The optional crls field may supply information (e.g. by means of X.509 crls or other revocation infos) 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 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.

For more information see RFC 5652.


When creating a SignedDataStream object for the content to be signed by using the SignedDataStream(InputStream is, 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 SignedDataStream.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 SignedDataStream.EXPLICIT. However, in both cases the content data has to be supplied when creating the SignedDataStream object, because it is needed for the digest computation:

 InputSrteam[] data_stream = ...; // the content data supplying input stream
 SignedDataStream signed_data = new SignedDataStream(data_stream, SignedDataStream.IMPLICIT);
 
respectively
 SignedDataStream signed_data_stream = new SignedDataStream(data_stream, SignedDataStream.EXPLICIT);
 
In contrast to the non-stream-variant of the CMS SignedData type (implemented by the SignedData class), where explicit and implicit mode can be handled in the same way when creating a SignedData object, they require a different proceeding for the stream-supporting SignedDataStream class. In this way, the steps for creating a SignedDataStream object and preparing it for transmission can be summarized as followed (to simplify matters, we will assume not to include certificate revocation lists):
  1. Create a new SignedDataStream object thereby supplying the content data to be signed as input stream and specifying the transmission mode to be used (either SignedDataStream.IMPLICIT or SignedDataStream.EXPLICIT):
         InputStream data_stream = ...;
         int mode = ...;
         SignedDataStream signed_data = new SignedDataStream(data_stream, mode);
         
  2. Set the certificates of all the signers by calling the setCertificates method. The certificates are supplied as array of instances iaik.x509.X509Certificate (and/or iaik.x509.attr.AttributeCertificate and/or iaik.cms.OtherCertificate):
         signed_data.setCertificates(certificates);
         
  3. For each participated signer, create a SignerInfo object, optionally supply it with attributes, and add it to the SignedDataStream 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.
    When actually adding a SignerInfo the digest computation is initialized by wrapping a digest stream for the digest algorithm of the SignerInfo around the data carrying input stream.

  4. If the mode chosen in step 1 when creating the SignedDataStream object has been SignedDataStream.EXPLICIT, now get and read the data from the data carrying input stream. Since in explicit mode the content data is not included in the SignedData message, the stream has to be read before actually performing the encoding. When reading the stream, the data is piped to all the signer specific digest streams for updating the hash computation.
         if (mode == SignedDataStream.EXPLICIT) {
           InputStream data_is = signed_data.getInputStream();
           byte[] buf = new byte[2048];
           int r;
           while ((r = data_is.read(buf)) > 0) {
             // do something useful 
           }
         }
         
    When using the implicit mode, do not explicitly read data from the input stream at all! This will be done automatically during the last step when performing the encoding.

  5. Use a proper writeTo method for BER encoding the the SignedDataStream object and writing it to an output stream. You optionally may specify a particular block size for splitting the data encoding:
         int blockSize = ...; 
         signed_data.writeTo(output_stream, blockSize);
         
    respectively
         signed_data.writeTo(output_stream);
         
    It is recommended only to use the writeTo method where a particular block size can be specified, because it is the intended purpose of this stream-supporting SignedData implementation to handle large amounts of data. When no block size is specified whole the content data is encoded as one primitive definite octet string, which advantageously may be done when using the non-stream supporting SignedData implementation. When a positive block size is specified for encoding the SignedData to a stream, the content data is BER encoded as indefinite constructed octet string being composed of a series of definite primitive encoded octet strings of blockSize length, 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. Of course, in practice block based encoding makes only sense when specifying a bigger block size (e.g. 4096 -- or even more -- to encode the data in blocks of 4096 bytes).

Again, it has to be distinguished between IMPLICIT and EXPLICIT mode when using the SignedDataStream implementation for 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 SignedDataStream object from the DER encoded SignedData object by calling the SignedDataStream(InputStream is) constructor.
On the other side, when the content data has been transmitted outside the SignedData message (EXPLICIT mode) there are two alternative ways for parsing the SignedData and verifying the signature(s):

The individual steps necessary for parsing a received SignedData message and verifying the signatures may be summarized as follows:

  1. If the InputStream supplies the BER encoding of an implicit SignedData object, use the SignedDataStream(InputStream is) constructor for creating a SignedDataStream object and implicitly performing the decoding:
         SignedDataStream signedData = new SignedDataStream(encoded_stream);
         
    On the other hand, if the BER encoding represents an explicit SignedData object, use one of the following alternatives:
  2. Get the data carrying input stream and entirely read the data from the stream. This has to be performed for both implicit and explicit modes at exactly this state of the parsing procedure. In both cases the constructor has initialized the digest computation by wrapping digest streams around the content data stream for all participated digest algorithms, either implicitly parsed from the supplied SignedData object, or explicitly supplied as an array of hash algorithm IDs. When now reading the stream, the data is piped through the digest streams for updating the hash computation:
         InputStream dataIs = signedData.getInputStream();
         byte[] buf = new byte[2048];
         int r;
         while ((r = dataIs.read(buf)) > 0) {
           // do something useful 
         }
         
  3. When dealing with an explicit message and using alternative 1(a) from above now explicitly perform the decoding by calling the decode method:
         signedData.decode(encoded_stream);
         
  4. Get the SignerInfos from the SignedData object and perform the signature verification:
         // get the signer infos
         SignerInfo[] signer_infos = signed_data.getSignerInfos();
         // verify the signatures
         int numberOfSigners = signer_infos.length;     
         if (numberOfSigners == 0) {
           System.out.println("Warning: Unsigned message (no SignerInfo included)!");
         } else {
           for (int i=0; i < numberOfSigners; 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(signer_infos[i].getSignerIdentifier()).getSubjectDN());
             }
           }  
         } 
         
The simple example above verifies the correctness of the signature value(s) and dumps the result to System.out. In practice an application will require some more sophisticated error processing.

See Also:
ContentStream, ContentInfoStream, SignerInfo, SignedData

Field Summary
protected  int blockSize_
          The block size for block oriented stream encoding.
protected  CertificateSet certSet_
          Repository for the signer certificates.
protected  ObjectID contentType_
          The content type of the to-be-signed content.
protected  RevocationInfoChoices crls_
          Repository for any included CRLs.
protected  EncapsulatedContentInfoStream encapContentInfo_
          The inherent EncapsualtedContentInfo.
static int EXPLICIT
          Mode where the signed content is NOT included in the SignedData object (the content is transferred by other means).
static int IMPLICIT
          Mode where the signed content is included in the SignedData object.
protected  java.io.InputStream inputStream_
          An InputStream holding the data.
protected  int mode_
          The mode specifying if the signed message is included in the Signature (IMPLICIT), or if is not transported within the Signature (EXPLICIT).
protected  SecurityProvider securityProvider_
          The SecurityProvider to be used.
protected  java.util.Vector signerInfos_
          Repository for the SignerInfos.
protected  DerInputStream thisObject_
          An InputStream from which a DER encoded SignedData object is read.
protected  int version_
          The version number, default 1.
 
Constructor Summary
protected SignedDataStream()
          Default constructor for dynamic object creation in ContentInfo.
  SignedDataStream(java.io.InputStream is)
          Creates a new SignedDataStream from a BER encoded SignedData object which is read from the given InputStream.
  SignedDataStream(java.io.InputStream data_is, AlgorithmID[] hashAlgorithms)
          Creates a new SignedDataStream from an InputStream holding the content that has been transmitted by other means, and an array specifying the hash algorithms to be used for digesting.
  SignedDataStream(java.io.InputStream data_is, AlgorithmID[] hashAlgorithms, SecurityProvider securityProvider)
          Creates a new SignedDataStream from an InputStream holding the content that has been transmitted by other means, and an array specifying the hash algorithms to be used for digesting.
  SignedDataStream(java.io.InputStream data_is, int mode)
          Creates a SignedDataStream object from an input stream supplying the data to be signed.
  SignedDataStream(java.io.InputStream data_is, ObjectID contentType, int mode)
          Creates a SignedDataStream object from an input stream supplying the data to be signed.
  SignedDataStream(java.io.InputStream is, SecurityProvider securityProvider)
          Creates a new SignedDataStream from a BER encoded SignedData object which is read from the given InputStream.
  SignedDataStream(ObjectID contentType)
          Creates a new SignedDataStream object without any content.
 
Method Summary
 void addCertificates(java.security.cert.Certificate[] certificates)
          Adds the given certificates.
 void addCRLs(X509CRL[] crls)
          Adds the given certificate-revocation information objects.
 void addDigestAlgorithm(AlgorithmID digestAlg)
          Adds a digest algorithm.
 void addSDSEncodeListener(SDSEncodeListener sdsEncodeListener)
          Adds an SDSEncodeListener for this SignedDataStream.
 void addSignerInfo(SignerInfo signerInfo)
          Adds a SignerInfo object to this SignedData.
 void clearSignatures(boolean applicationSet, boolean clearMessageDigestAttributes)
          Clears the signature values of all included SignerInfos.
 void decode(java.io.InputStream is)
          Reads and decodes the a BER encoded SignedData from the given input stream.
 void encodeCalled(ASN1Object obj, int id)
          This method implements the EncodeListener interface.
 AttributeCertificate[] getAttributeCertificates()
          Returns the attribute certificates included in this SignedData.
 int getBlockSize()
          Gets the block size defining the length of each definite primitive encoded octet string component.
 X509Certificate getCertificate(CertificateIdentifier signerIdentifier)
          Tries to find the signer certificate specified by the given CertificateIdentidier.
 java.security.cert.Certificate[] getCertificates()
          Returns all certificates included.
 X509Certificate[] getCertificates(CertificateIdentifier signerIdentifier)
          Tries to find the signer certificate chain specified by the given CertificateIdentidier.
 CertificateSet getCertificateSet()
          Gets the certificateSet holding all certificates included in this SignedData.
 ObjectID getContentType()
          Returns the content type this class implements.
 X509CRL[] getCRLs()
          Returns all the cerificate-revocation lists included in this SignedData object.
 AlgorithmID[] getDigestAlgorithms()
          Returns a collection of message-digest algorithm identifiers.
 ObjectID getEncapsulatedContentType()
          Returns the content type the inherent EncapsulatetContentInfo represents.
 java.io.InputStream getInputStream()
          Returns an InputStream from where the signed content may be read.
 byte[] getMessageDigest(AlgorithmID digestAlgorithm)
          Returns the message digest calculated for a specific algorithm.
 int getMode()
          Returns the mode of this SignedData.
 RevocationInfoChoices getRevocationInfoChoices()
          Gets the crls (RevocationInfoChoices) included in this SignedData.
 SecurityProvider getSecurityProvider()
          Gets the SecurityProvider installed for this SignerInfo.
 byte[] getSignedDigest(int signerInfoIndex)
          Returns the message digest included in the authenticated attributes.
 SignerInfo getSignerInfo(CertificateIdentifier signerIdentifier)
          Searches for the SignerInfo identified by the given signer id.
 SignerInfo getSignerInfo(X509Certificate signerCertificate)
          Searches for the SignerInfo identified by the given certificate.
 int getSignerInfoIndex(X509Certificate signerCertificate)
          Searches for the index of the signerInfo belonging to the given signer certificate.
 SignerInfo[] getSignerInfos()
          Returns all the signer infos included in this SignedData object.
 int getVersion()
          Returns the syntax version number (1 or 3 or 4).
 X509Certificate[] getX509Certificates()
          Returns the X.509 public key certificates included.
 void notifyEOF()
          This method implements the EOFListener interface for performing the final decoding.
 boolean removeMessageDigest(AlgorithmID digestAlgorithm)
          This method can be used to remove a message digest.
 boolean removeSignerInfo(CertificateIdentifier signerIdentifier)
          Removes the SignerInfo(s) with the given id from the SignerInfo list.
 void setBlockSize(int blockSize)
          Sets the block size for defining the length of each definite primitive encoded octet string component.
 void setCertificates(java.security.cert.Certificate[] certificates)
          Sets the certificates of the several signers.
 void setCertificateSet(CertificateSet certSet)
          Sets the certificateSet to be included.
 void setCRLs(X509CRL[] crls)
          Sets a set of certificate-revocation information objects.
 void setInputStream(java.io.InputStream is)
          Sets the InputStream which holds the content to sign/verify.
 void setMessageDigest(AlgorithmID digestAlgorithm, byte[] digest)
          This method can be used to set an externally calculated message digest.
 void setRevocationInfoChoices(RevocationInfoChoices crls)
          Sets the crls (RevocationInfoChoices) to be included.
 void setSDSEncodeListener(SDSEncodeListener sdsEncodeListener)
          Sets an SDSEncodeListener for this SignedDataStream.
 void setSecurityProvider(SecurityProvider securityProvider)
          Sets the SecurityProvider for this SignerInfo.
 void setSignerInfos(SignerInfo[] signerInfos)
          Sets a collection of per-signer information.
 ASN1Object toASN1Object()
          Returns this SignedData as ASN1Object.
protected  ASN1Object toASN1Object(int blockSize)
          Returns this SignedData as ASN1Object where a constructed OCTET STRING is used for encoding the content.
 java.lang.String toString()
          Returns a string giving some information about this SignedDataStream object.
 java.lang.String toString(boolean detailed)
          Returns a string giving some - if requested - detailed information about this SignedDataStream object.
 X509Certificate verify(int signerInfoIndex)
          Verifies the signature that has been created by the signer at signerInfoIndex.
 void verify(java.security.PublicKey publicKey, int signerInfoIndex)
          Uses the provided public key for verifying the signature that has been created by the signer at index signerInfoIndex.
 SignerInfo verify(X509Certificate signerCertificate)
          Uses the provided signer certificate for verifying the signature that has been created by the signer being owner of the certificate.
 void writeTo(java.io.OutputStream os)
          BER encodes and writes this object to the supplied output stream.
 void writeTo(java.io.OutputStream os, int blockSize)
          Writes this object to the supplied output stream where a constructed OCTET STRING is used for encoding the content.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

IMPLICIT

public static final int IMPLICIT
Mode where the signed content is included in the SignedData object.

See Also:
Constant Field Values

EXPLICIT

public static final int EXPLICIT
Mode where the signed content is NOT included in the SignedData object (the content is transferred by other means).

See Also:
Constant Field Values

version_

protected int version_
The version number, default 1.


contentType_

protected ObjectID contentType_
The content type of the to-be-signed content.


encapContentInfo_

protected EncapsulatedContentInfoStream encapContentInfo_
The inherent EncapsualtedContentInfo.


certSet_

protected CertificateSet certSet_
Repository for the signer certificates.


crls_

protected RevocationInfoChoices crls_
Repository for any included CRLs.


signerInfos_

protected java.util.Vector signerInfos_
Repository for the SignerInfos.


thisObject_

protected DerInputStream thisObject_
An InputStream from which a DER encoded SignedData object is read.


inputStream_

protected java.io.InputStream inputStream_
An InputStream holding the data.


mode_

protected int mode_
The mode specifying if the signed message is included in the Signature (IMPLICIT), or if is not transported within the Signature (EXPLICIT).


blockSize_

protected int blockSize_
The block size for block oriented stream encoding. (Default: 2048 to enforce indefinite constructed encoding).


securityProvider_

protected SecurityProvider securityProvider_
The SecurityProvider to be used.

Constructor Detail

SignedDataStream

protected SignedDataStream()
Default constructor for dynamic object creation in ContentInfo. Shall not be used by an application for creating a SignedDataStream object. The block size is set to 2048 to enforce indefinite constructed encoding.


SignedDataStream

public SignedDataStream(ObjectID contentType)
Creates a new SignedDataStream object without any content. The content value to be signed has to be of the given content type and has to be supplied by other means.

Parameters:
contentType - the contentType of the data

SignedDataStream

public SignedDataStream(java.io.InputStream data_is,
                        int mode)
Creates a SignedDataStream object from an input stream supplying the data to be signed. The given mode specifies the way the content data is transmitted. If the mode is SignedDataStream.IMPLICIT, the content data is included in the SignedData message to be transmitted. If the mode is SignedDataStream.EXPLICIT, the content data is not included in the SignedData object. The content type of the inherent EncapsulatedContentInfo is set to CMS (PKCS#7) id-data.

Parameters:
data_is - a stream holding the data to sign
mode - IMPLICIT if the message shall be included in the DER encoding, EXPLICIT otherwise

SignedDataStream

public SignedDataStream(java.io.InputStream data_is,
                        ObjectID contentType,
                        int mode)
Creates a SignedDataStream object from an input stream supplying the data to be signed. The given mode specifies the way the content data is transmitted. If the mode is SignedDataStream.IMPLICIT, the content data is included in the SignedData message to be transmitted. If the mode is SignedDataStream.EXPLICIT, the content data is not included in the SignedData object.

Use this constructor for signing content having any other type than CMS (PKCS#7) id-data. In such cases typically the given InputStream 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 to read a DER encoded TSTInfo from an input stream it may be supplied to a SignedDataStream-object in a way similar to:

 // the input stream supplying the DER encoded TSTInfo:
 InputStream encodedTSTInfo = ...;
 // now sign the TSTInfo:
 ObjectID oid = ObjectID.tstInfo;
 int mode = SignedDataStream.IMPLICIT;
 SignedDataStream signedData = new SignedDataStream(enodedTSTInfo, oid, mode);
 ...
 

Parameters:
data_is - a stream holding the data to sign
contentType - the contentType for the inherent EncapsulatedContentInfo
mode - MPLICIT if the message shall be included in the DER encoding, EXPLICIT otherwise

SignedDataStream

public SignedDataStream(java.io.InputStream is)
                 throws CMSParsingException,
                        java.io.IOException
Creates a new SignedDataStream from a BER encoded SignedData object which is read from the given InputStream. The encoded SignedData may (or may not) be wrapped into a ContentInfo.

Do not use this constructor for supplying the content data to be signed. This constructor may be used by the recipient for parsing an already exisiting SignedDataStream object, supplied as DER encoding from an input stream, and may have been created by one of the writeTo methods.

Use the SignedDataStream(InputStream data_is, int mode) or SignedDataStream(InputStream data_is, ObjectID contentType, int mode) constructors for supplying the content data to be signed when creating a SignedDataStream object.

This constructor only shall be used for decoding a SignedData object with included content data (implicit mode) or in explicit mode (where the content data is not included) when subsequently supplying the content data by calling method setInputStream. In explicit mode alternatively the SignedDataStream(InputStream data_is, AlgorithmID[] hashAlgorithms) constructor maybe used to initialize the hash computation with content data and hash algorithms, and the decoding may be explicitly performed by calling the decode method.

Parameters:
is - the InputStream holding a DER encoded CMS SignedData object
Throws:
java.io.IOException - if an I/O error occurs during reading from the InputStream
CMSParsingException - if an error occurs while parsing the object

SignedDataStream

public SignedDataStream(java.io.InputStream is,
                        SecurityProvider securityProvider)
                 throws CMSParsingException,
                        java.io.IOException
Creates a new SignedDataStream from a BER encoded SignedData object which is read from the given InputStream. The encoded SignedData may (or may not) be wrapped into a ContentInfo.

Do not use this constructor for supplying the content data to be signed. This constructor may be used by the recipient for parsing an already existing SignedDataStream object, supplied as DER encoding from an input stream, and may have been created by one of the writeTo methods.

Use the SignedDataStream(InputStream data_is, int mode) or SignedDataStream(InputStream data_is, ObjectID contentType, int mode) constructors for supplying the content data to be signed when creating a SignedDataStream object.

This constructor only shall be used for decoding a SignedData object with included content data (implicit mode) or in explicit mode (where the content data is not included) when subsequently supplying the content data by calling method setInputStream. In explicit mode alternatively the SignedDataStream(InputStream data_is, AlgorithmID[] hashAlgorithms, SecurityProvider securityProvider) constructor maybe used to initialize the hash computation with content data and hash algorithms, and the decoding may be explicitly performed by calling the decode method.

Parameters:
is - the InputStream holding a DER encoded CMS SignedData object
securityProvider - the SecurityProvider to be used for this SignedData object; if null the default system-wide installed SecurityProvider is used
Throws:
java.io.IOException - if an I/O error occurs during reading from the InputStream
CMSParsingException - if an error occurs while parsing the object

SignedDataStream

public SignedDataStream(java.io.InputStream data_is,
                        AlgorithmID[] hashAlgorithms)
                 throws java.io.IOException
Creates a new SignedDataStream from an InputStream holding the content that has been transmitted by other means, and an array specifying the hash algorithms to be used for digesting.

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 SignedDataStream message where the content data is not included. The initialization is done by wrapping a digest stream around the supplied content data stream for any specified hash algorithm. Subsequently the hash values will be updated when reading the stream thereby piping the data through the digest streams.
For an explicit message the actual decoding has to be performed by calling the decode method just after reading the data:

 // initialize for hash computation:
 SignedDataStream signedData = new SignedDataStream(data_is, hashAlgorithms);
 //read the stream thereby updating the hash values:
 InputStream dataIs = signed_data.getInputStream();
 byte[] buf = new byte[2048];
 int r;
 while ((r = dataIs.read(buf)) > 0) {
   // do something useful 
 }
 // explicitly perform the decoding
 signedData.decode(encoded_stream);
 

A sender shall use the SignedDataStream(InputStream data_is, int mode) constructor for supplying the content to be signed when creating a SignedDataStream object.

For decoding an implicit SignedDataStream message, use the SignedDataStream(InputStream is) constructor.

Parameters:
data_is - the InputStream supplying the content data which has been transmitted by other means
hashAlgorithms - the hash algorithms used by the participated signers for digesting the content data
Throws:
java.io.IOException - if there is no implementation for the specified hash algorithm

SignedDataStream

public SignedDataStream(java.io.InputStream data_is,
                        AlgorithmID[] hashAlgorithms,
                        SecurityProvider securityProvider)
                 throws java.io.IOException
Creates a new SignedDataStream from an InputStream holding the content that has been transmitted by other means, and an array specifying the hash algorithms to be used for digesting.

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 SignedDataStream message where the content data is not included. The initialization is done by wrapping a digest stream around the supplied content data stream for any specified hash algorithm. Subsequently the hash values will be updated when reading the stream thereby piping the data through the digest streams.
For an explicit message the actual decoding has to be performed by calling the decode method just after reading the data:

 // initialize for hash computation:
 SignedDataStream signedData = new SignedDataStream(data_is, hashAlgorithms);
 //read the stream thereby updating the hash values:
 InputStream dataIs = signed_data.getInputStream();
 byte[] buf = new byte[2048];
 int r;
 while ((r = dataIs.read(buf)) > 0) {
   // do something useful 
 }
 // explicitly perform the decoding
 signedData.decode(encoded_stream);
 
Using this constructor requires that the digest algorithms for an explicit SignedData message have to be known in advance before actually parsing it.
When not knowing the digest algorithm(s) of the to-be-parsed SignedData message in advance it will be more appropriate to create the SignedDataStream with the SignedDataStream(InputStream is) constructor and subsequently call method setInputStream to provide the content data received by other means:
 // the stream from which to read the encoded SignedData
 InputStream encoded_stream = ...;
 SignedDataStream signedData = new SignedDataStream(encoded_stream);
 
 // in explicit mode explicitly supply the content for hash computation
 if (signed_data.getMode() == SignedDataStream.EXPLICIT) {
   // the content data provided by other means:
   InputStream dataIs = ...;  
   signedData.setInputStream(dataIs);
 }
 //read the stream thereby updating the hash values:
 InputStream dataIs = signedData.getInputStream();
 byte[] buf = new byte[4096];
 int r;
 while ((r = dataIs.read(buf)) > 0) {
   // do something useful 
 }
 .... 
 
 

A sender shall use the SignedDataStream(InputStream data_is, int mode) constructor for supplying the content to be signed when creating a SignedDataStream object.

For decoding an implicit SignedDataStream message, use the SignedDataStream(InputStream is) constructor.

Parameters:
data_is - the InputStream supplying the content data which has been transmitted by other means
hashAlgorithms - the hash algorithms used by the participated signers for digesting the content data
securityProvider - the SecurityProvider to be used for this SignedData object; if null the default system-wide installed SecurityProvider is used
Throws:
java.io.IOException - if there is no implementation for the specified hash algorithm
Method Detail

setSecurityProvider

public void setSecurityProvider(SecurityProvider securityProvider)
Sets the SecurityProvider for this SignerInfo.

This method allows to explicitly set a SecurityProvider for this SignerInfo. If no explicit SecurityProvider is set, the default system wide installed SecurityProvider will be used for the required cryptographic operations.

This class may use the following method(s) of the SecurityProvider, which may be overriden by an application, if required:

And the following methods may be used by the inherent SignerInfo objects: On the parsing side, an application may prefer to supply the SecurityProvider immediately when creating an implicit or explicit SignedDataStream object.

Parameters:
securityProvider - the SecurityProvider to be set

getSecurityProvider

public SecurityProvider getSecurityProvider()
Gets the SecurityProvider installed for this SignerInfo.

This class uses the following method(s) of the SecurityProvider, which may be overriden by an application, if required:

And the following methods may be used by the inherent SignerInfo objects: If no explicit SecurityProvider has been set for this object, the default system wide installed SecurityProvider will be used for the required cryptographic operations. However, this method will return null if it does not have its own SecurityProvider.

Returns:
the SecurityProvider explicitly installed for this object, or null if this object does not have its own SecurityProvider

decode

public void decode(java.io.InputStream is)
            throws java.io.IOException,
                   CMSParsingException
Reads and decodes the a BER encoded SignedData from the given input stream. The given SignedData may (or may not) be wrapped into a ContentInfo.

This method implicitly is called from inside the corresponding constructor for decoding an received implicit SignedDataStream object where the content data is included. This method has to be explicitly called for decoding a received explicit SignedDataStream object where the content data is not included. Before calling this method for decoding an explicit message, a new SignedDataStream object has to be created by means of the SignedDataStream(InputStream data_is, AlgorithmID[] hashAlgorithms) constructor for initializing it for hash computation, and the data has to be read from the stream for upadating the hash values:

 // initialize for hash computation:
 SignedDataStream signedData = new SignedDataStream(data_is, hashAlgorithms);
 //read the stream thereby updating the hash values:
 InputStream dataIs = signed_data.getInputStream();
 byte[] buf = new byte[2048];
 int r;
 while ((r = dataIs.read(buf)) > 0) {
   // do something useful 
 }
 // explicitly perform the decoding
 signedData.decode(encoded_stream);
 

Specified by:
decode in interface ContentStream
Parameters:
is - the InputStream holding a DER encoded CMS SignedData object
Throws:
java.io.IOException - if an I/O error occurs during reading from the InputStream
CMSParsingException - if an error occurs while parsing the object

notifyEOF

public void notifyEOF()
               throws java.io.IOException
This method implements the EOFListener interface for performing the final decoding. Since the certificates, crls, and signerInfos fields are located at the end of a SignedData structure, they only can be accessed after reading the data stream. For that reason, when starting the parsing of an implicit SignedData message only version, digestAlgorithms, and ContentInfo fields can be parsed before reading the data. Since the data is supplied from an input stream, a iaik.utils.NotifyEOFInputStream is wrapped around this content data stream for indicating that the parsing procedure is to be notified when the stream actually has been read. At that point, the programm exceuting automatically jumps to the actual notifyEOF method for finishing the decoding by parsing the remaining certificates, crls and signerInfos fields.
For any application it is strongly recommended recommended not to explicitly call this method. This method only is qualified as public method since it implements the iaik.utils.EOFListener interface.

Specified by:
notifyEOF in interface EOFListener
Throws:
java.io.IOException - if an error occurs while parsing the stream
See Also:
EOFListener, NotifyEOFInputStream

encodeCalled

public void encodeCalled(ASN1Object obj,
                         int id)
                  throws CodingException
This method implements the EncodeListener interface. During the encoding process the DerCoder calls this method when it actually is time for encoding certificates, crls and SignerInfos components. Before each SignerInfo is encoded its signature value is calculated. The message digest calculated over the content data cannot be computed before the content stream entirely has been read. Since the content stream actually is read during the encoding procedure, the SignerDataStream registers itself as encode listener for the SEQUENCE representing the final ASN.1 SignedData object. After the content stream has been read and before certificates, crls and SignerInfos are to be encoded, this class is notified by means of the EncodeListener utility.

Specified by:
encodeCalled in interface EncodeListener
Parameters:
obj - the SignedData SEQUENCE
id - the id identifying the SEQUENCE to be processed
Throws:
CodingException - if an error occurs when computing/signing the message digest

getMode

public int getMode()
Returns the mode of this SignedData.

Returns:
IMPLICIT or EXPLICIT

getMessageDigest

public byte[] getMessageDigest(AlgorithmID digestAlgorithm)
                        throws java.security.NoSuchAlgorithmException,
                               CMSRuntimeException
Returns the message digest calculated for a specific algorithm. This method implements the DigestProvider interface, and therefore has to be qualified as public method. However, there should be no necessity for an application to utilize this method. This method only is called from inside the SignerInfo class for obtaining the digest calculated on the content for the specified hash algorithm.

It is strongly recommended not to explicitly call this method, since it actually finshes the digest computation for all hash values resulting from piping the data through the digest streams. This only has to be performed once and is done from inside the SignerInfo class!

Parameters:
digestAlgorithm - the hash algorithm to be used for digest computation
Returns:
the message digest calculated on the content for the given hash algorithm
Throws:
java.security.NoSuchAlgorithmException - if there is no message digest for the specified algorithm
CMSRuntimeException - if an error occurs because of some kind of initiailization problem (e.g. the data to be digested has not been supplied)

setMessageDigest

public void setMessageDigest(AlgorithmID digestAlgorithm,
                             byte[] digest)
                      throws java.security.NoSuchAlgorithmException
This method can be used to set an externally calculated message digest. When having created a new SignedDataStream for signing some content, this method has to be called after having added the SignerInfos. If none of the SignerInfos uses the specified digest algorithm a NoSuchAlgorithmException is thrown and the digest cannot be added. On the parsing side a digest value can be set for any of the digest algorithms that are parsed from the digestAlgorithms field.

Parameters:
digestAlgorithm - the hash algorithm for which the digest shall be set
digest - the new value for the messsage digest
Throws:
java.security.NoSuchAlgorithmException - if the specified digest algorithm is not by any of the SignerInfos of this SignedData

removeMessageDigest

public boolean removeMessageDigest(AlgorithmID digestAlgorithm)
This method can be used to remove a message digest.

When calling this method please be sure that the MessageDigest is not required by any of the included SignerInfos.

Parameters:
digestAlgorithm - the hash algorithm to be removed
Returns:
true if the MessageDigest entry has been removed, false if it has been not removed or no entry with the given hash algorithm was present

setBlockSize

public void setBlockSize(int blockSize)
Sets the block size for defining the length of each definite primitive encoded octet string component. If the value of blockSize is smaller or equal to zero the whole data is encoded as definite primitive octet string. This method may be used for enforcing block encoding when wrapping the SignedData into a ContentInfo.

Specified by:
setBlockSize in interface ContentStream
Parameters:
blockSize - for defining the encoding scheme and setting the octet string component length, if positive
See Also:
OCTET_STRING

getBlockSize

public int getBlockSize()
Gets the block size defining the length of each definite primitive encoded octet string component. If the value of blockSize is smaller or equal to zero the whole data is encoded as definite primitive octet string. This method may be used for enforcing block encoding when wrapping the EncryptedData into a ContentInfo.

Specified by:
getBlockSize in interface ContentStream
Returns:
blockSize defining the encoding scheme and setting the octet string component length, if positive
See Also:
OCTET_STRING

setInputStream

public void setInputStream(java.io.InputStream is)
Sets the InputStream which holds the content to sign/verify.

Parameters:
is - InputSteam holding the content to sign/verify

getInputStream

public java.io.InputStream getInputStream()
Returns an InputStream from where the signed content may be read.

Attention! The stream only may be read once.

When having created a new SignedDataStream object to be encoded to a stream, this method should only be called in EXPLICT mode to get and read away the content to be transmitted by other means. In IMPLICT mode this method shall not be called at all since the content has to be included in the SignedData message (and therefore should not be read "away").
When having decoded and parsed a received SignedData object coming from some stream, this method may be used for obtaining the raw content.

Returns:
an InputSteam holding the signed content

getContentType

public ObjectID getContentType()
Returns the content type this class implements.

Specified by:
getContentType in interface ContentStream
Returns:
ObjectID.cms_signedData

getEncapsulatedContentType

public ObjectID getEncapsulatedContentType()
Returns the content type the inherent EncapsulatetContentInfo represents.

Returns:
the content type the inherent EncapsulatetContentInfo represents

setCertificates

public void setCertificates(java.security.cert.Certificate[] certificates)
Sets the certificates of the several signers.

Attention! Only X.509 public key certificates (instances of iaik.x509.X509Certificate) or X.509 attribute certificates (instances of iaik.x509.attr.AttributeCertificate) or other certificates (instances of iaik.cms.OtherCertificate) can be added to this CertificateSet; PKCS#6 extended certificates are obsolete and therefore not supported.

Parameters:
certificates - the certificates to be set
Throws:
java.lang.IllegalArgumentException - if any of the supplied certificates is not a iaik.x509.X509Certificate or iaik.x509.attr.AttributeCertificate or iaik.cms.OtherCertificate object

addCertificates

public void addCertificates(java.security.cert.Certificate[] certificates)
Adds the given certificates.

Attention! Only X.509 public key certificates (instances of iaik.x509.X509Certificate) or X.509 attribute certificates (instances of iaik.x509.attr.AttributeCertificate) or other certificates (instances of iaik.cms.OtherCertificate) can be added to this CertificateSet; PKCS#6 extended certificates are obsolete and therefore not supported.

Parameters:
certificates - the certificates to be added
Throws:
java.lang.IllegalArgumentException - if any of the supplied certificates is not a iaik.x509.X509Certificate or iaik.x509.attr.AttributeCertificate or iaik.cms.OtherCertificate object

setCertificateSet

public void setCertificateSet(CertificateSet certSet)
Sets the certificateSet to be included. This method provides an alternative way to set the certificates by immediately supplying a CertificateSet that may hold any number of X.509 public key and/or attribute certificates.
Attention! Only X.509 public key certificates (instances of iaik.x509.X509Certificate) or X.509 attribute certificates (instances of iaik.x509.attr.AttributeCertificate) or other certificates (instances of iaik.cms.OtherCertificate) can be added to this CertificateSet; PKCS#6 extended certificates are obsolete and therefore not supported.

Parameters:
certSet - the certificate set to be added
Throws:
java.lang.IllegalArgumentException - if any of the supplied certificates is not a iaik.x509.X509Certificate or iaik.x509.attr.AttributeCertificate or iaik.cms.OtherCertificate object

setRevocationInfoChoices

public void setRevocationInfoChoices(RevocationInfoChoices crls)
Sets the crls (RevocationInfoChoices) to be included. This method provides an alternative way to set the crls by immediately supplying a RevocationInfoChoices set that may hold any number of X.509 or other crls.
Attention! Only X.509 crls (instances of iaik.x509.X509CRL) or other revocation infos (instances of iaik.cms.OtherRevocationInfo) can be included in the given RevocationInfoChoices set.

Parameters:
crls - the RevocationInfoChoices to be set
Throws:
java.lang.IllegalArgumentException - if any of the supplied revocation infos is not a iaik.x509.X509CRL or iaik.cms.OtherCertificate object

setCRLs

public void setCRLs(X509CRL[] crls)
Sets a set of certificate-revocation information objects.

The given CRLs supply information about the revocation status of the certificates specified in the certificates field.

Parameters:
crls - the certificate-revocation information objects as array of CRL
Throws:
java.lang.IllegalArgumentException - if any of the supplied RevocationInfos is not a iaik.x509.X509CRL or iaik.cms.OtherRevocationInfo, iaik.cms.OCSPRevocationInfo object

addCRLs

public void addCRLs(X509CRL[] crls)
Adds the given certificate-revocation information objects.

The given CRLs supply information about the revocation status of the certificates specified in the certificates field.

Parameters:
crls - the certificate-revocation information objects to be added
Throws:
java.lang.IllegalArgumentException - if any of the supplied RevocationInfos is not a iaik.x509.X509CRL or iaik.cms.OtherRevocationInfo, iaik.cms.OCSPRevocationInfo object

setSignerInfos

public void setSignerInfos(SignerInfo[] signerInfos)
                    throws java.security.NoSuchAlgorithmException
Sets a collection of per-signer information.

There may be any number of elements in the collection, including zero.

Parameters:
signerInfos - a collection of per-signer information
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the message digest algorithm specified in one signerInfo
See Also:
SignerInfo

addSignerInfo

public void addSignerInfo(SignerInfo signerInfo)
                   throws java.security.NoSuchAlgorithmException
Adds a SignerInfo object to this SignedData.

This method not only adds the given SignerInfo, but also initializes the hash computation by wrapping a digest stream for the hash algorithm of the SignerInfo around the data carrying input stream.
If the given SignerInfo contains signed attributes, it must include the PKCS#9 content-type attribute and the PKCS#9 message-digest attribute. If the message-digest attribute is not included in the supplied signed attributes it is automatically calculated and set later during signature calculation. If the content-type attribute is not included it is automatically added and set to the eContentType of the SignedData EncapsulatedContentInfo. However, if the signature value is already set for the SignerInfo, an Exception is thrown if the content-type attribute is not included in the signed attributes. An Exception is also thrown if the content-type attribute is already included in the SignerInfo but does not match to the eContentType of the SignedData EncapsulatedContentInfo.

Parameters:
signerInfo - the SignerInfo to add
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the message digest algorithm specified in the signerInfo, or if the signature value is already set for the SignerInfo and the ContentType attribute is not included in the signed attributes, or if the content-type attribute is already included in the SignerInfo but does not match to the eContentType of the SignedData EncapsulatedContentInfo (for backwards compatibility only an NoSuchAlgorithmException can be thrown by this method)
See Also:
SignerInfo

addDigestAlgorithm

public void addDigestAlgorithm(AlgorithmID digestAlg)
                        throws java.security.NoSuchAlgorithmException
Adds a digest algorithm.

Usually any digest algorithm required by any SignerInfo is automatically added when adding a SignerInfo.
This method provides the possibility to add a digest algorithm that may be needed for calculating a digest over the data that may be required for other purposes than SignerInfo signature calculation.
AttentionThis method has to be called before the content data is processed (which is done either implicitly when the SignedData is encoded or explicitly when reading the content data in EXPLICIT mode).

Parameters:
digestAlg - the digest algorithm to add
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the message digest algorithm available

removeSignerInfo

public boolean removeSignerInfo(CertificateIdentifier signerIdentifier)
Removes the SignerInfo(s) with the given id from the SignerInfo list.

Parameters:
signerIdentifier - the id of the SignerInfo to be removed
Returns:
true if the SignerInfo has been successfully removed, false if it has not been removed

setSDSEncodeListener

public void setSDSEncodeListener(SDSEncodeListener sdsEncodeListener)
                          throws java.security.NoSuchAlgorithmException
Sets an SDSEncodeListener for this SignedDataStream.

An SDSEncodeListener allows an application to update a SignedDataStream object during it is encoded. This may be useful for adding SignerInfos/certificates/crls or adding SignerInfo attributes before or after the signatures are computed (e.g. when encoding an already exisiting and currently parsed SignedDataStream again). Since any SignerInfo to be added during the encoding process may use some digest algorithm not used by any already included SignerInfo, the SDSEncodeListener may announce the corresponding digest algorihtm(s) when it is bound to the SignedDataStream by calling this setSDSEncodeListener method.
An SDSEncodeListener can only be set for this stream version of the SignedData content type implementation, but not for the non-stream SignedData implementation, which does not need and SDSEncodeListener and simply will ignore it.

Any already set EncodeListener will be removed.

Parameters:
sdsEncodeListener - the SDSEncodeListener to be set
Throws:
if - the SDSEncodeListener announces any not supported digest algorithms to be used
java.security.NoSuchAlgorithmException
See Also:
SDSEncodeListener

addSDSEncodeListener

public void addSDSEncodeListener(SDSEncodeListener sdsEncodeListener)
                          throws java.security.NoSuchAlgorithmException
Adds an SDSEncodeListener for this SignedDataStream.

An SDSEncodeListener allows an application to update a SignedDataStream object during it is encoded. This may be useful for adding SignerInfos/certificates/crls or adding SignerInfo attributes before or after the signatures are computed (e.g. when encoding an already exisiting and currently parsed SignedDataStream again). Since any SignerInfo to be added during the encoding process may use some digest algorithm not used by any already included SignerInfo, the SDSEncodeListener may announce the corresponding digest algorihtm(s) when it is bound to the SignedDataStream by calling this setSDSEncodeListener method.
An SDSEncodeListener can only be set for this stream version of the SignedData content type implementation, but not for the non-stream SignedData implementation, which does not need and SDSEncodeListener and simply will ignore it.

Parameters:
sdsEncodeListener - the SDSEncodeListener to be added
Throws:
if - the SDSEncodeListener announces any not supported digest algorithms to be used
java.security.NoSuchAlgorithmException
See Also:
SDSEncodeListener

getVersion

public int getVersion()
Returns the syntax version number (1 or 3 or 4).

Returns:
the version number

getDigestAlgorithms

public AlgorithmID[] getDigestAlgorithms()
Returns a collection of message-digest algorithm identifiers.

There may be any number of elements in the collection, including zero. The returned OIDs identify the digest algorithms used by the several signers.

Returns:
the message-digest AlgorithmIDs

getCertificates

public java.security.cert.Certificate[] getCertificates()
Returns all certificates included.

Any certificate returned by this method either may be an X.509 public key certificate (iaik.x509.X509Certificate) or an X.509 attribute certificate (iaik.x509.attr.AttributeCertificate). PKCS#6 extended certificates are obsolete and therefore not supported.

Returns:
all certificates included; the array may be empty if no certificates are included

getX509Certificates

public X509Certificate[] getX509Certificates()
Returns the X.509 public key certificates included.

Returns:
the X.509 public key certificates; the array may be empty if no X.509 certificates are included

getAttributeCertificates

public AttributeCertificate[] getAttributeCertificates()
Returns the attribute certificates included in this SignedData.

Returns:
an array containing all attribute certificates included in this SignedData; the array may be empty if no attribute certificates are included

getCertificateSet

public CertificateSet getCertificateSet()
Gets the certificateSet holding all certificates included in this SignedData. This method never returns null, however the retrieved certificateSet maybe empty. If not empty, the CertificateSet returned may contain X.509 public key certificate (iaik.x509.X509Certificate objects) and/or or an X.509 attribute certificate (iaik.x509.attr.AttributeCertificate objects); PKCS#6 extended certificates are obsolete and therefore not supported.

Returns:
the certificateSet holding the certificates of this SignedData

verify

public void verify(java.security.PublicKey publicKey,
                   int signerInfoIndex)
            throws CMSSignatureException
Uses the provided public key for verifying the signature that has been created by the signer at index signerInfoIndex.

Note that this method does not perform any certificate verification.

Parameters:
signerInfoIndex - the index into the SignerInfos array for identifying the SignerInfo belonging to the signer whose signature has to be verified
publicKey - the public key of the signer to verify the message
Throws:
CMSSignatureException - if the signature verification fails for some reason
InvalidContentHashException - if the signature verification process fails because the content hash does not match to value of the included MessageDigest attribute
InvalidSignatureValueException - if the signature verification process fails because the signature value is invalid

verify

public X509Certificate verify(int signerInfoIndex)
                       throws CMSSignatureException
Verifies the signature that has been created by the signer at signerInfoIndex.

The signature is verified by using the public key of the specified signer, which is got from the signer certificate, derived from the certificates field.

Verifying the signatures of all the signers included into some specific SignedData object may be done by "looping" through all the included SignerInfos, e.g.:

 SignerInfo[] signerInfos = signed_data.getSignerInfos();
 int numberOfSigners = signer_infos.length;     
 if (numberOfSigners == 0) {
   System.out.println("Warning: Unsigned message (no SignerInfo included)!");
 } else {
   for (int i=0; i < numberOfSigners; i++) {     
     try {
       // verify the signed data using the 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].getSignerIdentifier()).getSubjectDN());
     }
   }  
 }
 
The simple example above verifies the correctness of the signature value(s) and dumps the result to System.out. In practice an application will require some more sophisticated error processing.

Note that this method does not perform any certificate validation.

Parameters:
signerInfoIndex - the index into the SignerInfos array for identifying the SignerInfo belonging to the signer whose signature has to be verified
Returns:
the certificate of the signer, if its signature turns out to be correct; otherwise a SignaturException is thrown
Throws:
java.security.SignatureException - if the signature verification fails for some reason
CertificateNotFoundException - if the certificate of the signer is not included in this SignedData object
InvalidContentHashException - if the signature verification process fails because the content hash does not match to value of the included MessageDigest attribute
InvalidSignatureValueException - if the signature verification process fails because the signature value is invalid
CMSSignatureException

verify

public SignerInfo verify(X509Certificate signerCertificate)
                  throws CMSSignatureException
Uses the provided signer certificate for verifying the signature that has been created by the signer being owner of the certificate. This method may be used for verifying the signature of a signer in situations where there are no certificates sent with the SignedData object. Of course, it also may be used when the certificate is not empty. However, take in mind that you should not step through the entries of the certificates field for calling verify(cert) for any certificate presented there since there also may (shall) be included issuer certificates and certificate chains leading to some trusted root.

Note that this method does not perform any certificate verification.

Parameters:
signerCertificate - the certificate of the signer whose signature should be verified
Returns:
the signerInfo belonging to the signer being owner of the given certificate
Throws:
CMSSignatureException - if the signature turns out to be incorrect or there is no signer with the given certificate or the certifcate
InvalidContentHashException - if the signature verification process fails because the content hash does not match to value of the included MessageDigest attribute
InvalidSignatureValueException - if the signature verification process fails because the signature value is invalid

getSignedDigest

public byte[] getSignedDigest(int signerInfoIndex)
                       throws CMSException
Returns the message digest included in the authenticated attributes. If the signed content is not included in the SignedData ASN.1 object this method can be used to get to message digest of the signed content.

Parameters:
signerInfoIndex - the index into the SignerInfos array for identifying the SignerInfo belonging to the signer whose message digest shall be returned
Throws:
CMSException

getCertificate

public X509Certificate getCertificate(CertificateIdentifier signerIdentifier)
                               throws CMSException
Tries to find the signer certificate specified by the given CertificateIdentidier.

This method searches the certificates field of this SignedData for a certificate identified by the given SignerIdentifier (either an IssuerAndSerialNumber or SubjectKeyIdentifier). If you additionally want to check if the certificate found is identified as signer certificate by means of a SigningCertificate attribute, you may use method isSignerCertificate of class SignerInfo, e.g.:

 try {
   SignerInfo signerInfo = signedData.getSignerInfos()[0];
   CertificateIdentifier signerIdentifier = signerInfo.getSignerIdentifier();
   X509Certificate signerCert = signedData.getCertificate(signerIdentifier);
   if (signerInfo.isSigningCertificate(signerCert)) {
     System.out.println("Signer certificate: " + signerCert);
   } else {
     System.out.pritnln("Signer certificate not included!");
   }
 } catch (CMSException ex) {
   System.out.println("Signer certificate not included!");
 }
 

Parameters:
signerIdentifier - the signerIdentifier IssuerAndSerialNumber or SubjectKeyIdentifier) identifying the certificate to search for
Returns:
the X509Certificate belonging to the given SignerIdentifier, if included; otherwise a CMSException is thrown
Throws:
CMSException - if the requested certificate cannot be found
CMSParsingException - may be thrown if any of the included certificates has not been parsed so far and has an invalid ASN.1 structure

getCertificates

public X509Certificate[] getCertificates(CertificateIdentifier signerIdentifier)
                                  throws CMSException
Tries to find the signer certificate chain specified by the given CertificateIdentidier.

This method searches the certificates field of this SignedData for the certificate chain belonging to the signer identified by the given SignerIdentifier (either an IssuerAndSerialNumber or SubjectKeyIdentifier), e.g.:

 try {
   SignerInfo signerInfo = signedData.getSignerInfos()[0];
   CertificateIdentifier signerIdentifier = signerInfo.getSignerIdentifier();
   X509Certificate[] signerCertChain = signedData.getCertificates(signerIdentifier);
 } catch (CMSException ex) {
   System.out.println("Signer certificate not included!");
 }
 

Parameters:
signerIdentifier - the signerIdentifier IssuerAndSerialNumber or SubjectKeyIdentifier) identifying the signer for which to search the certificate chain
Returns:
the certificate chain belonging to the given SignerIdentifier, if included; otherwise a CMSException is thrown
Throws:
CMSException - if the requested certificate chain cannot be found
CMSParsingException - may be thrown if any of the included certificates has not been parsed so far and has an invalid ASN.1 structure

getCRLs

public X509CRL[] getCRLs()
Returns all the cerificate-revocation lists included in this SignedData object.

Returns:
an array containing the cerificate-revocation lists included into this SignedData object; the array may be empty if there are no CRLs included
Throws:
CMSRuntimeException - may be thrown if any of the included RevocationInfos has not been parsed so far and has an invalid ASN.1 structure

getRevocationInfoChoices

public RevocationInfoChoices getRevocationInfoChoices()
Gets the crls (RevocationInfoChoices) included in this SignedData. This method never returns null, however the retrieved RevocationInfoChoices maybe empty. If not empty, the RevocationInfoChoices returned may contain X.509 crls (iaik.x509.X509CRL objects) and/or or other crls (iaik.cms.OtherRevocationInfo objects);

Returns:
the RevocationInfoChoices holding the crls of this SignedData

getSignerInfos

public SignerInfo[] getSignerInfos()
Returns all the signer infos included in this SignedData object.

Returns:
an array containing all the SignerInfo objects included into this SignedData; the array may be empty if there are no signers specified

getSignerInfoIndex

public int getSignerInfoIndex(X509Certificate signerCertificate)
Searches for the index of the signerInfo belonging to the given signer certificate.

Parameters:
signerCertificate - the certificate of the signer
Returns:
the index of the signerInfo or -1 if there is no signerInfo matching to the given certificate

getSignerInfo

public SignerInfo getSignerInfo(X509Certificate signerCertificate)
Searches for the SignerInfo identified by the given certificate.

Parameters:
signerCertificate - the certificate of the signer
Returns:
the SignerInfo identified by the given certificate or null if no SignerInfo for the given Certificate is included

getSignerInfo

public SignerInfo getSignerInfo(CertificateIdentifier signerIdentifier)
Searches for the SignerInfo identified by the given signer id.

Parameters:
signerIdentifier - the id of the signer
Returns:
the SignerInfo identified by the given id or null if no SignerInfo for the given id is included

toASN1Object

public ASN1Object toASN1Object()
                        throws CMSException
Returns this SignedData as ASN1Object. The ASN.1 SEQUENCE returned by this method only will contain the first components (version, message digest algorithms, EncapsulatedContentInfo without content) of the ASN.1 SignedData. The remaining components (content, certificates, crls, SignerInfos) are added later during the encoding procedure (when writeTo is called).

Specified by:
toASN1Object in interface ContentStream
Returns:
this SignedData as ASN1Object
Throws:
CMSException - if the ASN1Object could not be created

toASN1Object

protected ASN1Object toASN1Object(int blockSize)
                           throws CMSException
Returns this SignedData as ASN1Object where a constructed OCTET STRING is used for encoding the content. The ASN.1 SEQUENCE returned by this method only will contain the first components (version, message digest algorithms, EncapsulatedContentInfo without content) of the ASN.1 SignedData. The remaining components (content, certificates, crls, SignerInfos) are added later during the encoding procedure (when writeTo is called).

Parameters:
blockSize - the block size defining the encoding scheme - and specifying the length of each primitive encoded octet string component, if positive
Throws:
CMSException - if the ASN1Object could not be created

writeTo

public void writeTo(java.io.OutputStream os)
             throws java.io.IOException
BER encodes and writes this object to the supplied output stream. In implicit mode, whole the inherent data is encoded as one single primitive definite octet string:
 0x04 <length> <data>
 

Parameters:
os - the output stream to which this SignedDataStream shall be encoded
Throws:
java.io.IOException - if an error occurs when writing to the stream

writeTo

public void writeTo(java.io.OutputStream os,
                    int blockSize)
             throws java.io.IOException
Writes this object to the supplied output stream where a constructed OCTET STRING is used for encoding the content. If block size has a value > 0, in implicit mode the inherent content data is encoded as constructed OCTET STRING. In this case the encoding is splitted according to the defined block size:
 0x24 0x80
           0x04 <blocksize> <data>
           0x04 <blocksize> <data>
           0x04 <blocksize> <data>
                ...
 0x00 0x00
 
If the block size is not positive, whole the inherent data is encoded as one single primitive definite octet string:
 0x04 <length> <data>
 

Parameters:
os - the output stream to which this SignedData shall be written
blockSize - the block size defining the encoding scheme - and specifying the length of each primitive encoded octet string component, if positive
Throws:
java.io.IOException - if an error occurs during writing the object

toString

public java.lang.String toString()
Returns a string giving some information about this SignedDataStream object.

Overrides:
toString in class java.lang.Object
Returns:
the string representation

toString

public java.lang.String toString(boolean detailed)
Returns a string giving some - if requested - detailed information about this SignedDataStream object.

Specified by:
toString in interface ContentStream
Parameters:
detailed - - whether or not to give detailed information
Returns:
the string representation

clearSignatures

public void clearSignatures(boolean applicationSet,
                            boolean clearMessageDigestAttributes)
Clears the signature values of all included SignerInfos. Clearing all signature values may be desired when supplying a new content to be signed by means of method setInputStream. If the signature values are not cleared, they would not be calculated anew.

Parameters:
applicationSet - whether to clear signature values that have been explicitly set by the application by calling signerInfo.setSignatureValue
clearMessageDigestAttributes - whether to clear MessageDigest attributes, too

This Javadoc may contain text parts from text parts from IETF Internet Standard specifications (see copyright note).

IAIK-CMS 6.0, (c) 2002 IAIK, (c) 2003, 2023 SIC