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 
25 /*
26  * Secure Stream state
27  */
28 
29 typedef enum {
30 	SSSEQ_IDLE,
31 	SSSEQ_TRY_CONNECT,
32 	SSSEQ_TRY_CONNECT_NAUTH,
33 	SSSEQ_TRY_CONNECT_SAUTH,
34 	SSSEQ_RECONNECT_WAIT,
35 	SSSEQ_DO_RETRY,
36 	SSSEQ_CONNECTED,
37 } lws_ss_seq_state_t;
38 
39 
40 /**
41  * lws_ss_handle_t: publicly-opaque secure stream object implementation
42  */
43 
44 typedef struct lws_ss_handle {
45 	lws_ss_info_t		info;	  /**< copy of stream creation info */
46 	struct lws_dll2		list;	  /**< pt lists active ss */
47 	struct lws_dll2		to_list;  /**< pt lists ss with pending to-s */
48 
49 	struct lws_dll2_owner	src_list; /**< sink's list of bound sources */
50 
51 	struct lws_context      *context; /**< lws context we are created on */
52 	const lws_ss_policy_t	*policy;  /**< system policy for stream */
53 
54 	struct lws_sequencer	*seq;	  /**< owning sequencer if any */
55 	struct lws		*wsi;	  /**< the stream wsi if any */
56 
57 	void			*nauthi;  /**< the nauth plugin instance data */
58 	void			*sauthi;  /**< the sauth plugin instance data */
59 
60 	lws_ss_metadata_t	*metadata;
61 	const lws_ss_policy_t	*rideshare;
62 
63 	struct lws_ss_handle	*h_sink;  /**< sink we are bound to, or NULL */
64 	void 			*sink_obj;/**< sink's private object representing us */
65 
66 	lws_sorted_usec_list_t	sul;
67 	lws_ss_tx_ordinal_t	txord;
68 
69 	/* protocol-specific connection helpers */
70 
71 	union {
72 
73 		/* ...for http-related protocols... */
74 
75 		struct {
76 
77 			/* common to all http-related protocols */
78 
79 			/* incoming multipart parsing */
80 
81 			char boundary[24];	/* --boundary from headers */
82 			uint8_t boundary_len;	/* length of --boundary */
83 			uint8_t boundary_seq;	/* current match amount */
84 			uint8_t boundary_dashes; /* check for -- after */
85 			uint8_t boundary_post; /* swallow post CRLF */
86 
87 			uint8_t som:1;	/* SOM has been sent */
88 			uint8_t any:1;	/* any content has been sent */
89 
90 
91 			uint8_t good_respcode:1; /* 200 type response code */
92 
93 			union {
94 				struct { /* LWSSSP_H1 */
95 				} h1;
96 				struct { /* LWSSSP_H2 */
97 				} h2;
98 				struct { /* LWSSSP_WS */
99 				} ws;
100 			} u;
101 		} http;
102 
103 		/* details for non-http related protocols... */
104 #if defined(LWS_ROLE_MQTT)
105 		struct {
106 			lws_mqtt_topic_elem_t		topic_qos;
107 			lws_mqtt_topic_elem_t		sub_top;
108 			lws_mqtt_subscribe_param_t 	sub_info;
109 		} mqtt;
110 #endif
111 	} u;
112 
113 	unsigned long		writeable_len;
114 
115 	lws_ss_constate_t	connstate;/**< public connection state */
116 	lws_ss_seq_state_t	seqstate; /**< private connection state */
117 
118 	uint16_t		retry;	  /**< retry / backoff tracking */
119 	int16_t			temp16;
120 
121 	uint8_t			tsi;	  /**< service thread idx, usually 0 */
122 	uint8_t			subseq;	  /**< emulate SOM tracking */
123 	uint8_t			txn_ok;	  /**< 1 = transaction was OK */
124 
125 	uint8_t			hanging_som:1;
126 	uint8_t			inside_msg:1;
127 	uint8_t			being_serialized:1; /* we are not the consumer */
128 } lws_ss_handle_t;
129 
130 /* connection helper that doesn't need to hang around after connection starts */
131 
132 union lws_ss_contemp {
133 #if defined(LWS_ROLE_MQTT)
134 	lws_mqtt_client_connect_param_t ccp;
135 #endif
136 };
137 
138 /*
139  * When allocating the opaque handle, we overallocate for:
140  *
141  *  1) policy->nauth_plugin->alloc (.nauthi) if any
142  *  2) policy->sauth_plugin->alloc (.sauthi) if any
143  *  3) copy of creation info stream type pointed to by info.streamtype... this
144  *     may be arbitrarily long and since it may be coming from socket ipc and be
145  *     temporary at creation time, we need a place for the copy to stay in scope
146  *  4) copy of info->streamtype contents
147  */
148 
149 
150 /* the user object allocation is immediately after the ss object allocation */
151 #define ss_to_userobj(ss) ((void *)&(ss)[1])
152 
153 /*
154  * serialization parser state
155  */
156 
157 enum {
158 	KIND_C_TO_P,
159 	KIND_SS_TO_P,
160 };
161 
162 struct lws_ss_serialization_parser {
163 	char			streamtype[32];
164 	char			rideshare[32];
165 	char			metadata_name[32];
166 
167 	uint64_t		ust_pwait;
168 
169 	lws_ss_metadata_t	*ssmd;
170 
171 	int			ps;
172 	int			ctr;
173 
174 	uint32_t		usd_phandling;
175 	uint32_t		flags;
176 	int32_t			temp32;
177 
178 	int32_t			txcr_out;
179 	int32_t			txcr_in;
180 	uint16_t		rem;
181 
182 	uint8_t			type;
183 	uint8_t			frag1;
184 	uint8_t			slen;
185 	uint8_t			rsl_pos;
186 	uint8_t			rsl_idx;
187 };
188 
189 /*
190  * Unlike locally-fulfilled SS, SSS doesn't have to hold metadata on client side
191  * but pass it through to the proxy.  The client side doesn't know the real
192  * metadata names that are available in the policy (since it's hardcoded in code
193  * no point passing them back to the client from the policy).  Because of that,
194  * it doesn't know how many to allocate when we create the sspc_handle either.
195  *
196  * So we use a linked-list of changed-but-not-yet-proxied metadata allocated
197  * on the heap and items removed as they are proxied out.  Anything on the list
198  * is sent to the proxy before any requested tx is handled.
199  *
200  * This is also used to queue tx credit changes
201  */
202 
203 typedef struct lws_sspc_metadata {
204 	lws_dll2_t	list;
205 	char		name[32];  /* empty string, then actually TCXR */
206 	size_t		len;
207 	int		tx_cr_adjust;
208 
209 	/* the value of length .len is overallocated after this */
210 } lws_sspc_metadata_t;
211 
212 
213 typedef struct lws_sspc_handle {
214 	char			rideshare_list[128];
215 	lws_ss_info_t		ssi;
216 	lws_sorted_usec_list_t	sul_retry;
217 
218 	struct lws_ss_serialization_parser parser;
219 
220 	lws_dll2_owner_t	metadata_owner;
221 
222 	struct lws_dll2		client_list;
223 	struct lws_tx_credit	txc;
224 
225 	struct lws		*cwsi;
226 
227 	struct lws_dsh		*dsh;
228 	struct lws_context	*context;
229 
230 	lws_usec_t		us_earliest_write_req;
231 
232 	lws_ss_conn_states_t	state;
233 
234 	int16_t			temp16;
235 
236 	uint32_t		ord;
237 
238 	uint8_t			rideshare_ofs[4];
239 	uint8_t			conn_req;
240 	uint8_t			rsidx;
241 
242 	uint8_t			destroying:1;
243 } lws_sspc_handle_t;
244 
245 int
246 lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par,
247 			 struct lws_context *context,
248 			 struct lws_dsh *dsh, const uint8_t *cp, size_t len,
249 			 lws_ss_conn_states_t *state, void *parconn,
250 			 lws_ss_handle_t **pss, lws_ss_info_t *ssi, char client);
251 int
252 lws_ss_serialize_rx_payload(struct lws_dsh *dsh, const uint8_t *buf,
253 			    size_t len, int flags, const char *rsp);
254 int
255 lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
256 			      lws_ss_tx_ordinal_t ord, uint8_t *buf,
257 			      size_t *len, int *flags);
258 int
259 lws_ss_serialize_state(struct lws_dsh *dsh, lws_ss_constate_t state,
260 		       lws_ss_tx_ordinal_t ack);
261 
262 void
263 lws_ss_serialize_state_transition(lws_ss_conn_states_t *state, int new_state);
264 
265 const lws_ss_policy_t *
266 lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype);
267 
268 /* can be used as a cb from lws_dll2_foreach_safe() to destroy ss */
269 int
270 lws_ss_destroy_dll(struct lws_dll2 *d, void *user);
271 
272 int
273 lws_sspc_destroy_dll(struct lws_dll2 *d, void *user);
274 
275 
276 int
277 lws_ss_policy_parse_begin(struct lws_context *context);
278 
279 int
280 lws_ss_policy_parse(struct lws_context *context, const uint8_t *buf, size_t len);
281 
282 int
283 lws_ss_policy_set(struct lws_context *context, const char *name);
284 
285 int
286 lws_ss_policy_parse_abandon(struct lws_context *context);
287 
288 int
289 lws_ss_sys_fetch_policy(struct lws_context *context);
290 
291 int
292 lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs);
293 
294 int
295 lws_ss_backoff(lws_ss_handle_t *h);
296 
297 int
298 lws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us);
299 
300 void
301 ss_proxy_onward_txcr(void *userobj, int bump);
302 
303 int
304 lws_ss_serialize_txcr(struct lws_dsh *dsh, int txcr);
305 
306 int
307 lws_ss_sys_auth_api_amazon_com(struct lws_context *context);
308 
309 lws_ss_metadata_t *
310 lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name);
311 lws_ss_metadata_t *
312 lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index);
313 
314 lws_ss_metadata_t *
315 lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name);
316 
317 int
318 lws_ss_exp_cb_metadata(void *priv, const char *name, char *out, size_t *pos,
319 			size_t olen, size_t *exp_ofs);
320 
321 typedef int (* const secstream_protocol_connect_munge_t)(lws_ss_handle_t *h,
322 		char *buf, size_t len, struct lws_client_connect_info *i,
323 		union lws_ss_contemp *ct);
324 
325 typedef int (* const secstream_protocol_add_txcr_t)(lws_ss_handle_t *h, int add);
326 
327 typedef int (* const secstream_protocol_get_txcr_t)(lws_ss_handle_t *h);
328 
329 struct ss_pcols {
330 	const char					*name;
331 	const char					*alpn;
332 	const char					*protocol_name;
333 	const secstream_protocol_connect_munge_t	munge;
334 	const secstream_protocol_add_txcr_t		tx_cr_add;
335 	const secstream_protocol_get_txcr_t		tx_cr_est;
336 };
337 
338 extern const struct ss_pcols ss_pcol_h1;
339 extern const struct ss_pcols ss_pcol_h2;
340 extern const struct ss_pcols ss_pcol_ws;
341 extern const struct ss_pcols ss_pcol_mqtt;
342 
343 extern const struct lws_protocols protocol_secstream_h1;
344 extern const struct lws_protocols protocol_secstream_h2;
345 extern const struct lws_protocols protocol_secstream_ws;
346 extern const struct lws_protocols protocol_secstream_mqtt;
347 
348