Skip to content

Commit f190a04

Browse files
authored
quic: send correct OpenSSL alert for ALPN mismatches
Signed-off-by: Tim Perry <pimterry@gmail.com> PR-URL: #63193 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 274d799 commit f190a04

2 files changed

Lines changed: 19 additions & 15 deletions

File tree

src/quic/tlscontext.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ int TLSContext::OnSelectAlpn(SSL* ssl,
338338
in,
339339
inlen) == OPENSSL_NPN_NO_OVERLAP) {
340340
Debug(&tls_session.session(), "ALPN negotiation failed");
341-
return SSL_TLSEXT_ERR_NOACK;
341+
return SSL_TLSEXT_ERR_ALERT_FATAL;
342342
}
343343

344344
// ALPN negotiated successfully. *out/*outlen point to the selected

test/parallel/test-quic-alpn-mismatch.mjs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,39 @@
22

33
// Test: ALPN mismatch causes connection failure.
44
// The server offers 'quic-test' but the client requests 'nonexistent'.
5-
// The handshake should fail.
5+
// The handshake should fail with a `no_application_protocol` alert.
6+
//
7+
// The QUIC transport error code for a CRYPTO_ERROR carrying a TLS alert is
8+
// 0x100 | <tls_alert>. For `no_application_protocol` (alert 120 / 0x78) this
9+
// is 0x178 == 376. ERR_QUIC_TRANSPORT_ERROR formats the wire code into its
10+
// message as a bigint, so we match `376n` to assert the specific alert was
11+
// sent rather than some other handshake failure.
612

713
import { hasQuic, skip, mustCall } from '../common/index.mjs';
814
import assert from 'node:assert';
915

10-
const { rejects, strictEqual } = assert;
16+
const { rejects, strictEqual, match } = assert;
1117

1218
if (!hasQuic) {
1319
skip('QUIC is not enabled');
1420
}
1521

1622
const { listen, connect } = await import('../common/quic.mjs');
1723

24+
const expected = {
25+
code: 'ERR_QUIC_TRANSPORT_ERROR',
26+
message: /\b376n\b/,
27+
};
28+
1829
const onerror = mustCall((err) => {
1930
strictEqual(err.code, 'ERR_QUIC_TRANSPORT_ERROR');
31+
match(err.message, /\b376n\b/);
2032
}, 2);
2133
const transportParams = { maxIdleTimeout: 1 };
2234

2335
const serverEndpoint = await listen(mustCall(async (serverSession) => {
24-
await rejects(serverSession.opened, {
25-
code: 'ERR_QUIC_TRANSPORT_ERROR',
26-
});
27-
await rejects(serverSession.closed, {
28-
code: 'ERR_QUIC_TRANSPORT_ERROR',
29-
});
36+
await rejects(serverSession.opened, expected);
37+
await rejects(serverSession.closed, expected);
3038
}), {
3139
transportParams,
3240
onerror,
@@ -39,12 +47,8 @@ const clientSession = await connect(serverEndpoint.address, {
3947
onerror,
4048
});
4149

42-
await rejects(clientSession.opened, {
43-
code: 'ERR_QUIC_TRANSPORT_ERROR',
44-
});
50+
await rejects(clientSession.opened, expected);
4551

4652
// The handshake should fail — opened may reject or never resolve.
4753
// The session should close with an error.
48-
await rejects(clientSession.closed, {
49-
code: 'ERR_QUIC_TRANSPORT_ERROR',
50-
});
54+
await rejects(clientSession.closed, expected);

0 commit comments

Comments
 (0)