Skip to content

Commit

Permalink
Merge pull request #15 from OpenAS2/signingbug
Browse files Browse the repository at this point in the history
Custom Headers and Various Fixes
  • Loading branch information
pete-gilchrist committed Jun 7, 2016
2 parents afa627e + fde93cc commit 357b78c
Show file tree
Hide file tree
Showing 27 changed files with 324 additions and 61 deletions.
26 changes: 18 additions & 8 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
OpenAS2 Server
Version 1.3.7
Version 2.0.0
RELEASE NOTES

The OpenAS2 project is pleased to announce the release of OpenAS2 1.3.7
The OpenAS2 project is pleased to announce the release of OpenAS2 2.0.0

The release download file is: OpenAS2Server-1.3.6.zip
The release download file is: OpenAS2Server-2.0.0.zip
The zip file contains a PDF document providing information on installing and using the application.

This release is an enhancement and bugfix release:
1. Fix generator encoding for compression, encryption and signing
2. Support configurable control of canonicalization when signing
3. Support overriding digest "sha-1" algorithm name in signing to use "old" name without dash ("sha1")
4. Support AES128, AES192, AES256 ciphers
This release is an enhancement and bug fix release that includes compatibility testing with other AS2 systems:
1. Add support for custom HTTP headers
- configurable static headers as name/value pairs in the partnership
- configurable dynamic headers with header values set from parsing the name of the file to be sent
2. Fix generator encoding for compression, encryption and signing
3. Support configurable control of canonicalization when signing
4. Support overriding digest "sha-1" algorithm name in signing to use "old" name without dash ("sha1")
5. Support AES128, AES192, AES256 ciphers
6. Support disabling the CMS algorithm protection OID for older AS2 systems that do not support it
7. Added "Troubleshooting.." section to documentation

Upgrade Notes:
1. Canonicalization may affect existing working partnerships in prior versions of OpenAS2 if using a content transfer encoding other than "binary".
If the partnership stops working then add the following attribute to the partnership:
<attribute name="prevent_canonicalization_for_mic" value="true"/>

Java 1.5 or later is required.
NOTE FOR JAVA 1.5: Prior to java 1.6, the Javabeans Activation Framework is NOT included in the standard Java install. Download the 1.1.1 version and extract from the zip file from this web page: http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html#jaf-1.1.1-fcs-oth-JPR
Expand Down
1 change: 1 addition & 0 deletions Server/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<tokenfilter>
<replaceregex replace="\1"
pattern="^.*String VERSION\s*=\s* &quot;(.*)&quot;;.*$" />
<deletecharacters chars=" " />
</tokenfilter>
<striplinebreaks />
</filterchain>
Expand Down
4 changes: 2 additions & 2 deletions Server/config/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@
mimetype="application/EDI-X12"/>

<module classname="org.openas2.processor.storage.MDNFileModule"
filename="%home%/../data/$mdn.msg.sender.as2_id$-$mdn.msg.receiver.as2_id$/mdn/$date.yyyy-MM-DD$/$mdn.msg.content-disposition.filename$-$mdn.msg.headers.message-id$"
filename="%home%/../data/$mdn.msg.sender.as2_id$-$mdn.msg.receiver.as2_id$/mdn/$date.yyyy-MM-dd$/$mdn.msg.content-disposition.filename$-$mdn.msg.headers.message-id$"
protocol="as2"
tempdir="%home%/../data/temp"/>

<module classname="org.openas2.processor.storage.MessageFileModule"
filename="%home%/../data/$msg.sender.as2_id$-$msg.receiver.as2_id$/inbox/$msg.content-disposition.filename$-$msg.headers.message-id$"
header="%home%/../data/$msg.sender.as2_id$-$msg.receiver.as2_id$/msgheaders/$date.yyyy-MM-DD$/$msg.content-disposition.filename$-$msg.headers.message-id$"
header="%home%/../data/$msg.sender.as2_id$-$msg.receiver.as2_id$/msgheaders/$date.yyyy-MM-dd$/$msg.content-disposition.filename$-$msg.headers.message-id$"
protocol="as2"
tempdir="%home%/../data/temp"/>

Expand Down
28 changes: 25 additions & 3 deletions Server/config/partnerships.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,52 @@
<sender name="OpenAS2A"/>
<receiver name="OpenAS2B"/>
<attribute name="protocol" value="as2"/>
<attribute name="content_transfer_encoding" value="binary"/>
<attribute name="content_transfer_encoding" value="8bit"/>
<attribute name="compression_type" value="ZLIB"/>
<attribute name="subject" value="From OpenAS2A to OpenAS2B"/>
<attribute name="as2_url" value="http://localhost:10080"/>
<attribute name="as2_mdn_to" value="[email protected]"/>
<!-- <attribute name="as2_receipt_option" value="http://localhost:10080"/> ...for async MDN-->
<attribute name="as2_mdn_options" value="signed-receipt-protocol=optional, pkcs7-signature; signed-receipt-micalg=optional, SHA256"/>
<attribute name="encrypt" value="3DES"/>
<attribute name="sign" value="MD5"/>
<attribute name="sign" value="SHA1"/>
<attribute name="resend_max_retries" value="3"/>
<attribute name="prevent_canonicalization_for_mic" value="false"/>
<attribute name="no_set_transfer_encoding_for_signing" value="false"/>
<attribute name="no_set_transfer_encoding_for_encryption" value="false"/>
<attribute name="rename_digest_to_old_name" value="false"/>
<attribute name="remove_cms_algorithm_protection_attrib" value="false"/>
</partnership>

<partnership name="OpenAS2B-to-OpenAS2A">
<sender name="OpenAS2B"/>
<receiver name="OpenAS2A"/>
<attribute name="protocol" value="as2"/>
<attribute name="content_transfer_encoding" value="binary"/>
<attribute name="content_transfer_encoding" value="8bit"/>
<attribute name="subject" value="From OpenAS2B to OpenAS2A"/>
<attribute name="as2_url" value="http://localhost:10080"/>
<attribute name="as2_mdn_to" value="[email protected]"/>
<!-- <attribute name="as2_receipt_option" value="http://localhost:10080"/> ...for async MDN-->
<attribute name="as2_mdn_options" value="signed-receipt-protocol=optional, pkcs7-signature; signed-receipt-micalg=optional, SHA256"/>
<attribute name="encrypt" value="3DES"/>
<attribute name="sign" value="SHA256"/>
<attribute name="prevent_canonicalization_for_mic" value="false"/>
<attribute name="remove_cms_algorithm_protection_attrib" value="false"/>
<!--
Example for adding static custom headers to Mime body part and additionally add to HTTP
<attribute name="custom_mime_headers" value="X-CustomHeader: shift-shape ; X-CustomShape: oblong"/>
<attribute name="add_custom_mime_headers_to_http" value="true"/>
-->
<!--
Example for adding dynamic custom headers to Mime body part using delimiters where filename is of form XXX-YYY-ZZZ or XXX_YYY-ZZZ etc
<attribute name="custom_mime_header_names_from_filename" value="header.X-CustomRouteId,header.X-CustomCenter, junk.extraStuff"/>
<attribute name="custom_mime_header_name_delimiters_in_filename" value="-_"/>
Example for adding dynamic custom headers to Mime body part where filename is of form XXX-YYY.msg
<attribute name="custom_mime_header_names_from_filename" value="X-CustomRouteId,X-CustomCenter"/>
<attribute name="custom_mime_header_names_regex_on_filename" value="([^-]*)-([^.]*).msg"/>
-->
</partnership>

</partnerships>

Binary file added Server/dist/OpenAS2Server-2.0.0.zip
Binary file not shown.
Binary file modified Server/lib/openas2-server.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion Server/src/org/openas2/BaseComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public String getParameter(String key, boolean required)
String parameter = (String) getParameters().get(key);

if (required && (parameter == null)) {
throw new InvalidParameterException(this, key, null);
throw new InvalidParameterException("Missing required parameter.", this, key, null);
}

return parameter;
Expand Down
2 changes: 1 addition & 1 deletion Server/src/org/openas2/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/
public interface Session {
/** Official OpenAS2 release version */
public static final String VERSION = "1.3.7";
public static final String VERSION = "2.0.0";

/** Official OpenAS2 title */
public static final String TITLE = "OpenAS2 v" + VERSION;
Expand Down
5 changes: 3 additions & 2 deletions Server/src/org/openas2/app/OpenAS2Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ public void start(String[] args) {
session.getProcessor().startActiveModules();

// enter the command processing loop
write("OpenAS2 Started\r\n");
write("OpenAS2 V" + Session.VERSION + " Started\r\n");


logger.info("- OpenAS2 Started -");
logger.info("- OpenAS2 Started - V" + Session.VERSION);

CommandManager cmdMgr = session.getCommandManager();
List<BaseCommandProcessor> processors = cmdMgr.getProcessors();
for (int i = 0; i < processors.size(); i++) {
Expand Down
6 changes: 4 additions & 2 deletions Server/src/org/openas2/lib/MDNEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,14 @@ protected AS2MessageMDN createAS2MDN(AS2Message msg, EngineResults results) thro
ICertificateChooser certChooser = getCertificateChooser();
Certificate senderCert = certChooser.getSenderCertificate(mdn);
Key senderKey = certChooser.getSenderKey(mdn);
String contentTxfrEncoding = ((Message)msg).getPartnership().getAttribute(Partnership.PA_CONTENT_TRANSFER_ENCODING);
Partnership p = ((Message)msg).getPartnership();
String contentTxfrEncoding = p.getAttribute(Partnership.PA_CONTENT_TRANSFER_ENCODING);
boolean isRemoveCmsAlgorithmProtectionAttr = "true".equalsIgnoreCase(p.getAttribute(Partnership.PA_REMOVE_PROTECTION_ATTRIB));
if (contentTxfrEncoding == null)
contentTxfrEncoding = Session.DEFAULT_CONTENT_TRANSFER_ENCODING;
// sign the data using CryptoHelper
MimeBodyPart signedData = getCryptoHelper().sign(mdn.getData(), senderCert,
senderKey, dispOptions.getMicAlgorithm(),contentTxfrEncoding, false);
senderKey, dispOptions.getMicAlgorithm(),contentTxfrEncoding, false, isRemoveCmsAlgorithmProtectionAttr);
mdn.setData(signedData);
mdn.setContentType(signedData.getContentType());
}
Expand Down
30 changes: 28 additions & 2 deletions Server/src/org/openas2/lib/helper/BCCryptoHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

import javax.activation.CommandMap;
import javax.activation.MailcapCommandMap;
Expand All @@ -35,13 +36,17 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cms.CMSAlgorithm;
import org.bouncycastle.cms.CMSAttributeTableGenerator;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.DefaultSignedAttributeTableGenerator;
import org.bouncycastle.cms.KeyTransRecipientId;
import org.bouncycastle.cms.KeyTransRecipientInformation;
import org.bouncycastle.cms.RecipientInformation;
Expand Down Expand Up @@ -169,6 +174,8 @@ public String calculateMIC(MimeBodyPart part, String digest, boolean includeHead
// Canonicalize the data if not binary content transfer encoding
OutputStream os = null;
String encoding = part.getEncoding();
// Default encoding in case the bodypart does not have a transfer encoding set
if (encoding == null) encoding = Session.DEFAULT_CONTENT_TRANSFER_ENCODING;
if ("binary".equals(encoding) || noCanonicalize) os = bOut;
else os = new CRLFOutputStream(bOut);

Expand Down Expand Up @@ -306,7 +313,8 @@ public void initialize() {
CommandMap.setDefaultCommandMap(mc);
}

public MimeBodyPart sign(MimeBodyPart part, Certificate cert, Key key, String digest, String contentTxfrEncoding, boolean adjustDigestToOldName)
public MimeBodyPart sign(MimeBodyPart part, Certificate cert, Key key, String digest, String contentTxfrEncoding
, boolean adjustDigestToOldName, boolean isRemoveCmsAlgorithmProtectionAttr)
throws GeneralSecurityException, SMIMEException, MessagingException {
//String signDigest = convertAlgorithm(digest, true);
X509Certificate x509Cert = castCertificate(cert);
Expand Down Expand Up @@ -335,7 +343,20 @@ public MimeBodyPart sign(MimeBodyPart part, Certificate cert, Key key, String di
}
// Remove the dash for SHA based digest for signing call
if (digest.toUpperCase().startsWith("SHA-")) digest = digest.replaceAll("-", "");
sig = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build(digest+"with"+encryptAlg, privKey, x509Cert);
JcaSimpleSignerInfoGeneratorBuilder jSig = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC");
sig = jSig.build(digest+"with"+encryptAlg, privKey, x509Cert);
// Some AS2 systems cannot handle certain OID's ...
if (isRemoveCmsAlgorithmProtectionAttr)
{
final CMSAttributeTableGenerator sAttrGen = sig.getSignedAttributeTableGenerator();
sig = new SignerInfoGenerator(sig, new DefaultSignedAttributeTableGenerator(){
@Override
public AttributeTable getAttributes(@SuppressWarnings("rawtypes") Map parameters) {
AttributeTable ret = sAttrGen.getAttributes(parameters);
return ret.remove(CMSAttributes.cmsAlgorithmProtect);
}
}, sig.getUnsignedAttributeTableGenerator());
}
} catch (OperatorCreationException e) {
throw new GeneralSecurityException(e);
}
Expand Down Expand Up @@ -400,6 +421,11 @@ public MimeBodyPart verifySignature(MimeBodyPart part, Certificate cert)
while (it.hasNext())
{
SignerInformation signer = it.next();
if (logger.isTraceEnabled())
{
AttributeTable attrTbl = signer.getSignedAttributes();
logger.trace("Signer Attributes: " + (attrTbl==null?"NULL":attrTbl.toHashtable()));
}
if (signer.verify(signerInfoVerifier))
{
logSignerInfo("Verified signature for signer info", signer, part);
Expand Down
6 changes: 4 additions & 2 deletions Server/src/org/openas2/lib/helper/EDIINTHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ public void sign(EDIINTMessage msg, Certificate cert, Key key, String digest)
// get the data to sign
MimeBodyPart data = msg.getData();

String contentTxfrEncoding = ((Message)msg).getPartnership().getAttribute(Partnership.PA_CONTENT_TRANSFER_ENCODING);
Partnership p = ((Message)msg).getPartnership();
String contentTxfrEncoding = p.getAttribute(Partnership.PA_CONTENT_TRANSFER_ENCODING);
boolean isRemoveCmsAlgorithmProtectionAttr = "true".equalsIgnoreCase(p.getAttribute(Partnership.PA_REMOVE_PROTECTION_ATTRIB));
if (contentTxfrEncoding == null)
contentTxfrEncoding = Session.DEFAULT_CONTENT_TRANSFER_ENCODING;
// sign the data using CryptoHelper
MimeBodyPart signedData = getCryptoHelper().sign(data, cert, key, digest, contentTxfrEncoding, false);
MimeBodyPart signedData = getCryptoHelper().sign(data, cert, key, digest, contentTxfrEncoding, false, isRemoveCmsAlgorithmProtectionAttr);

// update the message's data and content type
msg.setData(signedData);
Expand Down
3 changes: 2 additions & 1 deletion Server/src/org/openas2/lib/helper/ICryptoHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ public interface ICryptoHelper {

void initialize() throws Exception;

MimeBodyPart sign(MimeBodyPart part, Certificate cert, Key key, String digest, String contentTxfrEncoding, boolean adjustDigestToOldName) throws Exception;
MimeBodyPart sign(MimeBodyPart part, Certificate cert, Key key, String digest, String contentTxfrEncoding
, boolean adjustDigestToOldName, boolean isRemoveCmsAlgorithmProtectionAttr) throws Exception;

MimeBodyPart verifySignature(MimeBodyPart part, Certificate cert) throws Exception;

Expand Down
17 changes: 17 additions & 0 deletions Server/src/org/openas2/message/BaseMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public abstract class BaseMessage implements Message {
private String calculatedMIC = null;
private String logMsg = null;
private String status = MSG_STATUS_MSG_INIT;
private Map<String, String> customOuterMimeHeaders = new HashMap<String, String>();


public BaseMessage() {
Expand All @@ -60,6 +61,22 @@ public void setStatus(String status)
this.status = status;
}

public Map<String, String> getCustomOuterMimeHeaders()
{
return customOuterMimeHeaders;
}


public void setCustomOuterMimeHeaders(Map<String, String> customOuterMimeHeaders)
{
this.customOuterMimeHeaders = customOuterMimeHeaders;
}

public void addCustomOuterMimeHeader(String key, String value)
{
this.customOuterMimeHeaders.put(key, value);
}

public void setOption(Object key, Object value) {
getOptions().put(key, value);
}
Expand Down
6 changes: 6 additions & 0 deletions Server/src/org/openas2/message/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public interface Message extends Serializable {

public String getStatus();

public Map<String, String> getCustomOuterMimeHeaders();

public void setCustomOuterMimeHeaders(Map<String, String> customOuterMimeHeaders);

public void addCustomOuterMimeHeader(String key, String value);

public Map<Object, Object> getOptions();

public void setOption(Object key, Object value);
Expand Down
11 changes: 2 additions & 9 deletions Server/src/org/openas2/params/InvalidParameterException.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ public InvalidParameterException(String msg, Object target, String key, String v
this.value = value;
}

public InvalidParameterException(Object target, String key, String value) {
super(toString(key, value));
this.target = target;
this.key = key;
this.value = value;
}

public InvalidParameterException(String msg) {
super(msg);
}
Expand Down Expand Up @@ -56,12 +49,12 @@ public void setValue(String value) {
public static void checkValue(Object target, String valueName, Object value)
throws InvalidParameterException {
if (value == null) {
throw new InvalidParameterException(target, valueName, null);
throw new InvalidParameterException("Missing value for required parameter: " + valueName, target, valueName, null);
}
}

public static String toString(String key, String value) {
return "Invalid parameter value for " + key + ": " + value;
return "Key/Value pair: " + key + "/" + value;
}

}
4 changes: 2 additions & 2 deletions Server/src/org/openas2/params/ParameterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void setParameters(String encodedParams) throws InvalidParameterException
key = params.nextToken().trim();

if (!params.hasMoreTokens()) {
throw new InvalidParameterException("Invalid value", this, key, null);
throw new InvalidParameterException("Invalid value for encoded param \"" + encodedParams + "\"", this, key, null);
}

value = params.nextToken();
Expand All @@ -54,7 +54,7 @@ public void setParameters(String format, String delimiters, String value)

while (keyIt.hasNext()) {
if (!valueTokens.hasMoreTokens()) {
throw new OpenAS2Exception("Invalid value: Format=" + format + ", value=" + value);
throw new OpenAS2Exception("String value does not match format: Format=" + format + " ::: Value=" + value + " ::: String delimiters=" + delimiters);
}

key = ((String) keyIt.next()).trim();
Expand Down
5 changes: 5 additions & 0 deletions Server/src/org/openas2/partner/AS2Partnership.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ public interface AS2Partnership {
public static final String PA_AS2_RECEIPT_OPTION = "as2_receipt_option"; // URL destination for an async MDN
public static final String PA_MESSAGEID = "messageid"; // format to use for message-id if not default
public static final String PA_RESEND_MAX_RETRIES = "resend_max_retries"; // format to use for message-id if not default
public static final String PA_CUSTOM_MIME_HEADERS = "custom_mime_headers";
public static final String PA_ADD_CUSTOM_MIME_HEADERS_TO_HTTP = "add_custom_mime_headers_to_http";
public static final String PA_CUSTOM_MIME_HEADER_NAMES_FROM_FILENAME = "custom_mime_header_names_from_filename";
public static final String PA_CUSTOM_MIME_HEADER_NAME_DELIMITERS_IN_FILENAME = "custom_mime_header_name_delimiters_in_filename";
public static final String PA_CUSTOM_MIME_HEADER_NAMES_REGEX_ON_FILENAME = "custom_mime_header_names_regex_on_filename";
}
Loading

0 comments on commit 357b78c

Please sign in to comment.