blob: 84b2764e9bd33d70906b927dfc6464ef084309d5 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Chapter 11 - SSL Filter &mdash; Apache MINA</title>
<link href="/assets/css/common.css" rel="stylesheet" type="text/css"/>
<link href="/assets/css/mina.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<script src="https://www.apachecon.com/event-images/snippet.js"></script>
<div id="container">
<div id="header">
<div id="subProjectsNavBar">
<a href="/">
Apache MINA Project
</a>
&nbsp;|&nbsp;
<a href="/mina-project/">
<strong>MINA</strong>
</a>
&nbsp;|&nbsp;
<a href="/asyncweb-project/">
AsyncWeb
</a>
&nbsp;|&nbsp;
<a href="/ftpserver-project/">
FtpServer
</a>
&nbsp;|&nbsp;
<a href="/sshd-project/">
SSHD
</a>
&nbsp;|&nbsp;
<a href="/vysper-project/">
Vysper
</a>
</div>
</div>
<div id="content">
<div id="leftColumn">
<div id="navigation">
<a class="acevent" data-format="wide" data-width="170"></a>
<h5>Social Networks</h5>
<ul>
<li><a href="https://fosstodon.org/@apachemina">Apache MINA Mastodon</a></li>
</ul>
<h5>Latest Downloads</h5>
<ul>
<li><a href="/mina-project/downloads_2_0.html">Mina 2.0.25</a></li>
<li><a href="/mina-project/downloads_2_1.html">Mina 2.1.8</a></li>
<li><a href="/mina-project/downloads_2_2.html">Mina 2.2.3</a></li>
<li><a href="/mina-project/downloads_old.html">Mina old versions</a></li>
</ul>
<h5>Documentation</h5>
<ul>
<li><a href="/mina-project/documentation.html" class="external-link" rel="nofollow">Base documentation</a></li>
<li><a href="/mina-project/userguide/user-guide-toc.html" class="external-link" rel="nofollow">User guide</a></li>
<li><a href="/mina-project/2.2-vs-2.1.html" class="external-link" rel="nofollow">2.2 vs 2.1</a></li>
<li><a href="/mina-project/2.1-vs-2.0.html" class="external-link" rel="nofollow">2.1 vs 2.0</a></li>
<li><a href="/mina-project/features.html" class="external-link" rel="nofollow">Features</a></li>
<li><a href="/mina-project/road-map.html" class="external-link" rel="nofollow">Road Map</a></li>
<li><a href="/mina-project/quick-start-guide.html" class="external-link" rel="nofollow">Quick Start Guide</a></li>
<li><a href="/mina-project/faq.html" class="external-link" rel="nofollow">FAQ</a></li>
</ul>
<h5>Resources</h5>
<ul>
<li><a href="/mina-project/mailing-lists.html" class="external-link" rel="nofollow">Mailing lists &amp; IRC</a></li>
<li><a href="/mina-project/issue-tracking.html" class="external-link" rel="nofollow">Issue tracking</a></li>
<li><a href="/mina-project/sources.html" class="external-link" rel="nofollow">Sources</a></li>
<li><a href="/mina-project/gen-docs/latest-2.0/apidocs/index.html" class="external-link" rel="nofollow">API Javadoc 2.0.25</a></li>
<li><a href="/mina-project/gen-docs/latest-2.1/apidocs/index.html" class="external-link" rel="nofollow">API Javadoc 2.1.8</a></li>
<li><a href="/mina-project/gen-docs/latest-2.2/apidocs/index.html" class="external-link" rel="nofollow">API Javadoc 2.2.3</a></li>
<li><a href="/mina-project/gen-docs/latest-2.0/xref/index.html" class="external-link" rel="nofollow">API xref 2.0.25</a></li>
<li><a href="/mina-project/gen-docs/latest-2.1/xref/index.html" class="external-link" rel="nofollow">API xref 2.1.8</a></li>
<li><a href="/mina-project/gen-docs/latest-2.2/xref/index.html" class="external-link" rel="nofollow">API xref 2.2.3</a></li>
<li><a href="/mina-project/performances.html" class="external-link" rel="nofollow">Performances</a></li>
<li><a href="/mina-project/testimonials.html" class="external-link" rel="nofollow">Testimonials</a></li>
<li><a href="/mina-project/conferences.html" class="external-link" rel="nofollow">Conferences</a></li>
<li><a href="/mina-project/developer-guide.html" class="external-link" rel="nofollow">Developers Guide</a></li>
<li><a href="/mina-project/related-projects.html" class="external-link" rel="nofollow">Related Projects</a></li>
<li><a href="https://people.apache.org/~vgritsenko/stats/projects/mina.html" class="external-link" rel="nofollow">Statistics</a></li>
</ul>
<h5>Community</h5>
<ul>
<li><a href="https://www.apache.org/foundation/contributing.html" class="external-link" rel="nofollow">Contributing</a></li>
<li><a href="/contributors.html" class="external-link" rel="nofollow">Team</a></li>
<li><a href="/special-thanks.html" class="external-link" rel="nofollow">Special Thanks</a></li>
<li><a href="https://www.apache.org/security/" class="external-link" rel="nofollow">Security</a></li>
</ul>
<h5>About Apache</h5>
<ul>
<li><a href="https://www.apache.org" class="external-link" rel="nofollow">Apache main site</a></li>
<li><a href="https://www.apache.org/licenses/" class="external-link" rel="nofollow">License</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html" title="The ASF sponsorship program" class="external-link" rel="nofollow">Sponsorship program</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html" class="external-link" rel="nofollow">Thanks</a></li>
</ul>
<h3><a name="Navigation-Upcoming"></a>Upcoming</h3>
<ul>
<li>No event</li>
</ul>
</div>
</div>
<div id="rightColumn">
<div class="nav">
<div class="nav_prev">
<a href="../ch10-executor-filter/ch10-executor-filter.html">Chapter 10 - Executor Filter</a>
</div>
<div class="nav_up">
<a href="../user-guide-toc.html">User Guide</a>
</div>
<div class="nav_next">
<a href="../ch12-logging-filter/ch12-logging-filter.html">Chapter 12 - Logging Filter</a>
</div>
<div class="clearfix"></div>
</div>
<h1 id="chapter-11---ssl-filter">Chapter 11 - SSL Filter</h1>
<p>The <strong>SslFilter</strong> is the filter in charge of managing the encryption and decryption of data sent through a secured connection. Whenever you need to establish a secured connection, or to transform an existing connection to make it secure, you have to add the <strong>SslFilter</strong> in your filter chain.</p>
<p>As any session can modify it&rsquo;s message filter chain at will, it allows for protocols like <strong>startTLS</strong> to be used on an opened connection.</p>
<div class="note" markdown="1">
Please note that although the name include <strong>SSL</strong>, <strong>SslFilter</strong> supports <strong>TLS</strong>.
<p>Actually, <strong>TLS</strong> is supposed to have replaced <strong>SSL</strong>, but for historical reason, <strong>SSL</strong> remains widely used.</p>
</div>
<h2 id="basic-usage">Basic usage</h2>
<p>If you want your application to support <strong>SSL/TLS</strong>, just add the <strong>SslFilter</strong> in your chain :</p>
<pre><code>...
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
SslFilter sslFilter = new SslFilter(sslContext);
chain.addFirst(&quot;sslFilter&quot;, sslFilter);
...
</code></pre>
<p>You obviously need a <strong>SslContext</strong> instance too :</p>
<pre><code>SSLContext sslContext;
try
{
// Initialize the SSLContext to work with our key managers.
sslContext = SSLContext.getInstance( &quot;TLS&quot; );
sslContext.init( ... ); // Provide the needed KeyManager[], TrustManager[] and SecureRandom instances
}
catch ( Exception e )
{
// Handle your exception
}
</code></pre>
<p>This is up to you to provide the <strong>KeyManager</strong>, <strong>TrustManager</strong> and <strong>SecureRandom</strong> instances.</p>
<p>Be sure to inject the <strong>SslFilter</strong> on the first position in your chain !</p>
<p>We will see later a detailed example on how to create a <strong>SSLContext</strong>.</p>
<h2 id="a-bit-of-theory">A bit of theory</h2>
<p>If you want to get a deeper understanding on how it all works, please read the following paragraphs&hellip;</p>
<h3 id="ssl-basics">SSL Basics</h3>
<p>We are not going to explain how <strong>SSL</strong> works, there are very <a href="http://www.amazon.com/SSL-TLS-Designing-Building-Systems/dp/0201615983">good books</a> out there. We will just give a quick introduction on how it works and how it is implemented in MINA.</p>
<p>First of all, you have to understand that <strong>SSL/TLS</strong> is a protocol defined in <strong>RFCs</strong> : <a href="https://www.rfc-editor.org/rfc/rfc2246.txt">TLS 1.0</a>, <a href="https://www.rfc-editor.org/rfc/rfc4346.txt">TLS 1.1</a>, <a href="https://www.rfc-editor.org/rfc/rfc5246.txt">TLS 1.2</a> and <a href="https://tools.ietf.org/html/rfc8446">RLS 1.3</a>.</p>
<p>It was initially developed by <strong>Netscape</strong>, and named <strong>SSL</strong> (from 1.0 to 3.0), before becoming <strong>TLS</strong>. Nowadays, *<strong>SSL 2.0</strong> and <strong>SSL 3.0</strong> have been deprecated and should not be used.</p>
<h3 id="the-ssltls-protocol">The SSL/TLS protocol</h3>
<p>As it&rsquo;s a protocol, it requires some dialog between a client and a server. This is all what <strong>SSL/TLS</strong> is about : describing this dialog.</p>
<p>It&rsquo;s enough to know that any secured exchange is precluded by a negotiation phase, called the <strong>Handshake</strong>, which role is to come to an agreement between the client and the server on what will be the encryption method to use. A basic <strong>SSL/TLS</strong> session will be something that looks like :</p>
<div align="center">
<img src="../images/TLS-protocol.png" alt="TLS Protocol"/>
</div>
<p>As you can see in this picture, it&rsquo;s a 2 phases protocol : first the handshake, then when completed the client and the server will be able to exchange data that will be encrypted.</p>
<p>There are also other phases, like the <strong>SSL/TLS</strong> closure, or a renegotiation phase.</p>
<h4 id="the-handshake">The Handshake</h4>
<p>Basically, it&rsquo;s all about negotiating many elements that are to be used to encrypt/decrypt the data. The details are not so interesting in the context of this document, enough said that many messages are going to be exchanged between the client and the server, and no data can be sent during this phase.</p>
<p>Actually, there are two conditions for the handshake to start :</p>
<ul>
<li>The server must be waiting for some handshake message to arrive</li>
<li>The client must send a <strong>ClientHello</strong> message</li>
</ul>
<p>We do use the Java <strong>SSLEngine</strong> class to manage the whole <strong>SSL/TLS</strong> protocol. What <strong>MINA</strong> should take care of is the current status of the session is such that it will be able to get and deal with the client <strong>HelloClient</strong> message. When you inject the <strong>SslFilter</strong> in your filter chain, a few things happen :</p>
<ul>
<li>A <strong>SslHandler</strong> instance is created (we create one instance per session). This <strong>SslHandler</strong> instance is in charge of the whole processing (handshake and encryption/decryption of forthcoming messages)</li>
<li>This <strong>SslHandler</strong> creates a <strong>SSLEngine</strong> using the <strong>SslContext</strong> instance that has been attached to the <strong>SslFilter</strong></li>
<li>The <strong>SslEngine</strong> instance is configured and initialized</li>
<li>The <strong>SslHandler</strong> instance is stored into the session</li>
<li>Unless required specifically, we initiate the Handshake (which has different meanings on client side and on server side : the client will then send the <strong>ClientHello</strong> message, while the server switch to a mode where it waits for some data to be unwrapped). Note that the handshake initialization can be done later on, if needed</li>
</ul>
<p>We are all set. The next few steps are pure <strong>SSL/TLS</strong> protocol exchange. If the <em>session.write()</em> method is called, the message will be enqueued waiting for the handshake to be completed. Any pending message at the time the <strong>SslFilter</strong> is added into the chain will cause the <strong>SSL/TLS</strong> handshake to fail, so be sure that you have a clean place when you want to inject it. We also won&rsquo;t receive any message that is not a <strong>SSL/TLS</strong> protocol message.</p>
<p>This last point is important if you are to implement <strong>StartTLS</strong> : as it allows your application to switch from a plain text exchange to an encrypted exchange at any time, you have to be sure that there are not pending messages on both side. Obviously, on the client side - the side that initiates <strong>StartTLS</strong> - every pending messages will have been sent before the <strong>StartTLS</strong> message can be sent, but it has to block any other message that are not part of the following handshake, until the handshake is completed. On the server side, once the <strong>StartTLS</strong> message has been received, no message should be written to the remote peer.</p>
<p>As a matter of fact, injecting the <strong>SslFilter</strong> in the chain should block any exchange that are not part of the handshake protocol until the handshake is completed. If you submit a message to be sent and encrypted before the handshake has been completed, the message will not be rejected but queued and will be processed when the handshake has been completed.</p>
<p>Afterward, every message sent will go through the <strong>SslHandler</strong> instance to be encrypted, and every message received will have to be fully decrypted by the <strong>SslHandler</strong> before being available to the next filters.</p>
<h4 id="sending-data">Sending data</h4>
<p>Ok, the Handshake has been completed. Your <strong>SslFilter</strong> is ready to process incoming and outgoing messages. Let&rsquo;s focus on those your session are going to write.</p>
<p>One important thing is that you may write more than one message on the same session (if you have an <strong>Executor</strong> in your chain). The problem is that the <strong>SSLEngine</strong> is not capable of dealing with more than one message at a time. We need to serialize the messages being written out. It&rsquo;s even worse : you can&rsquo;t process an incoming message <strong>and</strong> and outgoing message at the same time.</p>
<p>All in all, the <strong>SSL/TLS</strong> processing is like a black box that accept only one input and can&rsquo;t process anything until it has completed its task. the following schema represent the way it works for outgoing messages.</p>
<div align="center">
<img src="../images/TLS-outMessage.png" alt="Outgoing messages"/>
</div>
<p>It&rsquo;s not that different for incoming messages, except that we won&rsquo;t have an <strong>Executor</strong> between the <strong>IoProcessor</strong> and the <strong>SslFilter</strong>. That makes things simpler, except that one critical thing happens : when we process an incoming message, we can&rsquo;t anymore process outgoing messages. Note that it also works on the other way around : when an outgoing message is being processed, we can&rsquo;t process an incoming message :</p>
<div align="center">
<img src="../images/TLS-inMessage.png" alt="Incoming message"/>
</div>
<div class="note" markdown="1">
What is important here is that the <strong>SslHander</strong> can't process more than one message at a time.
</div>
<h2 id="ssltls-in-mina-2">SSL/TLS in MINA 2</h2>
<p>Now, we will dive a bit deeper into <strong>MINA</strong> code. We will cover all the filter operations:</p>
<ul>
<li>Management
<ul>
<li>init()</li>
<li>destroy()</li>
<li>onPreAdd(IoFilterChain, String, NextFilter)</li>
<li>onPostAdd(IoFilterChain, String, NextFilter)</li>
<li>onPreRemove(IoFilterChain, String, NextFilter)</li>
<li>onPostRemove(IoFilterChain, String, NextFilter)</li>
</ul>
</li>
<li>Session events
<ul>
<li>sessionCreated(NextFilter, IoSession)</li>
<li>sessionOpened(NextFilter, IoSession)</li>
<li>sessionClosed(NextFilter, IoSession)</li>
<li>sessionIdle(NextFilter, IoSession, IdleStatus)</li>
<li>exceptionCaught(NextFilter, IoSession, Throwable)</li>
<li>filterClose(NextFilter, IoSession)</li>
<li>inputClosed(NextFilter, IoSession)</li>
</ul>
</li>
<li>Messages events
<ul>
<li>messageReceived(NextFilter, IoSession, Object)</li>
<li>filterWrite(NextFilter, IoSession, WriteRequest)</li>
<li>messageSent(NextFilter, IoSession, WriteRequest)</li>
</ul>
</li>
</ul>
<h3 id="management">Management</h3>
<p>Here are the Filter&rsquo;s management methods :</p>
<h4 id="onpreadd">onPreAdd</h4>
<p>This is where we create the <strong>SslHandler</strong> instance, and initialize it. We also define the supported ciphers.</p>
<p>The <strong>SslHandler</strong> instance will itself create an instance of <strong>SSLEngine</strong>, and configure it with all the parameters set in the <strong>SslFilter</strong>:</p>
<ul>
<li>If this is client or a server side</li>
<li>When it&rsquo;s server side, the flag that says we want or require the client authentication</li>
<li>The list of enabled ciphers</li>
<li>The list of enabled protocols</li>
</ul>
<p>When it&rsquo;s done, the reference to this instance is stored into the Session&rsquo;s attributes.</p>
<h4 id="onpostadd">onPostAdd</h4>
<p>This is where we start the handshake if it&rsquo;s not explicitly postponed. This is all what this method does. All the logic is implemented by the <strong>SslHandler</strong></p>
<h4 id="onpreremove">onPreRemove</h4>
<p>Here, we stop the SSL session and we cleanup the session (removing the filter from the session&rsquo;s chain and the <strong>SslHandler</strong> instance from the session&rsquo;s attributes). The <strong>Sslhandler</strong> instance si also destroyed after having flushed any event that is not yet processed.</p>
<h3 id="session-events">Session events</h3>
<p>Here are the events that are propagated across the filter&rsquo;s chain and processed by the <strong>SslFilter</strong> :</p>
<h4 id="sessionclosed">sessionClosed</h4>
<p>We just destroy the <strong>SslHandler</strong> instance.</p>
<h4 id="exceptioncaught">exceptionCaught</h4>
<p>We have one special task to proceed when the exception is due to a closed session : we have to gather all the messages that were pending to add them to the exception that will be propagated.</p>
<h4 id="filterclose">filterClose</h4>
<p>Here, if there is a SSL session started, we need to close it. In any case, we propagate the event into the chain to the next filter.</p>
<h3 id="messages-events">Messages events</h3>
<p>Last, not least, the three events relative to messages :</p>
<h4 id="messagereceived-event">messageReceived event</h4>
<p>This event is received when we read some data from the socket. We have to take care of a few corner cases :</p>
<ul>
<li>The handshake has been completed</li>
<li>The handshake has been started but is not completed</li>
<li>No handshake has started, and the <strong>SslHandler</strong> is not yet initialized</li>
</ul>
<p>Those three use cases are listed by order of frequency. Let&rsquo;s see what is going to happen for each of those use cases.</p>
<h5 id="the-handshake-has-been-completed">The handshake has been completed</h5>
<p>Good ! That means every incoming message is encapsulated in a <strong>SSL/TLS</strong> envelop, and should be decrypted. Now, we are talking about messages, but we actually receive bytes, that may need to be aggregated to form a full message (at least in <strong>TCP</strong>). If a message is fragmented, we will receive many buffers, and we will be able to decrypt it fully when we will receive the last piece. Remember that we are blocked during all the process, which can block the <strong>SslHandler</strong> instance for this session for quite some time&hellip;</p>
<p>In any case, every block of data is processed by the <strong>SslHandler</strong>, which delegates to the <strong>SslEngine</strong> the decryption of the bytes it received.</p>
<p>Here is the basic algorithm we have implemented in <em>messageReceived()</em> :</p>
<pre><code>get the session's sslHandler
syncrhonized on sshHandler {
if handshake completed
then
get the sslHandler decrypting the data
if the application buffer is completed, push it into the message to forward to the IoHandler
else
enqueue the incoming data
}
flush the messages if any
</code></pre>
<p>The important part here is that the <strong>SslHandler</strong> will cumulate the data until it has a complete message to push into the chain. This may take a while, and many socket reads. The reason is that the <strong>SSLEngine</strong> cannot process a message unless it has all the bytes needed to decode the message fully.</p>
<div class="note" markdown="1">
<strong>Tip</strong> : increase the transmission buffer size to limit the number of round trips necessary to send a big message.
</div>
<h5 id="the-handshake-has-not-been-completed">The handshake has not been completed</h5>
<p>The means the received message is part of the Handshake protocol. Nothing will be propagated to the <strong>IoHandler</strong>, the message will be consumed by the <strong>SslHandler</strong>.</p>
<p>Until the full handshake is completed, every incoming data will be considered as a Handshake protocol message.</p>
<p>At the same time, messages that the <strong>IoHandler</strong> will be enqueued, waiting for the Handshake to be completed.</p>
<p>Here is a schema representing the full process when the data are received in two round-trips :</p>
<div align="center">
<img src="../images/TLS-unwrap.png" alt="Unwrapping message"/>
</div>
<h4 id="filterwwrite-event">filterwWrite event</h4>
<p>This event is processed when the <strong>IoSession.write()</strong> method is called.</p>
<p>If the SSL session is not started, we simply accumulate the message to write. It will be send later.</p>
<div class="note" markdown="1">
There is one tricky parameter that comes into play here, for some very specific need. Typically, when implementing the <strong>startTLS</strong> protocol, where the server is switching from a non secured connection to a secured connection by the mean of an application message (and potentially a response), we need the response to be send back to the client <strong>before</strong> the <strong>SslFilter</strong> is installed (otherwise, the response will be blocked, and the etablishement of a secured connection will simply fail). This is the <strong>DISABLE_ENCRYPTION_ONCE</strong> Attribute. It does not matter what it contains (it can be just a boolean), it's enough for this parameter to be present in the session for the first message to bypasse the <strong>SslFilter</strong>.
</div>
<p>We control the presence of the <strong>DISABLE_ENCRYPTION_ONCE</strong> flag in the session&rsquo;s attributes, and if present, we remove it from the session, and push the message uncrypted into the messages queue to be send.</p>
<p>Otherwise, if the handshake is not yet completed, we keep the message in a queue, and if it&rsquo;s completed, we encrypt it and schedule it to be written.</p>
<p>If some message has been scheduled for write, we flush them all.</p>
<h4 id="messagesent-event">messageSent event</h4>
<p>Here, it&rsquo;s just a matter of getting back the unencrypted message to propagate it to the <strong>IoHandler</strong></p>
<h2 id="sslcontext-initialisation">SSLContext initialisation</h2>
<p>We saw that in order to establish a <strong>SSL</strong> session, we need to create a <strong>SSLContext</strong>. Here is the code :</p>
<pre><code>SSLContext sslContext;
try
{
// Initialize the SSLContext to work with our key managers.
sslContext = SSLContext.getInstance( &quot;TLS&quot; );
sslContext.init( ... ); // Provide the needed KeyManager[], TrustManager[] and SecureRandom instances
}
catch ( Exception e )
{
// Handle your exception
}
</code></pre>
<p>What we have not exposed here is the constructor and the <strong>init()</strong> method.</p>
<p>The <strong>SSLContext</strong> can either be created explicitly - through its constructor -, or we ask the static factory to return an instance (this is what we have done in the previous code. teh second method is quite straightforward, and would fit most of the time. It&rsquo;s enough to pass it the name of the protocol to use, which is one of :</p>
<ul>
<li><strong>SSL</strong></li>
<li><strong>SSLv2</strong></li>
<li><strong>SSLv3</strong></li>
<li><strong>TLS</strong></li>
<li><strong>TLSv1</strong></li>
<li><strong>TLSv1.1</strong></li>
<li><strong>TLSv1.2</strong> (not supported in Java 6)</li>
</ul>
<p>It&rsquo;s strongly suggested to pick the higher algorithm (ie <strong>TLSv1.2</strong>) if your client supports it.</p>
<p>The <strong>init()</strong> method takes 3 arguments :</p>
<ul>
<li>a <strong>KeyManager</strong> (can be null)</li>
<li>a <strong>TrustManager</strong> (can be null)</li>
<li>a random generator (can be null)</li>
</ul>
<p>If the parameters are set to null, the installed security provider will pick the highest priority implementation.</p>
<div class="nav">
<div class="nav_prev">
<a href="../ch10-executor-filter/ch10-executor-filter.html">Chapter 10 - Executor Filter</a>
</div>
<div class="nav_up">
<a href="../user-guide-toc.html">User Guide</a>
</div>
<div class="nav_next">
<a href="../ch12-logging-filter/ch12-logging-filter.html">Chapter 12 - Logging Filter</a>
</div>
<div class="clearfix"></div>
</div>
</div>
<div id="endContent"></div>
</div>
<div id="footer">
&copy; 2003-2024, <a href="https://www.apache.org">The Apache Software Foundation</a> - <a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a><br />
Apache MINA, MINA, Apache Vysper, Vysper, Apache SSHd, SSHd, Apache FtpServer, FtpServer, Apache AsyncWeb, AsyncWeb,
Apache, the Apache feather logo, and the Apache Mina project logos are trademarks of The Apache Software Foundation.
</div>
</div>
</body>
</html>