//$Header: /cvsroot-fuse/mec-as2/39/mendelson/comm/as2/message/AS2MessageCreation.java,v 1.1 2012/04/18 14:10:30 heller Exp $
package de.mendelson.comm.as2.message;
import com.sun.mail.util.LineOutputStream;
import de.mendelson.util.security.cert.CertificateManager;
import de.mendelson.comm.as2.partner.Partner;
import de.mendelson.util.AS2Tools;
import de.mendelson.util.MecResourceBundle;
import de.mendelson.util.security.BCCryptoHelper;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.activation.DataHandler;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;
import org.apache.commons.io.output.DeferredFileOutputStream;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSEnvelopedDataStreamGenerator;
import org.bouncycastle.mail.smime.SMIMECompressedGenerator;
import org.bouncycastle.mail.smime.SMIMEException;
/*
* Copyright (C) mendelson-e-commerce GmbH Berlin Germany
*
* This software is subject to the license agreement set forth in the license.
* Please read and agree to all terms before using this software.
* Other product and brand names are trademarks of their respective owners.
*/
/**
* Packs a message with all necessary headers and attachments
* @author S.Heller
* @version $Revision: 1.1 $
*/
public class AS2MessageCreation {
private Logger logger = null;
private MecResourceBundle rb = null;
private MecResourceBundle rbMessage = null;
private CertificateManager signatureCertManager = null;
private CertificateManager encryptionCertManager = null;
//Database connection
private Connection runtimeConnection;
private Connection configConnection;
public AS2MessageCreation(CertificateManager signatureCertManager, CertificateManager encryptionCertManager) {
//Load resourcebundle
try {
this.rb = (MecResourceBundle) ResourceBundle.getBundle(
ResourceBundleAS2MessagePacker.class.getName());
this.rbMessage = (MecResourceBundle) ResourceBundle.getBundle(
ResourceBundleAS2Message.class.getName());
} //load up resourcebundle
catch (MissingResourceException e) {
throw new RuntimeException("Oops..resource bundle " + e.getClassName() + " not found.");
}
this.signatureCertManager = signatureCertManager;
this.encryptionCertManager = encryptionCertManager;
}
/**Passes a logger to this creation class*/
public void setLogger(Logger logger) {
this.logger = logger;
}
/**Passes a database connection to this class to allow logging functionality*/
public void setServerResources(Connection configConnection, Connection runtimeConnection) {
this.runtimeConnection = runtimeConnection;
this.configConnection = configConnection;
}
/**Escapes the AS2-TO and AS2-FROM headers in sending direction, related to
* RFC 4130 section 6.2
* @param identification as2-from or as2-to value to escape
* @return escaped value
*/
public static String escapeFromToHeader(String identification) {
boolean containsBlank = false;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < identification.length(); i++) {
char singleChar = identification.charAt(i);
if (singleChar == ' ') {
containsBlank = true;
} else if (singleChar == '"') {
builder.append("\\");
} else if (singleChar == '\\') {
builder.append("\\");
}
builder.append(singleChar);
}
//quote the value if it contains blanks
if (containsBlank) {
builder.insert(0, "\"");
builder.append("\"");
}
return (builder.toString());
}
/**Displays a bundle of byte arrays as hex string, for debug purpose only*/
private String toHexDisplay(byte[] data) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < data.length; i++) {
result.append(Integer.toString((data[i] & 0xff) + 0x100, 16).substring(1));
result.append(" ");
}
return result.toString();
}
/**Prepares the message if it contains no MIME structure*/
public AS2Message createMessageNoMIME(AS2Message message, Partner receiver) throws Exception {
AS2MessageInfo info = (AS2MessageInfo) message.getAS2Info();
BCCryptoHelper cryptoHelper = new BCCryptoHelper();
//payload content type.
message.setContentType(receiver.getContentType());
message.setRawData(message.getPayload(0).getData());
message.setDecryptedRawData(message.getPayload(0).getData());
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.notsigned",
new Object[]{
info.getMessageId()
}), info);
}
//compute content mic. Use sha1 as hash alg.
String digestOID = cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_SHA1);
String mic = cryptoHelper.calculateMIC(message.getPayload(0).getData(), digestOID);
info.setReceivedContentMIC(mic + ", sha1");
//add compression
if (receiver.getCompressionType() == AS2Message.COMPRESSION_ZLIB) {
info.setCompressionType(AS2Message.COMPRESSION_ZLIB);
int uncompressedSize = message.getDecryptedRawData().length;
MimeBodyPart bodyPart = this.compressPayload(receiver, message.getDecryptedRawData(), receiver.getContentType());
int compressedSize = bodyPart.getSize();
//sometimes size() is unable to determine the size of the compressed body part and will return -1. Dont log the
//compression ratio in this case.
if (compressedSize == -1) {
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.compressed.unknownratio",
new Object[]{
info.getMessageId()
}), info);
}
} else {
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.compressed",
new Object[]{
info.getMessageId(), AS2Tools.getDataSizeDisplay(uncompressedSize),
AS2Tools.getDataSizeDisplay(compressedSize)
}), info);
}
}
//write compressed data into the message array
ByteArrayOutputStream bodyOutStream = new ByteArrayOutputStream();
bodyPart.writeTo(bodyOutStream);
bodyOutStream.flush();
bodyOutStream.close();
message.setDecryptedRawData(bodyOutStream.toByteArray());
}
//no encryption
if (info.getEncryptionType() == AS2Message.ENCRYPTION_NONE) {
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.notencrypted",
new Object[]{
info.getMessageId()
}), info);
}
message.setRawData(message.getDecryptedRawData());
} else {
//encrypt the message raw data
String cryptAlias = this.encryptionCertManager.getAliasByFingerprint(receiver.getCryptFingerprintSHA1());
this.encryptDataToMessage(message, cryptAlias, info.getEncryptionType(), receiver);
}
return (message);
}
/**Enwrapps the data into a signed MIME message structure and returns it*/
private void enwrappInMessageAndSign(AS2Message message, Part contentPart, Partner sender, Partner receiver) throws Exception {
AS2MessageInfo info = (AS2MessageInfo) message.getAS2Info();
MimeMessage messagePart = new MimeMessage(Session.getInstance(System.getProperties(), null));
//sign message if this is requested
if (info.getSignType() != AS2Message.SIGNATURE_NONE) {
MimeMultipart signedPart = this.signContentPart(contentPart, sender, receiver);
if (this.logger != null) {
String signAlias = this.signatureCertManager.getAliasByFingerprint(sender.getSignFingerprintSHA1());
this.logger.log(Level.INFO, this.rb.getResourceString("message.signed",
new Object[]{
info.getMessageId(), signAlias,
this.rbMessage.getResourceString("signature." + receiver.getSignType())
}), info);
}
messagePart.setContent(signedPart);
messagePart.saveChanges();
} else {
//unsigned message
if (contentPart instanceof MimeBodyPart) {
MimeMultipart unsignedPart = new MimeMultipart();
unsignedPart.addBodyPart((MimeBodyPart) contentPart);
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.notsigned",
new Object[]{
info.getMessageId()
}), info);
}
messagePart.setContent(unsignedPart);
} else if (contentPart instanceof MimeMultipart) {
messagePart.setContent((MimeMultipart) contentPart);
} else if (contentPart instanceof MimeMessage) {
messagePart = (MimeMessage) contentPart;
} else {
throw new IllegalArgumentException("enwrappInMessageAndSign: Unable to set the content of a "
+ contentPart.getClass().getName());
}
messagePart.saveChanges();
}
//store signed or unsigned data
ByteArrayOutputStream signedOut = new ByteArrayOutputStream();
//normally the content type header is folded (which is correct but some products are not able to parse this properly)
//Now take the content-type, unfold it and write it
Enumeration headerLines = messagePart.getMatchingHeaderLines(new String[]{"Content-Type"});
LineOutputStream los = new LineOutputStream(signedOut);
while (headerLines.hasMoreElements()) {
//requires java mail API >= 1.4
String nextHeaderLine = MimeUtility.unfold((String) headerLines.nextElement());
//write the line only if the as2 message is encrypted. If the as2 message is unencrypted this header is added later
//in the class MessageHttpUploader
if (info.getEncryptionType() != AS2Message.ENCRYPTION_NONE) {
los.writeln(nextHeaderLine);
}
//store the content line in the as2 message object, this value is required later in MessageHttpUploader
message.setContentType(nextHeaderLine.substring(nextHeaderLine.indexOf(':') + 1));
}
messagePart.writeTo(signedOut,
new String[]{"Message-ID", "Mime-Version", "Content-Type"});
signedOut.flush();
signedOut.close();
message.setDecryptedRawData(signedOut.toByteArray());
}
/**Builds up a new message from the passed message parts
*/
public AS2Message createMessage(Partner sender, Partner receiver, File[] payloadFiles) throws Exception {
return (this.createMessage(sender, receiver, payloadFiles, AS2Message.MESSAGETYPE_AS2));
}
/**Builds up a new message from the passed message parts
* @param messageType one of the message types definfed in the class AS2Message
*/
public AS2Message createMessage(Partner sender, Partner receiver, File[] payloadFiles, int messageType) throws Exception {
//create payloads from the payload files
AS2Payload[] payloads = new AS2Payload[payloadFiles.length];
for (int i = 0; i < payloadFiles.length; i++) {
File payloadFile = payloadFiles[i];
InputStream inStream = new FileInputStream(payloadFile);
ByteArrayOutputStream payloadOut = new ByteArrayOutputStream();
this.copyStreams(inStream, payloadOut);
inStream.close();
payloadOut.flush();
payloadOut.close();
//add payload
AS2Payload payload = new AS2Payload();
payload.setData(payloadOut.toByteArray());
payload.setOriginalFilename(payloadFile.getName().replace(' ', '_'));
payloads[i] = payload;
}
return (this.createMessage(sender, receiver, payloads, messageType));
}
/**Builds up a new message from the passed message parts
* @param messageType one of the message types definfed in the class AS2Message
*/
public AS2Message createMessage(Partner sender, Partner receiver, AS2Payload[] payloads, int messageType) throws Exception {
return( this.createMessage(sender, receiver, payloads, messageType, null ));
}
/**Builds up a new message from the passed message parts
* @param messageType one of the message types definfed in the class AS2Message
*/
public AS2Message createMessage(Partner sender, Partner receiver, AS2Payload[] payloads, int messageType,
String messageId ) throws Exception {
if( messageId == null ){
messageId = UniqueId.createMessageId(sender.getAS2Identification(), receiver.getAS2Identification());
}
BCCryptoHelper cryptoHelper = new BCCryptoHelper();
AS2MessageInfo info = new AS2MessageInfo();
info.setMessageType(messageType);
info.setSenderId(sender.getAS2Identification());
info.setReceiverId(receiver.getAS2Identification());
info.setSenderEMail(sender.getEmail());
info.setMessageId(messageId);
info.setDirection(AS2MessageInfo.DIRECTION_OUT);
info.setSignType(receiver.getSignType());
info.setEncryptionType(receiver.getEncryptionType());
info.setRequestsSyncMDN(receiver.isSyncMDN());
if (!receiver.isSyncMDN()) {
info.setAsyncMDNURL(sender.getMdnURL());
}
info.setSubject(receiver.getSubject());
try {
info.setSenderHost(InetAddress.getLocalHost().getCanonicalHostName());
} catch (UnknownHostException e) {
//nop
}
//create message object to return
AS2Message message = new AS2Message(info);
//stores all the available body parts that have been prepared
List<MimeBodyPart> contentPartList = new ArrayList<MimeBodyPart>();
for (AS2Payload as2Payload : payloads) {
//add payload
message.addPayload(as2Payload);
if (this.runtimeConnection != null) {
MessageAccessDB messageAccess = new MessageAccessDB(this.configConnection, this.runtimeConnection);
messageAccess.initializeOrUpdateMessage(info);
}
//no MIME message: single payload, unsigned, no CEM
if (info.getSignType() == AS2Message.SIGNATURE_NONE && payloads.length == 1
&& info.getMessageType() != AS2Message.MESSAGETYPE_CEM) {
return (this.createMessageNoMIME(message, receiver));
}
//MIME message
MimeBodyPart bodyPart = new MimeBodyPart();
String contentType = null;
if (as2Payload.getContentType() == null) {
contentType = receiver.getContentType();
} else {
contentType = as2Payload.getContentType();
}
bodyPart.setDataHandler(new DataHandler(new ByteArrayDataSource(as2Payload.getData(), contentType)));
bodyPart.addHeader("Content-Type", contentType);
if (as2Payload.getContentId() != null) {
bodyPart.addHeader("Content-ID", as2Payload.getContentId());
}
if (receiver.getContentTransferEncoding() == AS2Message.CONTENT_TRANSFER_ENCODING_BASE64) {
bodyPart.addHeader("Content-Transfer-Encoding", "base64");
} else {
bodyPart.addHeader("Content-Transfer-Encoding", "binary");
}
//prepare filename to not violate the MIME header rules
if (as2Payload.getOriginalFilename() == null) {
as2Payload.setOriginalFilename(new File(as2Payload.getPayloadFilename()).getName());
}
String newFilename = as2Payload.getOriginalFilename().replace(' ', '_');
newFilename = newFilename.replace('@', '_');
newFilename = newFilename.replace(':', '_');
newFilename = newFilename.replace(';', '_');
newFilename = newFilename.replace('(', '_');
newFilename = newFilename.replace(')', '_');
bodyPart.addHeader("Content-Disposition", "attachment; filename=" + newFilename);
contentPartList.add(bodyPart);
}
Part contentPart = null;
//sigle attachment? No CEM? Every CEM is in a multipart/related container
if (contentPartList.size() == 1 && info.getMessageType() != AS2Message.MESSAGETYPE_CEM) {
contentPart = contentPartList.get(0);
} else {
//build up a new MimeMultipart container for the multiple attachments, content-type
//is "multipart/related"
MimeMultipart multipart = null;
//CEM messages are always in a multipart container (even the response which contains only a single
//payload) with the subtype "application/ediint-cert-exchange+xml".
if (info.getMessageType() == AS2Message.MESSAGETYPE_CEM) {
multipart = new MimeMultipart("related; type=\"application/ediint-cert-exchange+xml\"");
} else {
multipart = new MimeMultipart("related");
}
for (MimeBodyPart bodyPart : contentPartList) {
multipart.addBodyPart(bodyPart);
}
contentPart = new MimeMessage(Session.getInstance(System.getProperties(), null));
contentPart.setContent(multipart, multipart.getContentType());
((MimeMessage) contentPart).saveChanges();
}
//should the content be compressed and enwrapped or just enwrapped?
if (receiver.getCompressionType() == AS2Message.COMPRESSION_ZLIB) {
info.setCompressionType(AS2Message.COMPRESSION_ZLIB);
int uncompressedSize = contentPart.getSize();
contentPart = this.compressPayload(receiver, contentPart);
int compressedSize = contentPart.getSize();
//sometimes size() is unable to determine the size of the compressed body part and will return -1. Dont log the
//compression ratio in this case.
if (uncompressedSize == -1 || compressedSize == -1) {
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.compressed.unknownratio",
new Object[]{
info.getMessageId()
}), info);
}
} else {
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.compressed",
new Object[]{
info.getMessageId(), AS2Tools.getDataSizeDisplay(uncompressedSize),
AS2Tools.getDataSizeDisplay(compressedSize)
}), info);
}
}
}
//compute content mic. Try to use sign digest as hash alg. For unsigned messages take sha-1
String digestOID = null;
if (info.getSignType() == AS2Message.SIGNATURE_MD5) {
digestOID = cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_MD5);
} else {
digestOID = cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_SHA1);
}
String mic = cryptoHelper.calculateMIC(contentPart, digestOID);
if (info.getSignType() == AS2Message.SIGNATURE_MD5) {
info.setReceivedContentMIC(mic + ", md5");
} else {
info.setReceivedContentMIC(mic + ", sha1");
}
this.enwrappInMessageAndSign(message, contentPart, sender, receiver);
//encryption requested for the receiver?
if (info.getEncryptionType() != AS2Message.ENCRYPTION_NONE) {
String cryptAlias = this.encryptionCertManager.getAliasByFingerprint(receiver.getCryptFingerprintSHA1());
this.encryptDataToMessage(message, cryptAlias, info.getEncryptionType(), receiver);
} else {
message.setRawData(message.getDecryptedRawData());
if (this.logger != null) {
this.logger.log(Level.INFO, this.rb.getResourceString("message.notencrypted",
new Object[]{
info.getMessageId()
}), info);
}
}
return (message);
}
/**Encrypts a byte array and returns it*/
private void encryptDataToMessage(AS2Message message, String receiverCryptAlias, int encryptionType, Partner receiver) throws Exception {
AS2MessageInfo info = (AS2MessageInfo) message.getAS2Info();
BCCryptoHelper cryptoHelper = new BCCryptoHelper();
X509Certificate certificate = this.encryptionCertManager.getX509Certificate(receiverCryptAlias);
CMSEnvelopedDataStreamGenerator dataGenerator = new CMSEnvelopedDataStreamGenerator();
dataGenerator.addKeyTransRecipient(certificate);
DeferredFileOutputStream encryptedOutput = new DeferredFileOutputStream(1024 * 1024, "as2encryptdata_", ".mem", null);
OutputStream out = null;
if (encryptionType == AS2Message.ENCRYPTION_3DES) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.DES_EDE3_CBC, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_DES) {
out = dataGenerator.open(encryptedOutput, cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_DES), 56, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC2_40) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.RC2_CBC, 40, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC2_64) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.RC2_CBC, 64, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC2_128) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.RC2_CBC, 128, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC2_196) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.RC2_CBC, 196, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_AES_128) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.AES128_CBC, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_AES_192) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.AES192_CBC, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_AES_256) {
out = dataGenerator.open(encryptedOutput, CMSEnvelopedDataGenerator.AES256_CBC, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC4_40) {
out = dataGenerator.open(encryptedOutput, cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_RC4), 40, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC4_56) {
out = dataGenerator.open(encryptedOutput, cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_RC4), 56, "BC");
} else if (encryptionType == AS2Message.ENCRYPTION_RC4_128) {
out = dataGenerator.open(encryptedOutput, cryptoHelper.convertAlgorithmNameToOID(BCCryptoHelper.ALGORITHM_RC4), 128, "BC");
}
if (out == null) {
throw new Exception("Internal failure: unsupported encryption type " + encryptionType);
}
out.write(message.getDecryptedRawData());
out.close();
encryptedOutput.close();
//size of the data was < than the threshold
if (encryptedOutput.isInMemory()) {
message.setRawData(encryptedOutput.getData());
} else {
//data has been written to a temp file: reread and return
ByteArrayOutputStream memOut = new ByteArrayOutputStream();
encryptedOutput.writeTo(memOut);
memOut.flush();
memOut.close();
//finally delete the temp file
boolean deleted = encryptedOutput.getFile().delete();
message.setRawData(memOut.toByteArray());
}
if (this.logger != null) {
String cryptAlias = this.encryptionCertManager.getAliasByFingerprint(receiver.getCryptFingerprintSHA1());
this.logger.log(Level.INFO, this.rb.getResourceString("message.encrypted",
new Object[]{
info.getMessageId(), cryptAlias,
this.rbMessage.getResourceString("encryption." + receiver.getEncryptionType())
}), info);
}
}
/**Compresses the payload using the ZLIB algorithm
*/
private MimeBodyPart compressPayload(Partner receiver, byte[] data, String contentType) throws SMIMEException, MessagingException {
MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setDataHandler(new DataHandler(new ByteArrayDataSource(data, contentType)));
bodyPart.addHeader("Content-Type", contentType);
if (receiver.getContentTransferEncoding() == AS2Message.CONTENT_TRANSFER_ENCODING_BASE64) {
bodyPart.addHeader("Content-Transfer-Encoding", "base64");
} else {
bodyPart.addHeader("Content-Transfer-Encoding", "binary");
}
SMIMECompressedGenerator generator = new SMIMECompressedGenerator();
if (receiver.getContentTransferEncoding() == AS2Message.CONTENT_TRANSFER_ENCODING_BASE64) {
generator.setContentTransferEncoding("base64");
} else {
generator.setContentTransferEncoding("binary");
}
return (generator.generate(bodyPart, SMIMECompressedGenerator.ZLIB));
}
/**Compresses the payload using the ZLIB algorithm
*/
private MimeBodyPart compressPayload(Partner receiver, Part contentPart) throws SMIMEException {
SMIMECompressedGenerator generator = new SMIMECompressedGenerator();
if (receiver.getContentTransferEncoding() == AS2Message.CONTENT_TRANSFER_ENCODING_BASE64) {
generator.setContentTransferEncoding("base64");
} else {
generator.setContentTransferEncoding("binary");
}
if (contentPart instanceof MimeBodyPart) {
return (generator.generate((MimeBodyPart) contentPart, SMIMECompressedGenerator.ZLIB));
} else if (contentPart instanceof MimeMessage) {
return (generator.generate((MimeMessage) contentPart, SMIMECompressedGenerator.ZLIB));
} else {
throw new IllegalArgumentException("compressPayload: Unable to compress a Part of class " + contentPart.getClass().getName());
}
}
/**Signs the passed data and returns it
*/
private MimeMultipart signContentPart(Part part, Partner sender, Partner receiver) throws Exception {
MimeMultipart signedPart = null;
if (part instanceof MimeBodyPart) {
signedPart = this.signContent((MimeBodyPart) part, sender, receiver);
} else if (part instanceof MimeMessage) {
signedPart = this.signContent((MimeMessage) part, sender, receiver);
} else {
throw new IllegalArgumentException("signContentPart: unable to sign a " + part.getClass().getName() + ".");
}
return (signedPart);
}
/**Signs the passed data and returns it
*/
private MimeMultipart signContent(MimeMessage message, Partner sender, Partner receiver) throws Exception {
PrivateKey senderKey = this.signatureCertManager.getPrivateKeyByFingerprintSHA1(sender.getSignFingerprintSHA1());
if (senderKey == null) {
throw new Exception("AS2MessageCreation.signContent: Key with serial " + sender.getSignFingerprintSHA1()
+ " does not exist in the keystore.");
}
String senderSignAlias = this.signatureCertManager.getAliasByFingerprint(sender.getSignFingerprintSHA1());
Certificate[] chain = this.signatureCertManager.getCertificateChain(senderSignAlias);
String digest = null;
if (receiver.getSignType() == AS2Message.SIGNATURE_SHA1) {
digest = "sha1";
} else if (receiver.getSignType() == AS2Message.SIGNATURE_MD5) {
digest = "md5";
} else {
throw new Exception("Internal failure: Unsupported sign type " + receiver.getSignType());
}
BCCryptoHelper helper = new BCCryptoHelper();
return (helper.sign(message, chain, senderKey, digest));
}
/**Signs the passed message and returns it
*/
private MimeMultipart signContent(MimeBodyPart body, Partner sender, Partner receiver) throws Exception {
PrivateKey senderKey = this.signatureCertManager.getPrivateKeyByFingerprintSHA1(sender.getSignFingerprintSHA1());
String senderSignAlias = this.signatureCertManager.getAliasByFingerprint(sender.getSignFingerprintSHA1());
Certificate[] chain = this.signatureCertManager.getCertificateChain(senderSignAlias);
String digest = null;
if (receiver.getSignType() == AS2Message.SIGNATURE_SHA1) {
digest = "sha1";
} else if (receiver.getSignType() == AS2Message.SIGNATURE_MD5) {
digest = "md5";
} else {
throw new Exception("Internal failure: Unsupported sign type " + receiver.getSignType());
}
BCCryptoHelper helper = new BCCryptoHelper();
return (helper.sign(body, chain, senderKey, digest));
}
/**Copies all data from one stream to another*/
private void copyStreams(InputStream in, OutputStream out) throws IOException {
BufferedInputStream inStream = new BufferedInputStream(in);
BufferedOutputStream outStream = new BufferedOutputStream(out);
//copy the contents to an output stream
byte[] buffer = new byte[1024];
int read = 1024;
//a read of 0 must be allowed, sometimes it takes time to
//extract data from the input
while (read != -1) {
read = inStream.read(buffer);
if (read > 0) {
outStream.write(buffer, 0, read);
}
}
outStream.flush();
}
}