Skip to content

Commit d56159a

Browse files
committed
sso
1 parent 633463f commit d56159a

24 files changed

Lines changed: 1278 additions & 108 deletions

File tree

lib/roles/pipe/ops-pipe.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,17 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
5252
*/
5353
n = (int)read(wsi->desc.sockfd, s, sizeof(s));
5454
(void)n;
55-
if (n <= 0)
55+
/*
56+
* Only treat a real read error as a reason to close the pipe wsi.
57+
* read() returning 0 happens when the context is tearing down (the
58+
* write end is going away); closing the pipe wsi from inside its own
59+
* POLLIN handler during context destroy frees it out from under the
60+
* service loop that is still iterating on it, observed as a segfault
61+
* during lws_context_destroy() on libuv / distro-recommended builds.
62+
* The pipe is owned by the context and is explicitly closed as part
63+
* of normal pt destroy, so it does not need our help here.
64+
*/
65+
if (n < 0)
5666
return LWS_HPI_RET_PLEASE_CLOSE_ME;
5767
#elif defined(WIN32)
5868
char s[100];

lib/roles/quic/crypto-quic.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -946,19 +946,6 @@ lws_tls_quic_rx_crypto(struct lws *wsi, int level, const uint8_t *buf, size_t le
946946

947947
wsi->quic.qn->handshake_done = 1;
948948

949-
/*
950-
* If the client deferred its preferred_address migration until
951-
* the handshake was complete, execute it now: both sides have
952-
* APP keys so the PATH_CHALLENGE/RESPONSE will succeed.
953-
*/
954-
if (!wsi->quic.qn->is_server && wsi->quic.qn->prefaddr_pending) {
955-
wsi->quic.qn->prefaddr_pending = 0;
956-
lws_quic_client_probe_preferred_address(wsi,
957-
&wsi->quic.qn->probing_sa46,
958-
&wsi->quic.qn->prefaddr_rem_cid,
959-
wsi->quic.qn->prefaddr_rem_token);
960-
}
961-
962949
if (wsi->quic.qn->is_server) {
963950
struct lws_quic_tx_frame *f_hd = lws_zalloc(sizeof(*f_hd), "HANDSHAKE_DONE");
964951
if (f_hd) {

lib/roles/quic/ops-quic.c

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -149,22 +149,19 @@ lws_quic_client_probe_preferred_address(struct lws *nwsi,
149149
if (qn->is_server)
150150
return 1;
151151

152-
/* Save the migration parameters */
153-
qn->prefaddr_original_sa46 = nwsi->udp->sa46;
154-
qn->prefaddr_original_rem_cid = qn->rem_cid;
152+
/* Save the migration parameters for later */
155153
qn->probing_sa46 = *pref_sa46;
156-
qn->probing_sa46_valid = 1;
157154
if (pref_cid) {
158155
qn->prefaddr_rem_cid = *pref_cid;
159156
if (pref_token)
160157
memcpy(qn->prefaddr_rem_token, pref_token, 16);
161158
}
162159

163160
/*
164-
* Defer the actual socket swap + DCID change until the handshake is
165-
* complete: the preferred_address TP arrives during the handshake, and
166-
* swapping before both sides have APP keys strands the migration (the
167-
* server can't decrypt APP-level packets from the new source port).
161+
* Defer the actual socket swap + DCID change until the server confirms
162+
* handshake completion via HANDSHAKE_DONE. The preferred_address TP
163+
* arrives during the handshake; swapping before both sides have APP
164+
* keys strands the migration.
168165
*/
169166
if (!qn->handshake_done) {
170167
qn->prefaddr_pending = 1;
@@ -1272,7 +1269,9 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
12721269

12731270
/* F-57: Validate short header DCID */
12741271
if (!(p[0] & 0x80) && nwsi && nwsi->quic.qn && nwsi->quic.qn->loc_cid.len) {
1275-
if (local_dcid_len > (size_t)n - 1 || memcmp(&p[1], nwsi->quic.qn->loc_cid.id, local_dcid_len)) {
1272+
if (local_dcid_len > (size_t)n - 1 ||
1273+
(memcmp(&p[1], nwsi->quic.qn->loc_cid.id, local_dcid_len) &&
1274+
memcmp(&p[1], nwsi->quic.qn->prefaddr_rem_cid.id, local_dcid_len))) {
12761275
lwsl_wsi_notice(wsi, "QUIC RX: Short header DCID mismatch");
12771276
/* Drop packet */
12781277
p += packet_size;
@@ -1501,19 +1500,6 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
15011500
nwsi->quic.qn->probing_sa46 = migration_sa46;
15021501
nwsi->quic.qn->probing_sa46_valid = 1;
15031502

1504-
{
1505-
int _li;
1506-
for (_li = 0; _li <= LWS_QUIC_LEVEL_HANDSHAKE; _li++) {
1507-
lws_start_foreach_dll_safe(struct lws_dll2 *, _d, _d1,
1508-
nwsi->quic.qn->pending_tx[_li].head) {
1509-
struct lws_quic_tx_frame *_f = lws_container_of(_d,
1510-
struct lws_quic_tx_frame, list);
1511-
lws_dll2_remove(&_f->list);
1512-
lws_free(_f);
1513-
} lws_end_foreach_dll_safe(_d, _d1);
1514-
}
1515-
}
1516-
15171503
if (!nwsi->quic.qn->path_challenge_pending) {
15181504
struct lws_quic_tx_frame *f_pc =
15191505
lws_zalloc(sizeof(*f_pc) + 8,
@@ -1609,19 +1595,37 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
16091595
}
16101596

16111597
int parse_res = lws_quic_parse_frames(nwsi, pn_space, &p[pn_offset + (size_t)pn_len], (size_t)dec_len, &sa46);
1612-
1598+
16131599
/* ALPN negotiation might have migrated the network WSI! */
16141600
if (nwsi && !nwsi->quic.qn) {
16151601
nwsi = lws_get_quic_network_wsi(nwsi);
16161602
}
16171603

1604+
/*
1605+
* After frame parsing may have generated Handshake-level
1606+
* ACKs, discard any pending Initial/Handshake TX so those
1607+
* ACKs don't race ahead of PATH_CHALLENGE to the new path.
1608+
* The handshake is done; only APP-level frames (including
1609+
* PATH_CHALLENGE) should reach the new client port.
1610+
*/
1611+
if (nwsi && nwsi->quic.qn && nwsi->quic.qn->probing_sa46_valid &&
1612+
nwsi->quic.qn->handshake_done) {
1613+
int _li;
1614+
for (_li = 0; _li <= LWS_QUIC_LEVEL_HANDSHAKE; _li++) {
1615+
lws_start_foreach_dll_safe(struct lws_dll2 *, _d, _d1,
1616+
nwsi->quic.qn->pending_tx[_li].head) {
1617+
struct lws_quic_tx_frame *_f = lws_container_of(_d,
1618+
struct lws_quic_tx_frame, list);
1619+
lws_dll2_remove(&_f->list);
1620+
lws_free(_f);
1621+
} lws_end_foreach_dll_safe(_d, _d1);
1622+
}
1623+
}
1624+
16181625
/*
16191626
* The server commits the new path ONLY on PATH_RESPONSE
16201627
* validation (handled in parse-quic.c). Do NOT commit
1621-
* here on non-probing packets: doing so would make the
1622-
* first server datagram to the new client port be a
1623-
* regular ACK/STREAM frame instead of the PATH_CHALLENGE
1624-
* that QIR connectionmigration requires.
1628+
* here on non-probing packets.
16251629
*/
16261630

16271631
if (nwsi) {

lib/roles/quic/parse-quic.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,17 @@ lws_quic_parse_frames(struct lws *nwsi, int level, uint8_t *payload, size_t payl
11041104
return -1;
11051105
} else {
11061106
lws_quic_discard_keys(nwsi, LWS_QUIC_LEVEL_HANDSHAKE);
1107+
1108+
/*
1109+
* Now that the server confirmed handshake completion,
1110+
* both sides have APP keys — safe to execute a deferred
1111+
* preferred_address migration.
1112+
*/
1113+
if (nwsi->quic.qn && nwsi->quic.qn->prefaddr_pending)
1114+
lws_quic_client_probe_preferred_address(nwsi,
1115+
&nwsi->quic.qn->probing_sa46,
1116+
&nwsi->quic.qn->prefaddr_rem_cid,
1117+
nwsi->quic.qn->prefaddr_rem_token);
11071118
}
11081119
break;
11091120

lib/tls/schannel/schannel-quic.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,13 +535,22 @@ lws_tls_quic_advance_handshake(struct lws *wsi, int level,
535535
* hands us the symmetric algorithm and key size directly;
536536
* it does not currently negotiate ChaCha20-Poly1305, but
537537
* map it too for completeness.
538+
*
539+
* SEC_TRAFFIC_SECRETS.KeySize is the symmetric key size
540+
* in BYTES (matching msquic's QuicParseTrafficSecrets,
541+
* which switches on 16 / 32), not bits. The field name
542+
* is fixed by the Windows SDK header; copy it into a
543+
* local whose name carries the units so the comparison
544+
* cannot be misread as bits again.
538545
*/
539546
if (!wcscmp(secrets->SymmetricAlgId, L"CHACHA20_POLY1305"))
540547
wsi->tls.quic_aead = LWS_TLS_QUIC_AEAD_CHACHA20_POLY1305;
541-
else if (!wcscmp(secrets->SymmetricAlgId, L"AES"))
542-
wsi->tls.quic_aead = secrets->KeySize == 256 ?
548+
else if (!wcscmp(secrets->SymmetricAlgId, L"AES")) {
549+
unsigned short key_size_bytes = secrets->KeySize;
550+
wsi->tls.quic_aead = key_size_bytes == 32 ?
543551
LWS_TLS_QUIC_AEAD_AES_256_GCM :
544552
LWS_TLS_QUIC_AEAD_AES_128_GCM;
553+
}
545554

546555
/* SChannel outputs `1` and `2` for BOTH Handshake and Application secrets. */
547556
if (type == 1 || type == 2) {

minimal-examples-lowlevel/api-tests/api-test-secure-streams/CMakeLists.txt

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ require_lws_config(USE_WOLFSSL 0 requirements)
1414
if (requirements)
1515

1616
add_executable(${PROJECT_NAME} main.c)
17-
17+
1818
if (LWS_CTEST_INTERNET_AVAILABLE)
1919
add_test(NAME api-test-secure-streams COMMAND ${PROJECT_NAME})
2020
set_tests_properties(api-test-secure-streams
@@ -23,6 +23,41 @@ if (requirements)
2323
TIMEOUT 90)
2424
endif()
2525

26+
#
27+
# Local-server variant: runs the same test logic against a local
28+
# lws-minimal-http-server-httpbin over TLS, so it does not need any
29+
# external network egress. Suitable for IPv6-only / no-egress CI.
30+
#
31+
32+
if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32 AND LWS_WITH_SERVER)
33+
lws_get_free_port(PORT_ATS_SRV_TLS)
34+
35+
configure_file(policy-local.json.in policy-local.json @ONLY)
36+
37+
add_test(NAME st_ats_hbin
38+
COMMAND ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
39+
ats_hbin $<TARGET_FILE:lws-minimal-http-server-httpbin>
40+
-s -p ${PORT_ATS_SRV_TLS})
41+
add_test(NAME ki_ats_hbin
42+
COMMAND ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
43+
ats_hbin $<TARGET_FILE_NAME:lws-minimal-http-server-httpbin>
44+
-p ${PORT_ATS_SRV_TLS})
45+
set_tests_properties(st_ats_hbin PROPERTIES
46+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples-lowlevel/http-server/minimal-http-server-tls
47+
FIXTURES_SETUP ats_hbin
48+
TIMEOUT 800
49+
ENVIRONMENT "SAI_LIST_PORT=${PORT_ATS_SRV_TLS}")
50+
set_tests_properties(ki_ats_hbin PROPERTIES FIXTURES_CLEANUP ats_hbin)
51+
52+
add_test(NAME api-test-secure-streams-local
53+
COMMAND ${PROJECT_NAME}
54+
-c ${CMAKE_CURRENT_BINARY_DIR}/policy-local.json)
55+
set_tests_properties(api-test-secure-streams-local PROPERTIES
56+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples-lowlevel/api-tests/api-test-secure-streams
57+
FIXTURES_REQUIRED "ats_hbin"
58+
TIMEOUT 90)
59+
endif()
60+
2661
if (websockets_shared)
2762
target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
2863
add_dependencies(${PROJECT_NAME} websockets_shared)

minimal-examples-lowlevel/api-tests/api-test-secure-streams/main.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ static int interrupted, bad = 1;
1717
static lws_state_notify_link_t nl;
1818
static struct lws_context *context;
1919

20+
enum {
21+
LWS_SW_C,
22+
LWS_SW_HELP,
23+
};
24+
25+
static const struct lws_switches switches[] = {
26+
[LWS_SW_C] = { "-c", "Policy JSON filepath" },
27+
[LWS_SW_HELP] = { "--help", "Show this help information" },
28+
};
29+
2030
static const char * const default_ss_policy =
2131
"{"
2232
"\"release\":" "\"01234567\","
@@ -397,8 +407,16 @@ sigint_handler(int sig)
397407
int main(int argc, const char **argv)
398408
{
399409
struct lws_context_creation_info info;
410+
const char *pp;
400411
int n = 0;
401412

413+
(void)switches;
414+
415+
if ((argc == 1) || lws_cmdline_option(argc, argv, switches[LWS_SW_HELP].sw)) {
416+
lws_switches_print_help(argv[0], switches, LWS_ARRAY_SIZE(switches));
417+
return 0;
418+
}
419+
402420
signal(SIGINT, sigint_handler);
403421

404422
lws_context_info_defaults(&info, NULL);lws_cmdline_option_handle_builtin(argc, argv, &info);
@@ -409,7 +427,17 @@ int main(int argc, const char **argv)
409427

410428
info.fd_limit_per_thread = 1 + 6 + 1;
411429
info.port = CONTEXT_PORT_NO_LISTEN;
412-
info.pss_policies_json = default_ss_policy;
430+
431+
/*
432+
* If we're given a policy JSON filepath, use it; otherwise fall back to
433+
* the built-in default policy (which reaches out to libwebsockets.org).
434+
*/
435+
436+
if ((pp = lws_cmdline_option(argc, argv, switches[LWS_SW_C].sw)))
437+
info.pss_policies_json = pp;
438+
else
439+
info.pss_policies_json = default_ss_policy;
440+
413441
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
414442
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
415443
LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"release": "01234567",
3+
"product": "myproduct",
4+
"schema-version": 1,
5+
"retry": [
6+
{
7+
"default": {
8+
"backoff": [ 1000, 2000, 3000, 5000, 10000 ],
9+
"conceal": 5,
10+
"jitterpc": 20,
11+
"svalidping": 30,
12+
"svalidhup": 35
13+
}
14+
}
15+
],
16+
"certs": [
17+
{
18+
"localhost_100y": "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"
19+
}
20+
],
21+
"trust_stores": [
22+
{
23+
"name": "local_test",
24+
"stack": [ "localhost_100y" ]
25+
}
26+
],
27+
"s": [
28+
{
29+
"httpbin_get": {
30+
"endpoint": "@LWS_CTEST_SERVER_RESOLVE@",
31+
"port": @PORT_ATS_SRV_TLS@,
32+
"protocol": "h1",
33+
"http_method": "GET",
34+
"http_url": "/httpbin/bytes/2000",
35+
"tls": true,
36+
"opportunistic": true,
37+
"retry": "default",
38+
"tls_trust_store": "local_test"
39+
}
40+
},
41+
{
42+
"httpbin_get404": {
43+
"endpoint": "@LWS_CTEST_SERVER_RESOLVE@",
44+
"port": @PORT_ATS_SRV_TLS@,
45+
"protocol": "h1",
46+
"http_method": "GET",
47+
"http_url": "/httpbin/status/403",
48+
"tls": true,
49+
"opportunistic": true,
50+
"retry": "default",
51+
"tls_trust_store": "local_test"
52+
}
53+
},
54+
{
55+
"httpbin_post": {
56+
"endpoint": "@LWS_CTEST_SERVER_RESOLVE@",
57+
"port": @PORT_ATS_SRV_TLS@,
58+
"protocol": "h1",
59+
"http_method": "POST",
60+
"http_url": "/httpbin/bytes/2000",
61+
"tls": true,
62+
"opportunistic": true,
63+
"retry": "default",
64+
"tls_trust_store": "local_test"
65+
}
66+
}
67+
]
68+
}

0 commit comments

Comments
 (0)