use of com.helger.as2lib.crypto.ECryptoAlgorithmSign in project as2-lib by phax.
the class MainSendToMendelsonTestServer method main.
public static void main(final String[] args) throws Exception {
Proxy aHttpProxy = null;
if (false)
aHttpProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("1.2.3.4", 8080));
IHTTPOutgoingDumperFactory aOutgoingDumperFactory = null;
if (false)
aOutgoingDumperFactory = x -> new HTTPOutgoingDumperStreamBased(System.out);
if (false)
HTTPHelper.setHTTPIncomingDumperFactory(() -> new HTTPIncomingDumperStreamBased(new NonClosingOutputStream(System.out)));
// Start client configuration
final AS2ClientSettings aSettings = new AS2ClientSettings();
aSettings.setKeyStore(EKeyStoreType.PKCS12, new File("src/test/resources/mendelson/key3.pfx"), "test");
// Fixed sender
aSettings.setSenderData("mycompanyAS2", "phax.as2-lib@github.com", "key3");
// Fixed receiver - key alias must be "mendelsontestAS2"
aSettings.setReceiverData("mendelsontestAS2", "mendelsontestAS2", true ? "https://testas2.mendelson-e-c.com:8444/as2/HttpReceiver" : "http://testas2.mendelson-e-c.com:8080/as2/HttpReceiver");
final X509Certificate aReceiverCertificate = AS2KeyStoreHelper.readX509Certificate("src/test/resources/mendelson/key4.cer");
aSettings.setReceiverCertificate(aReceiverCertificate);
// AS2 stuff
aSettings.setPartnershipName(aSettings.getSenderAS2ID() + "_" + aSettings.getReceiverAS2ID());
// When a signed message is used, the algorithm for MIC and message must be
// identical
final ECryptoAlgorithmSign eSignAlgo = ECryptoAlgorithmSign.DIGEST_SHA_512;
// CBC works, GCM is not supported
final ECryptoAlgorithmCrypt eCryptAlgo = ECryptoAlgorithmCrypt.CRYPT_AES128_CBC;
final ECompressionType eCompress = ECompressionType.ZLIB;
final boolean bCompressBeforeSigning = AS2ClientSettings.DEFAULT_COMPRESS_BEFORE_SIGNING;
aSettings.setMDNOptions(new DispositionOptions().setMICAlg(eSignAlgo).setMICAlgImportance(DispositionOptions.IMPORTANCE_REQUIRED).setProtocol(DispositionOptions.PROTOCOL_PKCS7_SIGNATURE).setProtocolImportance(DispositionOptions.IMPORTANCE_REQUIRED));
aSettings.setEncryptAndSign(eCryptAlgo, eSignAlgo);
aSettings.setCompress(eCompress, bCompressBeforeSigning);
aSettings.setMessageIDFormat("github-phax-as2-lib-$date.uuuuMMdd-HHmmssZ$-$rand.1234$@$msg.sender.as2_id$_$msg.receiver.as2_id$");
aSettings.setRetryCount(1);
aSettings.setConnectTimeoutMS(10_000);
aSettings.setReadTimeoutMS(10_000);
aSettings.setHttpOutgoingDumperFactory(aOutgoingDumperFactory);
// Build client request
final AS2ClientRequest aRequest = new AS2ClientRequest("AS2 test message from as2-lib");
aRequest.setData(new DataHandler(new FileDataSource(new File("src/test/resources/mendelson/testcontent.attachment"))));
aRequest.setContentType(CMimeType.TEXT_PLAIN.getAsString());
if (false)
aRequest.setContentTransferEncoding(EContentTransferEncoding.BASE64);
// Send message
final AS2ClientResponse aResponse = new AS2Client().setHttpProxy(aHttpProxy).sendSynchronous(aSettings, aRequest);
if (aResponse.hasException())
LOGGER.info(aResponse.getAsString());
LOGGER.info("Done");
}
use of com.helger.as2lib.crypto.ECryptoAlgorithmSign in project as2-lib by phax.
the class AS2SenderModule method secure.
@Nonnull
protected MimeBodyPart secure(@Nonnull final IMessage aMsg, @Nonnull final EContentTransferEncoding eCTE) throws Exception {
final Partnership aPartnership = aMsg.partnership();
final ICertificateFactory aCertFactory = getSession().getCertificateFactory();
// Get compression parameters
// If compression is enabled, by default is is compressed before signing
ECompressionType eCompressionType = null;
boolean bCompressBeforeSign = true;
Consumer<MimeBodyPart> aCompressBeforeSignCallback = null;
{
final String sCompressionType = aPartnership.getCompressionType();
if (sCompressionType != null) {
eCompressionType = ECompressionType.getFromIDCaseInsensitiveOrNull(sCompressionType);
if (eCompressionType == null)
throw new AS2Exception("The compression type '" + sCompressionType + "' is not supported!");
bCompressBeforeSign = aPartnership.isCompressBeforeSign();
if (bCompressBeforeSign) {
// Replace the message data, because it is the basis for the MIC
aCompressBeforeSignCallback = aMsg::setData;
}
}
}
// Get signing parameters
ECryptoAlgorithmSign eSignAlgorithm = null;
X509Certificate aSenderCert = null;
PrivateKey aSenderKey = null;
boolean bIncludeCertificateInSignedContent = false;
boolean bUseRFC3851MICAlg = false;
boolean bRemoveCmsAlgorithmProtect = false;
{
final String sSignAlgorithm = aPartnership.getSigningAlgorithm();
if (sSignAlgorithm != null) {
aSenderCert = aCertFactory.getCertificate(aMsg, ECertificatePartnershipType.SENDER);
aSenderKey = aCertFactory.getPrivateKey(aSenderCert);
eSignAlgorithm = ECryptoAlgorithmSign.getFromIDOrNull(sSignAlgorithm);
if (eSignAlgorithm == null)
throw new AS2Exception("The signing algorithm '" + sSignAlgorithm + "' is not supported!");
// Include certificate in signed content?
final ETriState eIncludeCertificateInSignedContent = aMsg.partnership().getIncludeCertificateInSignedContent();
if (eIncludeCertificateInSignedContent.isDefined()) {
// Use per partnership
bIncludeCertificateInSignedContent = eIncludeCertificateInSignedContent.getAsBooleanValue();
} else {
// Use global value
bIncludeCertificateInSignedContent = getSession().isCryptoSignIncludeCertificateInBodyPart();
}
// Use old MIC algorithms?
bUseRFC3851MICAlg = aPartnership.isRFC3851MICAlgs();
// Remove CMS attributes?
bRemoveCmsAlgorithmProtect = aPartnership.isRemoveCmsAlgorithmProtect();
}
}
// Get encryption parameters
ECryptoAlgorithmCrypt eCryptAlgorithm = null;
X509Certificate aReceiverCert = null;
{
final String sCryptAlgorithm = aPartnership.getEncryptAlgorithm();
if (sCryptAlgorithm != null) {
aReceiverCert = aCertFactory.getCertificate(aMsg, ECertificatePartnershipType.RECEIVER);
eCryptAlgorithm = ECryptoAlgorithmCrypt.getFromIDOrNull(sCryptAlgorithm);
if (eCryptAlgorithm == null)
throw new AS2Exception("The crypting algorithm '" + sCryptAlgorithm + "' is not supported!");
}
}
// Set CTE once here - required for stream creation later on!
aMsg.headers().setHeader(CHttpHeader.CONTENT_TRANSFER_ENCODING, eCTE.getID());
if (eCompressionType != null || eCryptAlgorithm != null) {
// Header is needed when compression or encryption is enabled
if (aMsg.getData().getHeader(CHttpHeader.CONTENT_TRANSFER_ENCODING) == null)
aMsg.getData().setHeader(CHttpHeader.CONTENT_TRANSFER_ENCODING, eCTE.getID());
}
if (eCompressionType != null && eSignAlgorithm == null && eCryptAlgorithm == null) {
// Compression only - set the respective content type
aMsg.headers().setHeader(CHttpHeader.CONTENT_TYPE, CMimeType.APPLICATION_OCTET_STREAM.getAsStringWithoutParameters());
}
return secureMimeBodyPart(aMsg.getData(), eCTE, eCompressionType, bCompressBeforeSign, aCompressBeforeSignCallback, eSignAlgorithm, aSenderCert, aSenderKey, bIncludeCertificateInSignedContent, bUseRFC3851MICAlg, bRemoveCmsAlgorithmProtect, eCryptAlgorithm, aReceiverCert, aMsg.getLoggingText());
}
use of com.helger.as2lib.crypto.ECryptoAlgorithmSign in project as2-lib by phax.
the class AS2Helper method createMDN.
/**
* Create a new MDN
*
* @param aSession
* AS2 session to be used. May not be <code>null</code>.
* @param aMsg
* The source AS2 message for which the MDN is to be created. May not
* be <code>null</code>.
* @param aDisposition
* The disposition - either success or error. May not be
* <code>null</code>.
* @param sText
* The text to be send. May not be <code>null</code>.
* @return The created MDN object which is already attached to the passed
* source AS2 message.
* @throws Exception
* In case of an error
*/
@Nonnull
public static IMessageMDN createMDN(@Nonnull final IAS2Session aSession, @Nonnull final AS2Message aMsg, @Nonnull final DispositionType aDisposition, @Nonnull final String sText) throws Exception {
ValueEnforcer.notNull(aSession, "AS2Session");
ValueEnforcer.notNull(aMsg, "AS2Message");
ValueEnforcer.notNull(aDisposition, "Disposition");
ValueEnforcer.notNull(sText, "Text");
final Partnership aPartnership = aMsg.partnership();
final AS2MessageMDN aMDN = new AS2MessageMDN(aMsg);
aMDN.headers().setHeader(CHttpHeader.AS2_VERSION, aSession.getAS2VersionID());
aMDN.headers().setHeader(CHttpHeader.DATE, AS2DateHelper.getFormattedDateNow(CAS2Header.DEFAULT_DATE_FORMAT));
aMDN.headers().setHeader(CHttpHeader.SERVER, CAS2Info.NAME_VERSION);
aMDN.headers().setHeader(CHttpHeader.MIME_VERSION, CAS2Header.DEFAULT_MIME_VERSION);
aMDN.headers().setHeader(CHttpHeader.AS2_FROM, aPartnership.getReceiverAS2ID());
aMDN.headers().setHeader(CHttpHeader.AS2_TO, aPartnership.getSenderAS2ID());
// get the MDN partnership info
aMDN.partnership().setSenderAS2ID(aMDN.getHeader(CHttpHeader.AS2_FROM));
aMDN.partnership().setReceiverAS2ID(aMDN.getHeader(CHttpHeader.AS2_TO));
// Set the appropriate key store aliases
aMDN.partnership().setSenderX509Alias(aPartnership.getReceiverX509Alias());
aMDN.partnership().setReceiverX509Alias(aPartnership.getSenderX509Alias());
// Update the partnership
try {
aSession.getPartnershipFactory().updatePartnership(aMDN, true);
} catch (final AS2PartnershipNotFoundException ex) {
// This would block sending an MDN in case a PartnershipNotFoundException
// was the reason for sending the MDN :)
}
aMDN.headers().setHeader(CHttpHeader.FROM, aPartnership.getReceiverEmail());
final String sSubject = aMDN.partnership().getMDNSubject();
if (sSubject != null) {
aMDN.headers().setHeader(CHttpHeader.SUBJECT, new MessageParameters(aMsg).format(sSubject));
} else {
aMDN.headers().setHeader(CHttpHeader.SUBJECT, "Your Requested MDN Response");
}
// Content-Transfer-Encoding for outgoing MDNs
final String sCTE = aPartnership.getContentTransferEncodingSend(EContentTransferEncoding.AS2_DEFAULT.getID());
aMDN.headers().addHeader(CHttpHeader.CONTENT_TRANSFER_ENCODING, sCTE);
aMDN.setText(new MessageParameters(aMsg).format(sText));
aMDN.attrs().putIn(AS2MessageMDN.MDNA_REPORTING_UA, CAS2Info.NAME_VERSION + "@" + aMsg.attrs().getAsString(CNetAttribute.MA_DESTINATION_IP) + ":" + aMsg.attrs().getAsString(CNetAttribute.MA_DESTINATION_PORT));
aMDN.attrs().putIn(AS2MessageMDN.MDNA_ORIG_RECIPIENT, "rfc822; " + aMsg.getHeader(CHttpHeader.AS2_TO));
aMDN.attrs().putIn(AS2MessageMDN.MDNA_FINAL_RECIPIENT, "rfc822; " + aPartnership.getReceiverAS2ID());
aMDN.attrs().putIn(AS2MessageMDN.MDNA_ORIG_MESSAGEID, aMsg.getHeader(CHttpHeader.MESSAGE_ID));
aMDN.attrs().putIn(AS2MessageMDN.MDNA_DISPOSITION, aDisposition.getAsString());
final String sDispositionOptions = aMsg.getHeader(CHttpHeader.DISPOSITION_NOTIFICATION_OPTIONS);
final DispositionOptions aDispositionOptions = DispositionOptions.createFromString(sDispositionOptions);
ECryptoAlgorithmSign eSigningAlgorithm = aDispositionOptions.getFirstMICAlg();
if (eSigningAlgorithm == null) {
// Try from partnership (#93)
final String sSigningAlgorithm = aPartnership.getSigningAlgorithm();
eSigningAlgorithm = ECryptoAlgorithmSign.getFromIDOrNull(sSigningAlgorithm);
if (eSigningAlgorithm == null) {
if (LOGGER.isWarnEnabled())
LOGGER.warn("The partnership signing algorithm name '" + sSigningAlgorithm + "' is unknown.");
}
}
MIC aMIC = null;
if (eSigningAlgorithm != null) {
// If the source message was signed or encrypted, include the headers -
// see message sending for details
final boolean bIncludeHeadersInMIC = aPartnership.getSigningAlgorithm() != null || aPartnership.getEncryptAlgorithm() != null || aPartnership.getCompressionType() != null;
aMIC = getCryptoHelper().calculateMIC(aMsg.getData(), eSigningAlgorithm, bIncludeHeadersInMIC);
}
if (aMIC != null)
aMDN.attrs().putIn(AS2MessageMDN.MDNA_MIC, aMIC.getAsAS2String());
boolean bSignMDN = false;
boolean bIncludeCertificateInSignedContent = false;
if (aDispositionOptions.getProtocol() != null) {
if (aDispositionOptions.isProtocolRequired() || aDispositionOptions.hasMICAlg()) {
// Sign if required or if optional and a MIC algorithm is present
bSignMDN = true;
// Include certificate in signed content?
final ETriState eIncludeCertificateInSignedContent = aPartnership.getIncludeCertificateInSignedContent();
if (eIncludeCertificateInSignedContent.isDefined()) {
// Use per partnership
bIncludeCertificateInSignedContent = eIncludeCertificateInSignedContent.getAsBooleanValue();
} else {
// Use global value
bIncludeCertificateInSignedContent = aSession.isCryptoSignIncludeCertificateInBodyPart();
}
}
}
final boolean bUseOldRFC3851MicAlgs = aPartnership.isRFC3851MICAlgs();
final boolean bRemoveCmsAlgorithmProtect = aPartnership.isRemoveCmsAlgorithmProtect();
createMDNData(aSession, aMDN, bSignMDN, bIncludeCertificateInSignedContent, aDispositionOptions.getFirstMICAlg(), bUseOldRFC3851MicAlgs, bRemoveCmsAlgorithmProtect);
aMDN.updateMessageID();
// store MDN into msg in case AsynchMDN is sent fails, needs to be resent by
// send module
aMsg.setMDN(aMDN);
return aMDN;
}
use of com.helger.as2lib.crypto.ECryptoAlgorithmSign in project as2-lib by phax.
the class DispositionOptions method setMICAlg.
/**
* Set the MIC algorithm(s) to use. The passed string is parsed as a comma
* separated list. This overwrites all existing MIC algorithms. If any of the
* contained MIC algorithms is not supported by this library, a log message is
* emitted but no Exception is thrown.
*
* @param sMICAlgs
* The MIC algorithm(s). May be <code>null</code>.
* @return this
*/
@Nonnull
public DispositionOptions setMICAlg(@Nullable final String sMICAlgs) {
m_aMICAlgs.clear();
if (StringHelper.hasText(sMICAlgs)) {
final ICommonsList<String> aMICAlgs = StringHelper.getExploded(',', sMICAlgs.trim());
for (final String sMICAlg : aMICAlgs) {
// trim and lowercase
final String sRealMICAlg = sMICAlg.trim();
final ECryptoAlgorithmSign eMICAlg = ECryptoAlgorithmSign.getFromIDOrNull(sRealMICAlg);
if (eMICAlg == null) {
// Ignore all unsupported MIC algorithms and continue
if (LOGGER.isWarnEnabled())
LOGGER.warn("The passed MIC algorithm '" + sRealMICAlg + "' is unsupported!");
} else {
m_aMICAlgs.add(eMICAlg);
}
}
}
return this;
}
use of com.helger.as2lib.crypto.ECryptoAlgorithmSign in project as2-lib by phax.
the class AS2SenderModule method calculateAndStoreMIC.
/**
* From RFC 4130 section 7.3.1:
* <ul>
* <li>For any signed messages, the MIC to be returned is calculated on the
* RFC1767/RFC3023 MIME header and content. Canonicalization on the MIME
* headers MUST be performed before the MIC is calculated, since the sender
* requesting the signed receipt was also REQUIRED to canonicalize.</li>
* <li>For encrypted, unsigned messages, the MIC to be returned is calculated
* on the decrypted RFC 1767/RFC3023 MIME header and content. The content
* after decryption MUST be canonicalized before the MIC is calculated.</li>
* <li>For unsigned, unencrypted messages, the MIC MUST be calculated over the
* message contents without the MIME or any other RFC 2822 headers, since
* these are sometimes altered or reordered by Mail Transport Agents
* (MTAs).</li>
* </ul>
* So headers must be included if signing or crypting is enabled.<br>
* <br>
* From RFC 5402 section 4.1:
* <ul>
* <li>MIC Calculation for Signed Message: For any signed message, the MIC to
* be returned is calculated over the same data that was signed in the
* original message as per [AS1]. The signed content will be a MIME bodypart
* that contains either compressed or uncompressed data.</li>
* <li>MIC Calculation for Encrypted, Unsigned Message: For encrypted,
* unsigned messages, the MIC to be returned is calculated over the
* uncompressed data content including all MIME header fields and any applied
* Content-Transfer-Encoding.</li>
* <li>MIC Calculation for Unencrypted, Unsigned Message: For unsigned,
* unencrypted messages, the MIC is calculated over the uncompressed data
* content including all MIME header fields and any applied
* Content-Transfer-Encoding</li>
* </ul>
* So headers must always be included if compression is enabled.
*
* @param aMsg
* Source message
* @return MIC value. Neither <code>null</code> nor empty.
* @throws Exception
* On security or AS2 issues
*/
@Nonnull
protected MIC calculateAndStoreMIC(@Nonnull final AS2Message aMsg) throws Exception {
final Partnership aPartnership = aMsg.partnership();
// Calculate and get the original mic
final boolean bIncludeHeadersInMIC = aPartnership.getSigningAlgorithm() != null || aPartnership.getEncryptAlgorithm() != null || aPartnership.getCompressionType() != null;
// For sending, we need to use the Signing algorithm defined in the
// partnership
final String sSigningAlgorithm = aPartnership.getSigningAlgorithm();
ECryptoAlgorithmSign eSigningAlgorithm = ECryptoAlgorithmSign.getFromIDOrNull(sSigningAlgorithm);
if (eSigningAlgorithm == null) {
// If no valid algorithm is defined, fall back to the defaults
final boolean bUseRFC3851MICAlg = aPartnership.isRFC3851MICAlgs();
eSigningAlgorithm = bUseRFC3851MICAlg ? ECryptoAlgorithmSign.DEFAULT_RFC_3851 : ECryptoAlgorithmSign.DEFAULT_RFC_5751;
if (LOGGER.isWarnEnabled())
LOGGER.warn("The partnership signing algorithm name '" + sSigningAlgorithm + "' is unknown. Fallbacking back to the default '" + eSigningAlgorithm.getID() + "'");
}
final MIC aMIC = AS2Helper.getCryptoHelper().calculateMIC(aMsg.getData(), eSigningAlgorithm, bIncludeHeadersInMIC);
aMsg.attrs().putIn(AS2Message.ATTRIBUTE_MIC, aMIC.getAsAS2String());
if (aPartnership.getAS2ReceiptDeliveryOption() != null) {
// Async MDN is requested
// if yes : PA_AS2_RECEIPT_OPTION != null
// then keep the original mic & message id.
// then wait for the another HTTP call by receivers
storePendingInfo(aMsg, aMIC);
}
return aMIC;
}
Aggregations