001: /*
002: * Title: Oyster Project
003: * Description: S/MIME email sending capabilities
004: * @Author Vladan Obradovic, Vladimir Radisic
005: * @Version 2.1.6
006: */
007:
008: package org.enhydra.oyster.smime;
009:
010: import org.enhydra.oyster.exception.SMIMEException;
011: import org.enhydra.oyster.activation.CMSSignedDataSource;
012: import javax.mail.internet.MimeMessage;
013: import javax.mail.Multipart;
014: import javax.mail.internet.MimeMessage;
015: import javax.mail.internet.MimeBodyPart;
016: import javax.mail.internet.MimeMultipart;
017: import javax.activation.DataHandler;
018: import java.util.Vector;
019: import java.util.TimeZone;
020: import java.util.GregorianCalendar;
021: import java.io.FileInputStream;
022: import java.security.PrivateKey;
023: import java.security.KeyStore;
024: import java.security.cert.X509Certificate;
025:
026: /**
027: * SignedSMIME class is used for creating and sending signed S/MIME message.<BR>
028: * <BR>
029: * Email message is in general composed of the content of the message and of one or
030: * more attachments. The content is visible part of the message, and attacments are
031: * mostly files or other binary data, which are not visible parts of message and
032: * which are used by email as a transport medium. In this implementation content
033: * can be represented in two different forms: <BR>
034: * <BR>
035: * <UL><LI>
036: * text/plain (only text withouth any formating) or
037: * </LI> <LI>
038: * text/html (html coded view of message)
039: * </LI></UL>
040: * Also, content can be absent, but than at least one attachment must be added.
041: * Content can be set on few manners. For text/plain type it can be done in time
042: * of construction with constructor designed special for creation of text/plain
043: * messages. Also, text content can be created by any of setContent() methods,
044: * if construction of object was done by other constructor which creates object
045: * with empty content. Construction with other constructor offers a few different
046: * posibilities for importing content data (File, InputStream, String) by using
047: * appropriate setContent() method. If method with four parameters is used, 3rd
048: * ant 4th parameters are not in use for text/plain message and could be set to
049: * null. For setting text/html content, construction of object should be done
050: * only by second mentioned constructor, which creates object with empty content.
051: * Content should be populated by html code with setContent() method. 3rd
052: * parameter is used for resolving relative addresses of resources in html
053: * code (images, movies...) and 4th parameter serves as data source for resources
054: * that are on special way addressed in html code. Also, there is a setContent()
055: * method which doesn't care about resources and which creates message content
056: * withouth them. For more information refer to setContent() methods.<BR>
057: * <BR>
058: * Message can contain any number of attachments. Also, message can
059: * be wihouth any attachment, but then content must be present. Every attachment
060: * should be added by performing single addAttachment() method. Attachments
061: * can be added from file or from InputStream. Mime-type which corresponds to
062: * particular attachment is obtained according to extension of file name
063: * (virtual or real file name) passed to addAttachment() method. File mime.types
064: * in META_INF directory contains list of mime-types and corresponding extensions
065: * which are used in determination of mime-type. File can be changed to satisfy
066: * specific requrements. For more information refer to addAttachmenttent()
067: * method.<BR>
068: * <BR>
069: * Message can be external (explicit) or internal (implicit) signed. External
070: * signing allows email receiving clients wihouth implemented SMIME
071: * capabilities to preview the signed SMIME email messages.<BR>
072: * <BR>
073: * Message can be signed with or without Signed Attributes. Signed Attributes
074: * are one optional part of CMS (Cryptographic Message Syntax) signed objects,
075: * and consist of some atributes used in the process of signing (date and time
076: * of signing, capabilities of sending email client, message digest value...).
077: * If those attributes are ommited, only pure message is taken in the process
078: * of signing.<BR>
079: * <BR>
080: * Digest algorithm can be SHA1, MD2 or MD5 which depends on selected signing algorithm.<BR>
081: * <BR>
082: * Capabilities Attributes are one of Signed Attributes, and in the process of
083: * signing (if Signed Attributes are involved) can be set. This attributes
084: * indicate to recipient email client which encipher, symmetric and/or signature
085: * algorithms signer's email client preferes, and they can be used in the next
086: * communication between each others. Setting this posibilities is optional, but
087: * if it is set, order of adding gives the information about most preferes algorithms
088: * within paricular group of algorithms. Defined Capabilities Attributes in this version
089: * of Signed SMIME can be from group: RC2 40, RC2 64, RC2 128, DES and DES_EDE3 for
090: * symmetric encryption algorihms, from group: MD2 with RSA, MD5 with RSA, SHA1 with RSA
091: * and SHA1 with DSA for signing algorithms, and RSA for encipher algorithm. For more
092: * information see setCapabilities method in this class.<BR>
093: * <BR>
094: * Certificates of signers and their root authorities can be included in the
095: * signed message. This posibilities allow the recipient of signed SMIME
096: * message to automatically include signer's certificates as trusted, and verify
097: * signed message. This posibilities are optional.<BR>
098: * <BR>
099: * More than one signer can perform signing of message and they can use
100: * different signing algorithms. Digital signing can be performed by SHA1_WITH_RSA,
101: * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA.<BR>
102: * <BR>
103: */
104: public class SignedSMIME extends BaseSignedSMIMEObject {
105:
106: /**
107: * Simple constructor. Dynamically loads the BC and SUN provider necessary for
108: * cryptography processing. This constructor does not create MIME message
109: * object, so it is obligatory to invoke initMimeMessage() method after this
110: * constructor.
111: */
112: protected SignedSMIME() {
113: super ();
114: }
115:
116: /**
117: * Initializes the JavaMail session for SMTP and the MimeMessage object for message
118: * which will be sent. Dynamically loads the BC and SUN provider necessary for
119: * cryptography processing. This constructor is used for creating message with
120: * text/plain content. For creating html formated content (text/html), other
121: * constructor should be used in combination with one of setContent methods.
122: * Note that after using this constructor setContent method can be used only
123: * if "content" argument of constructor was given as null, otherwise setContent
124: * method can't be used because content is already set as text/plain.
125: * @param smtpHost name of SMTP host used for sending email
126: * @param fromAddress email address of sender (FROM field in email header)
127: * @param subject subject of email (SUBJECT field in email header). This
128: * argument can be null, but email message will be sent withouth SUBJECT.
129: * @param content text/plain content of email message. This argument can be
130: * null, but later one of setContent() methods or one of addAttachment()
131: * methods should be called
132: * @param charset character set for passed subject and content. The given
133: * Unicode string will be charset-encoded using the specified charset. The
134: * charset is also used to set the "charset" parameter. For example German
135: * letters should be encoded by usage of 'ISO-8859-1' charset. If charset
136: * parameter is null and subject or content contains non US-ASCII characters,
137: * it will be encoded using the platform's default charset.
138: * @exception SMIMEException if smtpHost or fromAddress parameters are null.
139: * Also, it can be caused by non SMIMEException which is MessagingException.
140: */
141: public SignedSMIME(String smtpHost, String fromAddress,
142: String subject, String content, String charset)
143: throws SMIMEException {
144: super (smtpHost, fromAddress, subject, content, charset);
145: }
146:
147: /**
148: * Initializes the JavaMail session for SMTP and the MimeMessage object for message
149: * which will be sent. Dynamically loads the BC and SUN provider necessary for
150: * cryptography processing. This constructor does not create content of message
151: * and it can be set later with one of setContent methods. Also, message can be
152: * left withouth content, but then at least one attachement must be added.
153: * @param smtpHost name of SMTP host used for sending email
154: * @param fromAddress email address of sender (FROM field in email header)
155: * @param subject subject of email (SUBJECT field in email header). This
156: * argument can be null, but email message will be sent withouth SUBJECT.
157: * @param charset character set for passed subject and content. The given
158: * Unicode string will be charset-encoded using the specified charset. The
159: * charset is also used to set the "charset" parameter. For example German
160: * letters should be encoded by usage of 'ISO-8859-1' charset. If charset
161: * parameter is null and subject or content contains non US-ASCII characters,
162: * it will be encoded using the platform's default charset.
163: * @exception SMIMEException if smtpHost or fromAddress parameters are null.
164: * Also, it can be caused by non SMIMEException which is MessagingException.
165: */
166: public SignedSMIME(String smtpHost, String fromAddress,
167: String subject, String charset) throws SMIMEException {
168: super (smtpHost, fromAddress, subject, null, charset);
169: }
170:
171: /**
172: * Construction of message with external prepared MimeMessage object. Usage of
173: * this constructor disables usage of setContent() and addAttachment() methods.
174: * Also, all recipients (TO, CC or BCC type) must be declared again via
175: * setRecipient() method, even if they were previously set. Be very carefull
176: * with usage of this constructor because all MimeBodyPart objects and
177: * MimeMultipart objects used in construction of given MimeMessage object,
178: * must have correct defined Content header arguments, and contents. Contents
179: * must be formed in format which can be recognised and appropriate interpreted
180: * in the process of sending mail. If there is any special content object
181: * added to MimeBodyPart object or MimeMultipart object, the appropriate
182: * DataContent handler must be created for that object and set to corresponding
183: * BodyPart.
184: * @param mimeMessage external created MimeMessage object
185: * @exception SMIMEException if smtpHost or fromAddress parameter is null.
186: * Also, it can be caused by non SMIMEException which is MessagingException.
187: */
188: public SignedSMIME(MimeMessage mimeMessage) throws SMIMEException {
189: super (mimeMessage);
190: }
191:
192: /**
193: * Adds recipient email address and type. At least one recipient must be declared
194: * as TO type.
195: * @param recipientAddress email address of recipent (fields TO or CC or BCC
196: * in email message header)
197: * @param type should be TO, CC or BCC.
198: * @exception SMIMEException if type of addressing of the messages is not TO, CC,
199: * or BCC. Also it can be caused by non SMIMEException which is MessagingException.
200: */
201: public void addRecipient(String recipientAddress, String type)
202: throws SMIMEException {
203: super .addRecipient(recipientAddress, type, null);
204: }
205:
206: /**
207: * Creates and signes the message with default implicit signing.
208: * @exception SMIMEException if one of recipients is not declared as TO
209: * recipient, or if there is no message for signing. Also, it can be caused
210: * by non SMIMEException which can be one of the following: MessagingException
211: * or IOException.
212: */
213: public void signing() throws SMIMEException {
214: this .signing(false);
215: }
216:
217: /**
218: * Creates and signes the message.
219: * @param externalSignature choice between implicit and explicit signing
220: * (true = explicit or external signing, false = implicit or internal signing).
221: * @exception SMIMEException if one of recipients is not declared as TO
222: * recipient, or if there is no message for signing. Also, it can be caused
223: * by non SMIMEException which can be one of the following: MessagingException,
224: * or IOException.
225: */
226: public void signing(boolean externalSignature)
227: throws SMIMEException {
228: try {
229: if (super .indicatorTo != true)
230: throw new SMIMEException(1043);
231:
232: if (!super .externalMessagePresence) { // external MimeMessage object presence cheking
233:
234: if (super .contentPresence
235: & super .bodyPartArray.size() == 1) { // message contains only content
236: if (super .bodyPartArray.elementAt(0) instanceof MimeBodyPart) { // text/plain message
237: MimeBodyPart contentBody = (MimeBodyPart) super .bodyPartArray
238: .elementAt(0);
239: super .message.setContent((String) contentBody
240: .getContent(), contentBody
241: .getContentType());
242: super .message
243: .setDisposition(super .message.INLINE);
244: } else
245: // text/html message
246: super .message
247: .setContent((MimeMultipart) super .bodyPartArray
248: .elementAt(0));
249: } else if (super .bodyPartArray.size() != 0) {
250: Multipart mp = new MimeMultipart();
251: for (int i = 0; i != super .bodyPartArray.size(); i++) {
252: if (super .bodyPartArray.elementAt(i) instanceof MimeMultipart) {
253: MimeBodyPart forMulti = new MimeBodyPart();
254: forMulti
255: .setContent((MimeMultipart) super .bodyPartArray
256: .elementAt(i));
257: mp.addBodyPart(forMulti);
258: } else
259: mp
260: .addBodyPart((MimeBodyPart) super .bodyPartArray
261: .elementAt(i));
262: }
263: super .message.setContent(mp);
264: } else
265: throw new SMIMEException(1044);
266:
267: }
268:
269: CMSSignedDataSource ss = new CMSSignedDataSource(
270: super .message, externalSignature);
271: for (int i = 0; i < super .ksArray.size(); i++) {
272: boolean[] incl = (boolean[]) super .including
273: .elementAt(i);
274: for (int j = 6 * i; j != (6 * (i + 1)); j = j + 2) {
275: if (super .capabilities.elementAt(j) == null)
276: continue;
277: String[] capabil = (String[]) super .capabilities
278: .elementAt(j + 1);
279: ss.setCapabilities((String) super .capabilities
280: .elementAt(j), capabil);
281: }
282: ss.addSigner((KeyStore) super .ksArray.elementAt(i),
283: incl[0], incl[1], (String) super .digestArray
284: .elementAt(i));
285: }
286: for (int i = 0; i < super .certChainArray.size(); i++) {
287: boolean[] incl2 = (boolean[]) super .including2
288: .elementAt(i);
289: for (int j = 6 * i; j != (6 * (i + 1)); j = j + 2) {
290: if (super .capabilities2.elementAt(j) == null)
291: continue;
292: String[] capabil = (String[]) super .capabilities2
293: .elementAt(j + 1);
294: ss.setCapabilities((String) super .capabilities2
295: .elementAt(j), capabil);
296: }
297: ss.addSigner((X509Certificate[]) certChainArray
298: .elementAt(i), (PrivateKey) super .privKeyArray
299: .elementAt(i), incl2[0], incl2[1],
300: (String) super .digestArray2.elementAt(i));
301: }
302: for (int i = 0; i < super .aditionalCerts.size(); i++) {
303: ss
304: .addCertificate((X509Certificate) super .aditionalCerts
305: .elementAt(i));
306: }
307: super .message.setDataHandler(new DataHandler(ss));
308: super .message.saveChanges();
309: super .message.setDescription("Signed SMIME message.");
310:
311: super .message.setDisposition(super .message.ATTACHMENT);
312: TimeZone tz = TimeZone.getDefault(); // Sets date and time
313: GregorianCalendar cal = new GregorianCalendar(tz);
314: super .message.setSentDate(cal.getTime());
315: clean();
316: } catch (Exception e) {
317: throw new SMIMEException(e);
318: }
319:
320: }
321:
322: /**
323: * Returns SMIME Message. This method returns same object as getMimeMessage()
324: * method located in super class and will be removed in future release.
325: * @deprecated
326: * @return Signed S/MIME message
327: */
328: public MimeMessage getSignedMessage() {
329: return super .message;
330: }
331:
332: /**
333: * Releases unnecessary memory.
334: */
335: private void clean() {
336: super .reset();
337: System.gc(); // Calling garbage collector
338: }
339: }
|