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 | |
27 | typedef int (*plugin_auth_status_cb)(struct lws_ss_handle *ss, int status); |
28 | |
29 | /** |
30 | * lws_ss_plugin_auth_t - api for an auth plugin |
31 | * |
32 | * Auth plugins create and sequence authenticated connections that can carry one |
33 | * or more streams to an endpoint. That may involve other connections to other |
34 | * places to eg, gather authenticated tokens and then make the real connection |
35 | * using the tokens. |
36 | * |
37 | * The secure stream object contains members to record which auth plugin the |
38 | * stream is bound to and an over-allocation of the secure stream object to |
39 | * contain the plugin auth private data. |
40 | * |
41 | * The auth plugin controls the state of the stream connection via the status |
42 | * callback, and handles retries. |
43 | * |
44 | * Network connections may require one kind of auth sequencing, and streams |
45 | * inside those connections another kind of auth sequencing depending on their |
46 | * role. So the secure stream object allows defining plugins for both kinds. |
47 | * |
48 | * Streams may disappear at any time and require reauth to bring a new one up. |
49 | * The auth plugin sequencer will connect / reconnect either on demand, or from |
50 | * the start and after any connectivity loss if any stream using the connection |
51 | * has the LWSSSPOLF_NAILED_UP flag. |
52 | */ |
53 | |
54 | #if defined(LWS_WITH_SSPLUGINS) |
55 | typedef struct lws_ss_plugin { |
56 | struct lws_ss_plugin *next; |
57 | const char *name; /**< auth plugin name */ |
58 | size_t alloc; /**< size of private allocation */ |
59 | |
60 | int (*create)(struct lws_ss_handle *ss, void *info, |
61 | plugin_auth_status_cb status); |
62 | /**< called when the auth plugin is instantiated |
63 | and bound to the secure stream. status is |
64 | called back with advisory information about |
65 | the authenticated stream state as it |
66 | proceeds */ |
67 | int (*destroy)(struct lws_ss_handle *ss); |
68 | /**< called when the related secure stream is |
69 | being destroyed, and anything the auth |
70 | plugin is doing should also be destroyed */ |
71 | int (*munge)(struct lws_ss_handle *ss, char *path, |
72 | size_t path_len); |
73 | /**< if the plugin needs to munge transactions |
74 | that have metadata outside the payload (eg, |
75 | add http headers) this callback will give |
76 | it the opportunity to do so */ |
77 | } lws_ss_plugin_t; |
78 | #endif |
79 | |
80 | /* the public, const metrics policy definition */ |
81 | |
82 | typedef struct lws_metric_policy { |
83 | /* order of first two mandated by JSON policy parsing scope union */ |
84 | const struct lws_metric_policy *next; |
85 | const char *name; |
86 | |
87 | const char *report; |
88 | |
89 | /**< the metrics policy name in the policy, used to bind to it */ |
90 | uint64_t us_schedule; |
91 | /**< us interval between lws_system metrics api reports */ |
92 | |
93 | uint32_t us_decay_unit; |
94 | /**< how many us to decay avg by half, 0 = no decay */ |
95 | uint8_t min_contributors; |
96 | /**< before we can judge something is an outlier */ |
97 | } lws_metric_policy_t; |
98 | |
99 | typedef struct lws_ss_x509 { |
100 | struct lws_ss_x509 *next; |
101 | const char *vhost_name; /**< vhost name using cert ctx */ |
102 | const uint8_t *ca_der; /**< DER x.509 cert */ |
103 | size_t ca_der_len; /**< length of DER cert */ |
104 | uint8_t keep:1; /**< ie, if used in server tls */ |
105 | } lws_ss_x509_t; |
106 | |
107 | enum { |
108 | LWSSSPOLF_OPPORTUNISTIC = (1 << 0), |
109 | /**< the connection doesn't exist unless client asks to write */ |
110 | LWSSSPOLF_NAILED_UP = (1 << 1), |
111 | /**< the connection tries to be connected the whole life of the ss */ |
112 | LWSSSPOLF_URGENT_TX = (1 << 2), |
113 | /**< this connection carries critical tx data */ |
114 | LWSSSPOLF_URGENT_RX = (1 << 3), |
115 | /**< this connection carries critical rx data */ |
116 | LWSSSPOLF_TLS = (1 << 4), |
117 | /**< stream must be connected via a tls tunnel */ |
118 | LWSSSPOLF_LONG_POLL = (1 << 5), |
119 | /**< stream used to receive async rx at arbitrary intervals */ |
120 | LWSSSPOLF_AUTH_BEARER = (1 << 6), |
121 | /**< for http, use lws_system auth token 0 in authentication: bearer */ |
122 | LWSSSPOLF_HTTP_NO_CONTENT_LENGTH = (1 << 7), |
123 | /**< don't add any content length even if we have it */ |
124 | LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM = (1 << 8), |
125 | /**< set the client flag LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM */ |
126 | LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR = (1 << 9), |
127 | /**< set the client flag LCCSCF_H2_QUIRK_OVERFLOWS_TXCR */ |
128 | LWSSSPOLF_H2_QUIRK_UNCLEAN_HPACK_STATE = (1 << 10), |
129 | /**< HPACK decoder state does not end cleanly */ |
130 | LWSSSPOLF_HTTP_MULTIPART = (1 << 11), |
131 | /**< indicates stream goes out as specifically a multipart mime POST |
132 | * section... if the tx has LWSSS_FLAG_COALESCE_CONTINUES flag then more |
133 | * multipart sections are expected. Without it, the multipart wrapper |
134 | * is closed and the http transaction issue completed when this message |
135 | * finishes. */ |
136 | LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED = (1 << 12), |
137 | /**< set up lws_system client cert */ |
138 | LWSSSPOLF_LOCAL_SINK = (1 << 13), |
139 | /**< expected to bind to a local sink only */ |
140 | LWSSSPOLF_WAKE_SUSPEND__VALIDITY = (1 << 14), |
141 | /**< this stream's idle validity checks are critical enough we |
142 | * should arrange to wake from suspend to perform them |
143 | */ |
144 | LWSSSPOLF_SERVER = (1 << 15), |
145 | /**< we listen on a socket as a server */ |
146 | LWSSSPOLF_ALLOW_REDIRECTS = (1 << 16), |
147 | /**< follow redirects */ |
148 | LWSSSPOLF_HTTP_MULTIPART_IN = (1 << 17), |
149 | /**< handle inbound multipart mime at SS level */ |
150 | |
151 | LWSSSPOLF_ATTR_LOW_LATENCY = (1 << 18), |
152 | /**< stream requires low latency */ |
153 | LWSSSPOLF_ATTR_HIGH_THROUGHPUT = (1 << 19), |
154 | /**< stream requires high throughput */ |
155 | LWSSSPOLF_ATTR_HIGH_RELIABILITY = (1 << 20), |
156 | /**< stream requires high reliability */ |
157 | LWSSSPOLF_ATTR_LOW_COST = (1 << 21), |
158 | /**< stream is not critical and should be handled as cheap as poss */ |
159 | LWSSSPOLF_PERF = (1 << 22), |
160 | /**< capture and report performace information */ |
161 | LWSSSPOLF_DIRECT_PROTO_STR = (1 << 23), |
162 | /**< metadata as direct protocol string, e.g. http header */ |
163 | LWSSSPOLF_HTTP_CACHE_COOKIES = (1 << 24), |
164 | /**< Record http cookies and pass them back on future requests */ |
165 | LWSSSPOLF_PRIORITIZE_READS = (1 << 25), |
166 | /**< prioritize clearing reads at expense of writes */ |
167 | |
168 | }; |
169 | |
170 | typedef struct lws_ss_trust_store { |
171 | struct lws_ss_trust_store *next; |
172 | const char *name; |
173 | |
174 | const lws_ss_x509_t *ssx509[6]; |
175 | int count; |
176 | } lws_ss_trust_store_t; |
177 | |
178 | enum { |
179 | LWSSSP_H1, |
180 | LWSSSP_H2, |
181 | LWSSSP_WS, |
182 | LWSSSP_MQTT, |
183 | LWSSSP_RAW, |
184 | |
185 | |
186 | LWSSS_HBI_AUTH = 0, |
187 | LWSSS_HBI_DSN, |
188 | LWSSS_HBI_FWV, |
189 | LWSSS_HBI_TYPE, |
190 | |
191 | _LWSSS_HBI_COUNT /* always last */ |
192 | }; |
193 | |
194 | /* |
195 | * This does for both the static policy metadata entry, and the runtime metadata |
196 | * handling object. |
197 | */ |
198 | |
199 | typedef struct lws_ss_metadata { |
200 | struct lws_ss_metadata *next; |
201 | const char *name; |
202 | void *value__may_own_heap; |
203 | size_t length; |
204 | |
205 | uint8_t value_length; /* only valid if set by policy */ |
206 | uint8_t value_is_http_token; /* valid if set by policy */ |
207 | #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR) |
208 | uint8_t name_on_lws_heap:1; /* proxy metatadata does this */ |
209 | #endif |
210 | uint8_t value_on_lws_heap:1; /* proxy + rx metadata does this */ |
211 | #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) |
212 | uint8_t pending_onward:1; |
213 | #endif |
214 | } lws_ss_metadata_t; |
215 | |
216 | typedef struct lws_ss_http_respmap { |
217 | uint16_t resp; /* the http response code */ |
218 | uint16_t state; /* low 16-bits of associated state */ |
219 | } lws_ss_http_respmap_t; |
220 | |
221 | /* |
222 | * This is a mapping between an auth streamtype and a name and other information |
223 | * that can be independently instantiated. Other streamtypes can indicate they |
224 | * require this authentication on their connection. |
225 | */ |
226 | |
227 | typedef struct lws_ss_auth { |
228 | struct lws_ss_auth *next; |
229 | const char *name; |
230 | |
231 | const char *type; |
232 | const char *streamtype; |
233 | uint8_t blob_index; |
234 | } lws_ss_auth_t; |
235 | |
236 | /** |
237 | * lws_ss_policy_t: policy database entry for a stream type |
238 | * |
239 | * Decides the system policy for how to implement connections of name |
240 | * .streamtype. |
241 | * |
242 | * Streams may need one kind of auth sequencing for the network connection and |
243 | * another kind of auth sequencing for the streams that are carried inside it, |
244 | * this is the purpose of .nauth and .sauth. Both are optional and may be NULL. |
245 | * |
246 | * An array of these is set at context creation time, ending with one with a |
247 | * NULL streamtype. |
248 | */ |
249 | typedef struct lws_ss_policy { |
250 | struct lws_ss_policy *next; |
251 | const char *streamtype; /**< stream type lhs to match on */ |
252 | |
253 | const char *endpoint; /**< DNS address to connect to */ |
254 | const char *rideshare_streamtype; /**< optional transport |
255 | * on another, preexisting stream of this |
256 | * streamtype name */ |
257 | const char *payload_fmt; |
258 | const char *socks5_proxy; |
259 | lws_ss_metadata_t *metadata; /* linked-list of metadata */ |
260 | const lws_metric_policy_t *metrics; /* linked-list of metric policies */ |
261 | const lws_ss_auth_t *auth; /* NULL or auth object we bind to */ |
262 | |
263 | /* protocol-specific connection policy details */ |
264 | |
265 | union { |
266 | |
267 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) || defined(LWS_ROLE_WS) |
268 | |
269 | /* details for http-related protocols... */ |
270 | |
271 | struct { |
272 | |
273 | /* common to all http-related protocols */ |
274 | |
275 | const char *method; |
276 | const char *url; |
277 | |
278 | const char *multipart_name; |
279 | const char *multipart_filename; |
280 | const char *multipart_content_type; |
281 | |
282 | const char *[_LWSSS_HBI_COUNT]; |
283 | const char *auth_preamble; |
284 | |
285 | const lws_ss_http_respmap_t *respmap; |
286 | |
287 | union { |
288 | // struct { /* LWSSSP_H1 */ |
289 | // } h1; |
290 | // struct { /* LWSSSP_H2 */ |
291 | // } h2; |
292 | struct { /* LWSSSP_WS */ |
293 | const char *subprotocol; |
294 | uint8_t binary; |
295 | /* false = TEXT, true = BINARY */ |
296 | } ws; |
297 | } u; |
298 | |
299 | uint16_t resp_expect; |
300 | uint8_t count_respmap; |
301 | uint8_t fail_redirect:1; |
302 | } http; |
303 | |
304 | #endif |
305 | |
306 | #if defined(LWS_ROLE_MQTT) |
307 | |
308 | struct { |
309 | const char *topic; /* stream sends on this topic */ |
310 | const char *subscribe; /* stream subscribes to this topic */ |
311 | |
312 | const char *will_topic; |
313 | const char *will_message; |
314 | |
315 | const char *birth_topic; |
316 | const char *birth_message; |
317 | |
318 | uint16_t keep_alive; |
319 | uint8_t qos; |
320 | uint8_t clean_start; |
321 | uint8_t will_qos; |
322 | uint8_t will_retain; |
323 | uint8_t birth_qos; |
324 | uint8_t birth_retain; |
325 | uint8_t aws_iot; |
326 | uint8_t retain; |
327 | |
328 | } mqtt; |
329 | |
330 | #endif |
331 | |
332 | /* details for non-http related protocols... */ |
333 | } u; |
334 | |
335 | #if defined(LWS_WITH_SSPLUGINS) |
336 | const |
337 | struct lws_ss_plugin *plugins[2]; /**< NULL or auth plugin */ |
338 | const void *plugins_info[2]; /**< plugin-specific data */ |
339 | #endif |
340 | |
341 | #if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4) |
342 | /* directly point to the metadata name, no need to expand */ |
343 | const char *aws_region; |
344 | const char *aws_service; |
345 | #endif |
346 | /* |
347 | * We're either a client connection policy that wants a trust store, |
348 | * or we're a server policy that wants a mem cert and key... Hold |
349 | * these mutually-exclusive things in a union. |
350 | */ |
351 | |
352 | union { |
353 | const lws_ss_trust_store_t *store; |
354 | /**< CA certs needed for conn validation, only set between |
355 | * policy parsing and vhost creation */ |
356 | struct { |
357 | const lws_ss_x509_t *cert; |
358 | /**< the server's signed cert with the pubkey */ |
359 | const lws_ss_x509_t *key; |
360 | /**< the server's matching private key */ |
361 | } server; |
362 | } trust; |
363 | |
364 | const lws_retry_bo_t *retry_bo; /**< retry policy to use */ |
365 | |
366 | uint32_t proxy_buflen; /**< max dsh alloc for proxy */ |
367 | uint32_t proxy_buflen_rxflow_on_above; |
368 | uint32_t proxy_buflen_rxflow_off_below; |
369 | |
370 | uint32_t client_buflen; /**< max dsh alloc for client */ |
371 | uint32_t client_buflen_rxflow_on_above; |
372 | uint32_t client_buflen_rxflow_off_below; |
373 | |
374 | |
375 | uint32_t timeout_ms; /**< default message response |
376 | * timeout in ms */ |
377 | uint32_t flags; /**< stream attribute flags */ |
378 | |
379 | uint16_t port; /**< endpoint port */ |
380 | |
381 | uint8_t metadata_count; /**< metadata count */ |
382 | uint8_t protocol; /**< protocol index */ |
383 | uint8_t client_cert; /**< which client cert to apply |
384 | 0 = none, 1+ = cc 0+ */ |
385 | uint8_t priority; /* 0 = normal, 6 = max normal, |
386 | * 7 = network management */ |
387 | } lws_ss_policy_t; |
388 | |
389 | #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
390 | |
391 | /* |
392 | * These only exist / have meaning if there's a dynamic JSON policy enabled |
393 | */ |
394 | |
395 | LWS_VISIBLE LWS_EXTERN int |
396 | lws_ss_policy_parse_begin(struct lws_context *context, int overlay); |
397 | |
398 | LWS_VISIBLE LWS_EXTERN int |
399 | lws_ss_policy_parse_abandon(struct lws_context *context); |
400 | |
401 | LWS_VISIBLE LWS_EXTERN int |
402 | lws_ss_policy_parse(struct lws_context *context, const uint8_t *buf, size_t len); |
403 | |
404 | LWS_VISIBLE LWS_EXTERN int |
405 | lws_ss_policy_overlay(struct lws_context *context, const char *overlay); |
406 | |
407 | /* |
408 | * You almost certainly don't want these, they return the first policy or auth |
409 | * object in a linked-list of objects created by lws_ss_policy_parse above, |
410 | * they are exported to generate static policy with |
411 | */ |
412 | LWS_VISIBLE LWS_EXTERN const lws_ss_policy_t * |
413 | lws_ss_policy_get(struct lws_context *context); |
414 | |
415 | LWS_VISIBLE LWS_EXTERN const lws_ss_auth_t * |
416 | lws_ss_auth_get(struct lws_context *context); |
417 | |
418 | #endif |
419 | |