public class SignedContent
extends javax.mail.internet.MimeMultipart
javax.mail package.
S/MIME (Secure/Multipurpose Internet Mail Extensions) provides a consistent way to send and receive secure MIME data. Based on the popular Internet MIME standard, S/MIME provides the following cryptographic security services for electronic messaging applications: authentication, message integrity and non-repudiation of origin (using digital signatures) and privacy and data security (using encryption) (see S/MIME Version 2 Message Specification).
This class supports the creation and handling of S/MIME signed
messages in combination with the javax.mail architecture.
For creating and working with encrypted S/MIME messages, use the
EncryptedContent
class of the iaik.security.smime package.
S/MIME provides two formats for signed messages:
application/pkcs7-mime and SignedData (or
application/x-pkcs7-mime for early implementations)
multipart/signed
The first format (application/pkcs7-mime and SignedData) processes
the whole (prepared) MIME entity to be signed into a PKCS #7 object of type SignedData which
subsequently is inserted into an application/pkcs7-mime MIME entity.
The smime-type parameter for messages signed using this format is
"signed-data", the file extension is ".p7m" (see
S/MIME Version 2 Message Specification). The "Content-" headers of a sample
message would look like:
Content-Type: application/pkcs7-mime; smime-type="signed-data";
name="smime.p7m"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="smime.p7m"
fgwehds...
For viewing a message that is signed using this format, a recipient must take care
for an S/MIME aware mail client.
The second format (multipart/signed) makes use of the multipart/signed
MIME type, consisting
of two parts. The first part contains the MIME entity to be signed, and the second
part contains the signature, which is a PKCS#7 detached signature,
inserted into a MIME entity of type application/pkcs7-signature (or
application/x-pkcs7-signature for early implementations) leaving the
ContentInfo (content) field of the
SignedData} object empty.
The multipart/signed Content type requires two parameters (see
S/MIME Version 2 Message Specification):
application/pkcs7-signature" - or
"application/x-pkcs7-signature" for early implementations)
md5, sha1, or any other (i.e. unknown))
Content-Type: multipart/signed;
protocol="application/pkcs7-signature";
micalg=sha1;
boundary="----=_NextPart_000_00AA_01BD7FE8.1CD08610"
------_NextPart_000_00AA_01BD7FE8.1CD08610
Content-Type: text/plain ;
charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
This is a clear-signed message.
------_NextPart_000_00AA_01BD7FE8.1CD08610
Content-Type: application/pkcs7-signature;
name=smime.p7s
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename=smime.p7s
sdefqj...
------_NextPart_000_00AA_01BD7FE8.1CD08610--
Messages signed using this format can be viewed by the recipient, regardless of
being equipped with S/MIME aware software.
This class supports both formats, application/x-pkcs7-mime and
multipart/signed. For distinguishing between the two formats when creating
a new SignedContent object using the SignedContent(boolean implicit) constructor, the implicit
parameter has to be set either to true or to false, depending
on whether to use the application/x-pkcs7-mime format or the multipart/signed
format:
In the first case, aSignedContent sc = new SignedContent(true); respectively SignedContent sc = new SignedContent(false);
javax.mail.internet.ContentType (representing
a MIME content type)
object is created setting the primary (media) type to "application",
and the sub type to "x-pkcs7-mime". The signature will be "carried" by a
SMimeSigned object
including the signed message in the inherent SignedData structure.
In the second case, the primary (media) type of the new created
javax.mail.internet.ContentType object is set to "multipart", and the
sub type is set to "signed". The required multipart/signed parameters protocol
and micalg specify the "application/x-pkcs7-signature" type for leaving
the ContentInfo field of the signature carrying
SMimeSigned --> SignedData
object empty, and the "SHA-1" (FIPS PUB 180-1) message digest algorithm to be used
for MIC computation.
When creating an implicit message you also may wish to set the smime-type parameter to signed-data or certs-only, depending what kind of message to be sent:
SignedContent sc = new SignedContent(true, SignedContent.SIGNED_DATA);respectively
SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);For signing some message to be sent using the features of the MIME implementing
javax.mail.internet package, first create an (either implicit or explicit)
SignedContent object, supply the content and sign it with your
private key (note: since this implementation uses the PKCS#1 rsaEncryption
method for encrypting the digest (SHA-1 hash over the message), the supplied "signing"
key has to be a RSAPrivateKey!). Subsequently
incorporate this SignedContent object into a
javax.mail.internet.MimeMessage by calling a proper setContent
method. As usually, finally the message is sent by calling Transport.send(msg):
SignedContent sc = new SignedContent(false); sc.setContent(...); sc.setCertificates(certificates); sc.setSigner(privateKey, signerCertificate); ... MimeMessage msg = new MimeMessage(session); ... set sender, recipient(s), subject, ... ... msg.setContent(sc, sc.getContentType()); Transport.send(msg);The recipient verifies a S/MIME signed message by either calling
verify() or verify(PublicKey),
depending on whether the signer´s certificate list is included in the received message
or not. If not, the signer´s public key explicitly has to be supplied. When certificates
are included, the verify() method returns the signer´s certificate if
the verification process turns out that the signature is correct. If the verification
process fails, a SignatureException is thrown:
SignedContent sc = (SignedContent)msg.getContent();
try {
X509Certificate signer = sc.verify();
System.out.println("This message is signed from: "+signer.getSubjectDN());
} catch (java.security.SignatureException ex) {
...
}
// get the content:
Object content = sc.getContent();
...
For more information about the JavaMail architecture, consult Sun´s JavaMail specification. Note, that
JavaMail uses the
JavaBeans Activation Framework (JAF) for encapsulating the message data. To confirm
with the JAF, this class also supports a setDataHandler
method for supplying the content to be signed, wrapped by a javax.activation.DataHandler,
e.g.:
MimeBodyPart mbp1 = new SMimeBodyPart();
mbp1.setText("The message!\n\n");
MimeBodyPart mbp2 = new SMimeBodyPart();
mbp2.setDataHandler(new DataHandler(new FileDataSource("C:/users/idea.key")));
mbp2.setFileName("pop3.jar");
Multipart mp = new SMimeMultipart();
mp.addBodyPart(mbp1);
mp.addBodyPart(mbp2);
DataHandler dataHandler = new DataHandler(mp, mp.getContentType());
SignedContent sc = new SignedContent(false);
sc.setDataHandler(dataHandler);
sc.setCertificates(certificates);
sc.setSigner(privateKey, signerCertificate);
...
MimeMessage msg = new MimeMessage(session);
...
set sender, recipient(s), subject, ...
...
msg.setContent(sc, sc.getContentType());
Transport.send(msg);
Notice, that when creating a multipart/signed message as above, body parts and
multiparts have to be supplied as instances of SMimeBodyPart and SMimeMultipart for ensuring a proper canonicalization.
Additional setContent (or setText) methods provide alternative ways for supplying the content, which
then internally is wrapped by a data handler, e.g.:
SignedContent sc = new SignedContent(true);
sc.setText("Immediately supplied text/plain data which internally will be wrapped by a data handler");
When creating a certs-only message for sending certificates/crls no content has to be supplied at all:
SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY); sc.setCertificates(certificates); msg.setContent(sc, sc.getContentType()); //set filename and attachment parameters sc.setHeaders(msg); ...For using the IAIK-JCE S/MIME classes, an application also will need the packages:
# Default mailcap file for the JavaMail System # # for our content-handlers # text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed message/*;; x-java-content-handler=com.sun.mail.handlers.message_rfc822 # # IAIK 'mailcap' file # multipart/signed;; x-java-content-handler=iaik.security.smime.signed_content application/x-pkcs7-signature;; x-java-content-handler=iaik.security.smime.signed_content application/x-pkcs7-mime;; x-java-content-handler=iaik.security.smime.encrypted_content application/x-pkcs10;; x-java-content-handler=iaik.security.smime.pkcs10_content application/pkcs7-signature;; x-java-content-handler=iaik.security.smime.signed_content application/pkcs7-mime;; x-java-content-handler=iaik.security.smime.encrypted_content application/pkcs10;; x-java-content-handler=iaik.security.smime.pkcs10_contentWhen creating a new SignedContent to be sent per default the old S/MIME content typs (application/x-pkcs7-mime, application/x-pkcs7-signature) are used. For using the new types call the static
useNewContentTypes method of the SMimeParameters class before creating a new SignedContent
object, e.g.:
//switch to new content types SMimeParameters.useNewContentTypes(true); //create a SignedContent boolean implicit = ...; SignedContent sc = new SignedContent(implicit); ...
SMimeSigned,
JMailSMimeSigned,
EncryptedContent,
SignedContent| Modifier and Type | Field and Description |
|---|---|
static java.lang.String |
CERTS_ONLY
SMime-type "certs-only".
|
static java.lang.String |
SIGNED_DATA
SMime-type "signed-data".
|
| Constructor and Description |
|---|
SignedContent(boolean implicit)
Creates a new S/MIME signed content.
|
SignedContent(boolean implicit,
java.lang.String smimeType)
Creates a new S/MIME signed content.
|
SignedContent(javax.activation.DataSource dataSource)
Creates a
SignedContent object from the given DataSource. |
| Modifier and Type | Method and Description |
|---|---|
void |
addBodyPart(javax.mail.BodyPart part)
Throws a Messaging Exception.
|
void |
addBodyPart(javax.mail.BodyPart part,
int index)
Throws a Messaging Exception.
|
X509Certificate[] |
getCertificates()
Returns the certificates included in this S/MIME messages.
|
java.lang.Object |
getContent()
Returns the content as a Java object.
|
java.io.InputStream |
getContentInputStream()
Returns an InputStream for this part's unparsed content.
|
X509CRL[] |
getCRLs()
Returns the CRLs included in this S/MIME messages.
|
javax.activation.DataHandler |
getDataHandler()
Returns a DataHandler holding the content of this
SignedContent object. |
java.io.InputStream |
getInputStream()
Returns an input stream holding the content of this
SignedContent object. |
SignerInfo[] |
getSignerInfos()
Returns all the signer infos included in the underlying SignedData object.
|
java.lang.String |
getSMimeType()
Returns the S/MIME type of this SignedContent.
|
void |
requestTimeStamp(TimeStampClient timeStampClient)
Requests that the signature that exists in this SignedContent structure be
time-stamped.
|
void |
setCertificates(X509Certificate[] certificates)
Sets the certificates to be included in the S/MIME message.
|
void |
setContent(javax.mail.Multipart multipart)
This method sets the given Multipart object as this SignedContent's content.
|
void |
setContent(java.lang.Object content,
java.lang.String type)
A convenience method for setting this SignedContent's content.
|
void |
setContentContentHeaders(javax.mail.Header[] headers)
Set some headers for the entity to be signed.
|
void |
setContentContentTransferEncoding(java.lang.String cte)
Sets the content transfer encoding of the entity to be signed.
|
void |
setCRLs(X509CRL[] crls)
Sets the crls to be included in the S/MIME message.
|
void |
setDataHandler(javax.activation.DataHandler dataHandler)
Sets the content wrapped by a
javax.activation.DataHandler. |
void |
setHeaders(javax.mail.Message message)
Sets additional headers of the message containing this SignedContent.
|
void |
setSigner(java.security.PrivateKey privateKey,
X509Certificate signerCertificate)
Uses the given private key to sign this SignedContent.
|
void |
setText(java.lang.String text)
A convenience method that sets the given String as this SignedContent's content.
|
X509Certificate |
verify()
Verifies this S/MIME signed content and returns the certificate
of the signer.
|
void |
verify(java.security.PublicKey publicKey)
Uses the given PublicKey to verify this S/MIME signed content.
|
X509Certificate |
verifyAndValidate(CertVerifier certVerifier)
Verifies and validates the SignerInfo structure that exists in this
SignedContent object. |
SignerInfo |
verifyAndValidate(X509Certificate signerCert,
CertVerifier certVerifier)
Verifies and validates the SignerInfo structure that exists in this
SignedContent using the indicated signer certificate. |
void |
writeTo(java.io.OutputStream os)
Writes this SignedContent to the given output stream.
|
createInternetHeaders, createMimeBodyPart, createMimeBodyPart, getBodyPart, getBodyPart, getCount, getPreamble, isComplete, parse, removeBodyPart, removeBodyPart, setPreamble, setSubType, updateHeaderspublic static final java.lang.String SIGNED_DATA
public static final java.lang.String CERTS_ONLY
public SignedContent(boolean implicit,
java.lang.String smimeType)
Explicitly signed messages consist of a multipart/signed content where the first part contains the human readable content and the second part contains the signature.
When creating an implicit message the smime-type may be set to either SignedContent.SIGNED_DATA ("signed-data") or SignedContent.CERTS_ONLY ("certs-only"). Per default (smimeType = null) the smime-type parameter is not set.
implicit - true if the message shall be included in the signature,
false otherwisesmimeType - the smime-type (SignedContent.SIGNED_DATA or SignedContent.CERTS_ONLY)public SignedContent(boolean implicit)
Explicitly signed messages consist of a multipart/signed content where the first part contains the human readable content and the second part contains the signature.
When using this constructor for creating an implicit message the smime-type parameter will not be set.
implicit - true if the message shall be included in the signature,
false otherwisepublic SignedContent(javax.activation.DataSource dataSource)
throws java.io.IOException
SignedContent object from the given DataSource.
From the given data source the content type of the inherent message is
parsed to determine if it represents an application/pkcs7-mime
(implicit), or an multipart/sigend (explicit) message. If an
application/pkcs7-mime message is encapsulated by the data source, the
message is included in the signature, and a SMimeSigned
object is created from the whole data to be parsed for the message. Otherwise,
if an multipart/signed message is encapsulated by the data source, an
javax.mail.internet.MimeMultipart is created from the data
source containing the message in its first (0th) body part and the
"non-message-including" signature in its second (1st) body part. In
this case, the signature is parsed from the second body part to create
a SMimeSigned.
During a mail session an application usually won´t call this constructor
directly. Rather it will be called by a proper data content handler signed_content supplying the data source.
For more information on data handling using the
javax.activation.DataSource for "MIME type based" data
access, see Sun´s
JavaBeans Activation Framework (JAF) sepecification.
dataSource - the DataSourcejava.io.IOException - if an error occurs when parsing the message, e.g. an unknown
MIME type is requested or the message content cannot be readpublic void setDataHandler(javax.activation.DataHandler dataHandler)
javax.activation.DataHandler.
This method provides the mechanism to set this SignedContent's content, e.g:
DataHandler dataHandler = new DataHandler(...); SignedContent sc = new SignedContent(false); sc.setDataHandler(dataHandler);The DataHandler wraps around the actual content. It allows clients to discover the operations available on the content, and to instantiate the appropriate component to perform those operations. For more information consult Sun´s JavaBeans Activation Framework (JAF) sepecification.
Please ensure to set the content before calling
method setSigner!
dataHandler - the DataHandler for the contentpublic void setContent(java.lang.Object content,
java.lang.String type)
javax.activation.DataHandler.
Note that a DataContentHandler class for the specified type should be available
to the JavaMail implementation for this to work right. i.e., to do
setContent(foobar, "application/x-foobar"), a DataContentHandler for
"application/x-foobar" should be installed. Refer to the Java Activation Framework
for more information.
Please ensure to set the content before calling
method setSigner!
content - a java objecttype - MIME type of this objectpublic void setText(java.lang.String text)
javax.activation.DataHandler
thereby specifying "text/plain" as MIME type.
Please ensure to set the text content before calling
method setSigner!
text - the text that is the SignedObject's contentpublic void setContent(javax.mail.Multipart multipart)
javax.activation.DataHandler.
Refer to the Java Activation Framework
for more information.
Please ensure to set the content before calling
method setSigner!
multipart - the multipart object that is the SignedObject's contentpublic void addBodyPart(javax.mail.BodyPart part)
throws javax.mail.MessagingException
addBodyPart in class javax.mail.internet.MimeMultipartpart - the body part to be added; not usedjavax.mail.MessagingException - since not supported for this classpublic void addBodyPart(javax.mail.BodyPart part,
int index)
throws javax.mail.MessagingException
addBodyPart in class javax.mail.internet.MimeMultipartpart - the body part to be added; not usedindex - the index; not usedjavax.mail.MessagingException - since not supported for this classpublic void setContentContentTransferEncoding(java.lang.String cte)
setText or
setDataHandler is used for
supplying the content. However, the supplied content transfer
encoding will be ignored when the inner entity is a structured
entity.cte - the content transfer encoding to be applied to the
inner entity to be signedpublic void setContentContentHeaders(javax.mail.Header[] headers)
setText or
setDataHandler is used for
supplying the content. However, the supplied header will be ignored
when the inner entity is a structured entity. The supplied headers
are not cloned!headers - the headers to be applied to the
inner entity to be signedpublic X509Certificate verify() throws java.security.SignatureException
verify(PublicKey) for verification when the signer
certificate is not included in the signature.
To validate the certificates received when calling getCertificates(),
use the method validate(X509Certificate certificate) from the class
com.entrust.toolkit.User.java.java.security.SignatureException - if this message does not verify, the signer certificate
is not included in the message or if this is a certs-only messagepublic void verify(java.security.PublicKey publicKey)
throws java.security.SignatureException
java.security.SignatureException - if this message does not verify or if this is a certs-only messagepublic X509Certificate verifyAndValidate(CertVerifier certVerifier) throws java.security.SignatureException, CertificationException, TimeStampException, RevocationWarningException
SignedContent object.
First the signature is verified to ensure that the data has not been tampered since it was signed. Then, if the signature does not contain a time-stamp, the signer's certificate is validated at the present time. However, if the signature does contain a time-stamp, the time-stamp token is decoded, verified and validated, and then the signer's certificate is validated at the time specified in the time-stamp.
In order to verify a signature contained in a SignerInfo structure, the
corresponding signer certificate must be located. Using the signer
identifer from the SignerInfo structure, the signer certificate is
located by searching the 'certificates' included in the
SignedContent and then searching the trusted certificates
contained in the certificate validation mechanism.
When validating the signer's certificate at the time specified by the
time-stamp, a revocation warning can occur. This happens when the signer's
certificate has been revoked, but was revoked after the time specified in
the time-stamp. When this occurs, the signer's certificate can still be
considered valid, depending on the policy surrounding time-stamping and the
reason it was revoked. In this case, a
RevocationWarningException exception will be thrown; it is then
up to the caller to decide whether the warning should be ignored, or acted
upon.
certVerifier - the certificate validation mechansim; used to validate the signer's
certificatejava.security.SignatureException - thrown if the signature has been tampered, or a SignerInfo structure
does not exist (not signed), or the corresponding signer certificate
could not be foundCertificateException - thrown if the signature cannot be trustedTimeStampException - thrown if the signature is time-stamped, but the time-stamp is invalid
or cannot be trustedRevocationWarningException - thrown if the signer's certificate was revoked, but was revoked
after the time specified in the time-stamp; the caller must then
decided if the signature can be trustedCertificationExceptionpublic SignerInfo verifyAndValidate(X509Certificate signerCert, CertVerifier certVerifier) throws java.security.SignatureException, CertificationException, TimeStampException, RevocationWarningException
SignedContent using the indicated signer certificate.
First the signature is verified to ensure that the data has not been tampered since it was signed. Then, if the signature does not contain a time-stamp, the signer's certificate is validated at the present time. However, if the signature does contain a time-stamp, the time-stamp token is decoded, verified and validated, and then the signer's certificate is validated at the time specified in the time-stamp.
When validating the signer's certificate at the time specified by the
time-stamp, a revocation warning can occur. This happens when the signer's
certificate has been revoked, but was revoked after the the time specified
in the time-stamp. When this occurs, the signer's certificate can still be
considered valid, depending on the policy surrounding time-stamping and the
reason it was revoked. In this case, a
RevocationWarningException exception will be thrown; it is then
up to the caller to decide whether the warning should be ignored, or acted
upon.
signerCert - the certificate that will be used to verified/validated the signaturecertVerifier - the certificate validation mechansim; used to validate the signer's
certificatejava.security.SignatureException - thrown if the signature has been tampered or the SignerInfo structure
this object contains does not corresponds to the indicated certificateCertificateException - thrown if the signature cannot be trustedTimeStampException - thrown if the signature is time-stamped, but the time-stamp is invalid
or cannot be trustedRevocationWarningException - thrown if the signer's certificate was revoked, but was revoked
after the time specified in the time-stamp; the caller must then
decided if the signature can be trustedCertificationExceptionpublic java.lang.Object getContent()
throws java.io.IOException,
javax.mail.MessagingException
getContent() method. Refer to the
Java Activation Framework
for more information.java.io.IOException - if an I/O error occurs when getting the content from the inherent data handlerjavax.mail.MessagingException - if an error occurs when fetching the inherent data handlerpublic javax.activation.DataHandler getDataHandler()
throws javax.mail.MessagingException
SignedContent object.
The DataHandler allows clients to operate on as well as retrieve the content. Refer to the Java Activation Framework for more information.
javax.mail.MessagingException - if an error occurs when fetching the data handlerpublic java.io.InputStream getInputStream()
throws java.io.IOException,
javax.mail.MessagingException
SignedContent object.
Any mail-specific transfer encodings will be decoded before the input stream
is provided. This is typically a convenience method that just invokes the
inherent DataHandler's getInputStream() method.java.io.IOException - if an I/O error occurs when getting the content from the inherent data handlerjavax.mail.MessagingException - if an error occurs when fetching the inherent data handlerpublic java.io.InputStream getContentInputStream()
throws java.io.IOException
This method can be used to get the content of large messages.
java.io.IOExceptionpublic void setCertificates(X509Certificate[] certificates)
X509Certificates representing
the certifcate chain of the signer. It is intended that the certificate list
is sufficient to contain chains from a recognized 'top level CA' to the signer.
Any certificates to be included have to be set before calling
method setSigner!
Note: Setting the signer´s certificates is an optional task. If no signer
certificates are included, the recipient explicitly has to supply the signer´s
public key when verifying the message:
verify(PublicKey). Otherwise - if the
signer´s certificate chain is included in the S/MIME message - the
verify() method obtains the signer´s
public key from the inherent certificate and the recipient must not extra take
care for explicitly supplying the public key.
certificates - an array of certificatespublic void setCRLs(X509CRL[] crls)
Any CRLs to be included have to be set before calling
method setSigner!
crls - an array of crlspublic void setHeaders(javax.mail.Message message)
Content-Disposition: attachment";
filename="smime.p7m"
or
filename="smime.p7c"
message - message to add the headerspublic X509Certificate[] getCertificates()
public X509CRL[] getCRLs()
public java.lang.String getSMimeType()
public SignerInfo[] getSignerInfos()
SignerInfo objectspublic void setSigner(java.security.PrivateKey privateKey,
X509Certificate signerCertificate)
throws java.security.InvalidKeyException,
java.security.SignatureException
Please ensure that you already have supplied the content and
any certificates and/or crls before calling this setSigner
method.
privateKey - the private key to sign the contentsignerCertificate - the certificate of the signerjava.security.InvalidKeyException - if the key cannot be used for signingjava.security.SignatureException - if the signing process failspublic void writeTo(java.io.OutputStream os)
throws java.io.IOException,
javax.mail.MessagingException
writeTo in class javax.mail.internet.MimeMultipartjava.io.IOException - if an error occurs while writing to the streamjavax.mail.MessagingException - if an error occurs when fetching the data
to be writtenpublic void requestTimeStamp(TimeStampClient timeStampClient)
This API can be used following the setSigner() API to ensure
that the signature is time-stamped.
When this SignedContent structure is encoded to an ASN1 object, a time-stamp will automatically be requested for the signature from the TimeStamp Authority. It will then be added to the SignerInfo structure that represents the signature, causing the signature to be time-stamped.
A time-stamp will NOT be requested under the following circumstances:
timeStampClient parameter is nullnullSignedContent encoding is done, which occurs during a
close operation. Thus, if the time-stamp client that was used to
request that the signature be time-stamped is modified (hash
algorithm changed, TSA policy changed, ...) before the write
operation, these changes will apply to the time-stamp that is
requested during the encoding.timeStampClient - the time-stamp client that will be used to request a time-stamp for
the signature value from a TimeStamp Authority