|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object | +--iaik.pkcs.pkcs7.SignedDataStream | +--iaik.pkcs.pkcs7.SignedAndEnvelopedDataStream
This class represents the stream-supporting implementation of the PKCS#7
SignedAndEnvelopedData
type.
Each PKCS#7 content type is associated with a specific object identifier, derived from:
pkcs-7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1) 7 }
The object identifier for the SignedAndEnvelopedData
content
type is defined as:
signedAndEnvelopedData OBJECT IDENTIFIER ::= { pkcs-7 4 }
which corresponds to the OID string "1.2.840.1.113549.1.7.4".
The PKCS#7
Cryptographic Message Standard specifies the SignedAndEnvelopedData
content type for providing a syntax for building digital envelopes
whose authenticity and integrity is ensured by digatal signatures.
Content of any type may be enveloped for any number of recipients and signed
by any number of signers in parallel.
For each recipient, a commonly at random generated content-encryption key is
encrypted with the particular recipientīs public key and - together with
recipient-specific information - collected into a RecipientInfo
value. The content is encrypted with the content-encryption key giving a
EncryptedContent
value, which - in combination with a
recipient-specific encrypted content-encryption key - forms the digital
envelope for each particular recipient.
For each signer, a message digest is computed on the content with a
signer-specific message-digest algorithm. Subsequently, again for each
signer, the corresponding message digest from the previous step is
encrypted with the particular signerīs private key, and the result is
encrypted with the content-encryption key. This double encrypted message
digest and some signer-specific information are collected into a
SignerInfo
value. The digital signature for each signer is the
recovered single encrypted message digest.
Finally all created SignerInfo
and
RecipientInfo
values are collected together with the encrypted
content for forming a SignedAndEnvelopedData
structure.
This class implements the SignedAndEnvelopedData
structure
resulting from the last step described above. The SignedAndEnvelopedData
type is defined as ASN.1 SEQUENCE type containing the following
components (see PKCS#7 specification,
Version 1.5):
SignedAndEnvelopedData ::= SEQUENCE { version Version, recipientInfos RecipientInfos, digestAlgorithms DigestAlgorithmIdentifiers, encryptedContentInfo EncryptedContentInfo, certificates [0] IMPLICIT Certificates OPTIONAL, crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, signerInfos SignerInfos }
The digestAlgorithms
field contains the object identifiers of
the message digest algorithms used by the several signers for digesting the
content. The optional certificates
field shall contain
certificate chains for all the signers of the signerInfos
field. The optional crls
field may supply information about the
revocation status of the certificates specified in the certificates
field. The encryptedContentInfo
field specifies the content
type, the content-encryption algorithm, and holds the encrypted content.
The non-empty SignerInfos
and RecipientInfos
collect per-signer (respectively per-recipient) information for all
parciticipated signers (recipients). Each SignerInfo
includes
the double encrypted message digest in its encrypted_digest
field, and each RecipientInfo
includes the content-encryption
key, encrypted with the particular recipientīs public key.
A recipient, when receiving the SignedAndEnvelopedData
message,
decrypts the encrypted content-encryption key from the corresponding
RecipientInfo
with his/her private key for subsequently decrypting the
encrypted content using the content-encryption key just recovered.
Subsequently the recovered content-encryption key is used for decrypting
the double encrypted message digest for each signer, and the result is
decrypted with the signerīs public key giving the recovered message digest,
which can be compared with an independently computed message digest for
verifying the signature.
For more information consult the RSA PKCS#7 specification. Note, that PKCS#7 Vesrsion 1.6 removes support for extended certificates, which already is considered by this implementation.
It is recommendet to use a sequential combination of the signed-data and the enveloped-data content types instead of using the signed-and-enveloped-data content type, since the signed-and-enveloped-data content type does not have authenticated or unauthenticated attributes, and does not provide enveloping of signer inforamtion other than the signature.
Assuming that signer_certs
and recipient_certs
represent the certifcate chains of some single signer and some intended
recipient, a typical proceeding may perform the following steps for
building a SignedAndEnvelopedDataStream
object to be sent to the
recipient:
//the data to be signed and enveloped supplied from an input stream: InputStream data_is = ...; //create a SignedAndEnvelopedDataStream object thereby supplying the data //input stream and the content-encryption algorithm: SignedAndEnvelopedDataStream saed = new new SignedAndEnvelopedDataStream(data_is, AlgorithmID.des_EDE3_CBC); //supply the signerīs certificate chain (generally, there may be more than only //one signer): saed.setCertificates(signer_certs); //create a SignerInfo structure for the signer entity thereby //specifying the signerīs certificate by an IssuerAndSerialNumber //structure, the signerīs digest algorithm, and the signerīs private key; //the IssuerAndSerialNumber can be created from signer_certs[0], which constitutes //the signerīs certificate: IssuerAndSerialNumber issuer_and_serialNr = new IssuerAndSerialNumber(signer_certs[0]); SignerInfo signer_info = new SignerInfo(issuer_and_serialNr, AlgorithmID.sha, privateKey); //add the SignerInfo just created to the SignedAndEnvelopedDataStream object: saed.addSignerInfo(signer_info); //create a RecipientInfo for the intended recipient thereby specifiying //its certificate (for obtaining the IssuerAndSerialNumber) and the key //encryption algorithm to be used (at this time only the rsaEncryption method //is supported): RecipientInfo recipient = new RecipientInfo(recipient_certs[0], AlgorithmID.rsaEncryption); //add the recipient to the SignedAndEnvelopedDataStream object: saed.addRecipientInfo(recipient); //write the SignedAndEnvelopedDataStream structure to an output stream thereby //actually performing digest computation, encryption and encoding: int blockSize = ...; OuputStream encoded_stream = ...; saed.writeTo(encoded_stream, blockSize);When a positve block size is specified for encoding the SignedAndEnvelopedData to a stream, the encrypted 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 <blocksize> <first encrypted content block> 0x04 <blocksize> <second encrypted content block> 0x04 <blocksize> <third encrypted content block> ... 0x00 0x00instead of:
0x04 <length> <encrypted content>The indefinte constrcuted encoding scheme also may be preferable when intending to be compatible to the encoding practice of some particular application (for instance some versions of Netscape Navigator).
Each recipient decrypts the content-encryption key with his/her private key and subsequently decrypts the encrypted content and the double-encrypted message digest for each signer with the recovered content-encryption key. The signature is verifiied by decrypting the (now single-) encrypted message digest with the signerīs public key for comparing it with a independently computet message digest, e.g.:
//create a SignedAndEnvelopedDataStream from the received DER encoding SignedAndEnvelopedDataStream saed = new SignedAndEnvelopedDataStream(encoded_stream); //setup the cipher for decryption with the recipientīs private key int recipientInfoIndex = 0; saed.setupCipher(privateKey, recipientInfoIndex); //get and read the data for decrypting the content and updating the hash computation //needed for verification: InputStream data_is = saed.getInputStream(); byte[] buf = new byte[1024]; int r; while ((r = data_is.read(buf)) > 0) { // do something useful } //verify the signatures of all participated signers: SignerInfo[] signer_infos = saed.getSignerInfos(); for (int i=0; i<signer_infos.length; i++) { try { // verify the signed data using the SignerInfo at index i X509Certificate signer_cert = saed.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_and_enveloped_data.getCertificate(signer_infos[i].getIssuerAndSerialNumber()).getSubjectDN()); } }
SignerInfo
,
RecipientInfo
,
IssuerAndSerialNumber
,
SignedDataStream
,
EnvelopedDataStream
Fields inherited from class iaik.pkcs.pkcs7.SignedDataStream |
block_size, certificates, content_info, content_type, crls, EXPLICIT, IMPLICIT, input_stream, mode, signer_infos, this_object, version |
Constructor Summary | |
protected |
SignedAndEnvelopedDataStream()
Default constructor for dynamic object creation in ContentInfo. |
|
SignedAndEnvelopedDataStream(InputStream is)
Creates a new SignedAndEnvelopedDataStream where the DER encoded data is read from the given InputStream. |
|
SignedAndEnvelopedDataStream(InputStream is,
AlgorithmID contentEA)
Creates a new PKCS#7 SignedAndEnvelopedData object where the content is read from the supplied InputStream. |
Method Summary | |
void |
addRecipientInfo(RecipientInfo recipient)
Adds one recipient to the list of recipient infos. |
void |
decode(InputStream is)
Reads and decodes the SignedAndEnvelopedData from a DerInputStream. |
ObjectID |
getContentType()
Returns the content type this class implements. |
EncryptedContentInfoStream |
getEncryptedContentInfo()
Returns the encrypted content info included in this SignedAndEnvelopedData object. |
byte[] |
getMessageDigest(AlgorithmID digestAlgorithm)
Returns the message digest calculated for a specific algorithm. |
RecipientInfo[] |
getRecipientInfos()
Returns all the recipient infos included in this SignedAndEnvelopedData object. |
void |
setRecipientInfos(RecipientInfo[] recipients)
Sets the recipient infos. |
void |
setupCipher(PrivateKey recipientPrivateKey,
int recipientInfoIndex)
Uses the specified private key to setup the Cipher for decrypting the content-encryption key and subsequently using it to decrypt the encrypted content of this
SignedAndEnvelopedData object for the requesting recipient, specified by its
recipientInfoIndex .
|
ASN1Object |
toASN1Object()
Returns this PKCS#7 SignedAndEnvelopedDataStream as ASN1Object. |
protected ASN1Object |
toASN1Object(int blockSize)
Returns this SignedAndEnvelopedDataStream as ASN1Object where a constructed OCTET STRING is used for encoding the content. |
String |
toString()
Returns a string giving some information about this SignedAndEnvelopedDataStream object. |
String |
toString(boolean detailed)
Returns a string giving some - if requested - detailed information about this SignedAndEnvelopedDataStream object. |
void |
verify(PublicKey publicKey,
int signerInfoIndex)
Uses the provided public key for verifying the signature that has been created by the signerInfoIndex īth signer. |
Methods inherited from class iaik.pkcs.pkcs7.SignedDataStream |
addSignerInfo, getBlockSize, getCertificate, getCertificates, getCRLs, getDigestAlgorithms, getInputStream, getMode, getSignedDigest, getSignerInfos, getVersion, notifyEOF, setBlockSize, setCertificates, setCRLs, setInputStream, setMessageDigest, setSignerInfos, verify, verify, writeTo, writeTo |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Methods inherited from interface iaik.pkcs.pkcs7.ContentStream |
getBlockSize, setBlockSize |
Methods inherited from interface iaik.utils.EOFListener |
notifyEOF |
Constructor Detail |
protected SignedAndEnvelopedDataStream()
public SignedAndEnvelopedDataStream(InputStream is, AlgorithmID contentEA) throws NoSuchAlgorithmException
is
- the InputStream containg the data to envelopecontentEA
- the content encryption algorithm for encrypting the contentNoSuchAlgorithmException
- if there is no implementation for the specified algorithmpublic SignedAndEnvelopedDataStream(InputStream is) throws PKCSParsingException, IOException
is
- the InputStream holding a DER encoded PKCS#7 SignedAndEnvelopedData objectIOException
- if an I/O error occurs during reading from the InputStreamPKCSParsingException
- if an error occurs while parsing the objectMethod Detail |
public void decode(InputStream is) throws IOException, PKCSParsingException
DerInputStream
,
internally a DerInputStream is created before parsing the data.
decode
in interface ContentStream
decode
in class SignedDataStream
is
- the InputStream holding a DER encoded PKCS#7 SignedAndEnvelopedData objectIOException
- if an I/O error occurs during reading from the InputStreamPKCSParsingException
- if an error occurs while parsing the objectpublic void setupCipher(PrivateKey recipientPrivateKey, int recipientInfoIndex) throws PKCSException, NoSuchAlgorithmException, InvalidKeyException
SignedAndEnvelopedData
object for the requesting recipient, specified by its
recipientInfoIndex
.
This method first uses the given private key for decrypting the encrypted
temporary symmetric key obtained from the corresponding RecipientInfo
structure, and subsequently uses this key to setup a CipherInputStream.
Unlike the non-stream supporting SignedAndEnvelopedData
class where the encrypted-content decryption
already is performed inside the setupCipher
method, the cipher
will be only initialized for decrypting in this class. The encrypted-content
decryption actually is done during reading the data obtained by calling the
getInputStream
method. So donīt call
getInputStream
before setting up the cipher!
recipientPrivateKey
- the private key of one recipient specified in
a RecipientInfo objectrecipientInfoIndex
- specifies which RecipientInfo the private key belongs toPKCSException
- if there occurs an error while decrypting the dataNoSuchAlgorithmException
- if there is no implementation of the content-encryption algorithmInvalidKeyException
- if the specified private key is not validpublic ObjectID getContentType()
getContentType
in interface ContentStream
getContentType
in class SignedDataStream
ObjectID.pkcs7_signedAndEnvelopedData
public void setRecipientInfos(RecipientInfo[] recipients)
Each single RecipientInfo
specifies the particular recipientīs certificate by IssuerAndSerialNumber, and the
key encryption algorithm to be used; currently only PKCS#1 rsaEncryption is supported.
Example:
RecipientInfo[] recipients = new RecipientInfo[2]; recipients[0] = new RecipientInfo(cert1, AlgorithmID.rsaEncryption); recipients[1] = new RecipientInfo(cert2, AlgorithmID.rsaEncryption); enveloped_data.setRecipientInfos(recipients);
recipients
- a collection of per-recipient informationRecipientInfo
public void addRecipientInfo(RecipientInfo recipient)
The RecipientInfo
specifies the particular recipientīs certificate by IssuerAndSerialNumber, and the
key encryption algorithm to be used; currently only PKCS#1 rsaEncryption is supported.
Example:
RecipientInfo recipient = new RecipientInfo(cert, AlgorithmID.rsaEncryption); enveloped_data.addRecipientInfos(recipient);
recipient
- the RecipientInfo to be addedpublic void verify(PublicKey publicKey, int signerInfoIndex) throws SignatureException
signerInfoIndex
īth signer.verify
in class SignedDataStream
publicKey
- the public key of the signer to verify the messagesignerInfoIndex
- the index into the SignerInfos array for identifying the
SignerInfo belonging to the signer whose signature has to be verifiedSignatureException
- if the signature turns out to be incorrectpublic RecipientInfo[] getRecipientInfos()
RecipientInfo
objects
included in this SignedAndEnvelopedData
setRecipientInfos(iaik.pkcs.pkcs7.RecipientInfo[])
public EncryptedContentInfoStream getEncryptedContentInfo()
EncryptedContentInfoStream
an explicit cast to EncryptedContentInfoStream
has to be made:
EncryptedContentInfoStream eci = (EncryptedContentInfoStream)saed.getEncryptedContentInfo();
public ASN1Object toASN1Object() throws PKCSException
toASN1Object
in interface ContentStream
toASN1Object
in class SignedDataStream
SignedAndEnvelopedData
as ASN1Object.PKCSException
- if the ASN1Object could not be createdprotected ASN1Object toASN1Object(int blockSize) throws PKCSException
toASN1Object
in class SignedDataStream
blockSize
- the block size defining the encoding scheme - and specifying the
length of each primitive encoded octet string component, if positivePKCSException
- if the ASN1Object could not be createdpublic String toString()
toString
in class SignedDataStream
public String toString(boolean detailed)
toString
in interface ContentStream
toString
in class SignedDataStream
detailed
- - whether or not to give detailed informationpublic byte[] getMessageDigest(AlgorithmID digestAlgorithm) throws NoSuchAlgorithmException
NoSuchAlgorithmException
- if there is no message digest for the specified algorithm
|
This Javadoc may contain text parts from Internet Standard specifications (RFC 2459, 3280, 3039, 2560, 1521, 821, 822, 2253, 1319, 1321, ,2630, 2631, 2268, 3058, 2984, 2104, 2144, 2040, 2311, 2279, see copyright note) and RSA Data Security Public-Key Cryptography Standards (PKCS#1,3,5,7,8,9,10,12, see copyright note). | ||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |