mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-07 08:33:50 +08:00
Use the default TLS version bound for null minVersion and maxVersion in tls.createServer
tls.createServer validated minVersion and maxVersion with its own loop, which threw ERR_TLS_INVALID_PROTOCOL_VERSION for null. It now uses the same check as tls.connect, where null and undefined select the default bound, as in Node.
This commit is contained in:
@@ -1813,38 +1813,11 @@ static bool scr_tls_opts_validate(const ScrDyn *opts) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static const char *const VERSION_OPTS[] = { "minVersion", "maxVersion", NULL };
|
||||
for (size_t i = 0; VERSION_OPTS[i] != NULL; i++) {
|
||||
const ScrDyn *v = scr_dyn_obj_get(opts, VERSION_OPTS[i], strlen(VERSION_OPTS[i]));
|
||||
if (v == NULL || v->kind == SCR_DYN_UNDEF) continue;
|
||||
bool valid = false;
|
||||
if (v->kind == SCR_DYN_STR) {
|
||||
static const char *const KNOWN[] = { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3", NULL };
|
||||
for (size_t k = 0; KNOWN[k] != NULL; k++) {
|
||||
if (v->v.str->len == strlen(KNOWN[k]) && memcmp(v->v.str->data, KNOWN[k], v->v.str->len) == 0) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
/* %j: strings render JSON-quoted, everything else inspect-lite. */
|
||||
char rendered[96];
|
||||
if (v->kind == SCR_DYN_STR) {
|
||||
snprintf(rendered, sizeof rendered, "\"%.*s\"",
|
||||
(int)(v->v.str->len < 80 ? v->v.str->len : 80), v->v.str->data);
|
||||
} else {
|
||||
/* %j over non-strings: JSON.stringify's scalar renderings. */
|
||||
char lite[64];
|
||||
snprintf(rendered, sizeof rendered, "%s", scr_dyn_inspect_lite(v, lite, sizeof lite));
|
||||
}
|
||||
char msg[192];
|
||||
int len = snprintf(msg, sizeof msg, "%s is not a valid %s TLS protocol version",
|
||||
rendered, VERSION_OPTS[i][2] == 'n' ? "minimum" : "maximum");
|
||||
scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)len, "ERR_TLS_INVALID_PROTOCOL_VERSION");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* Node's toV: null and undefined select the default bound. */
|
||||
int version;
|
||||
if (!scr_tls_version_dyn(scr_dyn_obj_get(opts, "minVersion", 10), "minimum", 12, &version) ||
|
||||
!scr_tls_version_dyn(scr_dyn_obj_get(opts, "maxVersion", 10), "maximum", 13, &version))
|
||||
return false;
|
||||
static const char *const NUM_OPTS[] = { "handshakeTimeout", "keepAliveInitialDelay", NULL };
|
||||
for (size_t i = 0; NUM_OPTS[i] != NULL; i++) {
|
||||
const ScrDyn *v = scr_dyn_obj_get(opts, NUM_OPTS[i], strlen(NUM_OPTS[i]));
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
// ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION, a client range with neither TLSv1.2
|
||||
// nor TLSv1.3 fails with ERR_SSL_NO_PROTOCOLS_AVAILABLE once the handshake
|
||||
// starts, and an invalid version or a secureProtocol conflict throws Node's
|
||||
// TypeError from tls.connect.
|
||||
// TypeError from tls.connect and tls.createServer. null selects the default
|
||||
// bound, as undefined does.
|
||||
import * as tls from "node:tls";
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
@@ -16,6 +17,17 @@ const key = readFileSync(dir + "localhost-key.pem");
|
||||
const upTo12 = tls.createServer({ cert, key, maxVersion: "TLSv1.2" }, (s) => s.end(`server:${s.getProtocol()}`));
|
||||
const from13 = tls.createServer({ cert, key, minVersion: "TLSv1.3" }, (s) => s.end(`server:${s.getProtocol()}`));
|
||||
const any = tls.createServer({ cert, key }, (s) => s.end(`server:${s.getProtocol()}`));
|
||||
const nullBounds = tls.createServer({ cert, key, minVersion: null as any, maxVersion: null as any }, (s) =>
|
||||
s.end(`server:${s.getProtocol()}`),
|
||||
);
|
||||
for (const maxVersion of [3, "TLSv9"]) {
|
||||
try {
|
||||
tls.createServer({ cert, key, maxVersion: maxVersion as any });
|
||||
} catch (e) {
|
||||
const err = e as NodeJS.ErrnoException;
|
||||
console.log("createServer", err.name, err.code, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
function listen(server: tls.Server): Promise<number> {
|
||||
return new Promise<number>((resolve) =>
|
||||
@@ -74,12 +86,16 @@ async function main(): Promise<void> {
|
||||
await attempt("max-1.1", pAny, { maxVersion: "TLSv1.1" });
|
||||
await attempt("min-above-max", pAny, { minVersion: "TLSv1.3", maxVersion: "TLSv1.2" });
|
||||
await attempt("null-min", pAny, { minVersion: null });
|
||||
const pNull = await listen(nullBounds);
|
||||
await attempt("null-server", pNull, {});
|
||||
await attempt("null-both", pNull, { minVersion: null, maxVersion: null });
|
||||
await attempt("invalid-min", pAny, { minVersion: "TLSv9" });
|
||||
await attempt("invalid-max", pAny, { maxVersion: 3 });
|
||||
await attempt("conflict", pAny, { minVersion: "TLSv1.2", secureProtocol: "TLSv1_2_method" });
|
||||
upTo12.close();
|
||||
from13.close();
|
||||
any.close();
|
||||
nullBounds.close();
|
||||
}
|
||||
|
||||
void main();
|
||||
|
||||
Reference in New Issue
Block a user