dev@grizzly.java.net

Re: Grizzly 2.0: SSL support

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Tue, 18 Nov 2008 22:58:11 -0500

Salut,

Oleksiy Stashok wrote:
> Hi,
>
>>>
>>> Hi,
>>> I would like to ask for the community feedback on current SSL
>>> implementation in Grizzly 2.0
>>> Unlike Grizzly 1.x, Grizzly 2.0 doesn't have special SSL transport,
>>> but uses SSL Encoder and Decoder Transformers.
>>> Transformer API is topic for separate email and blog ;).
>>
>> Blog? Long time I saw one from you (:-) :-) :-))
>
> :)) You will.
>
>> Just in several
>>> words - Transformer knows how to transform data from one
>>> representation to another.
>>
>> Needs to improve the JavaDocs :-) I think it is time to publish the
>> API online :-) :-)
>>
>>
>>> In our case:
>>> SSLEncoderTransformer encodes plaintext input Buffer into TLS/SSL
>>> encoded output Buffer.
>>> SSLDecoderTransformer decodes TLS/SSL encoded Buffer into plaintext
>>> data Buffer.
>>> SSLCodec - incapsulates encoder and decoder transformers and SSL
>>> configuration objects.
>>> It's possible to work with SSL in both standalone and Filter modes.
>>> 1) Standalone mode.
>>> In standalone mode developer should implicitly initialize SSL
>>> connection with SSL handshake. And then use Connection I/O methods
>>> (read/write) to send and receive data.
>>> Example:
>>> Connection connection = null;
>>> // Initiate the SSLCodec
>>> SSLCodec sslCodec = new SSLCodec(createSSLContext());
>>
>> Can you describe what you need to create inside the createSSLContext()?
> Currently, for unit test, it looks like that:
>
> private SSLContext createSSLContext() {
> SSLContextConfigurator sslContextConfigurator =
> new SSLContextConfigurator();
> ClassLoader cl = getClass().getClassLoader();
> // override system properties
> URL cacertsUrl = cl.getResource("ssltest-cacerts.jks");
> if (cacertsUrl != null) {
> sslContextConfigurator.setTrustStoreFile(cacertsUrl.getFile());
> }
>
> // override system properties
> URL keystoreUrl = cl.getResource("ssltest-keystore.jks");
> if (keystoreUrl != null) {
> sslContextConfigurator.setKeyStoreFile(keystoreUrl.getFile());
> }
>
> return sslContextConfigurator.createSSLContext();
> }
>
> There could be different ways to create SSLContext... Grizzly 2.0 just
> has a helper class SSLContextConfigurator, which makes SSLContext
> initialization easier.

OK fortunatly JDK 6 have SSLContext.getDefault(). One day we can get rid
of the configuration paty.



>
>
>>> TCPNIOTransport transport =
>>> TransportManager.instance().createTCPTransport();
>>
>> I think we have discused that part already :-), but should we rename
>> TransportManager to TransportManagerFactory, and replace instance()
>> with getInstance()?
> TransportManagerFactory sounds like factory for TransportManagers... It
> could be TransportFactory.getInstance().create(...) ?

+1

>
>
>>> try {
>>> transport.bind(PORT);
>>> transport.start();
>>> // Connect client
>>> ConnectFuture future = transport.connect("localhost", PORT);
>>> connection = (TCPNIOConnection) future.get(10,
>>> TimeUnit.SECONDS);
>>
>> This is not related to SSL only, but since we are on the topic, I
>> think we need to have a a way to execute asynchronous connect. Right
>> now the connect operation is blocking (10 seconds). I would like to be
>> able to pass some CallbackHandler (or CompletionHandler like NIO.2) so
>> asynchronous operations without blocking.
> Agree. CompletionHandler could be useful.

+1


>
>
>>> // Run handshake
>>> Future handshakeFuture = sslCodec.handshake(connection);
>>> // Wait until handshake will be completed
>>> handshakeFuture.get(10, TimeUnit.SECONDS);
>>
>> Same here. We need a CompletionHandler.
> Ok, agree.
>
>
>>> MemoryManager memoryManager = transport.getMemoryManager();
>>> Buffer message = MemoryUtils.wrap(memoryManager, "Hello
>>> world!");
>>
>> What MemoryUtil.wrap does exactly?
> It wraps the String to a Grizzly Buffer. It's possible to set charset
> encoding additionally.

Great!

>
>
>>> // Write the message with SSLCodec.getEncoder() parameter.
>>> Future writeFuture = connection.write(null, message, null,
>>> sslCodec.getEncoder(), 10, TimeUnit.SECONDS);
>>> writeFuture.get();
>>
>> To make the review easier, do you think you can reference the method
>> description/javadoc from here? So people don't have to checkout the
>> code to understand the sample :-). Here, writeFuture.get() doesn't
>> block, right?
> Actually it blocks and waits the result. But the actual operation
> (write) is executed async.

OK then it need to throw some exception when it gets interrupted. I
guess the Future API already gives us that features. Just need to add it
to the example :-)


>
>
>>> // Obtain the Buffer, which corresponds to the SSLEngine
>>> requirements.
>>> Buffer receiverBuffer = SSLResourcesAccessor.getInstance().
>>> obtainAppBuffer(connection);
>>
>> Hum...do we really need another "Factory" to get the receiverBuffer?
>> Should this be retrieved from the Transport instance instead. I'm -1
>> on having a specialized object (at least with this current API).
>> Should we have a concept of Context/Session?
> We have Connection, which actually represents session.
> SSLResourcesAccessor just helps us to retrieve SSL related artifacts
> from a connection. It's possible to get the same info using:
> attribute.get(connection). For example to get SSLEngine, we can use:
>
> Attribute<SSLEngine> sslEngineAttribute =
> attributeBuilder.createAttribute("sslEngine");
> SSLEngine sslEngine = sslEngineAttribute.get(connection);
>
> But in that case we always have to care about Attribute, it's name etc.
> With accessor it's just becoming easier.

Ok I would rename the class to a more trivial name then.


>
> Also in Grizzly 2.0 Transport is not aware of SSL. These 2 are
> independent things.

Yes, that one we need to discuss :-). So you consider SSL/TLS as a
protocol and not a transport, right? Can you describe why? We discussed
the topic during another discussion already, but just to share with this
community :-)


>
>
>>> // Read the message with SSLCodec.getDecoder() parameter
>>> Future readFuture =
>>> connection.read(receiverBuffer, null,
>>> sslCodec.getDecoder(), null, 10, TimeUnit.SECONDS);
>>> .....................................................
>>> 2) Filter mode.
>>> In Filter mode developer should just add SSLFilter to the transport
>>> filter chain. The SSLFilter itself has a SSLCodec, which in its turn
>>> has SSL encode/decode transformers and SSL configuration.
>>> Example (SSL Echo server)
>>> Connection connection = null;
>>> SSLCodec sslCodec = new SSLCodec(createSSLContext());
>>> TCPNIOTransport transport =
>>> TransportManager.instance().createTCPTransport();
>>> transport.getFilterChain().add(new TransportFilter());
>>> // Add SSLFilter
>>> transport.getFilterChain().add(new SSLFilter(sslCodec));
>>> transport.getFilterChain().add(new EchoFilter());
>>
>> Inside the EchoFilter, calling connection.write() will make sure the
>> output is encrypted if SSL is used, and clean if not, right? That's
>> something we don't support in 1.x and that would be nice if Filter can
>> be written without knowing which transport is used.
> Not exactly. connection.write(), if used without Transformers, will
> write plain data. Though if you'll use filterChain.write(....), it will
> pass throw all the filter chain's filter codecs (SSL, Transport, etc)
> and will be written encrypted.

OK but for the end user, writing a EchoFilter will just means calling
connection.write(), without having to care about TLS/SSL, right?


>
>
>>> try {
>>> transport.bind(PORT);
>>> transport.start();
>>> ...................
>>> Will appreciate the feedback.
>>
>> I think we need to update the main page (grizzly.dev.java.net) with
>> the following information:
>>
>> + Javadocs
>> + XREF Code
>> + Samples (like the on above).
> Agree :))

I need to start writing samples :-)

A+

-- Jeanfrancois


>
> Thanks.
>
> WBR,
> Alexey.
>
>>
>>
>> Great work!
>>
>> -- Jeanfrancois
>>
>>
>>
>>
>>> Thanks.
>>> WBR,
>>> Alexey.
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>> <mailto:dev-unsubscribe_at_grizzly.dev.java.net>
>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>> <mailto:dev-help_at_grizzly.dev.java.net>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>> <mailto:dev-unsubscribe_at_grizzly.dev.java.net>
>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>> <mailto:dev-help_at_grizzly.dev.java.net>
>>
>