So, we’re going to revise the handshaking protocol. It was under revision already, to support negotiation of crypto primitives, but I realized we had some additional requirements for NAT, and some people at Recon mentioned DoS resiliance as something that should be addressed up front. So, I figure we should take a step back, look at what other requirements we should address, and hopefully get the handshaking protocol stable so we can focus on other things, rather than have it be a moving target.
In some situations where we are NAT punching, we’ll be issuing initiation packets from both sides. If we’re doing that, we need a way to clean up the state so that we can sync up and complete handshaking by determining who becomes the initiator and who becomes the initiatee.
While we’re at it, we ought to harden handshaking to DoS attacks, and make the protocol capable of cipher primitive negotiation. And, hey, let’s clarify how the protocol tears down cleanly as well, so we can lose the quick-disconnect-restart class of bugs as well.
So, the following is a proposed set of requirements for the handshaking protocol. Feel free to propose additions or deletions to them:
- Cutlass must offer the ability to not answer to remote scanners that do not have a preshared secret
- Cutlass must not allow network observers to distinguish between an initial key exhange (where both sides do not know the other’s public keys), and subsequent key exchanges (where both sides are merely verifying the other’s public keys).
- Cutlass must offer the ability to exchange previously unknown public keys, offering usability no worse than that of ssh.
- Cutlass must require that initiators perform expensive computations before initiatees perform expensive computations
- Cutlass must require that the initiator prove receipt of initiatee information before the initiatee performs and expensive computations
- Cutlass must allow both sides to initiate connections simultaneously, over identical port pairs, and still be able to select disparate roles for each side (”initiator” and “initiatee”).
- Cutlass must allow one side to drop, and reconnect over identical port pairs, and still be able to take sensible action (Do we want to require the ability to renegotiate? Can we better define “sensible?”)
Now, I’m thinking that a great way to detect a potential drop-reattach situation is to have an undersized initiation packet. Since it’s hard right now to detect the difference between an invalid checksum and a reconnection attempt, if we detect a short packet, we could interpret that as a reconnection attempt.
How to prevent people from turning that into a DoS? We could start holding incomplete connections in a kind of kex purgatory, rather than in the connection hashtable proper. (This also makes it easier to allocate smaller amounts of memory until full handshake completion).
So once we detect a short packet of the proper format (whether or not we have an open connection), we can open a purgatory entry. From then on, incoming packets on that port pair get checked first to see if they kex properly. If they do, then we kill the purgatory connection.
If not, then we drop them down to the handshaking code to see if it can make sense of it. If we renegotiate a connection over the same port pair with the same public key, then we update the ephemeral keys and go forward from there. If it’s a different public key, tell the other side to kindly shove off.
So, in order for Cutlass to be popular, it’s gotta support Windows. That’s the reality in today’s world. So I figured I should talk about how Cutlass intends to accomplish that.
First, and most importantly, we’re trying to stay away from platform-specific calls, at least in the library layer. (Cutlass is divided into libcutlass and clients, if you haven’t been playing along up until now). The two areas that we haven’t been able to avoid platform specifics we wrap. Those two areas are threads and time.
Luckily, those really aren’t that hard to wrap. While Windows threads are slightly different from pthreads, we’re not using any of the pthreads functionality that Windows has no equivalent for. So pretty much we’ve created our own cutlass_thread_handle and cutlass_mutex_handle structures, which we #define at compile time to contain the platform-specific structures.
Then we wrap all of the thread creating, detatchment, etc. functions. pthread_create and CreateThread get merged into cutlass_thread_create. pthread_mutex_lock and EnterCriticalSection get merged into cutlass_mutex_lock, and so forth. All of this happens in wrap_thread.c, with the structure definitions in <cutlass/wrap_types.h>.
Time is a bit more complicated. Sadly, Windows only offers millisecond timers by default, while Linux now gives you access to nanosecond-aware functions (Whether they’re accurate to nanoseconds is unlikely, but the interfaces are there). Right now, we’re defining a cutlass_time structure that can support nanosecond accuracy, and under Windows we just multiply milliseconds by one million in order to get nanosecond-equivalence. I suspect we’ll find some issues when we start testing the transport layers under Windows that we’ll need to tune, probably by bunching packets together if we’ve slept for too long.
Anyways, time checking and sleep functions are all wrapped up in wrap_time.c, following the same strategy as for threads.
Using these wrappers, most of the code compiles under both Linux and Windows (using MinGW). Still having a few linking issues in Windows, and one issue with the crypto module not locating some headers. We’ll get it hammered out, though.
[powered by WordPress.]
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
| « Sep | ||||||
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
20 queries. 0.181 seconds