• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2019 - 2020 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  *
27  * Secure Streams is a *payload-only* client communication channel where all the
28  * details about the connection are held in a systemwide policy database and
29  * are keyed by the streamtype field... the user of the communication channel
30  * does not know or manage the choice of endpoint, tls CA, or even wire
31  * protocol.  The advantage is he then does not have any dependency on any of
32  * those and they can be changed just by changing the policy database without
33  * touching the code using the stream.
34  *
35  * There are two ways secure streams interfaces to user code:
36  *
37  * 1) [Linux / RTOS] the natural, smallest interface is to call back to user
38  *    code that only operates directly from the lws event loop thread context
39  *    (direct callbacks from lws_ss_t)
40  *
41  *    lws_thread( [user code] ---- lws )
42  *
43  * 2) [Linux] where the user code is in a different process and communicates
44  *    asynchronously via a proxy socket
45  *
46  *    user_process{ [user code] | shim | socket-}------ lws_process{ lws }
47  *
48  * In the second, IPC, case, all packets are prepended by one or more bytes
49  * indicating the packet type and serializing any associated data, known as
50  * Serialized Secure Streams or SSS.
51  *
52  * Serialized Secure Streams
53  * -------------------------
54  *
55  * On the transport, adjacent packets may be coalesced, that is, the original
56  * packet sizes are lost and two or more packets are combined.  For that reason
57  * the serialization format always contains a 1-byte type and then a 2-byte
58  * frame length.
59  *
60  * Client to proxy
61  *
62  * - Proxied connection setup
63  *
64  *   -  0: LWSSS_SER_TXPRE_STREAMTYPE
65  *   -  1: 2-byte MSB-first rest-of-frame length
66  *   -  3: 4 byte MSB-first initial tx credit
67  *   -  7: the streamtype name with no NUL
68  *
69  * - Proxied tx
70  *
71  *   -  0: LWSSS_SER_TXPRE_TX_PAYLOAD
72  *   -  1: 2 byte MSB-first rest-of-frame length
73  *   -  3: 4-byte MSB-first flags
74  *   -  7: 4-byte MSB-first us between client requested write and wrote to proxy
75  *   - 11: 8-byte MSB-first us resolution unix time client wrote to proxy
76  *   - 17: payload
77  *
78  * - Proxied secure stream destroy
79  *
80  *   -  0: LWSSS_SER_TXPRE_DESTROYING
81  *   -  1: 00, 00
82  *
83  * - Proxied metadata - sent when one metadata item set clientside
84  *
85  *   -  0: LWSSS_SER_TXPRE_METADATA
86  *   -  1: 2-byte MSB-first rest-of-frame length
87  *   -  2: 1-byte metadata name length
88  *   -  3: metadata name
89  *   -  ...: metadata value (for rest of packet)
90  *
91  * Proxy to client
92  *
93  * - Proxied connection setup result
94  *
95  *   -  0: LWSSS_SER_RXPRE_CREATE_RESULT
96  *   -  1: 2 byte MSB-first rest-of-frame length (usually 00, 03)
97  *   -  3: 1 byte result, 0 = success.  On failure, proxy will close connection.
98  *   -  4: 2 byte MSB-first initial tx credit
99  *   -  6: if present, comma-sep list of rideshare types from policy
100  *
101  * - Proxied rx
102  *
103  *   -  0: LWSSS_SER_RXPRE_RX_PAYLOAD
104  *   -  1: 2 byte MSB-first rest-of-frame length
105  *   -  3: 4-byte MSB-first flags
106  *   -  7: 4-byte MSB-first us between inbound read and wrote to client
107  *   - 11: 8-byte MSB-first us resolution unix time proxy wrote to client
108  *   - 17: (rideshare name len + rideshare name if flags & LWSSS_FLAG_RIDESHARE)
109  *          payload
110  *
111  * - Proxied tx credit
112  *
113  *   -  0: LWSSS_SER_RXPRE_TXCR_UPDATE
114  *   -  1: 00, 04
115  *   -  3: 4-byte MSB-first addition tx credit bytes
116  *
117  * - Proxied state
118  *
119  *   -  0: LWSSS_SER_RXPRE_CONNSTATE
120  *   -  1: 00, 05
121  *   -  3: 1 byte state index
122  *   -  7: 4-byte MSB-first ordinal
123  *
124  *
125  * Proxied tx may be read by the proxy but rejected due to lack of buffer space
126  * at the proxy.  For that reason, tx must be held at the sender until it has
127  * been acknowledged or denied.
128  *
129  * Sinks
130  * -----
131  *
132  * Sinks are logical "servers", you can register as a sink for a particular
133  * streamtype by using the lws_ss_create() api with ssi->register_sink set to 1.
134  *
135  * For directly fulfilled Secure Streams, new streams of that streamtype bind
136  * to the rx, tx and state handlers given when it was registered.
137  *
138  *  - When new streams are created the registered sink handler for (*state) is
139  *    called with event LWSSSCS_SINK_JOIN and the new client stream handle in
140  *    the h_src parameter.
141  *
142  *  - When the client stream sends something to the sink, it calls the sink's
143  *    (*rx) with the client stream's
144  */
145 
146 #define LWS_SS_MTU 1540
147 
148 struct lws_ss_handle;
149 typedef uint32_t lws_ss_tx_ordinal_t;
150 
151 /*
152  * connection state events
153  */
154 typedef enum {
155 	LWSSSCS_CREATING,
156 	LWSSSCS_DISCONNECTED,
157 	LWSSSCS_UNREACHABLE,
158 	LWSSSCS_AUTH_FAILED,
159 	LWSSSCS_CONNECTED,
160 	LWSSSCS_CONNECTING,
161 	LWSSSCS_DESTROYING,
162 	LWSSSCS_POLL,
163 	LWSSSCS_ALL_RETRIES_FAILED,	/* all retries in bo policy failed */
164 	LWSSSCS_QOS_ACK_REMOTE,		/* remote peer received and acked tx */
165 	LWSSSCS_QOS_NACK_REMOTE,
166 	LWSSSCS_QOS_ACK_LOCAL,		/* local proxy accepted our tx */
167 	LWSSSCS_QOS_NACK_LOCAL,		/* local proxy refused our tx */
168 
169 	LWSSSCS_SINK_JOIN,		/* sinks get this when a new source
170 					 * stream joins the sink */
171 	LWSSSCS_SINK_PART,		/* sinks get this when a new source
172 					 * stream leaves the sink */
173 } lws_ss_constate_t;
174 
175 enum {
176 	LWSSS_FLAG_SOM						= (1 << 0),
177 	/* payload contains the start of new message */
178 	LWSSS_FLAG_EOM						= (1 << 1),
179 	/* payload contains the end of message */
180 	LWSSS_FLAG_POLL						= (1 << 2),
181 	/* Not a real transmit... poll for rx if protocol needs it */
182 	LWSSS_FLAG_RELATED_START				= (1 << 3),
183 	/* Appears in a zero-length message indicating a message group of zero
184 	 * or more messages is now starting. */
185 	LWSSS_FLAG_RELATED_END					= (1 << 4),
186 	/* Appears in a zero-length message indicating a message group of zero
187 	 * or more messages has now finished. */
188 	LWSSS_FLAG_RIDESHARE					= (1 << 5),
189 	/* Serialized payload starts with non-default rideshare name length and
190 	 * name string without NUL, then payload */
191 
192 	/*
193 	 * In the case the secure stream is proxied across a process or thread
194 	 * boundary, eg by proxying through a socket for IPC, metadata must be
195 	 * carried in-band.  A byte is prepended to each rx payload to
196 	 * differentiate what it is.
197 	 *
198 	 * Secure streams where the user is called back directly does not need
199 	 * any of this and only pure payloads are passed.
200 	 *
201 	 * rx (received by client) prepends for proxied connections
202 	 */
203 
204 	LWSSS_SER_RXPRE_RX_PAYLOAD				= 0x55,
205 	LWSSS_SER_RXPRE_CREATE_RESULT,
206 	LWSSS_SER_RXPRE_CONNSTATE,
207 	LWSSS_SER_RXPRE_TXCR_UPDATE,
208 	LWSSS_SER_RXPRE_TLSNEG_ENCLAVE_SIGN,
209 
210 	/* tx (send by client) prepends for proxied connections */
211 
212 	LWSSS_SER_TXPRE_STREAMTYPE				= 0xaa,
213 	LWSSS_SER_TXPRE_ONWARD_CONNECT,
214 	LWSSS_SER_TXPRE_DESTROYING,
215 	LWSSS_SER_TXPRE_TX_PAYLOAD,
216 	LWSSS_SER_TXPRE_METADATA,
217 	LWSSS_SER_TXPRE_TXCR_UPDATE,
218 	LWSSS_SER_TXPRE_TLSNEG_ENCLAVE_SIGNED,
219 };
220 
221 typedef enum {
222 	LPCS_WAIT_INITIAL_TX = 1, /* after connect, must send streamtype */
223 	LPCS_REPORTING_FAIL, /* stream creation failed, wait to to tell */
224 	LPCS_REPORTING_OK, /* stream creation succeeded, wait to to tell */
225 	LPCS_OPERATIONAL, /* ready for payloads */
226 	LPCS_DESTROYED,
227 
228 	LPCS_SENDING_INITIAL_TX = 1,  /* after connect, must send streamtype */
229 	LPCS_WAITING_CREATE_RESULT,   /* wait to hear if proxy ss create OK */
230 	LPCS_LOCAL_CONNECTED,	      /* we are in touch with the proxy */
231 	LPCS_ONWARD_CONNECT,	      /* request onward ss connection */
232 
233 } lws_ss_conn_states_t;
234 
235 /**
236  * lws_ss_info_t: information about stream to be created
237  *
238  * Prepare this struct with information about what the stream type is and how
239  * the stream should interface with your code, and pass it to lws_ss_create()
240  * to create the requested stream.
241  */
242 
243 typedef struct lws_ss_info {
244 	const char *streamtype; /**< type of stream we want to create */
245 	size_t	    user_alloc; /**< size of user allocation */
246 	size_t	    handle_offset; /**< offset of handle stg in user_alloc type,
247 				    set to offsetof(mytype, my_handle_member) */
248 	size_t	    opaque_user_data_offset;
249 	/**< offset of opaque user data ptr in user_alloc type, set to
250 	     offsetof(mytype, opaque_ud_member) */
251 
252 	int	    (*rx)(void *userobj, const uint8_t *buf, size_t len,
253 			  int flags);
254 	/**< callback with rx payload for this stream */
255 	int	    (*tx)(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
256 			  size_t *len, int *flags);
257 	/**< callback to send payload on this stream... 0 = send as set in
258 	 * len and flags, 1 = do not send anything (ie, not even 0 len frame) */
259 	int	    (*state)(void *userobj, void *h_src /* ss handle type */,
260 			     lws_ss_constate_t state, lws_ss_tx_ordinal_t ack);
261 	/**< advisory cb about state of stream and QoS status if applicable...
262 	 * h_src is only used with sinks and LWSSSCS_SINK_JOIN/_PART events.
263 	 * Return nonzero to indicate you want to destroy the stream. */
264 	int	    manual_initial_tx_credit;
265 	/**< 0 = manage any tx credit automatically, nonzero explicitly sets the
266 	 * peer stream to have the given amount of tx credit, if the protocol
267 	 * can support it. */
268 	char	    register_sink;
269 	/**< If set, we're not creating a specific stream, but registering
270 	 * ourselves as the "sink" for .streamtype.  It's analogous to saying
271 	 * we want to be the many-to-one "server" for .streamtype; when other
272 	 * streams are created with that streamtype, they should be forwarded
273 	 * to this stream owner, where they join and part from the sink via
274 	 * (*state) LWSSSCS_SINK_JOIN / _PART events, the new client handle
275 	 * being provided in the h_src parameter.
276 	 */
277 } lws_ss_info_t;
278 
279 /**
280  * lws_ss_create() - Create secure stream
281  *
282  * \param context: the lws context to create this inside
283  * \param tsi: service thread index to create on (normally 0)
284  * \param ssi: pointer to lws_ss_info_t filled in with info about desired stream
285  * \param opaque_user_data: opaque data to set in the stream's user object
286  * \param ppss: pointer to secure stream handle pointer set on exit
287  * \param ppayload_fmt: NULL or pointer to a string ptr to take payload format
288  *			name from the policy
289  *
290  * Requests a new secure stream described by \p ssi be created.  If successful,
291  * the stream is created, its state callback called with LWSSSCS_CREATING, *ppss
292  * is set to point to the handle, and it returns 0.  If it failed, it returns
293  * nonzero.
294  *
295  * Along with the opaque stream object, streams overallocate
296  *
297  * 1) a user data struct whose size is set in ssi
298  * 2) nauth plugin instantiation data (size set in the plugin struct)
299  * 3) sauth plugin instantiation data (size set in the plugin struct)
300  * 4) space for a copy of the stream type name
301  *
302  * The user data struct is initialized to all zeros, then the .handle_offset and
303  * .opaque_user_data_offset fields of the ssi are used to prepare the user data
304  * struct with the ss handle that was created, and a copy of the
305  * opaque_user_data pointer given as an argument.
306  *
307  * If you want to set up the stream with specific information, point to it in
308  * opaque_user_data and use the copy of that pointer in your user data member
309  * for it starting from the LWSSSCS_CREATING state call.
310  *
311  * Since different endpoints chosen by the policy may require different payload
312  * formats, \p ppayload_fmt is set to point to the name of the needed payload
313  * format from the policy database if non-NULL.
314  */
315 LWS_VISIBLE LWS_EXTERN int
316 lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
317 	      void *opaque_user_data, struct lws_ss_handle **ppss,
318 	      struct lws_sequencer *seq_owner, const char **ppayload_fmt);
319 
320 /**
321  * lws_ss_destroy() - Destroy secure stream
322  *
323  * \param ppss: pointer to lws_ss_t pointer to be destroyed
324  *
325  * Destroys the lws_ss_t pointed to by *ppss, and sets *ppss to NULL.
326  */
327 LWS_VISIBLE LWS_EXTERN void
328 lws_ss_destroy(struct lws_ss_handle **ppss);
329 
330 /**
331  * lws_ss_request_tx() - Schedule stream for tx
332  *
333  * \param pss: pointer to lws_ss_t representing stream that wants to transmit
334  *
335  * Schedules a write on the stream represented by \p pss.  When it's possible to
336  * write on this stream, the *tx callback will occur with an empty buffer for
337  * the stream owner to fill in.
338  */
339 LWS_VISIBLE LWS_EXTERN void
340 lws_ss_request_tx(struct lws_ss_handle *pss);
341 
342 /**
343  * lws_ss_request_tx() - Schedule stream for tx
344  *
345  * \param pss: pointer to lws_ss_t representing stream that wants to transmit
346  * \param len: the length of the write in bytes
347  *
348  * Schedules a write on the stream represented by \p pss.  When it's possible to
349  * write on this stream, the *tx callback will occur with an empty buffer for
350  * the stream owner to fill in.
351  *
352  * This api variant should be used when it's possible the payload will go out
353  * over h1 with x-web-form-urlencoded or similar Content-Type.
354  */
355 LWS_VISIBLE LWS_EXTERN void
356 lws_ss_request_tx_len(struct lws_ss_handle *pss, unsigned long len);
357 
358 
359 /**
360  * lws_ss_client_connect() - Attempt the client connect
361  *
362  * \param h: secure streams handle
363  *
364  * Starts the connection process for the secure stream.  Returns 0 if OK or
365  * nonzero if we have already failed.
366  */
367 LWS_VISIBLE LWS_EXTERN int
368 lws_ss_client_connect(struct lws_ss_handle *h);
369 
370 /**
371  * lws_ss_get_sequencer() - Return parent sequencer pointer if any
372  *
373  * \param h: secure streams handle
374  *
375  * Returns NULL if the secure stream is not associated with a sequencer.
376  * Otherwise returns a pointer to the owning sequencer.  You can use this to
377  * identify which sequencer to direct messages to, from the secure stream
378  * callback.
379  */
380 LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
381 lws_ss_get_sequencer(struct lws_ss_handle *h);
382 
383 /**
384  * lws_ss_proxy_create() - Start a unix domain socket proxy for Secure Streams
385  *
386  * \param context: lws_context
387  * \param bind: if port is 0, unix domain path with leading @ for abstract.
388  *		if port nonzero, NULL, or network interface to bind listen to
389  * \param port: tcp port to listen on
390  *
391  * Creates a vhost that listens either on an abstract namespace unix domain
392  * socket (port = 0) or a tcp listen socket (port nonzero).  If bind is NULL
393  * and port is 0, the abstract unix domain socket defaults to "proxy.ss.lws".
394  *
395  * Client connections to this proxy to Secure Streams are fulfilled using the
396  * policy local to the proxy and the data passed between the client and the
397  * proxy using serialized Secure Streams protocol.
398  */
399 LWS_VISIBLE LWS_EXTERN int
400 lws_ss_proxy_create(struct lws_context *context, const char *bind, int port);
401 
402 /**
403  * lws_ss_state_name() - convenience helper to get a printable conn state name
404  *
405  * \param state: the connection state index
406  *
407  * Returns a printable name for the connection state index passed in.
408  */
409 LWS_VISIBLE LWS_EXTERN const char *
410 lws_ss_state_name(int state);
411 
412 /**
413  * lws_ss_get_context() - convenience helper to recover the lws context
414  *
415  * \param h: secure streams handle
416  *
417  * Returns the lws context.  Dispenses with the need to pass a copy of it into
418  * your secure streams handler.
419  */
420 LWS_VISIBLE LWS_EXTERN struct lws_context *
421 lws_ss_get_context(struct lws_ss_handle *h);
422 
423 /**
424  * lws_ss_rideshare() - find the current streamtype when types rideshare
425  *
426  * \param h: the stream handle
427  *
428  * Under some conditions, the payloads may be structured using protocol-
429  * specific formatting, eg, http multipart mime.  It's possible to map the
430  * logical partitions in the payload to different stream types using
431  * the policy "rideshare" feature.
432  *
433  * This api lets the callback code find out which rideshare stream type the
434  * current payload chunk belongs to.
435  */
436 LWS_VISIBLE LWS_EXTERN const char *
437 lws_ss_rideshare(struct lws_ss_handle *h);
438 
439 
440 /**
441  * lws_ss_set_metadata() - allow user to bind external data to defined ss metadata
442  *
443  * \param h: secure streams handle
444  * \param name: metadata name from the policy
445  * \param value: pointer to user-managed data to bind to name
446  * \param len: length of the user-managed data in value
447  *
448  * Binds user-managed data to the named metadata item from the ss policy.
449  * If present, the metadata item is handled in a protocol-specific way using
450  * the associated policy information.  For example, in the policy
451  *
452  *  	"\"metadata\":"		"["
453  *		"{\"uptag\":"  "\"X-Upload-Tag:\"},"
454  *		"{\"ctype\":"  "\"Content-Type:\"},"
455  *		"{\"xctype\":" "\"\"}"
456  *	"],"
457  *
458  * when the policy is using h1 is interpreted to add h1 headers of the given
459  * name with the value of the metadata on the left.
460  *
461  * Return 0 if OK or nonzero if, eg, metadata name does not exist on the
462  * streamtype.
463  */
464 LWS_VISIBLE LWS_EXTERN int
465 lws_ss_set_metadata(struct lws_ss_handle *h, const char *name,
466 		    void *value, size_t len);
467 
468 
469 /**
470  * lws_ss_add_peer_tx_credit() - allow peer to transmit more to us
471  *
472  * \param h: secure streams handle
473  * \param add: additional tx credit (signed)
474  *
475  * Indicate to remote peer that we can accept \p add bytes more payload being
476  * sent to us.
477  */
478 LWS_VISIBLE LWS_EXTERN int
479 lws_ss_add_peer_tx_credit(struct lws_ss_handle *h, int32_t add);
480 
481 /**
482  * lws_ss_get_est_peer_tx_credit() - get our current estimate of peer's tx credit
483  *
484  * \param h: secure streams handle
485  *
486  * Based on what credit we gave it, and what we have received, report our
487  * estimate of peer's tx credit usable to transmit to us.  This may be outdated
488  * in that some or all of its credit may already have been expended by sending
489  * stuff to us that is in flight already.
490  */
491 LWS_VISIBLE LWS_EXTERN int
492 lws_ss_get_est_peer_tx_credit(struct lws_ss_handle *h);
493