1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_civoid 28d4afb5ceSopenharmony_cilws_tls_kid_copy(union lws_tls_cert_info_results *ci, lws_tls_kid_t *kid) 29d4afb5ceSopenharmony_ci{ 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci /* 32d4afb5ceSopenharmony_ci * KIDs all seem to be 20 bytes / SHA1 or less. If we get one that 33d4afb5ceSopenharmony_ci * is bigger, treat only the first 20 bytes as significant. 34d4afb5ceSopenharmony_ci */ 35d4afb5ceSopenharmony_ci 36d4afb5ceSopenharmony_ci if ((size_t)ci->ns.len > sizeof(kid->kid)) 37d4afb5ceSopenharmony_ci kid->kid_len = sizeof(kid->kid); 38d4afb5ceSopenharmony_ci else 39d4afb5ceSopenharmony_ci kid->kid_len = (uint8_t)ci->ns.len; 40d4afb5ceSopenharmony_ci 41d4afb5ceSopenharmony_ci memcpy(kid->kid, ci->ns.name, kid->kid_len); 42d4afb5ceSopenharmony_ci} 43d4afb5ceSopenharmony_ci 44d4afb5ceSopenharmony_civoid 45d4afb5ceSopenharmony_cilws_tls_kid_copy_kid(lws_tls_kid_t *kid, const lws_tls_kid_t *src) 46d4afb5ceSopenharmony_ci{ 47d4afb5ceSopenharmony_ci int klen = sizeof(kid->kid); 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci if (src->kid_len < klen) 50d4afb5ceSopenharmony_ci klen = src->kid_len; 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci kid->kid_len = (uint8_t)klen; 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci memcpy(kid->kid, src->kid, (size_t)klen); 55d4afb5ceSopenharmony_ci} 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ciint 58d4afb5ceSopenharmony_cilws_tls_kid_cmp(const lws_tls_kid_t *a, const lws_tls_kid_t *b) 59d4afb5ceSopenharmony_ci{ 60d4afb5ceSopenharmony_ci if (a->kid_len != b->kid_len) 61d4afb5ceSopenharmony_ci return 1; 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci return memcmp(a->kid, b->kid, a->kid_len); 64d4afb5ceSopenharmony_ci} 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci/* 67d4afb5ceSopenharmony_ci * We have the SKID and AKID for every peer cert captured, but they may be 68d4afb5ceSopenharmony_ci * in any order, and eg, falsely have sent the root CA, or an attacker may 69d4afb5ceSopenharmony_ci * send unresolveable self-referencing loops of KIDs. 70d4afb5ceSopenharmony_ci * 71d4afb5ceSopenharmony_ci * Let's sort them into the SKID -> AKID hierarchy, so the last entry is the 72d4afb5ceSopenharmony_ci * server cert and the first entry is the highest parent that the server sent. 73d4afb5ceSopenharmony_ci * Normally the top one will be an intermediate, and its AKID is the ID of the 74d4afb5ceSopenharmony_ci * root CA cert we would need to trust to validate the chain. 75d4afb5ceSopenharmony_ci * 76d4afb5ceSopenharmony_ci * It's not unknown the server is misconfigured to also send the root CA, if so 77d4afb5ceSopenharmony_ci * the top slot's AKID is empty and we should look for its SKID in the trust 78d4afb5ceSopenharmony_ci * blob. 79d4afb5ceSopenharmony_ci * 80d4afb5ceSopenharmony_ci * If we return 0, we succeeded and the AKID of ch[0] is the SKID we want to see 81d4afb5ceSopenharmony_ci * try to import from the trust blob. 82d4afb5ceSopenharmony_ci * 83d4afb5ceSopenharmony_ci * If we return nonzero, we can't identify what we want and should abandon the 84d4afb5ceSopenharmony_ci * connection. 85d4afb5ceSopenharmony_ci */ 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ciint 88d4afb5ceSopenharmony_cilws_tls_jit_trust_sort_kids(struct lws *wsi, lws_tls_kid_chain_t *ch) 89d4afb5ceSopenharmony_ci{ 90d4afb5ceSopenharmony_ci size_t hl; 91d4afb5ceSopenharmony_ci lws_tls_jit_inflight_t *inf; 92d4afb5ceSopenharmony_ci int n, m, sanity = 10; 93d4afb5ceSopenharmony_ci const char *host = wsi->cli_hostname_copy; 94d4afb5ceSopenharmony_ci char more = 1; 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci lwsl_info("%s\n", __func__); 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci if (!host) { 99d4afb5ceSopenharmony_ci if (wsi->stash && wsi->stash->cis[CIS_HOST]) 100d4afb5ceSopenharmony_ci host = wsi->stash->cis[CIS_HOST]; 101d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 102d4afb5ceSopenharmony_ci else 103d4afb5ceSopenharmony_ci host = lws_hdr_simple_ptr(wsi, 104d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_PEER_ADDRESS); 105d4afb5ceSopenharmony_ci } 106d4afb5ceSopenharmony_ci#endif 107d4afb5ceSopenharmony_ci if (!host) 108d4afb5ceSopenharmony_ci return 1; 109d4afb5ceSopenharmony_ci 110d4afb5ceSopenharmony_ci hl = strlen(host); 111d4afb5ceSopenharmony_ci 112d4afb5ceSopenharmony_ci /* something to work with? */ 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci if (!ch->count) 115d4afb5ceSopenharmony_ci return 1; 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci /* do we need to sort? */ 118d4afb5ceSopenharmony_ci 119d4afb5ceSopenharmony_ci if (ch->count > 1) { 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_ci /* okie... */ 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci while (more) { 124d4afb5ceSopenharmony_ci 125d4afb5ceSopenharmony_ci if (!sanity--) 126d4afb5ceSopenharmony_ci /* let's not get fooled into spinning */ 127d4afb5ceSopenharmony_ci return 1; 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci more = 0; 130d4afb5ceSopenharmony_ci for (n = 0; n < ch->count - 1; n++) { 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci if (!lws_tls_kid_cmp(&ch->skid[n], 133d4afb5ceSopenharmony_ci &ch->akid[n + 1])) 134d4afb5ceSopenharmony_ci /* next belongs with this one */ 135d4afb5ceSopenharmony_ci continue; 136d4afb5ceSopenharmony_ci 137d4afb5ceSopenharmony_ci /* 138d4afb5ceSopenharmony_ci * next doesn't belong with this one, let's 139d4afb5ceSopenharmony_ci * try to figure out where this one does belong 140d4afb5ceSopenharmony_ci * then 141d4afb5ceSopenharmony_ci */ 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci for (m = 0; m < ch->count; m++) { 144d4afb5ceSopenharmony_ci if (n == m) 145d4afb5ceSopenharmony_ci continue; 146d4afb5ceSopenharmony_ci if (!lws_tls_kid_cmp(&ch->skid[n], 147d4afb5ceSopenharmony_ci &ch->akid[m])) { 148d4afb5ceSopenharmony_ci lws_tls_kid_t t; 149d4afb5ceSopenharmony_ci 150d4afb5ceSopenharmony_ci /* 151d4afb5ceSopenharmony_ci * m references us, so we 152d4afb5ceSopenharmony_ci * need to go one step above m, 153d4afb5ceSopenharmony_ci * swap m and n 154d4afb5ceSopenharmony_ci */ 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci more = 1; 157d4afb5ceSopenharmony_ci t = ch->akid[m]; 158d4afb5ceSopenharmony_ci ch->akid[m] = ch->akid[n]; 159d4afb5ceSopenharmony_ci ch->akid[n] = t; 160d4afb5ceSopenharmony_ci t = ch->skid[m]; 161d4afb5ceSopenharmony_ci ch->skid[m] = ch->skid[n]; 162d4afb5ceSopenharmony_ci ch->skid[n] = t; 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci break; 165d4afb5ceSopenharmony_ci } 166d4afb5ceSopenharmony_ci } 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci if (more) 169d4afb5ceSopenharmony_ci break; 170d4afb5ceSopenharmony_ci } 171d4afb5ceSopenharmony_ci } 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci /* then we should be sorted */ 174d4afb5ceSopenharmony_ci } 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci for (n = 0; n < ch->count; n++) { 177d4afb5ceSopenharmony_ci lwsl_info("%s: AKID[%d]\n", __func__, n); 178d4afb5ceSopenharmony_ci lwsl_hexdump_info(ch->akid[n].kid, ch->akid[n].kid_len); 179d4afb5ceSopenharmony_ci lwsl_info("%s: SKID[%d]\n", __func__, n); 180d4afb5ceSopenharmony_ci lwsl_hexdump_info(ch->skid[n].kid, ch->skid[n].kid_len); 181d4afb5ceSopenharmony_ci } 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_ci /* to go further, user must provide a lookup helper */ 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci if (!wsi->a.context->system_ops || 186d4afb5ceSopenharmony_ci !wsi->a.context->system_ops->jit_trust_query) 187d4afb5ceSopenharmony_ci return 1; 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci /* 190d4afb5ceSopenharmony_ci * If there's already a pending lookup for this host, let's bail and 191d4afb5ceSopenharmony_ci * just wait for that to complete (since it will be done async if we 192d4afb5ceSopenharmony_ci * can see it) 193d4afb5ceSopenharmony_ci */ 194d4afb5ceSopenharmony_ci 195d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, 196d4afb5ceSopenharmony_ci wsi->a.context->jit_inflight.head) { 197d4afb5ceSopenharmony_ci inf = lws_container_of(d, lws_tls_jit_inflight_t, list); 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci if (!strcmp((const char *)&inf[1], host)) 200d4afb5ceSopenharmony_ci /* already being handled */ 201d4afb5ceSopenharmony_ci return 1; 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci /* 206d4afb5ceSopenharmony_ci * No... let's make an inflight entry for this host, then 207d4afb5ceSopenharmony_ci */ 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci inf = lws_zalloc(sizeof(*inf) + hl + 1, __func__); 210d4afb5ceSopenharmony_ci if (!inf) 211d4afb5ceSopenharmony_ci return 1; 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci memcpy(&inf[1], host, hl + 1); 214d4afb5ceSopenharmony_ci inf->refcount = (char)ch->count; 215d4afb5ceSopenharmony_ci lws_dll2_add_tail(&inf->list, &wsi->a.context->jit_inflight); 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci /* 218d4afb5ceSopenharmony_ci * ...kid_chain[0] AKID should indicate the right CA SKID that we want. 219d4afb5ceSopenharmony_ci * 220d4afb5ceSopenharmony_ci * Because of cross-signing, we check all of them and accept we may get 221d4afb5ceSopenharmony_ci * multiple (the inflight accepts up to 2) CAs needed. 222d4afb5ceSopenharmony_ci */ 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci for (n = 0; n < ch->count; n++) 225d4afb5ceSopenharmony_ci wsi->a.context->system_ops->jit_trust_query(wsi->a.context, 226d4afb5ceSopenharmony_ci ch->akid[n].kid, (size_t)ch->akid[n].kid_len, 227d4afb5ceSopenharmony_ci (void *)inf); 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci return 0; 230d4afb5ceSopenharmony_ci} 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_cistatic void 233d4afb5ceSopenharmony_citag_to_vh_name(char *result, size_t max, uint32_t tag) 234d4afb5ceSopenharmony_ci{ 235d4afb5ceSopenharmony_ci lws_snprintf(result, max, "jitt-%08X", tag); 236d4afb5ceSopenharmony_ci} 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ciint 239d4afb5ceSopenharmony_cilws_tls_jit_trust_vhost_bind(struct lws_context *cx, const char *address, 240d4afb5ceSopenharmony_ci struct lws_vhost **pvh) 241d4afb5ceSopenharmony_ci{ 242d4afb5ceSopenharmony_ci lws_tls_jit_cache_item_t *ci, jci; 243d4afb5ceSopenharmony_ci lws_tls_jit_inflight_t *inf; 244d4afb5ceSopenharmony_ci char vhtag[32]; 245d4afb5ceSopenharmony_ci size_t size; 246d4afb5ceSopenharmony_ci int n; 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci if (lws_cache_item_get(cx->trust_cache, address, (const void **)&ci, 249d4afb5ceSopenharmony_ci &size)) 250d4afb5ceSopenharmony_ci /* 251d4afb5ceSopenharmony_ci * There's no cached info, we have to start from scratch on 252d4afb5ceSopenharmony_ci * this one 253d4afb5ceSopenharmony_ci */ 254d4afb5ceSopenharmony_ci return 1; 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ci /* gotten cache item may be evicted by jit_trust_query */ 257d4afb5ceSopenharmony_ci jci = *ci; 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci /* 260d4afb5ceSopenharmony_ci * We have some trust cache information for this host already, it tells 261d4afb5ceSopenharmony_ci * us the trusted CA SKIDs we found before, and the xor tag used to name 262d4afb5ceSopenharmony_ci * the vhost configured for these trust CAs in its SSL_CTX. 263d4afb5ceSopenharmony_ci * 264d4afb5ceSopenharmony_ci * Let's check first if the correct prepared vhost already exists, if 265d4afb5ceSopenharmony_ci * so, we can just bind to that and go. 266d4afb5ceSopenharmony_ci */ 267d4afb5ceSopenharmony_ci 268d4afb5ceSopenharmony_ci tag_to_vh_name(vhtag, sizeof(vhtag), jci.xor_tag); 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci *pvh = lws_get_vhost_by_name(cx, vhtag); 271d4afb5ceSopenharmony_ci if (*pvh) { 272d4afb5ceSopenharmony_ci lwsl_info("%s: %s -> existing %s\n", __func__, address, vhtag); 273d4afb5ceSopenharmony_ci /* hit, let's just use that then */ 274d4afb5ceSopenharmony_ci return 0; 275d4afb5ceSopenharmony_ci } 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci /* 278d4afb5ceSopenharmony_ci * ... so, we know the SKIDs of the missing CAs, but we don't have the 279d4afb5ceSopenharmony_ci * DERs for them, and so no configured vhost trusting them yet. We have 280d4afb5ceSopenharmony_ci * had the DERs at some point, but we can't afford to cache them, so 281d4afb5ceSopenharmony_ci * we will have to get them again. 282d4afb5ceSopenharmony_ci * 283d4afb5ceSopenharmony_ci * Let's make an inflight for this, it will create the vhost when it 284d4afb5ceSopenharmony_ci * completes. If syncrhronous, then it will complete before we leave 285d4afb5ceSopenharmony_ci * here, otherwise it will have a life of its own until all the 286d4afb5ceSopenharmony_ci * queries use the cb to succeed or fail. 287d4afb5ceSopenharmony_ci */ 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci size = strlen(address); 290d4afb5ceSopenharmony_ci inf = lws_zalloc(sizeof(*inf) + size + 1, __func__); 291d4afb5ceSopenharmony_ci if (!inf) 292d4afb5ceSopenharmony_ci return 1; 293d4afb5ceSopenharmony_ci 294d4afb5ceSopenharmony_ci memcpy(&inf[1], address, size + 1); 295d4afb5ceSopenharmony_ci inf->refcount = (char)jci.count_skids; 296d4afb5ceSopenharmony_ci lws_dll2_add_tail(&inf->list, &cx->jit_inflight); 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci /* 299d4afb5ceSopenharmony_ci * ...kid_chain[0] AKID should indicate the right CA SKID that we want. 300d4afb5ceSopenharmony_ci * 301d4afb5ceSopenharmony_ci * Because of cross-signing, we check all of them and accept we may get 302d4afb5ceSopenharmony_ci * multiple (we can handle 3) CAs needed. 303d4afb5ceSopenharmony_ci */ 304d4afb5ceSopenharmony_ci 305d4afb5ceSopenharmony_ci for (n = 0; n < jci.count_skids; n++) 306d4afb5ceSopenharmony_ci cx->system_ops->jit_trust_query(cx, jci.skids[n].kid, 307d4afb5ceSopenharmony_ci (size_t)jci.skids[n].kid_len, 308d4afb5ceSopenharmony_ci (void *)inf); 309d4afb5ceSopenharmony_ci 310d4afb5ceSopenharmony_ci /* ... in case synchronous and it already finished the queries */ 311d4afb5ceSopenharmony_ci 312d4afb5ceSopenharmony_ci *pvh = lws_get_vhost_by_name(cx, vhtag); 313d4afb5ceSopenharmony_ci if (*pvh) { 314d4afb5ceSopenharmony_ci /* hit, let's just use that then */ 315d4afb5ceSopenharmony_ci lwsl_info("%s: bind to created vhost %s\n", __func__, vhtag); 316d4afb5ceSopenharmony_ci return 0; 317d4afb5ceSopenharmony_ci } else 318d4afb5ceSopenharmony_ci lwsl_err("%s: unable to bind to %s\n", __func__, vhtag); 319d4afb5ceSopenharmony_ci 320d4afb5ceSopenharmony_ci /* right now, nothing to offer */ 321d4afb5ceSopenharmony_ci 322d4afb5ceSopenharmony_ci return 1; 323d4afb5ceSopenharmony_ci} 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_civoid 326d4afb5ceSopenharmony_cilws_tls_jit_trust_inflight_destroy(lws_tls_jit_inflight_t *inf) 327d4afb5ceSopenharmony_ci{ 328d4afb5ceSopenharmony_ci int n; 329d4afb5ceSopenharmony_ci 330d4afb5ceSopenharmony_ci for (n = 0; n < inf->ders; n++) 331d4afb5ceSopenharmony_ci lws_free_set_NULL(inf->der[n]); 332d4afb5ceSopenharmony_ci lws_dll2_remove(&inf->list); 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci lws_free(inf); 335d4afb5ceSopenharmony_ci} 336d4afb5ceSopenharmony_ci 337d4afb5ceSopenharmony_cistatic int 338d4afb5ceSopenharmony_ciinflight_destroy(struct lws_dll2 *d, void *user) 339d4afb5ceSopenharmony_ci{ 340d4afb5ceSopenharmony_ci lws_tls_jit_inflight_t *inf; 341d4afb5ceSopenharmony_ci 342d4afb5ceSopenharmony_ci inf = lws_container_of(d, lws_tls_jit_inflight_t, list); 343d4afb5ceSopenharmony_ci 344d4afb5ceSopenharmony_ci lws_tls_jit_trust_inflight_destroy(inf); 345d4afb5ceSopenharmony_ci 346d4afb5ceSopenharmony_ci return 0; 347d4afb5ceSopenharmony_ci} 348d4afb5ceSopenharmony_ci 349d4afb5ceSopenharmony_civoid 350d4afb5ceSopenharmony_cilws_tls_jit_trust_inflight_destroy_all(struct lws_context *cx) 351d4afb5ceSopenharmony_ci{ 352d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&cx->jit_inflight, cx, inflight_destroy); 353d4afb5ceSopenharmony_ci} 354d4afb5ceSopenharmony_ci 355d4afb5ceSopenharmony_cistatic void 356d4afb5ceSopenharmony_ciunref_vh_grace_cb(lws_sorted_usec_list_t *sul) 357d4afb5ceSopenharmony_ci{ 358d4afb5ceSopenharmony_ci struct lws_vhost *vh = lws_container_of(sul, struct lws_vhost, 359d4afb5ceSopenharmony_ci sul_unref); 360d4afb5ceSopenharmony_ci 361d4afb5ceSopenharmony_ci lwsl_info("%s: %s\n", __func__, vh->lc.gutag); 362d4afb5ceSopenharmony_ci 363d4afb5ceSopenharmony_ci lws_vhost_destroy(vh); 364d4afb5ceSopenharmony_ci} 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_civoid 367d4afb5ceSopenharmony_cilws_tls_jit_trust_vh_start_grace(struct lws_vhost *vh) 368d4afb5ceSopenharmony_ci{ 369d4afb5ceSopenharmony_ci lwsl_info("%s: %s: unused, grace %dms\n", __func__, vh->lc.gutag, 370d4afb5ceSopenharmony_ci vh->context->vh_idle_grace_ms); 371d4afb5ceSopenharmony_ci lws_sul_schedule(vh->context, 0, &vh->sul_unref, unref_vh_grace_cb, 372d4afb5ceSopenharmony_ci (lws_usec_t)vh->context->vh_idle_grace_ms * 373d4afb5ceSopenharmony_ci LWS_US_PER_MS); 374d4afb5ceSopenharmony_ci} 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci#if defined(_DEBUG) 377d4afb5ceSopenharmony_cistatic void 378d4afb5ceSopenharmony_cilws_tls_jit_trust_cert_info(const uint8_t *der, size_t der_len) 379d4afb5ceSopenharmony_ci{ 380d4afb5ceSopenharmony_ci struct lws_x509_cert *x; 381d4afb5ceSopenharmony_ci union lws_tls_cert_info_results *u; 382d4afb5ceSopenharmony_ci char p = 0, buf[192 + sizeof(*u)]; 383d4afb5ceSopenharmony_ci 384d4afb5ceSopenharmony_ci if (lws_x509_create(&x)) 385d4afb5ceSopenharmony_ci return; 386d4afb5ceSopenharmony_ci 387d4afb5ceSopenharmony_ci if (!lws_x509_parse_from_pem(x, der, der_len)) { 388d4afb5ceSopenharmony_ci 389d4afb5ceSopenharmony_ci u = (union lws_tls_cert_info_results *)buf; 390d4afb5ceSopenharmony_ci 391d4afb5ceSopenharmony_ci if (!lws_x509_info(x, LWS_TLS_CERT_INFO_ISSUER_NAME, u, 192)) { 392d4afb5ceSopenharmony_ci lwsl_info("ISS: %s\n", u->ns.name); 393d4afb5ceSopenharmony_ci p = 1; 394d4afb5ceSopenharmony_ci } 395d4afb5ceSopenharmony_ci if (!lws_x509_info(x, LWS_TLS_CERT_INFO_COMMON_NAME, u, 192)) { 396d4afb5ceSopenharmony_ci lwsl_info("CN: %s\n", u->ns.name); 397d4afb5ceSopenharmony_ci p = 1; 398d4afb5ceSopenharmony_ci } 399d4afb5ceSopenharmony_ci 400d4afb5ceSopenharmony_ci if (!p) { 401d4afb5ceSopenharmony_ci lwsl_err("%s: unable to get any info\n", __func__); 402d4afb5ceSopenharmony_ci lwsl_hexdump_err(der, der_len); 403d4afb5ceSopenharmony_ci } 404d4afb5ceSopenharmony_ci } else 405d4afb5ceSopenharmony_ci lwsl_err("%s: unable to load DER\n", __func__); 406d4afb5ceSopenharmony_ci 407d4afb5ceSopenharmony_ci lws_x509_destroy(&x); 408d4afb5ceSopenharmony_ci} 409d4afb5ceSopenharmony_ci#endif 410d4afb5ceSopenharmony_ci 411d4afb5ceSopenharmony_ci/* 412d4afb5ceSopenharmony_ci * This processes the JIT Trust lookup results independent of the tls backend. 413d4afb5ceSopenharmony_ci */ 414d4afb5ceSopenharmony_ci 415d4afb5ceSopenharmony_ciint 416d4afb5ceSopenharmony_cilws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque, 417d4afb5ceSopenharmony_ci const uint8_t *skid, size_t skid_len, 418d4afb5ceSopenharmony_ci const uint8_t *der, size_t der_len) 419d4afb5ceSopenharmony_ci{ 420d4afb5ceSopenharmony_ci lws_tls_jit_inflight_t *inf = (lws_tls_jit_inflight_t *)got_opaque; 421d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 422d4afb5ceSopenharmony_ci lws_tls_jit_cache_item_t jci; 423d4afb5ceSopenharmony_ci struct lws_vhost *v; 424d4afb5ceSopenharmony_ci char vhtag[20]; 425d4afb5ceSopenharmony_ci char hit = 0; 426d4afb5ceSopenharmony_ci int n; 427d4afb5ceSopenharmony_ci 428d4afb5ceSopenharmony_ci /* 429d4afb5ceSopenharmony_ci * Before anything else, check the inf is still valid. In the low 430d4afb5ceSopenharmony_ci * probability but possible case it was reallocated to be a different 431d4afb5ceSopenharmony_ci * inflight, that may cause different CA certs to apply to a connection, 432d4afb5ceSopenharmony_ci * but since mbedtls will then validate the server cert using the wrong 433d4afb5ceSopenharmony_ci * trusted CA, it will just cause temporary conn fail. 434d4afb5ceSopenharmony_ci */ 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, e, cx->jit_inflight.head) { 437d4afb5ceSopenharmony_ci lws_tls_jit_inflight_t *i = lws_container_of(e, 438d4afb5ceSopenharmony_ci lws_tls_jit_inflight_t, list); 439d4afb5ceSopenharmony_ci if (i == inf) { 440d4afb5ceSopenharmony_ci hit = 1; 441d4afb5ceSopenharmony_ci break; 442d4afb5ceSopenharmony_ci } 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_ci } lws_end_foreach_dll(e); 445d4afb5ceSopenharmony_ci 446d4afb5ceSopenharmony_ci if (!hit) 447d4afb5ceSopenharmony_ci /* inf has already gone */ 448d4afb5ceSopenharmony_ci return 1; 449d4afb5ceSopenharmony_ci 450d4afb5ceSopenharmony_ci inf->refcount--; 451d4afb5ceSopenharmony_ci 452d4afb5ceSopenharmony_ci if (skid_len >= 4) 453d4afb5ceSopenharmony_ci inf->tag ^= *((uint32_t *)skid); 454d4afb5ceSopenharmony_ci 455d4afb5ceSopenharmony_ci if (der && inf->ders < (int)LWS_ARRAY_SIZE(inf->der) && inf->refcount) { 456d4afb5ceSopenharmony_ci /* 457d4afb5ceSopenharmony_ci * We have a trusted CA, but more results coming... stash it 458d4afb5ceSopenharmony_ci * in heap. 459d4afb5ceSopenharmony_ci */ 460d4afb5ceSopenharmony_ci 461d4afb5ceSopenharmony_ci inf->kid[inf->ders].kid_len = (uint8_t)((skid_len > 462d4afb5ceSopenharmony_ci (uint8_t)sizeof(inf->kid[inf->ders].kid)) ? 463d4afb5ceSopenharmony_ci sizeof(inf->kid[inf->ders].kid) : skid_len); 464d4afb5ceSopenharmony_ci memcpy(inf->kid[inf->ders].kid, skid, 465d4afb5ceSopenharmony_ci inf->kid[inf->ders].kid_len); 466d4afb5ceSopenharmony_ci 467d4afb5ceSopenharmony_ci inf->der[inf->ders] = lws_malloc(der_len, __func__); 468d4afb5ceSopenharmony_ci if (!inf->der[inf->ders]) 469d4afb5ceSopenharmony_ci return 1; 470d4afb5ceSopenharmony_ci memcpy(inf->der[inf->ders], der, der_len); 471d4afb5ceSopenharmony_ci inf->der_len[inf->ders] = (short)der_len; 472d4afb5ceSopenharmony_ci inf->ders++; 473d4afb5ceSopenharmony_ci 474d4afb5ceSopenharmony_ci return 0; 475d4afb5ceSopenharmony_ci } 476d4afb5ceSopenharmony_ci 477d4afb5ceSopenharmony_ci /* 478d4afb5ceSopenharmony_ci * We accept up to three valid CA, and then end the inflight early. 479d4afb5ceSopenharmony_ci * Any further pending results are dropped, since we got all we could 480d4afb5ceSopenharmony_ci * use. Up to two valid CA would be held in the inflight and the other 481d4afb5ceSopenharmony_ci * provided in the params. 482d4afb5ceSopenharmony_ci * 483d4afb5ceSopenharmony_ci * If we did not already fill up the inflight, keep waiting for any 484d4afb5ceSopenharmony_ci * others expected 485d4afb5ceSopenharmony_ci */ 486d4afb5ceSopenharmony_ci 487d4afb5ceSopenharmony_ci if (inf->refcount && inf->ders < (int)LWS_ARRAY_SIZE(inf->der)) 488d4afb5ceSopenharmony_ci return 0; 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_ci if (!der && !inf->ders) { 491d4afb5ceSopenharmony_ci lwsl_warn("%s: no trusted CA certs matching\n", __func__); 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci goto destroy_inf; 494d4afb5ceSopenharmony_ci } 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_ci tag_to_vh_name(vhtag, sizeof(vhtag), inf->tag); 497d4afb5ceSopenharmony_ci 498d4afb5ceSopenharmony_ci /* 499d4afb5ceSopenharmony_ci * We have got at least one CA, it's all the CAs we're going to get, 500d4afb5ceSopenharmony_ci * or that we can handle. So we have to process and drop the inf. 501d4afb5ceSopenharmony_ci * 502d4afb5ceSopenharmony_ci * First let's make a cache entry with a shortish ttl, mapping the 503d4afb5ceSopenharmony_ci * hostname we were trying to connect to, to the SKIDs that actually 504d4afb5ceSopenharmony_ci * had trust results. This may come in handy later when we want to 505d4afb5ceSopenharmony_ci * connect to the same host again, but any vhost from before has been 506d4afb5ceSopenharmony_ci * removed... we can just ask for the specific CAs to regenerate the 507d4afb5ceSopenharmony_ci * vhost, without having to first fail the connection attempt to get the 508d4afb5ceSopenharmony_ci * server cert. 509d4afb5ceSopenharmony_ci * 510d4afb5ceSopenharmony_ci * The cache entry can be evicted at any time, so it is selfcontained. 511d4afb5ceSopenharmony_ci * If it's also lost, we start over with the initial failing connection 512d4afb5ceSopenharmony_ci * to figure out what we need to make it work. 513d4afb5ceSopenharmony_ci */ 514d4afb5ceSopenharmony_ci 515d4afb5ceSopenharmony_ci memset(&jci, 0, sizeof(jci)); 516d4afb5ceSopenharmony_ci 517d4afb5ceSopenharmony_ci jci.xor_tag = inf->tag; 518d4afb5ceSopenharmony_ci 519d4afb5ceSopenharmony_ci /* copy the SKIDs from the inflight and params into the cache item */ 520d4afb5ceSopenharmony_ci 521d4afb5ceSopenharmony_ci for (n = 0; n < (int)LWS_ARRAY_SIZE(inf->der); n++) 522d4afb5ceSopenharmony_ci if (inf->kid[n].kid_len) 523d4afb5ceSopenharmony_ci lws_tls_kid_copy_kid(&jci.skids[jci.count_skids++], 524d4afb5ceSopenharmony_ci &inf->kid[n]); 525d4afb5ceSopenharmony_ci 526d4afb5ceSopenharmony_ci if (skid_len) { 527d4afb5ceSopenharmony_ci if (skid_len > sizeof(inf->kid[0].kid)) 528d4afb5ceSopenharmony_ci skid_len = sizeof(inf->kid[0].kid); 529d4afb5ceSopenharmony_ci jci.skids[jci.count_skids].kid_len = (uint8_t)skid_len; 530d4afb5ceSopenharmony_ci memcpy(jci.skids[jci.count_skids++].kid, skid, skid_len); 531d4afb5ceSopenharmony_ci } 532d4afb5ceSopenharmony_ci 533d4afb5ceSopenharmony_ci lwsl_info("%s: adding cache mapping %s -> %s\n", __func__, 534d4afb5ceSopenharmony_ci (const char *)&inf[1], vhtag); 535d4afb5ceSopenharmony_ci 536d4afb5ceSopenharmony_ci if (lws_cache_write_through(cx->trust_cache, (const char *)&inf[1], 537d4afb5ceSopenharmony_ci (const uint8_t *)&jci, sizeof(jci), 538d4afb5ceSopenharmony_ci lws_now_usecs() + (3600ll *LWS_US_PER_SEC), 539d4afb5ceSopenharmony_ci NULL)) 540d4afb5ceSopenharmony_ci lwsl_warn("%s: add to cache failed\n", __func__); 541d4afb5ceSopenharmony_ci 542d4afb5ceSopenharmony_ci /* is there already a vhost for this commutative-xor SKID trust? */ 543d4afb5ceSopenharmony_ci 544d4afb5ceSopenharmony_ci if (lws_get_vhost_by_name(cx, vhtag)) { 545d4afb5ceSopenharmony_ci lwsl_info("%s: tag vhost %s already exists, skipping\n", 546d4afb5ceSopenharmony_ci __func__, vhtag); 547d4afb5ceSopenharmony_ci goto destroy_inf; 548d4afb5ceSopenharmony_ci } 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci /* 551d4afb5ceSopenharmony_ci * We only end up here when we attempted a connection to this hostname. 552d4afb5ceSopenharmony_ci * 553d4afb5ceSopenharmony_ci * We have the identified CA trust DER(s) to hand, let's create the 554d4afb5ceSopenharmony_ci * necessary vhost + prepared SSL_CTX for it to use on the retry, it 555d4afb5ceSopenharmony_ci * will be used straight away if the retry comes before the idle vhost 556d4afb5ceSopenharmony_ci * timeout. 557d4afb5ceSopenharmony_ci * 558d4afb5ceSopenharmony_ci * We also use this path in the case we have the cache entry but no 559d4afb5ceSopenharmony_ci * matching vhost already existing, to create one. 560d4afb5ceSopenharmony_ci */ 561d4afb5ceSopenharmony_ci 562d4afb5ceSopenharmony_ci memset(&info, 0, sizeof(info)); 563d4afb5ceSopenharmony_ci info.vhost_name = vhtag; 564d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; 565d4afb5ceSopenharmony_ci info.options = cx->options; 566d4afb5ceSopenharmony_ci 567d4afb5ceSopenharmony_ci /* 568d4afb5ceSopenharmony_ci * We have to create the vhost with the first valid trusted DER... 569d4afb5ceSopenharmony_ci * if we have a params one, use that so the rest are all from inflight 570d4afb5ceSopenharmony_ci */ 571d4afb5ceSopenharmony_ci 572d4afb5ceSopenharmony_ci if (der) { 573d4afb5ceSopenharmony_ci info.client_ssl_ca_mem = der; 574d4afb5ceSopenharmony_ci info.client_ssl_ca_mem_len = (unsigned int)der_len; 575d4afb5ceSopenharmony_ci n = 0; 576d4afb5ceSopenharmony_ci } else { 577d4afb5ceSopenharmony_ci info.client_ssl_ca_mem = inf->der[0]; 578d4afb5ceSopenharmony_ci info.client_ssl_ca_mem_len = (unsigned int)inf->der_len[0]; 579d4afb5ceSopenharmony_ci n = 1; 580d4afb5ceSopenharmony_ci } 581d4afb5ceSopenharmony_ci 582d4afb5ceSopenharmony_ci#if defined(_DEBUG) 583d4afb5ceSopenharmony_ci lws_tls_jit_trust_cert_info(info.client_ssl_ca_mem, 584d4afb5ceSopenharmony_ci info.client_ssl_ca_mem_len); 585d4afb5ceSopenharmony_ci#endif 586d4afb5ceSopenharmony_ci 587d4afb5ceSopenharmony_ci info.protocols = cx->protocols_copy; 588d4afb5ceSopenharmony_ci 589d4afb5ceSopenharmony_ci v = lws_create_vhost(cx, &info); 590d4afb5ceSopenharmony_ci if (!v) 591d4afb5ceSopenharmony_ci lwsl_err("%s: failed to create vh %s\n", __func__, vhtag); 592d4afb5ceSopenharmony_ci 593d4afb5ceSopenharmony_ci v->grace_after_unref = 1; 594d4afb5ceSopenharmony_ci lws_tls_jit_trust_vh_start_grace(v); 595d4afb5ceSopenharmony_ci 596d4afb5ceSopenharmony_ci /* 597d4afb5ceSopenharmony_ci * Do we need to add more trusted certs from inflight? 598d4afb5ceSopenharmony_ci */ 599d4afb5ceSopenharmony_ci 600d4afb5ceSopenharmony_ci while (n < inf->ders) { 601d4afb5ceSopenharmony_ci 602d4afb5ceSopenharmony_ci#if defined(_DEBUG) 603d4afb5ceSopenharmony_ci lws_tls_jit_trust_cert_info(inf->der[n], 604d4afb5ceSopenharmony_ci (size_t)inf->der_len[n]); 605d4afb5ceSopenharmony_ci#endif 606d4afb5ceSopenharmony_ci 607d4afb5ceSopenharmony_ci if (lws_tls_client_vhost_extra_cert_mem(v, inf->der[n], 608d4afb5ceSopenharmony_ci (size_t)inf->der_len[n])) 609d4afb5ceSopenharmony_ci lwsl_err("%s: add extra cert failed\n", __func__); 610d4afb5ceSopenharmony_ci n++; 611d4afb5ceSopenharmony_ci } 612d4afb5ceSopenharmony_ci 613d4afb5ceSopenharmony_ci lwsl_info("%s: created jitt %s -> vh %s\n", __func__, 614d4afb5ceSopenharmony_ci (const char *)&inf[1], vhtag); 615d4afb5ceSopenharmony_ci 616d4afb5ceSopenharmony_cidestroy_inf: 617d4afb5ceSopenharmony_ci lws_tls_jit_trust_inflight_destroy(inf); 618d4afb5ceSopenharmony_ci 619d4afb5ceSopenharmony_ci return 0; 620d4afb5ceSopenharmony_ci} 621d4afb5ceSopenharmony_ci 622d4afb5ceSopenharmony_ci/* 623d4afb5ceSopenharmony_ci * Refer to ./READMEs/README.jit-trust.md for blob layout specification 624d4afb5ceSopenharmony_ci */ 625d4afb5ceSopenharmony_ci 626d4afb5ceSopenharmony_ciint 627d4afb5ceSopenharmony_cilws_tls_jit_trust_blob_queury_skid(const void *_blob, size_t blen, 628d4afb5ceSopenharmony_ci const uint8_t *skid, size_t skid_len, 629d4afb5ceSopenharmony_ci const uint8_t **prpder, size_t *prder_len) 630d4afb5ceSopenharmony_ci{ 631d4afb5ceSopenharmony_ci const uint8_t *pskidlen, *pskids, *pder, *blob = (uint8_t *)_blob; 632d4afb5ceSopenharmony_ci const uint16_t *pderlen; 633d4afb5ceSopenharmony_ci int certs; 634d4afb5ceSopenharmony_ci 635d4afb5ceSopenharmony_ci /* sanity check blob length and magic */ 636d4afb5ceSopenharmony_ci 637d4afb5ceSopenharmony_ci if (blen < 32768 || 638d4afb5ceSopenharmony_ci lws_ser_ru32be(blob) != LWS_JIT_TRUST_MAGIC_BE || 639d4afb5ceSopenharmony_ci lws_ser_ru32be(blob + LJT_OFS_END) != blen) { 640d4afb5ceSopenharmony_ci lwsl_err("%s: blob not sane\n", __func__); 641d4afb5ceSopenharmony_ci 642d4afb5ceSopenharmony_ci return -1; 643d4afb5ceSopenharmony_ci } 644d4afb5ceSopenharmony_ci 645d4afb5ceSopenharmony_ci if (!skid_len) 646d4afb5ceSopenharmony_ci return 1; 647d4afb5ceSopenharmony_ci 648d4afb5ceSopenharmony_ci /* point into the various sub-tables */ 649d4afb5ceSopenharmony_ci 650d4afb5ceSopenharmony_ci certs = (int)lws_ser_ru16be(blob + LJT_OFS_32_COUNT_CERTS); 651d4afb5ceSopenharmony_ci 652d4afb5ceSopenharmony_ci pderlen = (uint16_t *)(blob + lws_ser_ru32be(blob + 653d4afb5ceSopenharmony_ci LJT_OFS_32_DERLEN)); 654d4afb5ceSopenharmony_ci pskidlen = blob + lws_ser_ru32be(blob + LJT_OFS_32_SKIDLEN); 655d4afb5ceSopenharmony_ci pskids = blob + lws_ser_ru32be(blob + LJT_OFS_32_SKID); 656d4afb5ceSopenharmony_ci pder = blob + LJT_OFS_DER; 657d4afb5ceSopenharmony_ci 658d4afb5ceSopenharmony_ci /* check each cert SKID in turn, return the DER if found */ 659d4afb5ceSopenharmony_ci 660d4afb5ceSopenharmony_ci while (certs--) { 661d4afb5ceSopenharmony_ci 662d4afb5ceSopenharmony_ci /* paranoia / sanity */ 663d4afb5ceSopenharmony_ci 664d4afb5ceSopenharmony_ci assert(pskids < blob + blen); 665d4afb5ceSopenharmony_ci assert(pder < blob + blen); 666d4afb5ceSopenharmony_ci assert(pskidlen < blob + blen); 667d4afb5ceSopenharmony_ci assert((uint8_t *)pderlen < blob + blen); 668d4afb5ceSopenharmony_ci 669d4afb5ceSopenharmony_ci /* we will accept to match on truncated SKIDs */ 670d4afb5ceSopenharmony_ci 671d4afb5ceSopenharmony_ci if (*pskidlen >= skid_len && 672d4afb5ceSopenharmony_ci !memcmp(skid, pskids, skid_len)) { 673d4afb5ceSopenharmony_ci /* 674d4afb5ceSopenharmony_ci * We found a trusted CA cert of the right SKID 675d4afb5ceSopenharmony_ci */ 676d4afb5ceSopenharmony_ci *prpder = pder; 677d4afb5ceSopenharmony_ci *prder_len = lws_ser_ru16be((uint8_t *)pderlen); 678d4afb5ceSopenharmony_ci 679d4afb5ceSopenharmony_ci return 0; 680d4afb5ceSopenharmony_ci } 681d4afb5ceSopenharmony_ci 682d4afb5ceSopenharmony_ci pder += lws_ser_ru16be((uint8_t *)pderlen); 683d4afb5ceSopenharmony_ci pskids += *pskidlen; 684d4afb5ceSopenharmony_ci pderlen++; 685d4afb5ceSopenharmony_ci pskidlen++; 686d4afb5ceSopenharmony_ci } 687d4afb5ceSopenharmony_ci 688d4afb5ceSopenharmony_ci return 1; 689d4afb5ceSopenharmony_ci} 690