/src/libwebsockets/lib/tls/tls-network.c
Line | Count | Source |
1 | | /* |
2 | | * libwebsockets - small server side websockets and web server implementation |
3 | | * |
4 | | * Copyright (C) 2010 - 2019 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 | | #include "private-lib-core.h" |
26 | | |
27 | | /* |
28 | | * fakes POLLIN on all tls guys with buffered rx |
29 | | * |
30 | | * returns nonzero if any tls guys had POLLIN faked |
31 | | */ |
32 | | |
33 | | int |
34 | | lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt) |
35 | 0 | { |
36 | 0 | int ret = 0; |
37 | |
|
38 | 0 | lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, |
39 | 0 | lws_dll2_get_head(&pt->tls.dll_pending_tls_owner)) { |
40 | 0 | struct lws *wsi = lws_container_of(p, struct lws, |
41 | 0 | tls.dll_pending_tls); |
42 | | |
43 | | /* |
44 | | * ... allow custom event loop to override our POLLIN-setting |
45 | | * implementation if it knows how to do it better for its case |
46 | | */ |
47 | | |
48 | 0 | if (pt->context->event_loop_ops && |
49 | 0 | pt->context->event_loop_ops->fake_POLLIN_override) |
50 | 0 | pt->context->event_loop_ops->fake_POLLIN_override( |
51 | 0 | pt->context, pt->tid); |
52 | 0 | else { |
53 | 0 | if (wsi->position_in_fds_table >= 0) { |
54 | |
|
55 | 0 | pt->fds[wsi->position_in_fds_table].revents = (short) |
56 | 0 | (pt->fds[wsi->position_in_fds_table].revents | |
57 | 0 | (pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN)); |
58 | 0 | ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN; |
59 | 0 | } |
60 | 0 | } |
61 | |
|
62 | 0 | } lws_end_foreach_dll_safe(p, p1); |
63 | |
|
64 | 0 | return !!ret; |
65 | 0 | } |
66 | | |
67 | | void |
68 | | __lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) |
69 | 0 | { |
70 | 0 | lws_dll2_remove(&wsi->tls.dll_pending_tls); |
71 | 0 | } |
72 | | |
73 | | void |
74 | | lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) |
75 | 0 | { |
76 | 0 | struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; |
77 | |
|
78 | 0 | lws_pt_lock(pt, __func__); |
79 | 0 | __lws_ssl_remove_wsi_from_buffered_list(wsi); |
80 | 0 | lws_pt_unlock(pt); |
81 | 0 | } |
82 | | |
83 | | #if defined(LWS_WITH_SERVER) |
84 | | int |
85 | | lws_tls_check_cert_lifetime(struct lws_vhost *v) |
86 | 0 | { |
87 | 0 | time_t now = (time_t)lws_now_secs(), life = 0; |
88 | 0 | struct lws_acme_cert_aging_args caa; |
89 | 0 | union lws_tls_cert_info_results ir; |
90 | 0 | int n; |
91 | |
|
92 | 0 | if (v->tls.ssl_ctx && !v->tls.skipped_certs) { |
93 | |
|
94 | 0 | if (now < 1542933698) /* Nov 23 2018 00:42 UTC */ |
95 | | /* our clock is wrong and we can't judge the certs */ |
96 | 0 | return -1; |
97 | | |
98 | 0 | n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO, |
99 | 0 | &ir, 0); |
100 | 0 | if (n) |
101 | 0 | return 1; |
102 | | |
103 | 0 | life = (ir.time - now) / (24 * 3600); |
104 | 0 | lwsl_vhost_notice(v, " vhost %s: cert expiry: %lldd", v->name, |
105 | 0 | (long long)life); |
106 | 0 | } else |
107 | 0 | lwsl_vhost_info(v, " vhost %s: no cert", v->name); |
108 | | |
109 | 0 | memset(&caa, 0, sizeof(caa)); |
110 | 0 | caa.vh = v; |
111 | 0 | lws_broadcast(&v->context->pt[0], LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa, |
112 | 0 | (size_t)(ssize_t)life); |
113 | |
|
114 | 0 | return 0; |
115 | 0 | } |
116 | | |
117 | | int |
118 | | lws_tls_check_all_cert_lifetimes(struct lws_context *context) |
119 | 0 | { |
120 | 0 | struct lws_vhost *v = context->vhost_list; |
121 | |
|
122 | 0 | while (v) { |
123 | 0 | if (lws_tls_check_cert_lifetime(v) < 0) |
124 | 0 | return -1; |
125 | 0 | v = v->vhost_next; |
126 | 0 | } |
127 | | |
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | | /* |
132 | | * LWS_TLS_EXTANT_NO : skip adding the cert |
133 | | * LWS_TLS_EXTANT_YES : use the cert and private key paths normally |
134 | | * LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss |
135 | | */ |
136 | | enum lws_tls_extant |
137 | | lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert, |
138 | | const char *private_key) |
139 | 0 | { |
140 | 0 | int n, m; |
141 | | |
142 | | /* |
143 | | * The user code can choose to either pass the cert and |
144 | | * key filepaths using the info members like this, or it can |
145 | | * leave them NULL; force the vhost SSL_CTX init using the info |
146 | | * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and |
147 | | * set up the cert himself using the user callback |
148 | | * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which |
149 | | * happened just above and has the vhost SSL_CTX * in the user |
150 | | * parameter. |
151 | | */ |
152 | |
|
153 | 0 | if (!cert || !private_key) |
154 | 0 | return LWS_TLS_EXTANT_NO; |
155 | | |
156 | 0 | n = (int)lws_tls_use_any_upgrade_check_extant(cert); |
157 | 0 | if (n == LWS_TLS_EXTANT_ALTERNATIVE) |
158 | 0 | return LWS_TLS_EXTANT_ALTERNATIVE; |
159 | 0 | m = (int)lws_tls_use_any_upgrade_check_extant(private_key); |
160 | 0 | if (m == LWS_TLS_EXTANT_ALTERNATIVE) |
161 | 0 | return LWS_TLS_EXTANT_ALTERNATIVE; |
162 | | |
163 | 0 | if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) && |
164 | 0 | (vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) { |
165 | 0 | lwsl_vhost_notice(vhost, "Ignoring missing %s or %s", cert, private_key); |
166 | 0 | vhost->tls.skipped_certs = 1; |
167 | |
|
168 | 0 | return LWS_TLS_EXTANT_NO; |
169 | 0 | } |
170 | | |
171 | | /* |
172 | | * the cert + key exist |
173 | | */ |
174 | | |
175 | 0 | return LWS_TLS_EXTANT_YES; |
176 | 0 | } |
177 | | |
178 | | /* |
179 | | * update the cert for every vhost using the given path |
180 | | */ |
181 | | |
182 | | int |
183 | | lws_tls_cert_updated(struct lws_context *context, const char *certpath, |
184 | | const char *keypath, |
185 | | const char *mem_cert, size_t len_mem_cert, |
186 | | const char *mem_privkey, size_t len_mem_privkey) |
187 | 0 | { |
188 | 0 | struct lws wsi; |
189 | |
|
190 | 0 | wsi.a.context = context; |
191 | |
|
192 | 0 | lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) { |
193 | 0 | wsi.a.vhost = v; /* not a real bound wsi */ |
194 | 0 | if (v->tls.alloc_cert_path && v->tls.key_path && |
195 | 0 | !strcmp(v->tls.alloc_cert_path, certpath) && |
196 | 0 | !strcmp(v->tls.key_path, keypath)) { |
197 | 0 | lws_tls_server_certs_load(v, &wsi, certpath, keypath, |
198 | 0 | mem_cert, len_mem_cert, |
199 | 0 | mem_privkey, len_mem_privkey); |
200 | |
|
201 | 0 | if (v->tls.skipped_certs) |
202 | 0 | lwsl_vhost_notice(v, "vhost %s: cert unset", v->name); |
203 | 0 | } |
204 | 0 | } lws_end_foreach_ll(v, vhost_next); |
205 | |
|
206 | 0 | return 0; |
207 | 0 | } |
208 | | |
209 | | int |
210 | | lws_gate_accepts(struct lws_context *context, int on) |
211 | 0 | { |
212 | 0 | struct lws_vhost *v = context->vhost_list; |
213 | |
|
214 | 0 | if (context->tls_gate_accepts == (char)on) |
215 | 0 | return 0; |
216 | | |
217 | 0 | lwsl_cx_info(context, "on = %d", on); |
218 | |
|
219 | 0 | context->tls_gate_accepts = (char)on; |
220 | |
|
221 | 0 | while (v) { |
222 | 0 | lws_start_foreach_dll(struct lws_dll2 *, d, |
223 | 0 | lws_dll2_get_head(&v->listen_wsi)) { |
224 | 0 | struct lws *wsi = lws_container_of(d, struct lws, |
225 | 0 | listen_list); |
226 | |
|
227 | 0 | if (v->tls.use_ssl && |
228 | 0 | lws_change_pollfd(wsi, on ? LWS_POLLIN : 0, |
229 | 0 | on ? 0 : LWS_POLLIN)) |
230 | 0 | lwsl_cx_notice(context, "Unable to set POLLIN %d", on); |
231 | 0 | } lws_end_foreach_dll(d); |
232 | |
|
233 | 0 | v = v->vhost_next; |
234 | 0 | } |
235 | |
|
236 | 0 | return 0; |
237 | 0 | } |
238 | | #endif |
239 | | |
240 | | /* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */ |
241 | | |
242 | | int |
243 | | lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len) |
244 | 0 | { |
245 | 0 | uint8_t *oos = os, *plen = NULL; |
246 | |
|
247 | 0 | if (!comma) |
248 | 0 | return 0; |
249 | | |
250 | 0 | while (*comma && len > 2) { |
251 | 0 | if (!plen && *comma == ' ') { |
252 | 0 | comma++; |
253 | 0 | continue; |
254 | 0 | } |
255 | 0 | if (!plen) { |
256 | 0 | plen = os++; |
257 | 0 | len--; |
258 | 0 | } |
259 | |
|
260 | 0 | if (*comma == ',') { |
261 | 0 | *plen = (uint8_t)lws_ptr_diff(os, plen + 1); |
262 | 0 | plen = NULL; |
263 | 0 | comma++; |
264 | 0 | } else { |
265 | 0 | *os++ = (uint8_t)*comma++; |
266 | 0 | len--; |
267 | 0 | } |
268 | 0 | } |
269 | |
|
270 | 0 | if (plen) |
271 | 0 | *plen = (uint8_t)lws_ptr_diff(os, plen + 1); |
272 | |
|
273 | 0 | *os = 0; |
274 | |
|
275 | 0 | return lws_ptr_diff(os, oos); |
276 | 0 | } |
277 | | |
278 | | |
279 | | |