protected void decompress(@Nonnull final IMessage aMsg) throws DispositionException { try { if (aMsg.getPartnership().isDisableDecompress()) { s_aLogger.info( "Message claims to be compressed but decompression is disabled" + aMsg.getLoggingText()); } else { if (s_aLogger.isDebugEnabled()) s_aLogger.debug("Decompressing a compressed AS2 message"); final SMIMECompressed aCompressed = new SMIMECompressed(aMsg.getData()); // decompression step MimeBodyPart final MimeBodyPart aDecompressedPart = SMIMEUtil.toMimeBodyPart(aCompressed.getContent(new ZlibExpanderProvider())); // Update the message object aMsg.setData(aDecompressedPart); // Remember that message was decompressed aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED_COMPRESSED, Boolean.TRUE.toString()); s_aLogger.info("Successfully decompressed incoming AS2 message" + aMsg.getLoggingText()); } } catch (final Exception ex) { s_aLogger.error("Error decompressing received message", ex); throw new DispositionException( DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_DECOMPRESSION_ERROR, ex); } }
protected void decrypt(@Nonnull final IMessage aMsg) throws OpenAS2Exception { final ICertificateFactory aCertFactory = m_aReceiverModule.getSession().getCertificateFactory(); final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper(); try { final boolean bDisableDecrypt = aMsg.getPartnership().isDisableDecrypt(); final boolean bMsgIsEncrypted = aCryptoHelper.isEncrypted(aMsg.getData()); final boolean bForceDecrypt = aMsg.getPartnership().isForceDecrypt(); if (bMsgIsEncrypted && bDisableDecrypt) { s_aLogger.info( "Message claims to be encrypted but decryption is disabled" + aMsg.getLoggingText()); } else if (bMsgIsEncrypted || bForceDecrypt) { // Decrypt if (bForceDecrypt && !bMsgIsEncrypted) s_aLogger.info("Forced decrypting" + aMsg.getLoggingText()); else if (s_aLogger.isDebugEnabled()) s_aLogger.debug("Decrypting" + aMsg.getLoggingText()); final X509Certificate aReceiverCert = aCertFactory.getCertificate(aMsg, ECertificatePartnershipType.RECEIVER); final PrivateKey aReceiverKey = aCertFactory.getPrivateKey(aMsg, aReceiverCert); final MimeBodyPart aDecryptedData = aCryptoHelper.decrypt(aMsg.getData(), aReceiverCert, aReceiverKey, bForceDecrypt); aMsg.setData(aDecryptedData); // Remember that message was encrypted aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED_ENCRYPTED, Boolean.TRUE.toString()); s_aLogger.info("Successfully decrypted incoming AS2 message" + aMsg.getLoggingText()); } } catch (final Exception ex) { s_aLogger.error("Error decrypting " + aMsg.getLoggingText() + ": " + ex.getMessage()); throw new DispositionException( DispositionType.createError("decryption-failed"), AbstractActiveNetModule.DISP_DECRYPTION_ERROR, ex); } }
protected void verify(@Nonnull final IMessage aMsg) throws OpenAS2Exception { final ICertificateFactory aCertFactory = m_aReceiverModule.getSession().getCertificateFactory(); final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper(); try { final boolean bDisableVerify = aMsg.getPartnership().isDisableVerify(); final boolean bMsgIsSigned = aCryptoHelper.isSigned(aMsg.getData()); final boolean bForceVerify = aMsg.getPartnership().isForceVerify(); if (bMsgIsSigned && bDisableVerify) { s_aLogger.info( "Message claims to be signed but signature validation is disabled" + aMsg.getLoggingText()); } else if (bMsgIsSigned || bForceVerify) { if (bForceVerify && !bMsgIsSigned) s_aLogger.info("Forced verify signature" + aMsg.getLoggingText()); else if (s_aLogger.isDebugEnabled()) s_aLogger.debug("Verifying signature" + aMsg.getLoggingText()); final X509Certificate aSenderCert = aCertFactory.getCertificateOrNull(aMsg, ECertificatePartnershipType.SENDER); boolean bUseCertificateInBodyPart; final ETriState eUseCertificateInBodyPart = aMsg.getPartnership().getVerifyUseCertificateInBodyPart(); if (eUseCertificateInBodyPart.isDefined()) { // Use per partnership bUseCertificateInBodyPart = eUseCertificateInBodyPart.getAsBooleanValue(); } else { // Use global value bUseCertificateInBodyPart = m_aReceiverModule.getSession().isCryptoVerifyUseCertificateInBodyPart(); } final MimeBodyPart aVerifiedData = aCryptoHelper.verify( aMsg.getData(), aSenderCert, bUseCertificateInBodyPart, bForceVerify); aMsg.setData(aVerifiedData); // Remember that message was signed and verified aMsg.setAttribute(AS2Message.ATTRIBUTE_RECEIVED_SIGNED, Boolean.TRUE.toString()); s_aLogger.info( "Successfully verified signature of incoming AS2 message" + aMsg.getLoggingText()); } } catch (final Exception ex) { s_aLogger.error( "Error verifying signature " + aMsg.getLoggingText() + ": " + ex.getMessage()); throw new DispositionException( DispositionType.createError("integrity-check-failed"), AbstractActiveNetModule.DISP_VERIFY_SIGNATURE_FAILED, ex); } }
/** * This method can be used to handle an incoming HTTP message AFTER the headers where extracted. * * @param sClientInfo Client connection info * @param aMsgData The message body * @param aMsg The AS2 message that will be filled by this method * @param aResponseHandler The response handler which handles HTTP error messages as well as * synchronous MDN. */ public void handleIncomingMessage( @Nonnull final String sClientInfo, @Nonnull final byte[] aMsgData, @Nonnull final AS2Message aMsg, @Nonnull final IAS2HttpResponseHandler aResponseHandler) { // TODO store HTTP request, headers, and data to file in Received folder // -> use message-id for filename? try { final IAS2Session aSession = m_aReceiverModule.getSession(); try { // Put received data in a MIME body part final ContentType aReceivedContentType = new ContentType(aMsg.getHeader(CAS2Header.HEADER_CONTENT_TYPE)); final String sReceivedContentType = aReceivedContentType.toString(); final MimeBodyPart aReceivedPart = new MimeBodyPart(); aReceivedPart.setDataHandler( new DataHandler(new ByteArrayDataSource(aMsgData, sReceivedContentType, null))); // Header must be set AFTER the DataHandler! aReceivedPart.setHeader(CAS2Header.HEADER_CONTENT_TYPE, sReceivedContentType); aMsg.setData(aReceivedPart); } catch (final Exception ex) { throw new DispositionException( DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_PARSING_MIME_FAILED, ex); } // Extract AS2 ID's from header, find the message's partnership and // update the message try { final String sAS2From = aMsg.getAS2From(); aMsg.getPartnership().setSenderAS2ID(sAS2From); final String sAS2To = aMsg.getAS2To(); aMsg.getPartnership().setReceiverAS2ID(sAS2To); // Fill all partnership attributes etc. aSession.getPartnershipFactory().updatePartnership(aMsg, false); } catch (final OpenAS2Exception ex) { throw new DispositionException( DispositionType.createError("authentication-failed"), AbstractActiveNetModule.DISP_PARTNERSHIP_NOT_FOUND, ex); } // Per RFC5402 compression is always before encryption but can be before // or after signing of message but only in one place final ICryptoHelper aCryptoHelper = AS2Helper.getCryptoHelper(); boolean bIsDecompressed = false; // Decrypt and verify signature of the data, and attach data to the // message decrypt(aMsg); if (aCryptoHelper.isCompressed(aMsg.getContentType())) { if (s_aLogger.isTraceEnabled()) s_aLogger.trace("Decompressing received message before checking signature..."); decompress(aMsg); bIsDecompressed = true; } verify(aMsg); if (aCryptoHelper.isCompressed(aMsg.getContentType())) { // Per RFC5402 compression is always before encryption but can be before // or after signing of message but only in one place if (bIsDecompressed) { throw new DispositionException( DispositionType.createError("decompression-failed"), AbstractActiveNetModule.DISP_DECOMPRESSION_ERROR, new Exception( "Message has already been decompressed. Per RFC5402 it cannot occur twice.")); } if (s_aLogger.isTraceEnabled()) if (aMsg.containsAttribute(AS2Message.ATTRIBUTE_RECEIVED_SIGNED)) s_aLogger.trace("Decompressing received message after verifying signature..."); else s_aLogger.trace("Decompressing received message after decryption..."); decompress(aMsg); bIsDecompressed = true; } if (s_aLogger.isTraceEnabled()) try { s_aLogger.trace( "SMIME Decrypted Content-Disposition: " + aMsg.getContentDisposition() + "\n Content-Type received: " + aMsg.getContentType() + "\n HEADERS after decryption: " + aMsg.getData().getAllHeaders() + "\n Content-Disposition in MSG detData() MIMEPART after decryption: " + aMsg.getData().getContentType()); } catch (final MessagingException ex) { s_aLogger.error("Failed to trace message: " + aMsg, ex); } // Validate the received message before storing try { aSession .getMessageProcessor() .handle(IProcessorStorageModule.DO_VALIDATE_BEFORE_STORE, aMsg, null); } catch (final NoModuleException ex) { // No module installed - ignore } catch (final OpenAS2Exception ex) { throw new DispositionException( DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_VALIDATION_FAILED + "\n" + StackTraceHelper.getStackAsString(ex), ex); } // Store the received message try { aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_STORE, aMsg, null); } catch (final NoModuleException ex) { // No module installed - ignore } catch (final OpenAS2Exception ex) { throw new DispositionException( DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_STORAGE_FAILED + "\n" + ex.getMessage(), ex); } // Validate the received message after storing try { aSession .getMessageProcessor() .handle(IProcessorStorageModule.DO_VALIDATE_AFTER_STORE, aMsg, null); } catch (final NoModuleException ex) { // No module installed - ignore } catch (final OpenAS2Exception ex) { throw new DispositionException( DispositionType.createError("unexpected-processing-error"), AbstractActiveNetModule.DISP_VALIDATION_FAILED + "\n" + StackTraceHelper.getStackAsString(ex), ex); } try { if (aMsg.isRequestingMDN()) { // Transmit a success MDN if requested sendSyncMDN( sClientInfo, aResponseHandler, aMsg, DispositionType.createSuccess(), AbstractActiveNetModule.DISP_SUCCESS); } else { // Just send a HTTP OK HTTPHelper.sendSimpleHTTPResponse(aResponseHandler, HttpURLConnection.HTTP_OK); s_aLogger.info("sent HTTP OK " + sClientInfo + aMsg.getLoggingText()); } } catch (final Exception ex) { throw new WrappedOpenAS2Exception( "Error creating and returning MDN, message was stilled processed", ex); } } catch (final DispositionException ex) { sendSyncMDN(sClientInfo, aResponseHandler, aMsg, ex.getDisposition(), ex.getText()); m_aReceiverModule.handleError(aMsg, ex); } catch (final OpenAS2Exception ex) { m_aReceiverModule.handleError(aMsg, ex); } }