Tls-crypt v2 is more complicated to implement a proper stateless
handshake. To allow state handshake this commit does
- introduce a new packet CONTROL_WKC_V1 that repeats the wrapped
client key.
- introduce a way to negotiate the support for this packet in the
three way handshake
Details about the protocol changes are in tls-crypt-v2.txt. Optional
arguments to the tls-crypt-v2 option have been added to explicitly
allow or disallow client that do not support the stateless handshake.
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Patch v3: improve grammar, style, comments, fix unit tests
Patch v4: remove explicit flag for ability to resend WKc,
clean up comments, improve code style in some instances
Acked-by: Antonio Quartulli <antonio@openvpn.net>
Message-Id: <20220505130348.1183195-1-arne@rfc2549.org>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg24287.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -69,6 +69,16 @@ Improved ``--mssfix`` and ``--fragment`` calculation |
| 69 | 69 |
account and the resulting size is specified as the total size of the VPN packets |
| 70 | 70 |
including IP and UDP headers. |
| 71 | 71 |
|
| 72 |
+Cookie based handshake for UDP server |
|
| 73 |
+ Instead of allocating a connection for each client on the initial packet |
|
| 74 |
+ OpenVPN server will now use an HMAC based cookie as its session id. This |
|
| 75 |
+ way the server can verify it on completing the handshake without keeping |
|
| 76 |
+ state. This eliminates the amplification and resource exhaustion attacks. |
|
| 77 |
+ For tls-crypt-v2 clients, this requires OpenVPN 2.6 clients or later |
|
| 78 |
+ because the client needs to resend its client key on completing the hand |
|
| 79 |
+ shake. The tls-crypt-v2 option allows controlling if older clients are |
|
| 80 |
+ accepted. |
|
| 81 |
+ |
|
| 72 | 82 |
Deprecated features |
| 73 | 83 |
------------------- |
| 74 | 84 |
``inetd`` has been removed |
| ... | ... |
@@ -486,6 +486,13 @@ certificates and keys: https://github.com/OpenVPN/easy-rsa |
| 486 | 486 |
8000 years'. |
| 487 | 487 |
|
| 488 | 488 |
--tls-crypt-v2 keyfile |
| 489 |
+ |
|
| 490 |
+ Valid syntax: |
|
| 491 |
+ :: |
|
| 492 |
+ tls-crypt-v2 keyfile |
|
| 493 |
+ tls-crypt-v2 keyfile force-cookie |
|
| 494 |
+ tls-crypt-v2 keyfile allow-noncookie |
|
| 495 |
+ |
|
| 489 | 496 |
Use client-specific tls-crypt keys. |
| 490 | 497 |
|
| 491 | 498 |
For clients, ``keyfile`` is a client-specific tls-crypt key. Such a key |
| ... | ... |
@@ -501,6 +508,13 @@ certificates and keys: https://github.com/OpenVPN/easy-rsa |
| 501 | 501 |
client is using client-specific keys, and automatically select the right |
| 502 | 502 |
mode. |
| 503 | 503 |
|
| 504 |
+ The optional parameters :code:`force-cookie` allows only tls-crypt-v2 |
|
| 505 |
+ clients that support a cookie based stateless three way handshake that |
|
| 506 |
+ avoids replay attacks and state exhaustion on the server side (OpenVPN |
|
| 507 |
+ 2.6 and later). The option :code:`allow-noncookie` explicitly allows |
|
| 508 |
+ older tls-crypt-v2 clients. The default is (currently) |
|
| 509 |
+ :code:`allow-noncookie`. |
|
| 510 |
+ |
|
| 504 | 511 |
--tls-crypt-v2-verify cmd |
| 505 | 512 |
Run command ``cmd`` to verify the metadata of the client-specific |
| 506 | 513 |
tls-crypt-v2 key of a connecting client. This allows server |
| ... | ... |
@@ -157,6 +157,50 @@ When setting up the openvpn connection: |
| 157 | 157 |
messages. |
| 158 | 158 |
|
| 159 | 159 |
|
| 160 |
+HMAC Cookie support |
|
| 161 |
+------------------- |
|
| 162 |
+To avoid exhaustion attack and keeping state for connections that fail to |
|
| 163 |
+complete the three-way handshake, the OpenVPN server will use its own session |
|
| 164 |
+id as challenge that the client must repeat in the third packet of the |
|
| 165 |
+handshake. This introduces a problem. If the server does not keep the wrapped |
|
| 166 |
+client key from the initial packet, the server cannot decode the third packet. |
|
| 167 |
+Therefore, tls-crypt-v2 in 2.6 allows resending the wrapped key in the third |
|
| 168 |
+packet of the handshake with the P_CONTROL_WKC_V1 message. The modified |
|
| 169 |
+handshake is as follows (the rest of the handshake is unmodified): |
|
| 170 |
+ |
|
| 171 |
+1. The client creates the P_CONTROL_HARD_RESET_CLIENT_V3 message as before |
|
| 172 |
+ but indicates that it supports resending the wrapped key. This is done |
|
| 173 |
+ by setting the packet id of the replay id to 0x0f000000. The first byte |
|
| 174 |
+ indicates the early negotiation support and the next byte the flags. |
|
| 175 |
+ All tls-crypt-v2 implementations that support early negotiation, must |
|
| 176 |
+ also support resending the wrapped key. The flags byte is therefore |
|
| 177 |
+ empty. |
|
| 178 |
+ |
|
| 179 |
+2. The server responds with a P_CONTROL_HARD_RESET_V2 message. Instead of having |
|
| 180 |
+ an empty payload like normally, the payload consists of TLV (type (uint16), |
|
| 181 |
+ length (uint16), value) packets. TLV was chosen |
|
| 182 |
+ to allow extensibility in the future. Currently only the following TLV is |
|
| 183 |
+ defined: |
|
| 184 |
+ |
|
| 185 |
+ flags - type 0x01, length 2. |
|
| 186 |
+ |
|
| 187 |
+ Bit 1 indicates that the client needs to resend the WKc in the third packet. |
|
| 188 |
+ |
|
| 189 |
+3. Instead of normal P_ACK_V1 or P_CONTROL_V1 packet, the client will send a |
|
| 190 |
+ P_CONTROL_WKC_V1 packet. The P_CONTROL_WKC_V1 is identical to a normal |
|
| 191 |
+ P_CONTROL_V1 packet but with the WKc appended. |
|
| 192 |
+ |
|
| 193 |
+ Normally the first message of the client is either P_ACK_V1, directly |
|
| 194 |
+ followed by a P_CONTROL_V1 message that contains the TLS Client Hello or |
|
| 195 |
+ just a P_CONTROL_V1 message. Instead of a P_ACK_V1 message the client should |
|
| 196 |
+ send a P_CONTROL_WKC_V1 message with an empty payload. This message must |
|
| 197 |
+ also include an ACK for the P_CONTROL_HARD_RESET_V2 message. |
|
| 198 |
+ |
|
| 199 |
+ When directly sending the TLS Client Hello message in the P_CONTROL_WKC_V1 |
|
| 200 |
+ message, the client must ensure that the resulting P_CONTROL_WKC_V1 message |
|
| 201 |
+ with the appended WKc does not extend the control message length. |
|
| 202 |
+ |
|
| 203 |
+ |
|
| 160 | 204 |
Considerations |
| 161 | 205 |
-------------- |
| 162 | 206 |
|
| ... | ... |
@@ -256,6 +256,14 @@ struct crypto_options |
| 256 | 256 |
/**< Bit-flag indicating that data channel key derivation |
| 257 | 257 |
* is done using TLS keying material export [RFC5705] |
| 258 | 258 |
*/ |
| 259 |
+#define CO_RESEND_WKC (1<<4) |
|
| 260 |
+ /**< Bit-flag indicating that the client is expected to |
|
| 261 |
+ * resend the wrapped client key with the 2nd packet (packet-id 1) |
|
| 262 |
+ * like with the HARD_RESET_CLIENT_V3 packet */ |
|
| 263 |
+#define CO_FORCE_TLSCRYPTV2_COOKIE (1<<5) |
|
| 264 |
+ /**< Bit-flag indicating that we do not allow clients that do |
|
| 265 |
+ * not support resending the wrapped client key (WKc) with the |
|
| 266 |
+ * third packet of the three-way handshake */ |
|
| 259 | 267 |
unsigned int flags; /**< Bit-flags determining behavior of |
| 260 | 268 |
* security operation functions. */ |
| 261 | 269 |
}; |
| ... | ... |
@@ -2960,6 +2960,10 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) |
| 2960 | 2960 |
{
|
| 2961 | 2961 |
to.tls_wrap.tls_crypt_v2_server_key = c->c1.ks.tls_crypt_v2_server_key; |
| 2962 | 2962 |
to.tls_crypt_v2_verify_script = c->options.tls_crypt_v2_verify_script; |
| 2963 |
+ if (options->ce.tls_crypt_v2_force_cookie) |
|
| 2964 |
+ {
|
|
| 2965 |
+ to.tls_wrap.opt.flags |= CO_FORCE_TLSCRYPTV2_COOKIE; |
|
| 2966 |
+ } |
|
| 2963 | 2967 |
} |
| 2964 | 2968 |
} |
| 2965 | 2969 |
|
| ... | ... |
@@ -40,7 +40,31 @@ |
| 40 | 40 |
#include <sys/inotify.h> |
| 41 | 41 |
#endif |
| 42 | 42 |
|
| 43 |
-/* Return true if this packet should create a new session */ |
|
| 43 |
+static void |
|
| 44 |
+send_hmac_reset_packet(struct multi_context *m, |
|
| 45 |
+ struct tls_pre_decrypt_state *state, |
|
| 46 |
+ struct tls_auth_standalone *tas, |
|
| 47 |
+ struct session_id *sid, |
|
| 48 |
+ bool request_resend_wkc) |
|
| 49 |
+{
|
|
| 50 |
+ reset_packet_id_send(&state->tls_wrap_tmp.opt.packet_id.send); |
|
| 51 |
+ state->tls_wrap_tmp.opt.packet_id.rec.initialized = true; |
|
| 52 |
+ uint8_t header = 0 | (P_CONTROL_HARD_RESET_SERVER_V2 << P_OPCODE_SHIFT); |
|
| 53 |
+ struct buffer buf = tls_reset_standalone(&state->tls_wrap_tmp, tas, sid, |
|
| 54 |
+ &state->peer_session_id, header, |
|
| 55 |
+ request_resend_wkc); |
|
| 56 |
+ |
|
| 57 |
+ struct context *c = &m->top; |
|
| 58 |
+ |
|
| 59 |
+ buf_reset_len(&c->c2.buffers->aux_buf); |
|
| 60 |
+ buf_copy(&c->c2.buffers->aux_buf, &buf); |
|
| 61 |
+ m->hmac_reply = c->c2.buffers->aux_buf; |
|
| 62 |
+ m->hmac_reply_dest = &m->top.c2.from; |
|
| 63 |
+ msg(D_MULTI_DEBUG, "Reset packet from client, sending HMAC based reset challenge"); |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+ |
|
| 67 |
+/* Returns true if this packet should create a new session */ |
|
| 44 | 68 |
static bool |
| 45 | 69 |
do_pre_decrypt_check(struct multi_context *m, |
| 46 | 70 |
struct tls_pre_decrypt_state *state, |
| ... | ... |
@@ -58,37 +82,64 @@ do_pre_decrypt_check(struct multi_context *m, |
| 58 | 58 |
struct openvpn_sockaddr *from = &m->top.c2.from.dest; |
| 59 | 59 |
int handwindow = m->top.options.handshake_window; |
| 60 | 60 |
|
| 61 |
- |
|
| 62 | 61 |
if (verdict == VERDICT_VALID_RESET_V3) |
| 63 | 62 |
{
|
| 64 |
- /* For tls-crypt-v2 we need to keep the state of the first packet to |
|
| 65 |
- * store the unwrapped key */ |
|
| 66 |
- return true; |
|
| 63 |
+ /* Extract the packet id to check if it has the special format that |
|
| 64 |
+ * indicates early negotiation support */ |
|
| 65 |
+ struct packet_id_net pin; |
|
| 66 |
+ struct buffer tmp = m->top.c2.buf; |
|
| 67 |
+ ASSERT(buf_advance(&tmp, 1 + SID_SIZE)); |
|
| 68 |
+ ASSERT(packet_id_read(&pin, &tmp, true)); |
|
| 69 |
+ |
|
| 70 |
+ /* The most significant byte is 0x0f if early negotiation is supported */ |
|
| 71 |
+ bool early_neg_support = (pin.id & EARLY_NEG_MASK) == EARLY_NEG_START; |
|
| 72 |
+ |
|
| 73 |
+ /* All clients that support early negotiation and tls-crypt are assumed |
|
| 74 |
+ * to also support resending the WKc in the 2nd packet */ |
|
| 75 |
+ if (early_neg_support) |
|
| 76 |
+ {
|
|
| 77 |
+ /* Calculate the session ID HMAC for our reply and create reset packet */ |
|
| 78 |
+ struct session_id sid = calculate_session_id_hmac(state->peer_session_id, |
|
| 79 |
+ from, hmac, handwindow, 0); |
|
| 80 |
+ send_hmac_reset_packet(m, state, tas, &sid, true); |
|
| 81 |
+ |
|
| 82 |
+ return false; |
|
| 83 |
+ } |
|
| 84 |
+ else |
|
| 85 |
+ {
|
|
| 86 |
+ /* For tls-crypt-v2 we need to keep the state of the first packet |
|
| 87 |
+ * to store the unwrapped key if the client doesn't support resending |
|
| 88 |
+ * the wrapped key. Unless the user specifically disallowed |
|
| 89 |
+ * compatibility with such clients to avoid state exhaustion */ |
|
| 90 |
+ if (tas->tls_wrap.opt.flags & CO_FORCE_TLSCRYPTV2_COOKIE) |
|
| 91 |
+ {
|
|
| 92 |
+ struct gc_arena gc = gc_new(); |
|
| 93 |
+ const char *peer = print_link_socket_actual(&m->top.c2.from, &gc); |
|
| 94 |
+ msg(D_MULTI_DEBUG, "tls-crypt-v2 force-cookie is enabled, " |
|
| 95 |
+ "ignoring connection attempt from old client (%s)", peer); |
|
| 96 |
+ gc_free(&gc); |
|
| 97 |
+ return false; |
|
| 98 |
+ } |
|
| 99 |
+ else |
|
| 100 |
+ {
|
|
| 101 |
+ return true; |
|
| 102 |
+ } |
|
| 103 |
+ } |
|
| 67 | 104 |
} |
| 68 | 105 |
else if (verdict == VERDICT_VALID_RESET_V2) |
| 69 | 106 |
{
|
| 70 | 107 |
/* Calculate the session ID HMAC for our reply and create reset packet */ |
| 71 | 108 |
struct session_id sid = calculate_session_id_hmac(state->peer_session_id, |
| 72 | 109 |
from, hmac, handwindow, 0); |
| 73 |
- reset_packet_id_send(&tas->tls_wrap.opt.packet_id.send); |
|
| 74 |
- tas->tls_wrap.opt.packet_id.rec.initialized = true; |
|
| 75 |
- uint8_t header = 0 | (P_CONTROL_HARD_RESET_SERVER_V2 << P_OPCODE_SHIFT); |
|
| 76 |
- struct buffer buf = tls_reset_standalone(tas, &sid, |
|
| 77 |
- &state->peer_session_id, header); |
|
| 78 |
- |
|
| 79 | 110 |
|
| 80 |
- struct context *c = &m->top; |
|
| 111 |
+ send_hmac_reset_packet(m, state, tas, &sid, false); |
|
| 81 | 112 |
|
| 82 |
- buf_reset_len(&c->c2.buffers->aux_buf); |
|
| 83 |
- buf_copy(&c->c2.buffers->aux_buf, &buf); |
|
| 84 |
- m->hmac_reply = c->c2.buffers->aux_buf; |
|
| 85 |
- m->hmac_reply_dest = &m->top.c2.from; |
|
| 86 |
- msg(D_MULTI_DEBUG, "Reset packet from client, sending HMAC based reset challenge"); |
|
| 87 | 113 |
/* We have a reply do not create a new session */ |
| 88 | 114 |
return false; |
| 89 | 115 |
|
| 90 | 116 |
} |
| 91 |
- else if (verdict == VERDICT_VALID_CONTROL_V1 || verdict == VERDICT_VALID_ACK_V1) |
|
| 117 |
+ else if (verdict == VERDICT_VALID_CONTROL_V1 || verdict == VERDICT_VALID_ACK_V1 |
|
| 118 |
+ || verdict == VERDICT_VALID_WKC_V1) |
|
| 92 | 119 |
{
|
| 93 | 120 |
/* ACK_V1 contains the peer id (our id) while CONTROL_V1 can but does not |
| 94 | 121 |
* need to contain the peer id */ |
| ... | ... |
@@ -8896,6 +8896,19 @@ add_option(struct options *options, |
| 8896 | 8896 |
options->ce.tls_crypt_v2_file = p[1]; |
| 8897 | 8897 |
options->ce.tls_crypt_v2_file_inline = is_inline; |
| 8898 | 8898 |
} |
| 8899 |
+ |
|
| 8900 |
+ if (p[2] && streq(p[2], "force-cookie")) |
|
| 8901 |
+ {
|
|
| 8902 |
+ options->ce.tls_crypt_v2_force_cookie = true; |
|
| 8903 |
+ } |
|
| 8904 |
+ else if (p[2] && streq(p[2], "allow-noncookie")) |
|
| 8905 |
+ {
|
|
| 8906 |
+ options->ce.tls_crypt_v2_force_cookie = false; |
|
| 8907 |
+ } |
|
| 8908 |
+ else if (p[2]) |
|
| 8909 |
+ {
|
|
| 8910 |
+ msg(msglevel, "Unsupported tls-crypt-v2 argument: %s", p[2]); |
|
| 8911 |
+ } |
|
| 8899 | 8912 |
} |
| 8900 | 8913 |
else if (streq(p[0], "tls-crypt-v2-verify") && p[1] && !p[2]) |
| 8901 | 8914 |
{
|
| ... | ... |
@@ -162,6 +162,9 @@ struct connection_entry |
| 162 | 162 |
* authenticated encryption v2 */ |
| 163 | 163 |
const char *tls_crypt_v2_file; |
| 164 | 164 |
bool tls_crypt_v2_file_inline; |
| 165 |
+ |
|
| 166 |
+ /* Allow only client that support resending the wrapped client key */ |
|
| 167 |
+ bool tls_crypt_v2_force_cookie; |
|
| 165 | 168 |
}; |
| 166 | 169 |
|
| 167 | 170 |
struct remote_entry |
| ... | ... |
@@ -361,8 +361,6 @@ struct reliable_entry *reliable_get_entry_sequenced(struct reliable *rel); |
| 361 | 361 |
* |
| 362 | 362 |
* @param rel The reliable structure associated with the given buffer. |
| 363 | 363 |
* @param buf The buffer of the reliable entry which is to be removed. |
| 364 |
- * @param inc_pid If true, the reliable structure's packet ID counter |
|
| 365 |
- * will be incremented. |
|
| 366 | 364 |
*/ |
| 367 | 365 |
void reliable_mark_deleted(struct reliable *rel, struct buffer *buf); |
| 368 | 366 |
|
| ... | ... |
@@ -1099,6 +1099,14 @@ tls_session_init(struct tls_multi *multi, struct tls_session *session) |
| 1099 | 1099 |
session->opt->replay_time, |
| 1100 | 1100 |
"TLS_WRAP", session->key_id); |
| 1101 | 1101 |
|
| 1102 |
+ /* If we are using tls-crypt-v2 we manipulate the packet id to be (ab)used |
|
| 1103 |
+ * to indicate early protocol negotiation */ |
|
| 1104 |
+ if (session->opt->tls_crypt_v2) |
|
| 1105 |
+ {
|
|
| 1106 |
+ session->tls_wrap.opt.packet_id.send.time = now; |
|
| 1107 |
+ session->tls_wrap.opt.packet_id.send.id = EARLY_NEG_START; |
|
| 1108 |
+ } |
|
| 1109 |
+ |
|
| 1102 | 1110 |
/* load most recent packet-id to replay protect on --tls-auth */ |
| 1103 | 1111 |
packet_id_persist_load_obj(session->tls_wrap.opt.pid_persist, |
| 1104 | 1112 |
&session->tls_wrap.opt.packet_id); |
| ... | ... |
@@ -2525,6 +2533,54 @@ session_skip_to_pre_start(struct tls_session *session, |
| 2525 | 2525 |
} |
| 2526 | 2526 |
|
| 2527 | 2527 |
/** |
| 2528 |
+ * Parses the TLVs (type, length, value) in the early negotiation |
|
| 2529 |
+ */ |
|
| 2530 |
+static bool |
|
| 2531 |
+parse_early_negotiation_tlvs(struct buffer *buf, struct key_state *ks) |
|
| 2532 |
+{
|
|
| 2533 |
+ while (buf->len > 0) |
|
| 2534 |
+ {
|
|
| 2535 |
+ if (buf_len(buf) < 4) |
|
| 2536 |
+ {
|
|
| 2537 |
+ goto error; |
|
| 2538 |
+ } |
|
| 2539 |
+ /* read type */ |
|
| 2540 |
+ uint16_t type = buf_read_u16(buf); |
|
| 2541 |
+ uint16_t len = buf_read_u16(buf); |
|
| 2542 |
+ if (buf_len(buf) < len) |
|
| 2543 |
+ {
|
|
| 2544 |
+ goto error; |
|
| 2545 |
+ } |
|
| 2546 |
+ |
|
| 2547 |
+ switch (type) |
|
| 2548 |
+ {
|
|
| 2549 |
+ case TLV_TYPE_EARLY_NEG_FLAGS: |
|
| 2550 |
+ if (len != sizeof(uint16_t)) |
|
| 2551 |
+ {
|
|
| 2552 |
+ goto error; |
|
| 2553 |
+ } |
|
| 2554 |
+ uint16_t flags = buf_read_u16(buf); |
|
| 2555 |
+ |
|
| 2556 |
+ if (flags & EARLY_NEG_FLAG_RESEND_WKC) |
|
| 2557 |
+ {
|
|
| 2558 |
+ ks->crypto_options.flags |= CO_RESEND_WKC; |
|
| 2559 |
+ } |
|
| 2560 |
+ break; |
|
| 2561 |
+ |
|
| 2562 |
+ default: |
|
| 2563 |
+ /* Skip types we do not parse */ |
|
| 2564 |
+ buf_advance(buf, len); |
|
| 2565 |
+ } |
|
| 2566 |
+ } |
|
| 2567 |
+ reliable_mark_deleted(ks->rec_reliable, buf); |
|
| 2568 |
+ |
|
| 2569 |
+ return true; |
|
| 2570 |
+error: |
|
| 2571 |
+ msg(D_TLS_ERRORS, "TLS Error: Early negotiation malformed packet"); |
|
| 2572 |
+ return false; |
|
| 2573 |
+} |
|
| 2574 |
+ |
|
| 2575 |
+/** |
|
| 2528 | 2576 |
* Read incoming ciphertext and passes it to the buffer of the SSL library. |
| 2529 | 2577 |
* Returns false if an error is encountered that should abort the session. |
| 2530 | 2578 |
*/ |
| ... | ... |
@@ -2556,6 +2612,13 @@ read_incoming_tls_ciphertext(struct buffer *buf, struct key_state *ks, |
| 2556 | 2556 |
return true; |
| 2557 | 2557 |
} |
| 2558 | 2558 |
|
| 2559 |
+static bool |
|
| 2560 |
+control_packet_needs_wkc(const struct key_state *ks) |
|
| 2561 |
+{
|
|
| 2562 |
+ return (ks->crypto_options.flags & CO_RESEND_WKC) |
|
| 2563 |
+ && (ks->send_reliable->packet_id == 1); |
|
| 2564 |
+} |
|
| 2565 |
+ |
|
| 2559 | 2566 |
|
| 2560 | 2567 |
static bool |
| 2561 | 2568 |
tls_process_state(struct tls_multi *multi, |
| ... | ... |
@@ -2625,9 +2688,21 @@ tls_process_state(struct tls_multi *multi, |
| 2625 | 2625 |
struct reliable_entry *entry = reliable_get_entry_sequenced(ks->rec_reliable); |
| 2626 | 2626 |
if (entry) |
| 2627 | 2627 |
{
|
| 2628 |
- if (!read_incoming_tls_ciphertext(&entry->buf, ks, &state_change)) |
|
| 2628 |
+ /* The first packet from the peer (the reset packet) is special and |
|
| 2629 |
+ * contains early protocol negotiation */ |
|
| 2630 |
+ if (entry->packet_id == 0 && is_hard_reset_method2(entry->opcode)) |
|
| 2629 | 2631 |
{
|
| 2630 |
- goto error; |
|
| 2632 |
+ if (!parse_early_negotiation_tlvs(&entry->buf, ks)) |
|
| 2633 |
+ {
|
|
| 2634 |
+ goto error; |
|
| 2635 |
+ } |
|
| 2636 |
+ } |
|
| 2637 |
+ else |
|
| 2638 |
+ {
|
|
| 2639 |
+ if (!read_incoming_tls_ciphertext(&entry->buf, ks, &state_change)) |
|
| 2640 |
+ {
|
|
| 2641 |
+ goto error; |
|
| 2642 |
+ } |
|
| 2631 | 2643 |
} |
| 2632 | 2644 |
} |
| 2633 | 2645 |
|
| ... | ... |
@@ -2720,7 +2795,12 @@ tls_process_state(struct tls_multi *multi, |
| 2720 | 2720 |
} |
| 2721 | 2721 |
if (status == 1) |
| 2722 | 2722 |
{
|
| 2723 |
- reliable_mark_active_outgoing(ks->send_reliable, buf, P_CONTROL_V1); |
|
| 2723 |
+ int opcode = P_CONTROL_V1; |
|
| 2724 |
+ if (control_packet_needs_wkc(ks)) |
|
| 2725 |
+ {
|
|
| 2726 |
+ opcode = P_CONTROL_WKC_V1; |
|
| 2727 |
+ } |
|
| 2728 |
+ reliable_mark_active_outgoing(ks->send_reliable, buf, opcode); |
|
| 2724 | 2729 |
INCR_GENERATED; |
| 2725 | 2730 |
state_change = true; |
| 2726 | 2731 |
dmsg(D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); |
| ... | ... |
@@ -2810,15 +2890,37 @@ tls_process(struct tls_multi *multi, |
| 2810 | 2810 |
|
| 2811 | 2811 |
update_time(); |
| 2812 | 2812 |
|
| 2813 |
+ /* We often send acks back to back to a following control packet. This |
|
| 2814 |
+ * normally does not create a problem (apart from an extra packet). |
|
| 2815 |
+ * However, with the P_CONTROL_WKC_V1 we need to ensure that the packet |
|
| 2816 |
+ * gets resent if not received by remote, so instead we use an empty |
|
| 2817 |
+ * control packet in this special case */ |
|
| 2818 |
+ |
|
| 2813 | 2819 |
/* Send 1 or more ACKs (each received control packet gets one ACK) */ |
| 2814 | 2820 |
if (!to_link->len && !reliable_ack_empty(ks->rec_ack)) |
| 2815 | 2821 |
{
|
| 2816 |
- struct buffer buf = ks->ack_write_buf; |
|
| 2817 |
- ASSERT(buf_init(&buf, multi->opt.frame.buf.headroom)); |
|
| 2818 |
- write_control_auth(session, ks, &buf, to_link_addr, P_ACK_V1, |
|
| 2819 |
- RELIABLE_ACK_SIZE, false); |
|
| 2820 |
- *to_link = buf; |
|
| 2821 |
- dmsg(D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); |
|
| 2822 |
+ if (control_packet_needs_wkc(ks)) |
|
| 2823 |
+ {
|
|
| 2824 |
+ struct buffer *buf = reliable_get_buf_output_sequenced(ks->send_reliable); |
|
| 2825 |
+ if (!buf) |
|
| 2826 |
+ {
|
|
| 2827 |
+ return false; |
|
| 2828 |
+ } |
|
| 2829 |
+ |
|
| 2830 |
+ /* We do not write anything to the buffer, this way this will be |
|
| 2831 |
+ * an empty control packet that gets the ack piggybacked and |
|
| 2832 |
+ * also appended the wrapped client key since it has a WCK opcode */ |
|
| 2833 |
+ reliable_mark_active_outgoing(ks->send_reliable, buf, P_CONTROL_WKC_V1); |
|
| 2834 |
+ } |
|
| 2835 |
+ else |
|
| 2836 |
+ {
|
|
| 2837 |
+ struct buffer buf = ks->ack_write_buf; |
|
| 2838 |
+ ASSERT(buf_init(&buf, multi->opt.frame.buf.headroom)); |
|
| 2839 |
+ write_control_auth(session, ks, &buf, to_link_addr, P_ACK_V1, |
|
| 2840 |
+ RELIABLE_ACK_SIZE, false); |
|
| 2841 |
+ *to_link = buf; |
|
| 2842 |
+ dmsg(D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); |
|
| 2843 |
+ } |
|
| 2822 | 2844 |
} |
| 2823 | 2845 |
|
| 2824 | 2846 |
/* When should we wake up again? */ |
| ... | ... |
@@ -3463,7 +3565,8 @@ tls_pre_decrypt(struct tls_multi *multi, |
| 3463 | 3463 |
} |
| 3464 | 3464 |
|
| 3465 | 3465 |
/* |
| 3466 |
- * We have an authenticated control channel packet (if --tls-auth was set). |
|
| 3466 |
+ * We have an authenticated control channel packet (if --tls-auth/tls-crypt |
|
| 3467 |
+ * or tls-crypt-v2 was set). |
|
| 3467 | 3468 |
* Now pass to our reliability layer which deals with |
| 3468 | 3469 |
* packet acknowledgements, retransmits, sequencing, etc. |
| 3469 | 3470 |
*/ |
| ... | ... |
@@ -3892,7 +3995,7 @@ protocol_dump(struct buffer *buffer, unsigned int flags, struct gc_arena *gc) |
| 3892 | 3892 |
|
| 3893 | 3893 |
if (op == P_ACK_V1) |
| 3894 | 3894 |
{
|
| 3895 |
- goto done; |
|
| 3895 |
+ goto print_data; |
|
| 3896 | 3896 |
} |
| 3897 | 3897 |
|
| 3898 | 3898 |
/* |
| ... | ... |
@@ -148,7 +148,8 @@ tls_wrap_control(struct tls_wrap_ctx *ctx, uint8_t header, struct buffer *buf, |
| 148 | 148 |
return; |
| 149 | 149 |
} |
| 150 | 150 |
|
| 151 |
- if ((header >> P_OPCODE_SHIFT) == P_CONTROL_HARD_RESET_CLIENT_V3) |
|
| 151 |
+ if ((header >> P_OPCODE_SHIFT) == P_CONTROL_HARD_RESET_CLIENT_V3 |
|
| 152 |
+ || (header >> P_OPCODE_SHIFT) == P_CONTROL_WKC_V1) |
|
| 152 | 153 |
{
|
| 153 | 154 |
if (!buf_copy(&ctx->work, |
| 154 | 155 |
ctx->tls_crypt_v2_wkc)) |
| ... | ... |
@@ -197,7 +198,8 @@ read_control_auth(struct buffer *buf, |
| 197 | 197 |
bool ret = false; |
| 198 | 198 |
|
| 199 | 199 |
const uint8_t opcode = *(BPTR(buf)) >> P_OPCODE_SHIFT; |
| 200 |
- if (opcode == P_CONTROL_HARD_RESET_CLIENT_V3 |
|
| 200 |
+ if ((opcode == P_CONTROL_HARD_RESET_CLIENT_V3 |
|
| 201 |
+ || opcode == P_CONTROL_WKC_V1) |
|
| 201 | 202 |
&& !tls_crypt_v2_extract_client_key(buf, ctx, opt)) |
| 202 | 203 |
{
|
| 203 | 204 |
msg(D_TLS_ERRORS, |
| ... | ... |
@@ -321,6 +323,7 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, |
| 321 | 321 |
if (op != P_CONTROL_HARD_RESET_CLIENT_V2 |
| 322 | 322 |
&& op != P_CONTROL_HARD_RESET_CLIENT_V3 |
| 323 | 323 |
&& op != P_CONTROL_V1 |
| 324 |
+ && op != P_CONTROL_WKC_V1 |
|
| 324 | 325 |
&& op != P_ACK_V1) |
| 325 | 326 |
{
|
| 326 | 327 |
/* |
| ... | ... |
@@ -397,6 +400,10 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, |
| 397 | 397 |
{
|
| 398 | 398 |
return VERDICT_VALID_RESET_V3; |
| 399 | 399 |
} |
| 400 |
+ else if (op == P_CONTROL_WKC_V1) |
|
| 401 |
+ {
|
|
| 402 |
+ return VERDICT_VALID_WKC_V1; |
|
| 403 |
+ } |
|
| 400 | 404 |
else |
| 401 | 405 |
{
|
| 402 | 406 |
return VERDICT_VALID_RESET_V2; |
| ... | ... |
@@ -410,10 +417,12 @@ error: |
| 410 | 410 |
|
| 411 | 411 |
|
| 412 | 412 |
struct buffer |
| 413 |
-tls_reset_standalone(struct tls_auth_standalone *tas, |
|
| 413 |
+tls_reset_standalone(struct tls_wrap_ctx *ctx, |
|
| 414 |
+ struct tls_auth_standalone *tas, |
|
| 414 | 415 |
struct session_id *own_sid, |
| 415 | 416 |
struct session_id *remote_sid, |
| 416 |
- uint8_t header) |
|
| 417 |
+ uint8_t header, |
|
| 418 |
+ bool request_resend_wkc) |
|
| 417 | 419 |
{
|
| 418 | 420 |
struct buffer buf = alloc_buf(tas->frame.buf.payload_size); |
| 419 | 421 |
ASSERT(buf_init(&buf, tas->frame.buf.headroom)); |
| ... | ... |
@@ -434,8 +443,16 @@ tls_reset_standalone(struct tls_auth_standalone *tas, |
| 434 | 434 |
|
| 435 | 435 |
ASSERT(buf_write(&buf, &net_pid, sizeof(net_pid))); |
| 436 | 436 |
|
| 437 |
+ /* Add indication for tls-crypt-v2 to resend the WKc with the reply */ |
|
| 438 |
+ if (request_resend_wkc) |
|
| 439 |
+ {
|
|
| 440 |
+ buf_write_u16(&buf, TLV_TYPE_EARLY_NEG_FLAGS); /* TYPE: flags */ |
|
| 441 |
+ buf_write_u16(&buf, sizeof(uint16_t)); |
|
| 442 |
+ buf_write_u16(&buf, EARLY_NEG_FLAG_RESEND_WKC); |
|
| 443 |
+ } |
|
| 444 |
+ |
|
| 437 | 445 |
/* Add tls-auth/tls-crypt wrapping, this might replace buf */ |
| 438 |
- tls_wrap_control(&tas->tls_wrap, header, &buf, own_sid); |
|
| 446 |
+ tls_wrap_control(ctx, header, &buf, own_sid); |
|
| 439 | 447 |
|
| 440 | 448 |
return buf; |
| 441 | 449 |
} |
| ... | ... |
@@ -54,11 +54,15 @@ |
| 54 | 54 |
/* indicates key_method >= 2 and client-specific tls-crypt key */ |
| 55 | 55 |
#define P_CONTROL_HARD_RESET_CLIENT_V3 10 /* initial key from client, forget previous state */ |
| 56 | 56 |
|
| 57 |
+/* Variant of P_CONTROL_V1 but with appended wrapped key |
|
| 58 |
+ * like P_CONTROL_HARD_RESET_CLIENT_V3 */ |
|
| 59 |
+#define P_CONTROL_WKC_V1 11 |
|
| 60 |
+ |
|
| 57 | 61 |
/* define the range of legal opcodes |
| 58 | 62 |
* Since we do no longer support key-method 1 we consider |
| 59 | 63 |
* the v1 op codes invalid */ |
| 60 | 64 |
#define P_FIRST_OPCODE 3 |
| 61 |
-#define P_LAST_OPCODE 10 |
|
| 65 |
+#define P_LAST_OPCODE 11 |
|
| 62 | 66 |
|
| 63 | 67 |
/* |
| 64 | 68 |
* Define number of buffers for send and receive in the reliability layer. |
| ... | ... |
@@ -86,6 +90,8 @@ enum first_packet_verdict {
|
| 86 | 86 |
/** This packet is a valid ACK control packet from the peer, |
| 87 | 87 |
* i.e. it has a valid session id hmac in it */ |
| 88 | 88 |
VERDICT_VALID_ACK_V1, |
| 89 |
+ /** The packet is a valid control packet with appended wrapped client key */ |
|
| 90 |
+ VERDICT_VALID_WKC_V1, |
|
| 89 | 91 |
/** the packet failed on of the various checks */ |
| 90 | 92 |
VERDICT_INVALID |
| 91 | 93 |
}; |
| ... | ... |
@@ -217,10 +223,12 @@ read_control_auth(struct buffer *buf, |
| 217 | 217 |
* The returned buf needs to be free with \c free_buf |
| 218 | 218 |
*/ |
| 219 | 219 |
struct buffer |
| 220 |
-tls_reset_standalone(struct tls_auth_standalone *tas, |
|
| 220 |
+tls_reset_standalone(struct tls_wrap_ctx *ctx, |
|
| 221 |
+ struct tls_auth_standalone *tas, |
|
| 221 | 222 |
struct session_id *own_sid, |
| 222 | 223 |
struct session_id *remote_sid, |
| 223 |
- uint8_t header); |
|
| 224 |
+ uint8_t header, |
|
| 225 |
+ bool request_resend_wkc); |
|
| 224 | 226 |
|
| 225 | 227 |
static inline const char * |
| 226 | 228 |
packet_opcode_name(int op) |
| ... | ... |
@@ -248,6 +256,9 @@ packet_opcode_name(int op) |
| 248 | 248 |
case P_CONTROL_V1: |
| 249 | 249 |
return "P_CONTROL_V1"; |
| 250 | 250 |
|
| 251 |
+ case P_CONTROL_WKC_V1: |
|
| 252 |
+ return "P_CONTROL_WKC_V1"; |
|
| 253 |
+ |
|
| 251 | 254 |
case P_ACK_V1: |
| 252 | 255 |
return "P_ACK_V1"; |
| 253 | 256 |
|
| ... | ... |
@@ -261,4 +272,20 @@ packet_opcode_name(int op) |
| 261 | 261 |
return "P_???"; |
| 262 | 262 |
} |
| 263 | 263 |
} |
| 264 |
+ |
|
| 265 |
+/* initial packet id (instead of 0) that indicates that the peer supports |
|
| 266 |
+ * early protocol negotiation. This will make the packet id turn a bit faster |
|
| 267 |
+ * but the network time part of the packet id takes care of that. And |
|
| 268 |
+ * this is also a rather theoretical scenario as it still needs more than |
|
| 269 |
+ * 2^31 control channel packets to happen */ |
|
| 270 |
+#define EARLY_NEG_MASK 0xff000000 |
|
| 271 |
+#define EARLY_NEG_START 0x0f000000 |
|
| 272 |
+ |
|
| 273 |
+ |
|
| 274 |
+/* Early negotiation that part of the server response in the RESET_V2 packet. |
|
| 275 |
+ * Since clients that announce early negotiation support will treat the payload |
|
| 276 |
+ * of reset packets special and parse it as TLV messages. |
|
| 277 |
+ * as TLV (type, length, value) */ |
|
| 278 |
+#define TLV_TYPE_EARLY_NEG_FLAGS 0x0001 |
|
| 279 |
+#define EARLY_NEG_FLAG_RESEND_WKC 0x0001 |
|
| 264 | 280 |
#endif /* ifndef SSL_PKT_H */ |
| ... | ... |
@@ -536,7 +536,7 @@ test_generate_reset_packet_plain(void **ut_state) |
| 536 | 536 |
|
| 537 | 537 |
uint8_t header = 0 | (P_CONTROL_HARD_RESET_CLIENT_V2 << P_OPCODE_SHIFT); |
| 538 | 538 |
|
| 539 |
- struct buffer buf = tls_reset_standalone(&tas, &client_id, &server_id, header); |
|
| 539 |
+ struct buffer buf = tls_reset_standalone(&tas.tls_wrap, &tas, &client_id, &server_id, header, false); |
|
| 540 | 540 |
|
| 541 | 541 |
|
| 542 | 542 |
verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); |
| ... | ... |
@@ -544,7 +544,7 @@ test_generate_reset_packet_plain(void **ut_state) |
| 544 | 544 |
|
| 545 | 545 |
/* Assure repeated generation of reset is deterministic/stateless*/ |
| 546 | 546 |
assert_memory_equal(state.peer_session_id.id, client_id.id, SID_SIZE); |
| 547 |
- struct buffer buf2 = tls_reset_standalone(&tas, &client_id, &server_id, header); |
|
| 547 |
+ struct buffer buf2 = tls_reset_standalone(&tas.tls_wrap, &tas, &client_id, &server_id, header, false); |
|
| 548 | 548 |
assert_int_equal(BLEN(&buf), BLEN(&buf2)); |
| 549 | 549 |
assert_memory_equal(BPTR(&buf), BPTR(&buf2), BLEN(&buf)); |
| 550 | 550 |
free_buf(&buf2); |
| ... | ... |
@@ -571,7 +571,7 @@ test_generate_reset_packet_tls_auth(void **ut_state) |
| 571 | 571 |
|
| 572 | 572 |
now = 0x22446688; |
| 573 | 573 |
reset_packet_id_send(&tas_client.tls_wrap.opt.packet_id.send); |
| 574 |
- struct buffer buf = tls_reset_standalone(&tas_client, &client_id, &server_id, header); |
|
| 574 |
+ struct buffer buf = tls_reset_standalone(&tas_client.tls_wrap, &tas_client, &client_id, &server_id, header, false); |
|
| 575 | 575 |
|
| 576 | 576 |
enum first_packet_verdict verdict = tls_pre_decrypt_lite(&tas_server, &state, &from, &buf); |
| 577 | 577 |
assert_int_equal(verdict, VERDICT_VALID_RESET_V2); |
| ... | ... |
@@ -580,11 +580,11 @@ test_generate_reset_packet_tls_auth(void **ut_state) |
| 580 | 580 |
|
| 581 | 581 |
/* Assure repeated generation of reset is deterministic/stateless*/ |
| 582 | 582 |
reset_packet_id_send(&tas_client.tls_wrap.opt.packet_id.send); |
| 583 |
- struct buffer buf2 = tls_reset_standalone(&tas_client, &client_id, &server_id, header); |
|
| 583 |
+ struct buffer buf2 = tls_reset_standalone(&tas_client.tls_wrap, &tas_client, &client_id, &server_id, header,false); |
|
| 584 | 584 |
assert_int_equal(BLEN(&buf), BLEN(&buf2)); |
| 585 | 585 |
assert_memory_equal(BPTR(&buf), BPTR(&buf2), BLEN(&buf)); |
| 586 |
- free_buf(&buf2); |
|
| 587 | 586 |
|
| 587 |
+ free_buf(&buf2); |
|
| 588 | 588 |
free_tls_pre_decrypt_state(&state); |
| 589 | 589 |
|
| 590 | 590 |
packet_id_free(&tas_client.tls_wrap.opt.packet_id); |