Coverage Report

Created: 2025-11-11 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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