Skip to content

Commit

Permalink
Added automatic resource cleansing; #103
Browse files Browse the repository at this point in the history
  • Loading branch information
phax committed Mar 1, 2020
1 parent 5c73cc2 commit 0e494a0
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 51 deletions.
36 changes: 23 additions & 13 deletions as2-lib/src/main/java/com/helger/as2lib/crypto/BCCryptoHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.mail.smime.SMIMESignedParser;
import org.bouncycastle.mail.smime.SMIMEUtil;
import org.bouncycastle.mail.smime.util.FileBackedMimeBodyPart;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
Expand All @@ -96,6 +97,7 @@
import com.helger.as2lib.exception.AS2Exception;
import com.helger.as2lib.util.AS2HttpHelper;
import com.helger.as2lib.util.AS2IOHelper;
import com.helger.as2lib.util.AS2ResourceHelper;
import com.helger.bc.PBCProvider;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
Expand Down Expand Up @@ -395,15 +397,17 @@ private static void _dumpDecrypted (@Nonnull final byte [] aPayload)
public MimeBodyPart decrypt (@Nonnull final MimeBodyPart aPart,
@Nonnull final X509Certificate aX509Cert,
@Nonnull final PrivateKey aPrivateKey,
final boolean bForceDecrypt) throws GeneralSecurityException,
MessagingException,
CMSException,
SMIMEException,
IOException
final boolean bForceDecrypt,
@Nonnull final AS2ResourceHelper aResHelper) throws GeneralSecurityException,
MessagingException,
CMSException,
SMIMEException,
IOException
{
ValueEnforcer.notNull (aPart, "MimeBodyPart");
ValueEnforcer.notNull (aX509Cert, "X509Cert");
ValueEnforcer.notNull (aPrivateKey, "PrivateKey");
ValueEnforcer.notNull (aResHelper, "ResHelper");

if (LOGGER.isDebugEnabled ())
LOGGER.debug ("BCCryptoHelper.decrypt; X509 subject=" +
Expand Down Expand Up @@ -436,7 +440,9 @@ public MimeBodyPart decrypt (@Nonnull final MimeBodyPart aPart,
throw new GeneralSecurityException ("Certificate does not match part signature");

// try to decrypt the data
final MimeBodyPart aDecryptedDataBodyPart = SMIMEUtil.toMimeBodyPart (aRecipient.getContentStream (new JceKeyTransEnvelopedRecipient (aPrivateKey).setProvider (m_sSecurityProviderName)));
// Custom file: see #103
final FileBackedMimeBodyPart aDecryptedDataBodyPart = SMIMEUtil.toMimeBodyPart (aRecipient.getContentStream (new JceKeyTransEnvelopedRecipient (aPrivateKey).setProvider (m_sSecurityProviderName)),
aResHelper.createTempFile ());

if (s_aDumpDecryptedDirectory != null)
{
Expand Down Expand Up @@ -624,11 +630,12 @@ public MimeBodyPart verify (@Nonnull final MimeBodyPart aPart,
@Nullable final X509Certificate aX509Cert,
final boolean bUseCertificateInBodyPart,
final boolean bForceVerify,
@Nullable final Consumer <X509Certificate> aEffectiveCertificateConsumer) throws GeneralSecurityException,
IOException,
MessagingException,
CMSException,
OperatorCreationException
@Nullable final Consumer <X509Certificate> aEffectiveCertificateConsumer,
@Nonnull final AS2ResourceHelper aResHelper) throws GeneralSecurityException,
IOException,
MessagingException,
CMSException,
OperatorCreationException
{
if (LOGGER.isDebugEnabled ())
LOGGER.debug ("BCCryptoHelper.verify; X509 subject=" +
Expand All @@ -649,11 +656,13 @@ public MimeBodyPart verify (@Nonnull final MimeBodyPart aPart,
throw new IllegalStateException ("Expected Part content to be MimeMultipart but it isn't. It is " +
ClassHelper.getClassName (aContent));
final MimeMultipart aMainPart = (MimeMultipart) aContent;

// SMIMESignedParser uses "7bit" as the default - AS2 wants "binary"
final SMIMESignedParser aSignedParser = new SMIMESignedParser (new JcaDigestCalculatorProviderBuilder ().setProvider (m_sSecurityProviderName)
.build (),
aMainPart,
EContentTransferEncoding.AS2_DEFAULT.getID ());
EContentTransferEncoding.AS2_DEFAULT.getID (),
aResHelper.createTempFile ());

final X509Certificate aRealX509Cert = _verifyFindCertificate (aX509Cert, bUseCertificateInBodyPart, aSignedParser);

Expand All @@ -662,7 +671,8 @@ public MimeBodyPart verify (@Nonnull final MimeBodyPart aPart,
aX509Cert) ? "Verifying signature using the provided certificate (partnership)"
: "Verifying signature using the certificate contained in the MIME body part");

// Call before validity check to retrieve the information about the details
// Call before validity check to retrieve the information about the
// details
// outside
if (aEffectiveCertificateConsumer != null)
aEffectiveCertificateConsumer.accept (aRealX509Cert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import javax.mail.internet.MimeBodyPart;

import com.helger.as2lib.exception.AS2Exception;
import com.helger.as2lib.util.AS2ResourceHelper;
import com.helger.mail.cte.EContentTransferEncoding;
import com.helger.security.keystore.IKeyStoreType;

Expand Down Expand Up @@ -152,7 +153,8 @@ MimeBodyPart encrypt (@Nonnull MimeBodyPart aPart,
MimeBodyPart decrypt (@Nonnull MimeBodyPart aPart,
@Nonnull X509Certificate aCert,
@Nonnull PrivateKey aKey,
boolean bForceDecrypt) throws Exception;
boolean bForceDecrypt,
@Nonnull AS2ResourceHelper aResHelper) throws Exception;

/**
* Sign a MIME body part.
Expand Down Expand Up @@ -208,6 +210,8 @@ MimeBodyPart sign (@Nonnull MimeBodyPart aPart,
* @param aEffectiveCertificateConsumer
* An optional consumer that takes the effective certificate that was
* used for verification. May be <code>null</code>.
* @param aResHelper
* The resource helper to use. May not be <code>null</code>.
* @return The signed content. Never <code>null</code>.
* @throws Exception
* In case something goes wrong.
Expand All @@ -218,5 +222,6 @@ MimeBodyPart verify (@Nonnull MimeBodyPart aPart,
@Nullable X509Certificate aCert,
boolean bUseCertificateInBodyPart,
boolean bForceVerify,
@Nullable Consumer <X509Certificate> aEffectiveCertificateConsumer) throws Exception;
@Nullable Consumer <X509Certificate> aEffectiveCertificateConsumer,
@Nonnull AS2ResourceHelper aResHelper) throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import com.helger.as2lib.util.AS2Helper;
import com.helger.as2lib.util.AS2HttpHelper;
import com.helger.as2lib.util.AS2IOHelper;
import com.helger.as2lib.util.AS2ResourceHelper;
import com.helger.as2lib.util.dump.IHTTPIncomingDumper;
import com.helger.as2lib.util.http.AS2HttpClient;
import com.helger.as2lib.util.http.AS2HttpResponseHandlerSocket;
Expand Down Expand Up @@ -153,7 +154,7 @@ public void handle (@Nonnull final AbstractActiveNetModule aOwner, @Nonnull fina
byte [] aData = null;

// Read in the message request, headers, and data
try
try (final AS2ResourceHelper aResHelper = new AS2ResourceHelper ())
{
final IHTTPIncomingDumper aIncomingDumper = getEffectiveHttpIncomingDumper ();
final DataSource aDataSourceBody = readAndDecodeHttpRequest (new AS2InputStreamProviderSocket (aSocket),
Expand All @@ -180,7 +181,7 @@ public void handle (@Nonnull final AbstractActiveNetModule aOwner, @Nonnull fina

aMsg.setData (aReceivedPart);

receiveMDN (aMsg, aData, aResponseHandler);
receiveMDN (aMsg, aData, aResponseHandler, aResHelper);
}
catch (final Exception ex)
{
Expand All @@ -199,15 +200,17 @@ public void handle (@Nonnull final AbstractActiveNetModule aOwner, @Nonnull fina
* The MDN content
* @param aResponseHandler
* The HTTP response handler for setting the correct HTTP response code
* @param aResHelper
* Resource helper
* @throws AS2Exception
* In case of error
* @throws IOException
* In case of IO error
*/
protected final void receiveMDN (@Nonnull final AS2Message aMsg,
final byte [] aData,
@Nonnull final IAS2HttpResponseHandler aResponseHandler) throws AS2Exception,
IOException
@Nonnull final IAS2HttpResponseHandler aResponseHandler,
@Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception, IOException
{
try
{
Expand Down Expand Up @@ -244,7 +247,11 @@ protected final void receiveMDN (@Nonnull final AS2Message aMsg,
bUseCertificateInBodyPart = getModule ().getSession ().isCryptoVerifyUseCertificateInBodyPart ();
}

AS2Helper.parseMDN (aMsg, aSenderCert, bUseCertificateInBodyPart, getVerificationCertificateConsumer ());
AS2Helper.parseMDN (aMsg,
aSenderCert,
bUseCertificateInBodyPart,
getVerificationCertificateConsumer (),
aResHelper);

// in order to name & save the mdn with the original AS2-From + AS2-To +
// Message id.,
Expand Down Expand Up @@ -334,9 +341,8 @@ public boolean checkAsyncMDN (@Nonnull final AS2Message aMsg) throws AS2Exceptio
final String sOriginalMIC;
final MIC aOriginalMIC;
final File aPendingFile;
try (
final NonBlockingBufferedReader aPendingInfoReader = FileHelper.getBufferedReader (new File (sPendingInfoFile),
StandardCharsets.ISO_8859_1))
try (final NonBlockingBufferedReader aPendingInfoReader = FileHelper.getBufferedReader (new File (sPendingInfoFile),
StandardCharsets.ISO_8859_1))
{
// Get the original mic from the first line of pending information
// file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import com.helger.as2lib.util.AS2Helper;
import com.helger.as2lib.util.AS2HttpHelper;
import com.helger.as2lib.util.AS2IOHelper;
import com.helger.as2lib.util.AS2ResourceHelper;
import com.helger.as2lib.util.dump.IHTTPIncomingDumper;
import com.helger.as2lib.util.http.AS2HttpResponseHandlerSocket;
import com.helger.as2lib.util.http.AS2InputStreamProviderSocket;
Expand Down Expand Up @@ -208,7 +209,7 @@ protected AS2Message createMessage (@Nonnull final Socket aSocket)
return aMsg;
}

protected void decrypt (@Nonnull final IMessage aMsg) throws AS2Exception
protected void decrypt (@Nonnull final IMessage aMsg, @Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception
{
final ICertificateFactory aCertFactory = m_aReceiverModule.getSession ().getCertificateFactory ();
final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper ();
Expand Down Expand Up @@ -242,7 +243,8 @@ protected void decrypt (@Nonnull final IMessage aMsg) throws AS2Exception
final MimeBodyPart aDecryptedData = aCryptoHelper.decrypt (aMsg.getData (),
aReceiverCert,
aReceiverKey,
bForceDecrypt);
bForceDecrypt,
aResHelper);
aMsg.setData (aDecryptedData);
// Remember that message was encrypted
aMsg.attrs ().putIn (AS2Message.ATTRIBUTE_RECEIVED_ENCRYPTED, true);
Expand All @@ -262,7 +264,7 @@ protected void decrypt (@Nonnull final IMessage aMsg) throws AS2Exception
}
}

protected void verify (@Nonnull final IMessage aMsg) throws AS2Exception
protected void verify (@Nonnull final IMessage aMsg, @Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception
{
final ICertificateFactory aCertFactory = m_aReceiverModule.getSession ().getCertificateFactory ();
final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper ();
Expand Down Expand Up @@ -309,7 +311,8 @@ protected void verify (@Nonnull final IMessage aMsg) throws AS2Exception
aSenderCert,
bUseCertificateInBodyPart,
bForceVerify,
aCertHolder::set);
aCertHolder::set,
aResHelper);
final IConsumer <X509Certificate> aExternalConsumer = getVerificationCertificateConsumer ();
if (aExternalConsumer != null)
aExternalConsumer.accept (aCertHolder.get ());
Expand Down Expand Up @@ -520,7 +523,7 @@ public void handleIncomingMessage (@Nonnull final String sClientInfo,
@Nonnull final AS2Message aMsg,
@Nonnull final IAS2HttpResponseHandler aResponseHandler)
{
try
try (final AS2ResourceHelper aResHelper = new AS2ResourceHelper ())
{
final IAS2Session aSession = m_aReceiverModule.getSession ();

Expand Down Expand Up @@ -570,7 +573,7 @@ public void handleIncomingMessage (@Nonnull final String sClientInfo,

// Decrypt and verify signature of the data, and attach data to the
// message
decrypt (aMsg);
decrypt (aMsg, aResHelper);

if (aCryptoHelper.isCompressed (aMsg.getContentType ()))
{
Expand All @@ -580,7 +583,7 @@ public void handleIncomingMessage (@Nonnull final String sClientInfo,
bIsDecompressed = true;
}

verify (aMsg);
verify (aMsg, aResHelper);

if (aCryptoHelper.isCompressed (aMsg.getContentType ()))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import com.helger.as2lib.util.AS2Helper;
import com.helger.as2lib.util.AS2HttpHelper;
import com.helger.as2lib.util.AS2IOHelper;
import com.helger.as2lib.util.AS2ResourceHelper;
import com.helger.as2lib.util.CAS2Header;
import com.helger.as2lib.util.dump.IHTTPIncomingDumper;
import com.helger.as2lib.util.dump.IHTTPOutgoingDumper;
Expand Down Expand Up @@ -649,6 +650,8 @@ protected void updateHttpHeaders (@Nonnull final AS2HttpHeaderSetter aHeaderSett
* mic value from original msg
* @param aIncomingDumper
* Incoming dumper. May be <code>null</code>.
* @param aResHelper
* Resource helper
* @throws AS2Exception
* in case of an error
* @throws IOException
Expand All @@ -657,7 +660,8 @@ protected void updateHttpHeaders (@Nonnull final AS2HttpHeaderSetter aHeaderSett
protected void receiveSyncMDN (@Nonnull final AS2Message aMsg,
@Nonnull final AS2HttpClient aHttpClient,
@Nonnull final MIC aOriginalMIC,
@Nullable final IHTTPIncomingDumper aIncomingDumper) throws AS2Exception, IOException
@Nullable final IHTTPIncomingDumper aIncomingDumper,
@Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception, IOException
{
if (LOGGER.isDebugEnabled ())
LOGGER.debug ("Receiving synchronous MDN for message" + aMsg.getLoggingText ());
Expand Down Expand Up @@ -725,7 +729,7 @@ protected void receiveSyncMDN (@Nonnull final AS2Message aMsg,
bUseCertificateInBodyPart = getSession ().isCryptoVerifyUseCertificateInBodyPart ();
}

AS2Helper.parseMDN (aMsg, aSenderCert, bUseCertificateInBodyPart, m_aVerificationCertificateConsumer);
AS2Helper.parseMDN (aMsg, aSenderCert, bUseCertificateInBodyPart, m_aVerificationCertificateConsumer, aResHelper);

try
{
Expand Down Expand Up @@ -811,9 +815,10 @@ private void _sendViaHTTP (@Nonnull final AS2Message aMsg,
@Nullable final MIC aMIC,
@Nullable final EContentTransferEncoding eCTE,
@Nullable final IHTTPOutgoingDumper aOutgoingDumper,
@Nullable final IHTTPIncomingDumper aIncomingDumper) throws AS2Exception,
IOException,
MessagingException
@Nullable final IHTTPIncomingDumper aIncomingDumper,
@Nonnull final AS2ResourceHelper aResHelper) throws AS2Exception,
IOException,
MessagingException
{
final Partnership aPartnership = aMsg.partnership ();

Expand Down Expand Up @@ -876,7 +881,7 @@ private void _sendViaHTTP (@Nonnull final AS2Message aMsg,
// go ahead to receive sync MDN
// Note: If an MDN is requested, a MIC is present
assert aMIC != null;
receiveSyncMDN (aMsg, aConn, aMIC, aIncomingDumper);
receiveSyncMDN (aMsg, aConn, aMIC, aIncomingDumper, aResHelper);

if (LOGGER.isInfoEnabled ())
LOGGER.info ("message sent" + aMsg.getLoggingText ());
Expand Down Expand Up @@ -916,7 +921,7 @@ public void handle (@Nonnull final String sAction,

final int nRetries = getRetryCount (aMsg.partnership (), aOptions);

try
try (final AS2ResourceHelper aResHelper = new AS2ResourceHelper ())
{
// Get Content-Transfer-Encoding to use
final String sContentTransferEncoding = aMsg.partnership ()
Expand All @@ -943,7 +948,7 @@ public void handle (@Nonnull final String sAction,
{
final IHTTPIncomingDumper aIncomingDumper = getEffectiveHttpIncomingDumper ();
// Use no CTE, because it was set on all MIME parts
_sendViaHTTP (aMsg, aSecuredData, aMIC, true ? null : eCTE, aOutgoingDumper, aIncomingDumper);
_sendViaHTTP (aMsg, aSecuredData, aMIC, true ? null : eCTE, aOutgoingDumper, aIncomingDumper, aResHelper);
}
}
catch (final AS2HttpResponseException ex)
Expand Down
Loading

0 comments on commit 0e494a0

Please sign in to comment.