aboutsummaryrefslogtreecommitdiff
path: root/lib/secure-streams/private-lib-secure-streams.h
blob: 6af59e4707514f537af579fe9180803300fee16b (plain)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
/*
 * libwebsockets - small server side websockets and web server implementation
 *
 * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/* current SS Serialization protocol version */
#define LWS_SSS_CLIENT_PROTOCOL_VERSION 1

/*
 * Secure Stream state
 */

typedef enum {
	SSSEQ_IDLE,
	SSSEQ_TRY_CONNECT,
	SSSEQ_TRY_CONNECT_NAUTH,
	SSSEQ_TRY_CONNECT_SAUTH,
	SSSEQ_RECONNECT_WAIT,
	SSSEQ_DO_RETRY,
	SSSEQ_CONNECTED,
} lws_ss_seq_state_t;

struct conn;

/**
 * lws_ss_handle_t: publicly-opaque secure stream object implementation
 */

typedef struct lws_ss_handle {
	lws_ss_info_t		info;	  /**< copy of stream creation info */

	lws_lifecycle_t		lc;

#if defined(LWS_WITH_SYS_METRICS)
	lws_metrics_caliper_compose(cal_txn)
#endif

	struct lws_dll2		list;	  /**< pt lists active ss */
	struct lws_dll2		to_list;  /**< pt lists ss with pending to-s */
#if defined(LWS_WITH_SERVER)
	struct lws_dll2		cli_list;  /**< same server clients list */
#endif
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
	lws_fi_ctx_t		fic;	/**< Fault Injection context */
#endif

	struct lws_dll2_owner	src_list; /**< sink's list of bound sources */

	struct lws_context      *context; /**< lws context we are created on */
	const lws_ss_policy_t	*policy;  /**< system policy for stream */

	struct lws_sequencer	*seq;	  /**< owning sequencer if any */
	struct lws		*wsi;	  /**< the stream wsi if any */

	struct conn		*conn_if_sspc_onw;

#if defined(LWS_WITH_SSPLUGINS)
	void			*nauthi;  /**< the nauth plugin instance data */
	void			*sauthi;  /**< the sauth plugin instance data */
#endif

	lws_ss_metadata_t	*metadata;
#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
	lws_ss_metadata_t	*instant_metadata; /**< for set instant metadata */
	struct lwsac            *imd_ac;           /**< for get custom header */
#endif
	const lws_ss_policy_t	*rideshare;
	struct lws_ss_handle	*h_in_svc;

#if defined(LWS_WITH_CONMON)
	char			*conmon_json;
#endif

	//struct lws_ss_handle	*h_sink;  /**< sink we are bound to, or NULL */
	//void 			*sink_obj;/**< sink's private object representing us */

	lws_sorted_usec_list_t	sul_timeout;
	lws_sorted_usec_list_t	sul;
	lws_ss_tx_ordinal_t	txord;

	/* protocol-specific connection helpers */

	union {

		/* ...for http-related protocols... */

		struct {

			/* common to all http-related protocols */

			/* incoming multipart parsing */

			char boundary[24];	/* --boundary from headers */
			uint8_t boundary_len;	/* length of --boundary */
			uint8_t boundary_seq;	/* current match amount */
			uint8_t boundary_dashes; /* check for -- after */
			uint8_t boundary_post; /* swallow post CRLF */

			uint8_t som:1;	/* SOM has been sent */
			uint8_t eom:1;  /* EOM has been sent */
			uint8_t any:1;	/* any content has been sent */


			uint8_t good_respcode:1; /* 200 type response code */

			union {
				struct { /* LWSSSP_H1 */
#if defined(WIN32)
					uint8_t dummy;
#endif
				} h1;
				struct { /* LWSSSP_H2 */
#if defined(WIN32)
					uint8_t dummy;
#endif
				} h2;
				struct { /* LWSSSP_WS */
#if defined(WIN32)
					uint8_t dummy;
#endif
				} ws;
			} u;
		} http;

		/* details for non-http related protocols... */
#if defined(LWS_ROLE_MQTT)
		struct {
			lws_mqtt_topic_elem_t		topic_qos;
			lws_mqtt_topic_elem_t		sub_top;
			lws_mqtt_subscribe_param_t 	sub_info;
			/* allocation that must be destroyed with conn */
			void				*heap_baggage;
			const char			*subscribe_to;
			size_t				subscribe_to_len;
		} mqtt;
#endif
#if defined(LWS_WITH_SYS_SMD)
		struct {
			struct lws_smd_peer		*smd_peer;
			lws_sorted_usec_list_t		sul_write;
		} smd;
#endif
	} u;

	unsigned long		writeable_len;

	lws_ss_constate_t	connstate;/**< public connection state */
	lws_ss_seq_state_t	seqstate; /**< private connection state */
	lws_ss_state_return_t	pending_ret; /**< holds desired disposition
						* for ss during CCE */

#if defined(LWS_WITH_SERVER)
	int			txn_resp;
#endif

	uint16_t		retry;	  /**< retry / backoff tracking */
#if defined(LWS_WITH_CONMON)
	uint16_t		conmon_len;
#endif
	int16_t			temp16;

	uint8_t			tsi;	  /**< service thread idx, usually 0 */
	uint8_t			subseq;	  /**< emulate SOM tracking */
	uint8_t			txn_ok;	  /**< 1 = transaction was OK */
	uint8_t			prev_ss_state;

	uint8_t			txn_resp_set:1; /**< user code set one */
	uint8_t			txn_resp_pending:1; /**< we have yet to send */
	uint8_t			hanging_som:1;
	uint8_t			inside_msg:1;
	uint8_t			being_serialized:1; /* we are not the consumer */
	uint8_t			destroying:1;
	uint8_t			ss_dangling_connected:1;
	uint8_t			proxy_onward:1; /* opaque is conn */
	uint8_t			inside_connect:1; /* set if we are currently
						   * creating the onward
						   * connect */
} lws_ss_handle_t;

/* connection helper that doesn't need to hang around after connection starts */

union lws_ss_contemp {
#if defined(LWS_ROLE_MQTT)
	lws_mqtt_client_connect_param_t ccp;
#else
#if defined(WIN32)
	uint8_t	dummy;
#endif
#endif
};

/*
 * When allocating the opaque handle, we overallocate for:
 *
 *  1) policy->nauth_plugin->alloc (.nauthi) if any
 *  2) policy->sauth_plugin->alloc (.sauthi) if any
 *  3) copy of creation info stream type pointed to by info.streamtype... this
 *     may be arbitrarily long and since it may be coming from socket ipc and be
 *     temporary at creation time, we need a place for the copy to stay in scope
 *  4) copy of info->streamtype contents
 */


/* the user object allocation is immediately after the ss object allocation */
#define ss_to_userobj(ss) ((void *)&(ss)[1])

/*
 * serialization parser state
 */

enum {
	KIND_C_TO_P,
	KIND_SS_TO_P,
};

struct lws_ss_serialization_parser {
	char			streamtype[32];
	char			rideshare[32];
	char			metadata_name[32];

	uint64_t		ust_pwait;

	lws_ss_metadata_t	*ssmd;
	uint8_t			*rxmetaval;

	int			ps;
	int			ctr;

	uint32_t		usd_phandling;
	uint32_t		flags;
	uint32_t		client_pid;
	int32_t			temp32;

	int32_t			txcr_out;
	int32_t			txcr_in;
	uint16_t		rem;

	uint8_t			type;
	uint8_t			frag1;
	uint8_t			slen;
	uint8_t			rsl_pos;
	uint8_t			rsl_idx;
	uint8_t			protocol_version;
};

/*
 * Unlike locally-fulfilled SS, SSS doesn't have to hold metadata on client side
 * but pass it through to the proxy.  The client side doesn't know the real
 * metadata names that are available in the policy (since it's hardcoded in code
 * no point passing them back to the client from the policy).  Because of that,
 * it doesn't know how many to allocate when we create the sspc_handle either.
 *
 * So we use a linked-list of changed-but-not-yet-proxied metadata allocated
 * on the heap and items removed as they are proxied out.  Anything on the list
 * is sent to the proxy before any requested tx is handled.
 *
 * This is also used to queue tx credit changes
 */

typedef struct lws_sspc_metadata {
	lws_dll2_t	list;
	char		name[32];  /* empty string, then actually TCXR */
	size_t		len;
	int		tx_cr_adjust;

	/* the value of length .len is overallocated after this */
} lws_sspc_metadata_t;

/* state of the upstream proxy onward connection */

enum {
	LWSSSPC_ONW_NONE,
	LWSSSPC_ONW_REQ,
	LWSSSPC_ONW_ONGOING,
	LWSSSPC_ONW_CONN,
};

typedef struct lws_sspc_handle {
	char			rideshare_list[128];

	lws_lifecycle_t		lc;

	lws_ss_info_t		ssi;
	lws_sorted_usec_list_t	sul_retry;

	struct lws_ss_serialization_parser parser;

#if defined(LWS_WITH_SYS_FAULT_INJECTION)
	lws_fi_ctx_t		fic;	/**< Fault Injection context */
#endif

	lws_dll2_owner_t	metadata_owner;
	lws_dll2_owner_t	metadata_owner_rx;

	struct lws_dll2		client_list;
	struct lws_tx_credit	txc;

#if defined(LWS_WITH_SYS_METRICS)
	lws_metrics_caliper_compose(cal_txn)
#endif

	struct lws		*cwsi;

	struct lws_dsh		*dsh;
	struct lws_context	*context;

	struct lws_sspc_handle	*h_in_svc;
	/*
	 * Used to detect illegal lws_sspc_destroy() calls while still
	 * being serviced
	 */

	lws_usec_t		us_earliest_write_req;
	lws_usec_t		us_start_upstream;

	unsigned long		writeable_len;

	lws_ss_conn_states_t	state;

	uint32_t		timeout_ms;
	uint32_t		ord;

	int16_t			temp16;

	uint8_t			rideshare_ofs[4];
	uint8_t			rsidx;

	uint8_t			prev_ss_state;

	uint8_t			conn_req_state:2;
	uint8_t			destroying:1;
	uint8_t			non_wsi:1;
	uint8_t			ignore_txc:1;
	uint8_t			pending_timeout_update:1;
	uint8_t			pending_writeable_len:1;
	uint8_t			creating_cb_done:1;
	uint8_t			ss_dangling_connected:1;
} lws_sspc_handle_t;

typedef struct backoffs {
	struct backoffs *next;
	const char *name;
	lws_retry_bo_t r;
} backoff_t;

union u {
	backoff_t		*b;
	lws_ss_x509_t		*x;
	lws_ss_trust_store_t	*t;
	lws_ss_policy_t		*p;
	lws_ss_auth_t		*a;
	lws_metric_policy_t	*m;
};

enum {
	LTY_BACKOFF,
	LTY_X509,
	LTY_TRUSTSTORE,
	LTY_POLICY,
	LTY_AUTH,
	LTY_METRICS,

	_LTY_COUNT /* always last */
};


struct policy_cb_args {
	struct lejp_ctx jctx;
	struct lws_context *context;
	struct lwsac *ac;

	const char *socks5_proxy;

	struct lws_b64state b64;

	lws_ss_http_respmap_t respmap[16];

	union u heads[_LTY_COUNT];
	union u curr[_LTY_COUNT];

	uint8_t *p;

	int count;
	char pending_respmap;

	uint8_t parse_data:1;
};

#if defined(LWS_WITH_SYS_SMD)
extern const lws_ss_policy_t pol_smd;
#endif


/*
 * returns one of
 *
 * 	LWSSSSRET_OK
 *	LWSSSSRET_DISCONNECT_ME
 *	LWSSSSRET_DESTROY_ME
 */
int
lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par,
			 struct lws_context *context,
			 struct lws_dsh *dsh, const uint8_t *cp, size_t len,
			 lws_ss_conn_states_t *state, void *parconn,
			 lws_ss_handle_t **pss, lws_ss_info_t *ssi, char client);
int
lws_ss_serialize_rx_payload(struct lws_dsh *dsh, const uint8_t *buf,
			    size_t len, int flags, const char *rsp);
int
lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
			      lws_ss_tx_ordinal_t ord, uint8_t *buf,
			      size_t *len, int *flags);
int
lws_ss_serialize_state(struct lws *wsi, struct lws_dsh *dsh, lws_ss_constate_t state,
		       lws_ss_tx_ordinal_t ack);

const lws_ss_policy_t *
lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype);

/* can be used as a cb from lws_dll2_foreach_safe() to destroy ss */
int
lws_ss_destroy_dll(struct lws_dll2 *d, void *user);

int
lws_sspc_destroy_dll(struct lws_dll2 *d, void *user);

void
lws_sspc_rxmetadata_destroy(lws_sspc_handle_t *h);

int
lws_ss_policy_set(struct lws_context *context, const char *name);

int
lws_ss_sys_fetch_policy(struct lws_context *context);

lws_ss_state_return_t
lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs);

lws_ss_state_return_t
_lws_ss_backoff(lws_ss_handle_t *h, lws_usec_t us_override);

lws_ss_state_return_t
lws_ss_backoff(lws_ss_handle_t *h);

int
_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(lws_ss_state_return_t r, struct lws *wsi,
			 lws_ss_handle_t **ph);

int
lws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us);

void
ss_proxy_onward_txcr(void *userobj, int bump);

int
lws_ss_serialize_txcr(struct lws_dsh *dsh, int txcr);

int
lws_ss_sys_auth_api_amazon_com(struct lws_context *context);

lws_ss_metadata_t *
lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name);
lws_ss_metadata_t *
lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index);

#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
lws_ss_metadata_t *
lws_ss_get_handle_instant_metadata(struct lws_ss_handle *h, const char *name);
#endif

lws_ss_metadata_t *
lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name);

int
lws_ss_exp_cb_metadata(void *priv, const char *name, char *out, size_t *pos,
			size_t olen, size_t *exp_ofs);

int
_lws_ss_set_metadata(lws_ss_metadata_t *omd, const char *name,
		     const void *value, size_t len);

int
_lws_ss_alloc_set_metadata(lws_ss_metadata_t *omd, const char *name,
			   const void *value, size_t len);

lws_ss_state_return_t
_lws_ss_client_connect(lws_ss_handle_t *h, int is_retry, void *conn_if_sspc_onw);

lws_ss_state_return_t
_lws_ss_request_tx(lws_ss_handle_t *h);

int
__lws_ss_proxy_bind_ss_to_conn_wsi(void *parconn, size_t dsh_size);

struct lws_vhost *
lws_ss_policy_ref_trust_store(struct lws_context *context,
			      const lws_ss_policy_t *pol, char doref);

lws_ss_state_return_t
lws_sspc_event_helper(lws_sspc_handle_t *h, lws_ss_constate_t cs,
		      lws_ss_tx_ordinal_t flags);

int
lws_ss_check_next_state(lws_lifecycle_t *lc, uint8_t *prevstate,
			lws_ss_constate_t cs);

int
lws_ss_check_next_state_ss(lws_ss_handle_t *ss, uint8_t *prevstate,
			   lws_ss_constate_t cs);

int
lws_ss_check_next_state_sspc(lws_sspc_handle_t *ss, uint8_t *prevstate,
			     lws_ss_constate_t cs);

void
lws_proxy_clean_conn_ss(struct lws *wsi);

int
lws_ss_cancel_notify_dll(struct lws_dll2 *d, void *user);

int
lws_sspc_cancel_notify_dll(struct lws_dll2 *d, void *user);

#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
int
lws_ss_policy_unref_trust_store(struct lws_context *context,
				const lws_ss_policy_t *pol);
#endif

int
lws_ss_sys_cpd(struct lws_context *cx);

#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
int lws_ss_apply_sigv4(struct lws *wsi, struct lws_ss_handle *h,
		       unsigned char **p, unsigned char *end);
#endif

#if defined(_DEBUG)
void
lws_ss_assert_extant(struct lws_context *cx, int tsi, struct lws_ss_handle *h);
#else
#define lws_ss_assert_extant(_a, _b, _c)
#endif

typedef int (* const secstream_protocol_connect_munge_t)(lws_ss_handle_t *h,
		char *buf, size_t len, struct lws_client_connect_info *i,
		union lws_ss_contemp *ct);

typedef int (* const secstream_protocol_add_txcr_t)(lws_ss_handle_t *h, int add);

typedef int (* const secstream_protocol_get_txcr_t)(lws_ss_handle_t *h);

struct ss_pcols {
	const char					*name;
	const char					*alpn;
	const struct lws_protocols			*protocol;
	secstream_protocol_connect_munge_t		munge;
	secstream_protocol_add_txcr_t			tx_cr_add;
	secstream_protocol_get_txcr_t			tx_cr_est;
};

/*
 * Because both sides of the connection share the conn, we allocate it
 * during accepted adoption, and both sides point to it.
 *
 * When .ss or .wsi close, they must NULL their entry here so no dangling
 * refereneces.
 *
 * The last one of the accepted side and the onward side to close frees it.
 */

lws_ss_state_return_t
lws_conmon_ss_json(lws_ss_handle_t *h);

void
ss_proxy_onward_link_req_writeable(lws_ss_handle_t *h_onward);

struct conn {
	struct lws_ss_serialization_parser parser;

	lws_dsh_t		*dsh;	/* unified buffer for both sides */
	struct lws		*wsi;	/* the proxy's client side */
	lws_ss_handle_t		*ss;	/* the onward, ss side */

	lws_ss_conn_states_t	state;

	char			onward_in_flow_control;
};

extern const struct ss_pcols ss_pcol_h1;
extern const struct ss_pcols ss_pcol_h2;
extern const struct ss_pcols ss_pcol_ws;
extern const struct ss_pcols ss_pcol_mqtt;
extern const struct ss_pcols ss_pcol_raw;

extern const struct lws_protocols protocol_secstream_h1;
extern const struct lws_protocols protocol_secstream_h2;
extern const struct lws_protocols protocol_secstream_ws;
extern const struct lws_protocols protocol_secstream_mqtt;
extern const struct lws_protocols protocol_secstream_raw;