iaik.cms
Class SignedDataOutputStream

java.lang.Object
  extended by java.io.OutputStream
      extended by iaik.cms.SignedDataOutputStream
All Implemented Interfaces:
java.io.Closeable, java.io.Flushable

public class SignedDataOutputStream
extends java.io.OutputStream

This is an OutputStream implementation of the CMS ( RFC 5652) SignedData structure. It allows creating a signed object by writing the content to be signed to this stream.

It supports implicit (where the content is included in the SignedData object) and explicit (where the content is transmitted by other means) signatures.

This stream version will encode the content of the SignedData as a constructed OCTET STRING. Each write operation to this stream will result in an OCTET STRING block within this constructed OCTET STRING. Consequently, the size of each block equals the size of the data provided to the wirte operation.

The final call to close() will finish the encoding and write the certificates, CRLs (if set) and actual signatures, i.e. the SignerInfo structures.

The typical usage of this class looks like the following example for creating a CMS SignedData structure with the signed content included.

   // the private key of the signer
   PrivateKey signatureKey = ...
   // the certificates of the signer
   X509Certificate[] certificateChain = ...
   // the input stream from which to read the data to be signed
   InputStream dataInputStream = ...
   // the output stream to which to write the signed data
   OutputStream resultStream = ...
   
   // create SignedDataOutputStream
   SignedDataOutputStream signedData = 
     new SignedDataOutputStream(resultStream, SignedDataOutputStream.IMPLICIT);
       
   // add the certificates
   signedData.addCertificates(certificateChain);
   
   // add a SignerInfo
   X509Certificate signatureCert = certificateChain[0];
   SignerInfo signerInfo = new SignerInfo(
     new IssuerAndSerialNumber(signatureCert), AlgorithmID.sha1, signatureKey);
   // define some attributes
   Attribute[] attributes = { 
     new Attribute(new CMSContentType(ObjectID.cms_data)),
     new Attribute(new SigningTime())
   };
   // set the attributes
   signerInfo.setSignedAttributes(attributes);
   // and add the new signer
   signedData.addSignerInfo(signerInfo);
   
   // write in the data to be signed
   byte[] buffer = new byte[2048];
   int bytesRead;
   while ((bytesRead = dataInputStream.read(buffer)) != -1) {
     signedData.write(buffer, 0, bytesRead);
   }
   // closing the stream add the signer infos and closes the underlying stream
   signedData.close();
 
 
For using the SignedDataOutputStream in explicit mode, specify SignedDataOutputStream.EXPLICIT when creating the SignedDataOutputStream object:
   SignedDataOutputStream signedData = 
     new SignedDataOutputStream(resultStream, SignedDataOutputStream.EXPLICIT);
 
The further proceeding is the same as in implicit mode. When calling a write method, the content data is dropped (since it must not be included in the SignedData object and has to be transmitted by other means). However, piping the data through write calls is required for hash and signature calculation.

If you want to encapsulate the SignedData into a ContentInfo you first must wrap a ContentInfoOutputStream around the final output stream (the ContentInfoOutputStream has to write its headers to the stream at first, thus it must be created at the "lowest" level):

   ContentInfoOutputStream contentInfoStream = 
     new ContentInfoOutputStream(ObjectID.cms_signedData, resultStream);
   // now create SignedDataOutputStream for the ContentInfoStream:
   SignedDataOutputStream signedData = 
     new SignedDataOutputStream(contentInfoStream, SignedDataOutputStream.IMPLICIT);
       
   // the further proceeding is same as above
   
   // add the certificates
   signedData.addCertificates(certificateChain);
   
   // add a SignerInfo
   X509Certificate signatureCert = certificateChain[0];
   SignerInfo signerInfo = new SignerInfo(
     new IssuerAndSerialNumber(signatureCert), AlgorithmID.sha1, signatureKey);
   // define some attributes
   Attribute[] attributes = { 
     new Attribute(new CMSContentType(ObjectID.cms_data)),
     new Attribute(new SigningTime())
   };
   // set the attributes
   signerInfo.setSignedAttributes(attributes);
   // and add the new signer
   signedData.addSignerInfo(signerInfo);
   
   // write in the data to be signed
   byte[] buffer = new byte[2048];
   int bytesRead;
   while ((bytesRead = dataInputStream.read(buffer)) != -1) {
     signedData.write(buffer, 0, bytesRead);
   }
   // closing the stream add the signer infos and closes the underlying stream
   signedData.close();
 
Use class SignedDataStream to read in and parse the encoded SignedData and verify the signature(s).

See Also:
SignerInfo, SignedDataStream, ContentInfoStream

Field Summary
static int EXPLICIT
          Denotes a mode where the signed message is not transported within the Signature
static int IMPLICIT
          Denotes a mode where the signed message is included in the Signature
 
Constructor Summary
SignedDataOutputStream(java.io.OutputStream out, int mode)
          Creates a new SignedDataOutputStream object which later writes the complete encoded SignedData structure to the given output stream (e.g.
SignedDataOutputStream(java.io.OutputStream out, ObjectID contentType, int mode)
          Creates a new SignedDataOutputStream object which later writes the complete encoded SignedData structure to the given output stream (e.g.
SignedDataOutputStream(java.io.OutputStream out, ObjectID contentType, int mode, SecurityProvider securityProvider)
          Creates a new SignedDataOutputStream object which later writes the complete encoded SignedData structure to the given output stream (e.g.
 
Method Summary
 void addCertificates(java.security.cert.Certificate[] certificates)
          Adds the given certificates.
 void addCRLs(X509CRL[] crls)
          Adds the given cerificate-revocation lists.
 void addSignerInfo(SignerInfo signerInfo)
          Adds a SignerInfo object to this SignedData.
 void close()
          Finishes the encoding and writes the certificates, CRLs (if set) and the SignerInfo objects to the stream.
 void flush()
          Flushes any internal data and calls flush of the underlying stream.
 byte[] getMessageDigest(AlgorithmID digestAlgorithm)
          Returns the message digest calculated for a specific algorithm.
 SecurityProvider getSecurityProvider()
          Gets the SecurityProvider installed for this SignerInfo.
 boolean isPassThroughClose()
          Checks whether a call to close() will call close of the underlying output stream
 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 cerificate-revocation lists.
 void setMessageDigest(AlgorithmID digestAlgorithm, byte[] digest)
          This method can be used to set an externally calculated MessageDigest value.
 void setPassThroughClose(boolean passThroughClose)
          Setting this to true will cause close() to call close of the underlying output stream.
 void setRevocationInfoChoices(RevocationInfoChoices crls)
          Sets the crls (RevocationInfoChoices) to be included.
 void setSecurityProvider(SecurityProvider securityProvider)
          Sets the SecurityProvider for this SignedDataOutputStream.
 void setSignerInfos(SignerInfo[] signerInfos)
          Sets a collection of per-signer information.
 java.lang.String toString()
          Returns a string giving some information about this SignedDataOutputStream object.
 java.lang.String toString(boolean detailed)
          Returns a string giving some - if requested - detailed information about this SignedDataOutputStream object.
 void write(byte[] b)
          Processes the given content data to be signed.
 void write(byte[] b, int off, int len)
          Processes the given content data to be signed.
 void write(int b)
          Processes the given content byte to be signed.
 
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
Denotes a mode where the signed message is included in the Signature

See Also:
Constant Field Values

EXPLICIT

public static final int EXPLICIT
Denotes a mode where the signed message is not transported within the Signature

See Also:
Constant Field Values
Constructor Detail

SignedDataOutputStream

public SignedDataOutputStream(java.io.OutputStream out,
                              int mode)
Creates a new SignedDataOutputStream object which later writes the complete encoded SignedData structure to the given output stream (e.g. write(byte[])). The content type of the inherent content data is set to ObjectID.cms_data.

Parameters:
out - The output stream to which to write the encoded SignedData structure.
mode - The mode. Either IMPLICIT for including the content or EXPLICIT for not including it.

SignedDataOutputStream

public SignedDataOutputStream(java.io.OutputStream out,
                              ObjectID contentType,
                              int mode)
Creates a new SignedDataOutputStream object which later writes the complete encoded SignedData structure to the given output stream (e.g. write(byte[])).

Parameters:
out - The output stream to which to write the encoded SignedData structure.
contentType - The content type of the data signed by this object, e.g. ObjectID.cms_data.
mode - The mode. Either IMPLICIT for including the content or EXPLICIT for not including it.

SignedDataOutputStream

public SignedDataOutputStream(java.io.OutputStream out,
                              ObjectID contentType,
                              int mode,
                              SecurityProvider securityProvider)
Creates a new SignedDataOutputStream object which later writes the complete encoded SignedData structure to the given output stream (e.g. write(byte[])).

Parameters:
out - The output stream to which to write the encoded SignedData structure.
contentType - The content type of the data signed by this object, e.g. ObjectID.cms_data.
mode - The mode. Either IMPLICIT for including the content or EXPLICIT for not including it.
securityProvider - The optional security provider for getting the required crypto algorithm implementations.
Method Detail

write

public void write(byte[] b,
                  int off,
                  int len)
           throws java.io.IOException
Processes the given content data to be signed. For later signature calculation the data is hashed with any digest algorithm used by any of the SignerInfos that have been added so far. In IMPLICIT mode the content data is encoded and written to the output stream. In EXPLICIT mode the content data is not written to the output stream (since it must not be included in the SignedData and has to be transmitted by other means), but contributes to the hash calculation as required.

Overrides:
write in class java.io.OutputStream
Parameters:
b - The data to be signed as byte array.
off - The start offset in the data array b.
len - The number of bytes to write.
Throws:
java.io.IOException - If an I/O error occurs.

write

public void write(byte[] b)
           throws java.io.IOException
Processes the given content data to be signed. For later signature calculation the data is hashed with any digest algorithm used by any of the SignerInfos that have been added so far. In IMPLICIT mode the content data is encoded and written to the output stream. In EXPLICIT mode the content data is not written to the output stream (since it must not be included in the SignedData and has to be transmitted by other means), but contributes to the hash calculation as required.

Overrides:
write in class java.io.OutputStream
Parameters:
b - The data to be signed as byte array.
Throws:
java.io.IOException - If an I/O error occurs.

write

public void write(int b)
           throws java.io.IOException
Processes the given content byte to be signed. For later signature calculation the data is hashed with any digest algorithm used by any of the SignerInfos that have been added so far. In IMPLICIT mode the content data is encoded and written to the output stream. In EXPLICIT mode the content data is not written to the output stream (since it must not be included in the SignedData and has to be transmitted by other means), but contributes to the hash calculation as required.

Note that when repeatedly calling this method to write single data bytes the encoding may consist of many single-byte OCTET STRINGs. Thus it may be more appropriate to use a byte array expcting write method.

Specified by:
write in class java.io.OutputStream
Parameters:
b - The content data byte to be signed
Throws:
java.io.IOException - If an I/O error occurs.

flush

public void flush()
           throws java.io.IOException
Flushes any internal data and calls flush of the underlying stream.

Specified by:
flush in interface java.io.Flushable
Overrides:
flush in class java.io.OutputStream
Throws:
java.io.IOException - If flushing the stream fails.

close

public void close()
           throws java.io.IOException
Finishes the encoding and writes the certificates, CRLs (if set) and the SignerInfo objects to the stream.

Specified by:
close in interface java.io.Closeable
Overrides:
close in class java.io.OutputStream
Throws:
java.io.IOException - if an I/O error occurs while writing to the stream

isPassThroughClose

public boolean isPassThroughClose()
Checks whether a call to close() will call close of the underlying output stream

Returns:
true if a call to close() will call close of the underlying output stream; false if a call to close() will not close the underlying stream.

setPassThroughClose

public void setPassThroughClose(boolean passThroughClose)
Setting this to true will cause close() to call close of the underlying output stream. If false, a call to close() will not close the underlying stream.

Parameters:
passThroughClose - true to pass through close() calls. false to not pass them through.

setSecurityProvider

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

This method allows to explicitly set a SecurityProvider for this SignedDataOutputStream. 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:

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

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 MessageDigest value. When having created a new SignedDataOutputStream 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.

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

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 cerificate-revocation lists.

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

Parameters:
crls - a set of cerificate-revocation lists as array of X509CRLs

addCRLs

public void addCRLs(X509CRL[] crls)
Adds the given cerificate-revocation lists.

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

Parameters:
crls - the crls to be added

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. For digest engine initialization any SignerInfos shall be set before writing any content data to this SignedDataOutputStream.

Parameters:
signerInfos - a collection of per-signer information
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the message digest algorithm used by any of the given SignerInfos
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 signer around the content output stream. Thus this method shall be called before writing any content data to this SignedDataOutputStream.
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 used by the given 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

toString

public java.lang.String toString()
Returns a string giving some information about this SignedDataOutputStream 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 SignedDataOutputStream object.

Parameters:
detailed - - whether or not to give detailed information
Returns:
the string representation

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

IAIK-CMS 5.1, (c) 2002 IAIK, (c) 2003 - 2010 SIC