@Nullable
  @ReturnsMutableCopy
  public static byte[] getDecodedASCIIHex(@Nullable final byte[] aEncodedBuffer) {
    if (aEncodedBuffer == null) return null;

    final NonBlockingByteArrayOutputStream aBAOS = new NonBlockingByteArrayOutputStream();
    try {
      boolean bFirstByte = true;
      int nFirstByte = 0;
      for (final byte nEncByte : aEncodedBuffer) {
        if (nEncByte == '>') break;

        // Ignore whitespaces
        if (Character.isWhitespace(nEncByte)) continue;

        final byte nDecByte = (byte) StringHelper.getHexValue((char) nEncByte);
        if (nDecByte == CGlobal.ILLEGAL_UINT)
          throw new DecodeException(
              "Failed to convert byte '"
                  + nEncByte
                  + "/"
                  + ((char) nEncByte)
                  + "' to hex value in ASCIIHexDecode");
        if (bFirstByte) nFirstByte = nDecByte;
        else aBAOS.write((byte) (nFirstByte << 4 | nDecByte));
        bFirstByte = !bFirstByte;
      }

      // Write trailing byte
      if (!bFirstByte) aBAOS.write((byte) (nFirstByte << 4));
      return aBAOS.toByteArray();
    } finally {
      StreamHelper.close(aBAOS);
    }
  }
 public void save(@WillClose final OutputStream aOS, final char[] aPassword)
     throws OpenAS2Exception {
   try {
     final KeyStore aKeyStore = getKeyStore();
     synchronized (aKeyStore) {
       aKeyStore.store(aOS, aPassword);
     }
   } catch (final IOException ex) {
     throw WrappedOpenAS2Exception.wrap(ex);
   } catch (final GeneralSecurityException ex) {
     throw WrappedOpenAS2Exception.wrap(ex);
   } finally {
     StreamHelper.close(aOS);
   }
 }
 public void load(@Nonnull @WillClose final InputStream aIS, @Nonnull final char[] aPassword)
     throws OpenAS2Exception {
   try {
     final KeyStore aKeyStore = getKeyStore();
     synchronized (aKeyStore) {
       aKeyStore.load(aIS, aPassword);
     }
   } catch (final IOException ex) {
     throw WrappedOpenAS2Exception.wrap(ex);
   } catch (final GeneralSecurityException ex) {
     throw WrappedOpenAS2Exception.wrap(ex);
   } finally {
     StreamHelper.close(aIS);
   }
 }
  @Test
  public void testExternalEntityExpansion() throws SAXException, MalformedURLException {
    // Include a dummy file
    final File aFile = new File("src/test/resources/test1.txt");
    assertTrue(aFile.exists());
    final String sFileContent =
        StreamHelper.getAllBytesAsString(
            new FileSystemResource(aFile), CCharset.CHARSET_ISO_8859_1_OBJ);

    // The XML with XXE problem
    final String sXML =
        "<?xml version='1.0' encoding='utf-8'?>"
            + "<!DOCTYPE root ["
            + " <!ELEMENT root ANY >"
            + " <!ENTITY xxe SYSTEM \""
            + aFile.toURI().toURL().toExternalForm()
            + "\" >]>"
            + "<root>&xxe;</root>";
    final DOMReaderSettings aDRS =
        new DOMReaderSettings()
            .setEntityResolver(
                new EntityResolver() {
                  public InputSource resolveEntity(final String publicId, final String systemId)
                      throws SAXException, IOException {
                    // Read as URL
                    return InputSourceFactory.create(new URLResource(systemId));
                  }
                });

    // Read successful - entity expansion!
    final Document aDoc = DOMReader.readXMLDOM(sXML, aDRS);
    assertNotNull(aDoc);
    assertEquals(sFileContent, aDoc.getDocumentElement().getTextContent());

    // Should fail because inline DTD is present
    try {
      DOMReader.readXMLDOM(
          sXML, aDRS.getClone().setFeatureValues(EXMLParserFeature.AVOID_XXE_SETTINGS));
      fail();
    } catch (final SAXParseException ex) {
      // Expected
      assertTrue(ex.getMessage().contains("http://apache.org/xml/features/disallow-doctype-decl"));
    }
  }
  /**
   * Constructs {@link CSVReader} with supplied {@link CSVParser}.
   *
   * @param aReader the reader to an underlying CSV source.
   * @param aParser the parser to use to parse input
   * @param bKeepCR <code>true</code> to keep carriage returns in data read, <code>false</code>
   *     otherwise
   */
  public CSVReader(
      @Nonnull final Reader aReader, @Nonnull final CSVParser aParser, final boolean bKeepCR) {
    ValueEnforcer.notNull(aReader, "Reader");
    ValueEnforcer.notNull(aParser, "Parser");

    Reader aInternallyBufferedReader = StreamHelper.getBuffered(aReader);
    if (bKeepCR) m_aLineReader = new CSVLineReaderKeepCR(aInternallyBufferedReader);
    else if (aInternallyBufferedReader instanceof BufferedReader)
      m_aLineReader = new CSVLineReaderBufferedReader((BufferedReader) aInternallyBufferedReader);
    else {
      if (!(aInternallyBufferedReader instanceof NonBlockingBufferedReader)) {
        // It is buffered, but we need it to support readLine
        aInternallyBufferedReader = new NonBlockingBufferedReader(aInternallyBufferedReader);
      }
      m_aLineReader =
          new CSVLineReaderNonBlockingBufferedReader(
              (NonBlockingBufferedReader) aInternallyBufferedReader);
    }
    m_aReader = aInternallyBufferedReader;
    m_aParser = aParser;
    m_bKeepCR = bKeepCR;
  }
  protected void sendSyncMDN(
      @Nonnull final String sClientInfo,
      @Nonnull final IAS2HttpResponseHandler aResponseHandler,
      @Nonnull final AS2Message aMsg,
      @Nonnull final DispositionType aDisposition,
      @Nonnull final String sText) {
    final boolean bMDNBlocked = aMsg.getPartnership().isBlockErrorMDN();
    if (!bMDNBlocked) {
      try {
        final IAS2Session aSession = m_aReceiverModule.getSession();
        final IMessageMDN aMdn = AS2Helper.createMDN(aSession, aMsg, aDisposition, sText);

        if (aMsg.isRequestingAsynchMDN()) {
          // if asyncMDN requested, close connection and initiate separate MDN
          // send
          final InternetHeaders aHeaders = new InternetHeaders();
          aHeaders.setHeader(CAS2Header.HEADER_CONTENT_LENGTH, Integer.toString(0));
          // Empty data
          final NonBlockingByteArrayOutputStream aData = new NonBlockingByteArrayOutputStream();
          aResponseHandler.sendHttpResponse(HttpURLConnection.HTTP_OK, aHeaders, aData);

          s_aLogger.info(
              "Setup to send asynch MDN ["
                  + aDisposition.getAsString()
                  + "] "
                  + sClientInfo
                  + aMsg.getLoggingText());

          // trigger explicit sending
          aSession.getMessageProcessor().handle(IProcessorSenderModule.DO_SENDMDN, aMsg, null);
        } else {
          // otherwise, send sync MDN back on same connection
          s_aLogger.info(
              "Sending back sync MDN ["
                  + aDisposition.getAsString()
                  + "] "
                  + sClientInfo
                  + aMsg.getLoggingText());

          // Get data and therefore content length for sync MDN
          final NonBlockingByteArrayOutputStream aData = new NonBlockingByteArrayOutputStream();
          final MimeBodyPart aPart = aMdn.getData();
          StreamHelper.copyInputStreamToOutputStream(aPart.getInputStream(), aData);
          aMdn.setHeader(CAS2Header.HEADER_CONTENT_LENGTH, Integer.toString(aData.getSize()));

          // start HTTP response
          aResponseHandler.sendHttpResponse(HttpURLConnection.HTTP_OK, aMdn.getHeaders(), aData);

          // Save sent MDN for later examination
          try {
            aSession.getMessageProcessor().handle(IProcessorStorageModule.DO_STOREMDN, aMsg, null);
          } catch (final ComponentNotFoundException ex) {
            // No message processor found
          } catch (final NoModuleException ex) {
            // No module found in message processor
          }
          s_aLogger.info(
              "sent MDN ["
                  + aDisposition.getAsString()
                  + "] "
                  + sClientInfo
                  + aMsg.getLoggingText());
        }
      } catch (final Exception ex) {
        final OpenAS2Exception we = WrappedOpenAS2Exception.wrap(ex);
        we.addSource(OpenAS2Exception.SOURCE_MESSAGE, aMsg);
        we.terminate();
      }
    }
  }