libwebsockets
Lightweight C library for HTML5 websockets
lws-secure-streams-serialization.h
Go to the documentation of this file.
1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * included from libwebsockets.h
25 *
26 * This defines the Serialized Secure Streams framing, and the optional
27 * lws_transport_mux framing.
28 *
29 * APIs are declared for lws_transport and binding those to the SSPC and proxy
30 * sides in lws.
31 */
32
33#if defined(STANDALONE)
34struct lws_context_standalone;
35#define lws_context lws_context_standalone
36#endif
37
38#define LWSSSS_VERSION 1
39
40typedef enum {
41 /*
42 * This is the Serialized Serure Streams framing. It's sufficient to
43 * carry all SS API actions over a point-to-point bytestream between
44 * an SSPC client and an SS oroxy, in both directions.
45 *
46 * These serialized streams may be multiplexed by the transport (eg,
47 * for unix domain sockets transport, each SS opens its own UDS socket
48 * to the proxy) or via lws_transport_mux framing encapsulation.
49 *
50 *
51 * Framing for Proxy -> Client direction
52 */
53
55 /*
56 * Proxied rx
57 *
58 * - 0: LWSSS_SER_RXPRE_RX_PAYLOAD
59 * - 1: 2 byte MSB-first rest-of-frame length
60 * - 3: 4-byte MSB-first flags
61 * - 7: 4-byte MSB-first us between inbound read and wrote to client
62 * - 11: 8-byte MSB-first us resolution unix time proxy wrote to client
63 * - 17: (rideshare name len + rideshare name if flags &
64 * LWSSS_FLAG_RIDESHARE) payload
65 */
67 /*
68 * Proxied connection setup result
69 *
70 * - 0: LWSSS_SER_RXPRE_CREATE_RESULT
71 * - 1: 2 byte MSB-first rest-of-frame length (usually 00, 03)
72 * - 3: 1 byte result, 0 = success. On failure, proxy will close
73 * connection.
74 * - 4: 4 byte client dsh allocation recommended for stream type,
75 * from policy (introduced in SSSv1)
76 * - 8: 2 byte MSB-first initial tx credit
77 * - 10: if present, comma-sep list of rideshare types from policy
78 */
80 /*
81 * Proxied state (8 or 11 byte packet)
82 *
83 * - 0: LWSSS_SER_RXPRE_CONNSTATE
84 * - 1: 00, 05 if state < 256, else 00, 08
85 * - 3: 1 byte state index if state < 256, else 4-byte MSB-first
86 * state index
87 * - 4 or 7: 4-byte MSB-first ordinal
88 */
90 /*
91 * Proxied tx credit
92 *
93 * - 0: LWSSS_SER_RXPRE_TXCR_UPDATE
94 * - 1: 00, 04
95 * - 3: 4-byte MSB-first addition tx credit bytes
96 */
98 /*
99 * Proxied rx metadata
100 *
101 * - 0: LWSSS_SER_RXPRE_METADATA
102 * - 1: 2-byte MSB-first rest-of-frame length
103 * - 3: 1-byte metadata name length
104 * - 4: metadata name
105 * - ...: metadata value (for rest of packet)
106 */
108 /* reserved */
110 /*
111 * Proxied performance information
112 *
113 * - 0: LWSSS_SER_RXPRE_PERF
114 * - 1: 2-byte MSB-first rest-of-frame length
115 * - 3: ... performance JSON (for rest of packet)
116 */
117
118 /*
119 * Framing for Client -> Proxy direction
120 */
121
123 /*
124 * Proxied connection setup
125 *
126 * - 0: LWSSS_SER_TXPRE_STREAMTYPE
127 * - 1: 2-byte MSB-first rest-of-frame length
128 * - 3: 1-byte Client SSS protocol version (introduced in SSSv1)
129 * - 4: 4-byte Client PID (introduced in SSSv1)
130 * - 8: 4-byte MSB-first initial tx credit
131 * - 12: the streamtype name with no NUL
132 */
134 /*
135 * Proxied request for onward connection
136 *
137 * - 0: LWSSS_SER_TXPRE_ONWARD_CONNECT
138 * - 1: 00, 00
139 */
141 /*
142 * Proxied secure stream destroy
143 *
144 * - 0: LWSSS_SER_TXPRE_DESTROYING
145 * - 1: 00, 00
146 */
148 /*
149 * Proxied tx
150 *
151 * - 0: LWSSS_SER_TXPRE_TX_PAYLOAD
152 * - 1: 2 byte MSB-first rest-of-frame length
153 * - 3: 4-byte MSB-first flags
154 * - 7: 4-byte MSB-first us between client requested write and wrote
155 * to proxy
156 * - 11: 8-byte MSB-first us resolution unix time client wrote to proxy
157 * - 19: ...payload (for rest of packet)
158 */
160 /*
161 * Proxied metadata - sent when one metadata item set clientside
162 *
163 * - 0: LWSSS_SER_TXPRE_METADATA
164 * - 1: 2-byte MSB-first rest-of-frame length
165 * - 3: 1-byte metadata name length
166 * - 4: metadata name
167 * - ...: metadata value (for rest of packet)
168 */
170 /*
171 * TX credit management - sent when using tx credit apis, cf METADATA
172 *
173 * - 0: LWSSS_SER_TXPRE_TXCR_UPDATE
174 * - 1: 2-byte MSB-first rest-of-frame length 00, 04
175 * - 3: 4-byte additional tx credit adjust value
176 */
178 /*
179 * Stream timeout management - forwarded when user applying or
180 * cancelling t.o.
181 *
182 * - 0: LWSSS_SER_TXPRE_TIMEOUT_UPDATE
183 * - 1: 2-byte MSB-first rest-of-frame length 00, 04
184 * - 3: 4-byte MSB-first unsigned 32-bit timeout,
185 * 0 = use policy, -1 = cancel
186 */
188 /*
189 * Passing up payload length hint
190 *
191 * - 0: LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT
192 * - 1: 2-byte MSB-first rest-of-frame length 00, 04
193 * - 3: 4-byte MSB-first unsigned 32-bit payload length hint
194 */
196 /* reserved */
198} lws_sss_cmds_t;
199
200/* SSPC serialization states */
201
202 typedef enum {
203 LPCSPROX_WAIT_INITIAL_TX = 1, /* after connect, must send streamtype */
204 LPCSPROX_REPORTING_FAIL, /* stream creation failed, wait to to tell */
205 LPCSPROX_REPORTING_OK, /* stream creation succeeded, wait to to tell */
206 LPCSPROX_OPERATIONAL, /* ready for payloads */
208
209 LPCSCLI_SENDING_INITIAL_TX, /* after connect, must send streamtype */
210 LPCSCLI_WAITING_CREATE_RESULT, /* wait to hear if proxy ss create OK */
211 LPCSCLI_LOCAL_CONNECTED, /* we are in touch with the proxy */
212 LPCSCLI_ONWARD_CONNECT, /* request onward ss connection */
213 LPCSCLI_OPERATIONAL, /* ready for payloads */
214
215 } lws_ss_conn_states_t;
216
217 /*
218 * Optional multiplexing layer
219 *
220 * Either side can:
221 *
222 * - open and close channels asynchronously
223 * - send and receive transport-level (not mux channel) timed PINGs / PONGs
224 * - send and receive data bound to an open mux channel
225 *
226 * PONGs are produced and sent automatically on recipt of a PING from the peer
227 * The peer sends a PONGACK so the single transaction can validate connection
228 * viability in both directions.
229 */
230
231 enum {
233 /**<
234 * Either side proposes to open a new mux channel
235 *
236 * - 0: LWSSSS_LLM_CHANNEL_REQ
237 * - 1: 1-byte mux channel index, client initiated: first free from
238 * zero up, server initiated: first free from 0xff down
239 */
241 /**<
242 * Positive response to earlier LWSSSS_LLM_CHANNEL_REQ
243 *
244 * - 0: LWSSSS_LLM_CHANNEL_ACK
245 * - 1: 1-byte mux channel index, from the reqyuest
246 */
248 /**<
249 * Negative response to earlier LWSSSS_LLM_CHANNEL_REQ. This also acts
250 * as a FIN if one arrives on a channel unsolicited.
251 *
252 * - 0: LWSSSS_LLM_CHANNEL_NACK
253 * - 1: 1-byte mux channel index, from the reqyuest
254 */
256 /**<
257 * Either side informs peer it is closing a mux channel
258 *
259 * - 0: LWSSSS_LLM_CHANNEL_CLOSE
260 * - 1: 1-byte mux channel index
261 */
263 /**<
264 * Peer acknowledges closing a mux channel, so it can be reused
265 *
266 * - 0: LWSSSS_LLM_CHANNEL_CLOSE_ACK
267 * - 1: 1-byte mux channel index
268 */
270 /**<
271 * Encapsulate data on an open mux channel
272 *
273 * - 0: LWSSSS_LLM_MUX
274 * - 1: 1-byte mux channel index
275 * - 2: 2-byte MSB-first rest-of-frame length
276 * - 4... mux payload
277 */
279 /**<
280 * Either side wants to validate communication on mux transport
281 *
282 * - 0: LWSSSS_LLM_PING
283 * - 1: 8-byte MSB-first us resolution unix time this was issued
284 */
286 /**<
287 * Either side responds to peer's PING.
288 *
289 * - 0: LWSSSS_LLM_PONG
290 * - 1: 8-byte MSB-first us resolution unix time from PING
291 * - 9: 8-byte MSB-first us resolution unix time this PONG sent
292 */
294 /**<
295 * When the original PING sender receives a PONG, it immediately sends
296 * a PINGACK, which is not replied to. This allows the other side to
297 * also know the connection is valid in both directions, with only one
298 * side needing to issue PINGs.
299 *
300 * It also synchronizes both sides' understanding of the transport
301 * validity in one transaction.
302 *
303 * - 0: LWSSSS_LLM_PONGACK
304 * - 1: 8-byte MSB-first us resolution unix time from PING
305 */
307 /**<
308 * Either side can issue this to indicate they no longer trust the
309 * transport link. They should close all their channels and enter a
310 * state trying to resync using 3-way PINGs
311 */
312};
313
314typedef void * lws_transport_priv_t; /* care - this is a pointer type already */
315struct lws_transport_mux;
316struct lws_sss_proxy_conn;
319struct lws_sspc_handle;
320
321/*
322 * These describe the path through different transport layers. Each has an
323 * 'in' and 'onw' (onward) side that can be bound to different parts in lws.
324 * SSPC and the SS Proxy code in lws each exposes one of these as terminals
325 * for the "path" to handle the SS Serialization on each side.
326 *
327 * sspc-transport-wsi and proxy-transport-wsi expose possible endpoints for the
328 * paths, so you can simply "wire SSPC and proxy up to a wsi transport".
329 *
330 * You can also create a lws_transport_mux_t and interpose it in the transport
331 * path on each side, and produce your own custom lws_transport ops implementing
332 * arbitrary transport support.
333 */
334
335typedef struct lws_txp_path_client {
341} lws_txp_path_client_t;
342
343typedef struct lws_txp_path_proxy {
349} lws_txp_path_proxy_t;
350
351/*
352 * Operations for client-side transport
353 */
354
356 const char *name;
357
358 int (*event_retry_connect)(lws_txp_path_client_t *path,
359 struct lws_sspc_handle *h);
360 /**< Attempt to create a new connection / channel to the proxy */
362 struct lws_sspc_handle *h, int disposition);
363 /**< Connection attempt result, disposition 9 = success, else failed */
365 /**< Request a write to the proxy on this channel */
366 int (*_write)(lws_transport_priv_t priv, uint8_t *buf, size_t len);
367 /**< Write the requested data on the channel to the proxy *** MUST have
368 * LWS_PRE usable behind buf */
370 const uint8_t *buf, size_t len);
371 /**< len bytes at buf have been received */
373 /**< report that the framing inside the mux channel is broken */
375 /**< Close the channel to the proxy */
377 /**< Called when a new channel to the proxy is acknowledged as up */
379 /**< Called when a client channel is acknowledged as up */
382 /**< Called when possible to write on the transport, after req_write */
384 /**< we notice an onward proxy connection had closed */
386 /**< Used for DSH creation flags */
388} lws_transport_client_ops_t;
389
390/*
391 * Operations for proxy-side transport
392 */
393
395 const char *name;
396 int (*init_proxy_server)(struct lws_context *context,
397 const struct lws_transport_proxy_ops *txp_ops_inward,
398 lws_transport_priv_t txp_priv_inward,
399 lws_txp_path_proxy_t *txp_ppath, const void *aux,
400 const char *bind, int port);
401 /**< Instantiate a proxy transport... bind/port are as shown for wsi
402 * transport, but may be overloaded to provide transport-specific init */
403 int (*destroy_proxy_server)(struct lws_context *context);
407 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
408 const lws_fi_ctx_t *fic,
409 #endif
410 struct lws_sss_proxy_conn **conn,
412 /**< proxy has received a new connection from client */
414 struct lws_ss_handle *h);
415 /**< Called when the proxy creates an onward SS for a client channel */
417 /**< Request a write to the proxy on this channel */
420#if defined(LWS_WITH_SYS_FAULT_INJECTION)
421 , const lws_fi_ctx_t *fic
422#endif
423 );
424 /**< Transport can now be written on, after earlier proxy_req_write */
425 int (*proxy_write)(lws_transport_priv_t priv, uint8_t *buf, size_t *len);
426 /**< Write the requested data on the channel to the proxy *** MUST have
427 * LWS_PRE usable behind buf. May do partial writes, len is set on return
428 * to actual length written*/
430 struct lws_sss_proxy_conn *conn);
431 /**< proxy sees an existing conn closes */
432#if defined(LWS_WITH_SYS_FAULT_INJECTION)
434 /**< Get the fault context relating to the proxy connection, if any */
435#endif
437 /**< called to handle closure of underlying transport */
439 const uint8_t *buf, size_t len);
441 /**< Called when the proxy has accepted a new client conn */
443 /**< optional, allows checking if we can write again */
444 uint32_t flags; /* dsh flags */
445} lws_transport_proxy_ops_t;
446
447/* lws_transport_mux parser states */
448
459
460/* lws_transport_mux channel definitions */
461
463#define LWS_MUCH_RANGE 256
464
465/* lws_transport mux states */
466
467enum {
468 /* lws_transport_mux_ch_t created */
469 LWSTMC_PENDING_CREATE_CHANNEL, /* waiting to send create channel */
470 LWSTMC_AWAITING_CREATE_CHANNEL_ACK, /* sent create ch, awaiting ack */
471 LWSTMC_PENDING_CREATE_CHANNEL_NACK, /* waiting to send create ch ack */
472 LWSTMC_PENDING_CREATE_CHANNEL_ACK, /* waiting to send create ch ack */
473 LWSTMC_OPERATIONAL, /* had ack, we are operational */
474 LWSTMC_PENDING_CLOSE_CHANNEL, /* waiting to send close channel */
475 LWSTMC_AWAITING_CLOSE_CHANNEL_ACK, /* sent close ch, awaiting ack */
476 LWSTMC_PENDING_CLOSE_CHANNEL_ACK, /* waiting to send close ch ack */
477 /* lws_transport_mux_ch_t destroyed */
478};
479
480#define LWS_TRANSPORT_MUXCH_MAGIC LWS_FOURCC('T', 'm', 'C', 'h')
481#define assert_is_tmch(_tm) lws_assert_fourcc(_tm->magic, LWS_TRANSPORT_MUXCH_MAGIC)
482
483typedef struct lws_transport_mux_ch {
484#if defined(_DEBUG)
486#endif
491 void *opaque;
495} lws_transport_mux_ch_t;
496
497enum { /* states of the transport */
500};
501
502#define LWSTMINFO_SERVER (1 << 0)
503
504typedef struct lws_transport_info {
506 /**< us inbetween transport mux sending pings on transport */
508 /**< us we should wait for pong before assuming transport down */
509 lws_txp_path_client_t txp_cpath;
510 lws_txp_path_proxy_t txp_ppath;
512 uint32_t flags; /* LWSTMINFO_.... */
513} lws_transport_info_t;
514
515#define LWS_TRANSPORT_MUX_MAGIC LWS_FOURCC('I', 's', 'T', 'M')
516#define assert_is_tm(_tm) lws_assert_fourcc(_tm->magic, LWS_TRANSPORT_MUX_MAGIC)
517
518typedef struct lws_transport_mux {
519#if defined(_DEBUG)
521#endif
522 struct lws_context *cx;
523 lws_transport_info_t info;
526 void *txp_aux;
534 uint32_t mp_pay; /* remaining payload */
541 lws_dll2_owner_t owner; /* lws_mux_ch_t */
547} lws_transport_mux_t;
548
549lws_transport_mux_t *
550lws_transport_mux_create(struct lws_context *cx, lws_transport_info_t *info,
551 void *txp_handle);
552
553void
554lws_transport_mux_destroy(lws_transport_mux_t **tm);
555
556void
557lws_transport_mux_request_tx(lws_transport_mux_t *tm);
558
559#if defined(_DEBUG)
560void
561lws_transport_path_client_dump(lws_txp_path_client_t *path, const char *ctx);
562void
563lws_transport_path_proxy_dump(lws_txp_path_proxy_t *path, const char *ctx);
564#else
565#define lws_transport_path_client_dump(_a, _b)
566#define lws_transport_path_proxy_dump(_a, _b)
567#endif
568
569/*
570 * Callback set used to customize parser and _pending apis
571 */
572
573typedef struct lws_txp_mux_parse_cbs {
574 int (*payload)(lws_transport_mux_ch_t *tmc, const uint8_t *buf,
575 size_t len);
576 int (*ch_opens)(lws_transport_mux_ch_t *tmc, int determination);
577 int (*ch_closes)(lws_transport_mux_ch_t *tmc);
578 void (*txp_req_write)(lws_transport_mux_t *tm);
579 int (*txp_can_write)(lws_transport_mux_ch_t *tmc);
580} lws_txp_mux_parse_cbs_t;
581
582int
583lws_transport_mux_rx_parse(lws_transport_mux_t *tm, const uint8_t *buf,
584 size_t len, const lws_txp_mux_parse_cbs_t *cbs);
585
586int /* nonzero if the transport mux has filled buf and wants to write it */
587lws_transport_mux_pending(lws_transport_mux_t *tm, uint8_t *buf, size_t *len,
588 const lws_txp_mux_parse_cbs_t *cbs);
589
590extern const lws_transport_client_ops_t lws_transport_mux_client_ops;
591extern const lws_transport_proxy_ops_t lws_transport_mux_proxy_ops;
592
593extern const lws_transport_client_ops_t lws_txp_inside_sspc;
594extern const lws_transport_proxy_ops_t lws_txp_inside_proxy;
595
596#if defined(STANDALONE)
597#undef lws_context
598#endif
int lws_transport_mux_pending(lws_transport_mux_t *tm, uint8_t *buf, size_t *len, const lws_txp_mux_parse_cbs_t *cbs)
const struct lws_transport_client_ops * ops_onw
#define LWS_TRANSPORT_MUX_MAGIC
@ LWSTMC_PENDING_CREATE_CHANNEL_NACK
@ LWSTMC_AWAITING_CREATE_CHANNEL_ACK
@ LWSSS_SER_RXPRE_TLSNEG_ENCLAVE_SIGN
@ LWSSS_SER_TXPRE_LINK_VALIDITY_PROBE
@ LWSSS_SER_TXPRE_TLSNEG_ENCLAVE_SIGNED
@ LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT
uint8_t lws_mux_ch_idx_t
#define LWS_TRANSPORT_MUXCH_MAGIC
int lws_transport_mux_rx_parse(lws_transport_mux_t *tm, const uint8_t *buf, size_t len, const lws_txp_mux_parse_cbs_t *cbs)
void lws_transport_mux_request_tx(lws_transport_mux_t *tm)
struct lws_transport_info * onward_txp_info
struct lws_transport_mux * mux
const struct lws_transport_proxy_ops * ops_in
const struct lws_transport_client_ops * ops_in
void lws_transport_mux_destroy(lws_transport_mux_t **tm)
lws_transport_mux_t * lws_transport_mux_create(struct lws_context *cx, lws_transport_info_t *info, void *txp_handle)
struct lws_transport_mux * mux
void * lws_transport_priv_t
const struct lws_transport_proxy_ops * ops_onw
const lws_transport_proxy_ops_t lws_transport_mux_proxy_ops
const lws_transport_proxy_ops_t lws_txp_inside_proxy
const lws_transport_client_ops_t lws_txp_inside_sspc
const lws_transport_client_ops_t lws_transport_mux_client_ops
void(* req_write)(lws_transport_priv_t priv)
int(* event_retry_connect)(lws_txp_path_client_t *path, struct lws_sspc_handle *h)
void(* event_client_up)(lws_transport_priv_t priv)
void(* lost_coherence)(lws_transport_priv_t priv)
void(* event_stream_up)(lws_transport_priv_t priv)
void(* _close)(lws_transport_priv_t priv)
int(* _write)(lws_transport_priv_t priv, uint8_t *buf, size_t len)
void(* event_client_up)(lws_transport_priv_t priv)
void(* proxy_req_write)(lws_transport_priv_t priv)
int(* proxy_check_write_more)(lws_transport_priv_t priv)
int(* proxy_write)(lws_transport_priv_t priv, uint8_t *buf, size_t *len)
int(* destroy_proxy_server)(struct lws_context *context)
int(* txp_can_write)(lws_transport_mux_ch_t *tmc)
int(* ch_opens)(lws_transport_mux_ch_t *tmc, int determination)
int(* ch_closes)(lws_transport_mux_ch_t *tmc)
int(* payload)(lws_transport_mux_ch_t *tmc, const uint8_t *buf, size_t len)
void(* txp_req_write)(lws_transport_mux_t *tm)