I've finished a first sketch. The application knows about when the
engine is handshaking by checking SSLEngineResult.HandshakeStatus. All
we need to do is to provide a reliable UDP transport class (including
fragmentation and reassembly) as defined in the DTLS spec, which MUST
be used for transporting when the engine is not in the state of
NOT_HANDSHAKING. Anything else could be seamlessly integrated into
SSLEngine.
It would be nicer if this transport class wasn't specific to DTLS as
current and future connectionless protocols could provide comparable
features, but for DTLS 1.0 compliance I don't see a better way right
now. We are not forced to make this specific class mandatory, so
future implementations could just plug in alternatives when the
standard evolves.
Christian
Am 29.01.2008 um 12:39 schrieb Christian Uebber:
The network and security layer are not as easily separable in the
case of DTLS as they are in the case of TLS over TCP. During the
exchange of control data (handshake, change_cipher_spec, alert) the
network layer must provide reliability, but not anytime else.
As the SSLEngine must be extended anyway for a complete DTLS
implementation, I'm going to follow your suggested route and do that
first. I have had this option on the table anyways. Calling it the
"nio centered approach" i was referring, in a historical sense, to
the two traditional branches of network implementations in Java: the
legacy blocking sockets with attached SSL functionality and the
branch, which started with nio, where everything is nice, fresh, and
clean. I may sometimes be prone to sloppy, not very precise English,
when I'm missing precise vocabulary to express exactly what I want
to say. But I think we'll work it out.
To make SSLEngine DTLS-able most changes do not affect its interface
and could be implemented internally; for that alone we wouldn't even
need a separate DTLSEngine. After all it's just another record
format and a slightly modified handshake. I haven't spend much time
on the issue of how to integrate the reliable transport for the
handshake phase into the completely network-independent design. I'll
work that out and get back to you. If any ideas pop into your mind,
let me know.
Christian
Am 29.01.2008 um 09:52 schrieb Andreas Sterbenz:
Christian,
as you point out, in a datagram world some things are more
complicated and there are more choices to make than in a socket
world. How to handle handshaking, buffer data, etc. This is in many
ways similar to the issues that came up for TLS with non-blocking I/
O. There we made the decision to decouple the TLS aspects
(SSLEngine) from the I/O aspects. That way the choices of how to do
I/O, how many threads to use and for which tasks, etc. are left to
the application developer.
A similar approach may be useful here. In fact, you may be able to
use the existing SSLEngine API and write an implementation that
does DTLS instead of SSL/TLS. Note that SSLEngine is not tied to
java.nio at all. The only link to NIO in the API is the use of
ByteBuffers as a generic abstraction for a memory region.
Of course, having a drop-in replacement for DatagramSocket is still
useful. That could be implemented on top of the DTLS engine as as
simple way for applications to use DTLS without the extra
flexibility of the engine.
What do you think?
Andreas.
Christian Uebber wrote:
Dear Andreas,
due to some other current business my DTLS efforts were set back
for a couple of weeks. But I'm happy to be back on the task now.
First I'd like to discuss some architectural issues. I have put
much time into working out the best way of integrating DTLS into
the current APIs as transparently as possible. All solutions have
specific trade-offs.
The main class most users would use is going to be
TLSDatagramSocket extending the well known DatagramSocket. The
first design choice would be - DTLS differentiates between client
and server - if we should keep an unified DatagramSocket class
without a dedicated DatagramServerSocket. I would say yes and I
think that's an easy one. Users shouldn't be forced to understand
different Java networking concepts if all what is added is an
additional security layer. There are also sessions to be managed,
but this is also possible in a transparent way without a dedicated
server class. For security reasons a method as
acceptHandshakeRequests(boolean b) could be added to enable or
disable server like behavior.
In any case threads accessing the main I/O methods
send(DatagramPacket p) and receive() should never be blocked by
security layer events, as they are needed for bulk transfers from
and to anywhere at any time. Of course there must be mechanisms
(e.g. callbacks) for users wanting extended control.
TLS over TCP could attach session information to created sockets
in a 1:1 relationship. As we have just one (TLS)DatagramSocket
socket for any potential endpoint (1:n) this cannot be done easily
in the case of UDP. Since Java programmers never had to care about
anything else but single DatagramPackets in their application
space, this shouldn't change for anybody who doesn't need to deal
with cryptographic details. So my proposal would be letting
sessions be managed by the socket, but exposing control to those
who need it.
Trying to accomplish full transparency on the receiving side is
quite easy. All packets for which there is no established session
object and which are not handshake requests are silently dropped.
Handshake requests instead get forwared to a Handshaker class,
packets belonging to an established session get unwrapped and are
then fired through the send-method of the attached
TLSDatagramSocket.
Transparency on the sending side implies some trade-off decisions
in cases where the send-method gets packets for destinations
without an already established session.
1. Full Transparency:
1. Session initiation is started, packets for an
unestablished
target are buffered until the session is established and
then sent (or dropped if establishment failed).
2. Session initiation is started, packets get dropped (nobody
promised that UDP would be reliable).
2. Manual Session Initiation: A method as
initiateSession(InetAddress
a, int port, CallbackHandler c) must be called before any packet
can be send to a specific endpoint.
Buffers could fill up quite quickly under heavy load in the case
of 1.1. In the case of 1.2 no promises are broken, but it's not
really good style. An average handshake can take a second and a
lot of packets can already be lost during this time. The case No.
2 wouldn't be usable as a drop-in replacement anymore.
Maybe some aspects could be combined for the best solution. What
do you think?
But that should be it for today... I'm looking forward to your
remarks.
Christian
PS I've emailed the signed SCA today. It should get registered soon.
Am 30.11.2007 um 02:42 schrieb Andreas Sterbenz:
Christian Uebber wrote:
Is anybody already working on this for Java DatagramSockets? I'd
be interested in doing the work. Integration into and reuse of
the existing JSSE code would also be my preferred way to go.
That sounds like a great idea. We at Sun don't have any current
plans to implement DTLS due to a lack of resources, but we could
assist by answering questions about JSSE or commenting on your
code. There are also some architectural issues about fitting a
secure datagram transport into the current Networking APIs that
we may want to discuss.
BTW, you may want to look into signing the contributor agreement:
http://openjdk.java.net/contribute/
Andreas.