@ai-ecoverse/slicc-kernel 1.151.1 → 1.152.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -1898,6 +1898,7 @@ var KernelSocket = class _KernelSocket {
1898
1898
  return this.dial(addr, route2, secure2);
1899
1899
  }
1900
1900
  serving;
1901
+ pending;
1901
1902
  served = false;
1902
1903
  get loopbackLinked() {
1903
1904
  return this.state === "connected" && !this.switch;
@@ -2082,6 +2083,8 @@ var KernelSocket = class _KernelSocket {
2082
2083
  this.boundAt = void 0;
2083
2084
  this.serving?.release();
2084
2085
  this.serving = void 0;
2086
+ this.pending?.();
2087
+ this.pending = void 0;
2085
2088
  this.changes.wake();
2086
2089
  }
2087
2090
  static pair(net, domain, cred) {
@@ -2902,14 +2905,14 @@ var WsReader = class {
2902
2905
  }
2903
2906
  };
2904
2907
  function switchingHead(accept2, protocol = "") {
2905
- const chosen2 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
2908
+ const chosen3 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
2906
2909
  ` : "";
2907
2910
  return latin1Bytes(
2908
2911
  `HTTP/1.1 101 Switching Protocols\r
2909
2912
  Upgrade: websocket\r
2910
2913
  Connection: Upgrade\r
2911
2914
  Sec-WebSocket-Accept: ${accept2}\r
2912
- ${chosen2}\r
2915
+ ${chosen3}\r
2913
2916
  `
2914
2917
  );
2915
2918
  }
@@ -3362,7 +3365,7 @@ function satisfies(version, range2) {
3362
3365
  }
3363
3366
 
3364
3367
  // src/version.ts
3365
- var KERNEL_VERSION = true ? "1.151.1" : "0.0.0-dev";
3368
+ var KERNEL_VERSION = true ? "1.152.0" : "0.0.0-dev";
3366
3369
  var OS_RELEASE = "6.0.0-slicc";
3367
3370
  function procVersion() {
3368
3371
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12763,6 +12766,8 @@ var TLS_CLIENT_NO_SNI = 2;
12763
12766
  var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
12764
12767
  var TLS_SERVER_REQUEST_CERT = 1;
12765
12768
  var TLS_SERVER_REQUIRE_CERT = 2;
12769
+ var TLS_SERVER_SELECT = 4;
12770
+ var TLS_HANDSHAKE_SELECT = 2;
12766
12771
  var SCRATCH = 64 * 1024;
12767
12772
  var EOF = -1;
12768
12773
  var TlsError = class extends Error {
@@ -12830,12 +12835,15 @@ var TlsEngine = class {
12830
12835
  if (!ptr) throw this.error(this.m._tls_last_error(), "server certificate");
12831
12836
  return new TlsLeaf(this, this.m, ptr);
12832
12837
  }
12838
+ get serverSelect() {
12839
+ return typeof this.m._tls_server_select === "function";
12840
+ }
12833
12841
  serverSession(leaf, alpn, clientCa, flags2) {
12834
12842
  const open = this.m._tls_server_new;
12835
12843
  const wire = alpnWire(alpn);
12836
12844
  const ptr = this.withBytes(
12837
12845
  wire,
12838
- (p) => open(leaf.ptr, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
12846
+ (p) => open(leaf?.ptr ?? 0, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
12839
12847
  );
12840
12848
  if (!ptr) throw this.error(this.m._tls_last_error(), "tls server");
12841
12849
  return new TlsSession(this, this.m, ptr);
@@ -13034,9 +13042,35 @@ var TlsSession = class {
13034
13042
  return this.m;
13035
13043
  }
13036
13044
  handshake() {
13045
+ return this.step() === 1;
13046
+ }
13047
+ step() {
13037
13048
  const ret = this.c._tls_handshake(this.ptr);
13038
13049
  if (ret < 0) throw this.engine.error(ret, "tls handshake");
13039
- return ret === 1;
13050
+ return ret;
13051
+ }
13052
+ clientAlpn() {
13053
+ const list = this.m._tls_client_alpn;
13054
+ const out = this.engine.intoScratch((p, max) => list(this.ptr, p, max));
13055
+ if (!(out instanceof Uint8Array)) return [];
13056
+ const names2 = [];
13057
+ for (let at = 0; at < out.length; at += 1 + out[at]) {
13058
+ names2.push(new TextDecoder().decode(out.subarray(at + 1, at + 1 + out[at])));
13059
+ }
13060
+ return names2;
13061
+ }
13062
+ select(leaf, alpn) {
13063
+ const pick = this.m._tls_server_select;
13064
+ const name2 = new TextEncoder().encode(alpn ?? "");
13065
+ const ret = this.engine.withBytes(
13066
+ name2,
13067
+ (p) => pick(this.ptr, leaf?.ptr ?? 0, name2.length > 0 ? p : 0, name2.length)
13068
+ );
13069
+ if (ret !== 0) throw this.engine.error(ret, "tls select");
13070
+ }
13071
+ refuse(alert) {
13072
+ const ret = this.m._tls_server_refuse(this.ptr, alert);
13073
+ if (ret !== 0) throw this.engine.error(ret, "tls refuse");
13040
13074
  }
13041
13075
  get verifyResult() {
13042
13076
  return this.c._tls_verify_result(this.ptr);
@@ -14758,17 +14792,39 @@ function serverRefusal(err, session, first) {
14758
14792
  const text = err instanceof TlsError ? err.message : String(err);
14759
14793
  return new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
14760
14794
  }
14761
- async function serverHandshake(conn, session, inbox, first) {
14795
+ async function chosen(conn, session, select) {
14796
+ if (!select) throw new KernelError("EPROTO", "ERR_SSL_HANDSHAKE_FAILURE: no selection");
14797
+ const choice = await select({ servername: session.sni, protocols: session.clientAlpn() });
14798
+ if (choice.refuse === void 0) {
14799
+ try {
14800
+ session.select(choice.leaf, choice.alpn);
14801
+ } finally {
14802
+ choice.done?.();
14803
+ }
14804
+ return;
14805
+ }
14806
+ session.refuse(choice.refuse);
14807
+ await send(conn, session).catch(() => void 0);
14808
+ throw new KernelError(
14809
+ "EPROTO",
14810
+ `ERR_SSL_HANDSHAKE_FAILURE: the program refused the handshake (alert ${choice.refuse})`
14811
+ );
14812
+ }
14813
+ async function serverHandshake(conn, session, inbox, hooks) {
14762
14814
  for (; ; ) {
14763
- let done4;
14815
+ let step2;
14764
14816
  try {
14765
- done4 = session.handshake();
14817
+ step2 = session.step();
14766
14818
  } catch (err) {
14767
14819
  await send(conn, session).catch(() => void 0);
14768
- throw serverRefusal(err, session, first());
14820
+ throw serverRefusal(err, session, hooks.first());
14821
+ }
14822
+ if (step2 === TLS_HANDSHAKE_SELECT) {
14823
+ await chosen(conn, session, hooks.select);
14824
+ continue;
14769
14825
  }
14770
14826
  await send(conn, session);
14771
- if (done4) return;
14827
+ if (step2 === 1) return;
14772
14828
  if (!await inbox.more()) {
14773
14829
  throw new KernelError(
14774
14830
  "ECONNRESET",
@@ -14777,7 +14833,7 @@ async function serverHandshake(conn, session, inbox, first) {
14777
14833
  }
14778
14834
  }
14779
14835
  }
14780
- async function tlsServer(conn, session, clientCerts) {
14836
+ async function tlsServer(conn, session, clientCerts, select) {
14781
14837
  let first;
14782
14838
  const watched = {
14783
14839
  ...conn,
@@ -14789,7 +14845,7 @@ async function tlsServer(conn, session, clientCerts) {
14789
14845
  };
14790
14846
  const inbox = new Ciphertext(watched, session);
14791
14847
  try {
14792
- await serverHandshake(conn, session, inbox, () => first);
14848
+ await serverHandshake(conn, session, inbox, { first: () => first, select });
14793
14849
  const chain2 = session.peerChain();
14794
14850
  const code = clientCerts ? verifyCode(session.verifyResult) : void 0;
14795
14851
  const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
@@ -17994,10 +18050,35 @@ function storeOf(engine, ca) {
17994
18050
  throw new KernelError("EINVAL", `ERR_INVALID_ARG_VALUE: ca: ${err.message}`);
17995
18051
  }
17996
18052
  }
17997
- function flagsOf(req) {
18053
+ function certFlags(req) {
17998
18054
  if (!req.requestCert) return 0;
17999
18055
  return req.rejectUnauthorized === false ? TLS_SERVER_REQUEST_CERT : TLS_SERVER_REQUIRE_CERT;
18000
18056
  }
18057
+ function flagsOf(req) {
18058
+ if (!req.select) return certFlags(req);
18059
+ if (req.alpn && req.alpn.length > 0)
18060
+ throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
18061
+ return certFlags(req) | TLS_SERVER_SELECT;
18062
+ }
18063
+ async function engineOf(proc, select) {
18064
+ const engine = await supportOf(proc.net).engine();
18065
+ if (!engine.serverSessions)
18066
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
18067
+ if (select && !engine.serverSelect)
18068
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server selection");
18069
+ return engine;
18070
+ }
18071
+ async function importedLeaf(proc, own, select) {
18072
+ const cert = certBytes(own);
18073
+ let engine;
18074
+ try {
18075
+ engine = await engineOf(proc, select);
18076
+ } catch (err) {
18077
+ wipe(cert);
18078
+ throw err;
18079
+ }
18080
+ return { engine, leaf: leafOf(engine, cert) };
18081
+ }
18001
18082
  function timeoutOf(req) {
18002
18083
  const ms = req.handshakeTimeout ?? HANDSHAKE_TIMEOUT_MS;
18003
18084
  if (!Number.isInteger(ms) || ms <= 0)
@@ -18019,23 +18100,14 @@ function handshakeSignal(proc, ms) {
18019
18100
  async function serverOf(proc, req) {
18020
18101
  const own = req.cert;
18021
18102
  delete req.cert;
18022
- if (!own) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
18023
- const cert = certBytes(own);
18024
- let engine;
18025
- try {
18026
- engine = await supportOf(proc.net).engine();
18027
- if (!engine.serverSessions)
18028
- throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
18029
- } catch (err) {
18030
- wipe(cert);
18031
- throw err;
18032
- }
18033
- const leaf = leafOf(engine, cert);
18103
+ if (!own && !req.select)
18104
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
18105
+ const { engine, leaf } = own ? await importedLeaf(proc, own, req.select) : { engine: await engineOf(proc, true), leaf: void 0 };
18034
18106
  let mine;
18035
18107
  try {
18036
18108
  mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
18037
18109
  const flags2 = flagsOf(req);
18038
- const store = mine ?? (flags2 ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
18110
+ const store = mine ?? (flags2 & ~TLS_SERVER_SELECT ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
18039
18111
  return {
18040
18112
  engine,
18041
18113
  leaf,
@@ -18044,12 +18116,12 @@ async function serverOf(proc, req) {
18044
18116
  flags: flags2,
18045
18117
  timeoutMs: timeoutOf(req),
18046
18118
  release() {
18047
- leaf.release();
18119
+ leaf?.release();
18048
18120
  mine?.release();
18049
18121
  }
18050
18122
  };
18051
18123
  } catch (err) {
18052
- leaf.release();
18124
+ leaf?.release();
18053
18125
  mine?.release();
18054
18126
  throw err;
18055
18127
  }
@@ -18060,30 +18132,133 @@ async function listenSecure(proc, socket, req) {
18060
18132
  socket.serving?.release();
18061
18133
  socket.serving = server;
18062
18134
  }
18135
+ function servedOf(info) {
18136
+ return {
18137
+ path: "kernel",
18138
+ protocol: info.protocol,
18139
+ alpnProtocol: info.alpnProtocol,
18140
+ servername: info.servername,
18141
+ authorized: info.authorized,
18142
+ ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
18143
+ peerCertificates: info.peerCertificates.map(encode),
18144
+ cipher: info.cipher
18145
+ };
18146
+ }
18147
+ var selections = /* @__PURE__ */ new WeakMap();
18148
+ function pausing(signal) {
18149
+ let paused;
18150
+ const pausedAt = new Promise((resolve2) => {
18151
+ paused = resolve2;
18152
+ });
18153
+ const select = (offer) => new Promise((choose, fail3) => {
18154
+ if (signal.aborted) fail3(signal.reason);
18155
+ signal.addEventListener("abort", () => fail3(signal.reason), { once: true });
18156
+ paused({ offer, choose, fail: fail3 });
18157
+ });
18158
+ return { pausedAt, select };
18159
+ }
18063
18160
  async function serveSecure(proc, socket, req) {
18064
18161
  const shared = req.listener?.serving;
18065
18162
  if (req.listener && !shared) throw new KernelError("EINVAL", "the listener has no tls");
18066
18163
  const server = shared ?? await serverOf(proc, req);
18164
+ const { engine, leaf, alpn, store, flags: flags2 } = server;
18165
+ const limit = handshakeSignal(proc, server.timeoutMs);
18166
+ const { pausedAt, select } = pausing(limit.signal);
18167
+ const certs = (flags2 & ~TLS_SERVER_SELECT) !== 0;
18168
+ const run2 = socket.secureLink(
18169
+ (raw2) => tlsServer(
18170
+ raw2,
18171
+ engine.serverSession(leaf, alpn, store, flags2),
18172
+ certs,
18173
+ flags2 & TLS_SERVER_SELECT ? select : void 0
18174
+ ),
18175
+ limit.signal,
18176
+ (reason) => !shared && reason === timedOut
18177
+ ).finally(() => {
18178
+ limit.done();
18179
+ selections.delete(socket);
18180
+ socket.pending = void 0;
18181
+ if (!shared) server.release();
18182
+ });
18183
+ run2.catch(() => void 0);
18184
+ const first = await Promise.race([run2, pausedAt.then((pause2) => ({ pause: pause2 }))]);
18185
+ if (!("pause" in first)) return servedOf(first);
18186
+ selections.set(socket, { pause: first.pause, run: run2 });
18187
+ socket.pending = () => first.pause.fail(new KernelError("ECONNRESET"));
18188
+ return { select: first.pause.offer };
18189
+ }
18190
+ var REFUSALS = /* @__PURE__ */ new Set([112, 120, 40, 49, 80]);
18191
+ var TlsContext = class {
18192
+ leaf;
18193
+ constructor(leaf) {
18194
+ this.leaf = leaf;
18195
+ }
18196
+ close() {
18197
+ this.leaf.release();
18198
+ }
18199
+ };
18200
+ var TLS_CONTEXTS_MAX = 64;
18201
+ async function contextSecure(proc, cert) {
18202
+ if (!cert) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a context needs cert and key");
18203
+ const held = proc.fds.numbers().filter((fd) => proc.fds.get(fd).file instanceof TlsContext);
18204
+ if (held.length >= TLS_CONTEXTS_MAX) {
18205
+ wipe(certBytes(cert));
18206
+ throw new KernelError("EMFILE", `at most ${TLS_CONTEXTS_MAX} tls contexts per process`);
18207
+ }
18208
+ const { leaf } = await importedLeaf(proc, cert);
18209
+ const file = new OpenFile(new TlsContext(leaf));
18067
18210
  try {
18068
- const { engine, leaf, alpn, store, flags: flags2 } = server;
18069
- const limit = handshakeSignal(proc, server.timeoutMs);
18070
- const info = await socket.secureLink(
18071
- (raw2) => tlsServer(raw2, engine.serverSession(leaf, alpn, store, flags2), flags2 !== 0),
18072
- limit.signal,
18073
- (reason) => !shared && reason === timedOut
18074
- ).finally(limit.done);
18075
- return {
18076
- path: "kernel",
18077
- protocol: info.protocol,
18078
- alpnProtocol: info.alpnProtocol,
18079
- servername: info.servername,
18080
- authorized: info.authorized,
18081
- ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
18082
- peerCertificates: info.peerCertificates.map(encode),
18083
- cipher: info.cipher
18084
- };
18211
+ const fd = proc.fds.install(file, 3);
18212
+ proc.fds.setCloseOnExec(fd);
18213
+ return fd;
18214
+ } catch (err) {
18215
+ leaf.release();
18216
+ throw err;
18217
+ }
18218
+ }
18219
+ function contextAt(fds, fd) {
18220
+ const open = fds.get(fd);
18221
+ const file = open.file;
18222
+ if (!(file instanceof TlsContext)) throw new KernelError("EBADF", "not a tls context");
18223
+ const held = open.retain();
18224
+ let released2 = false;
18225
+ return {
18226
+ leaf: file.leaf,
18227
+ done: () => {
18228
+ if (released2) return;
18229
+ released2 = true;
18230
+ void held.release();
18231
+ }
18232
+ };
18233
+ }
18234
+ function choiceOf(fds, pause2, req) {
18235
+ if (req.refuse !== void 0) {
18236
+ if (!REFUSALS.has(req.refuse)) throw new KernelError("EINVAL", "not a refusal alert");
18237
+ return { refuse: req.refuse };
18238
+ }
18239
+ if (req.alpn !== void 0 && !pause2.offer.protocols.includes(req.alpn))
18240
+ throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_INVALID_RESULT: not offered");
18241
+ return {
18242
+ ...req.context === void 0 ? {} : contextAt(fds, req.context),
18243
+ ...req.alpn === void 0 ? {} : { alpn: req.alpn }
18244
+ };
18245
+ }
18246
+ async function selectSecure(fds, socket, req) {
18247
+ const selecting = selections.get(socket);
18248
+ if (!selecting) throw new KernelError("EINVAL", "no handshake waits for a selection");
18249
+ selections.delete(socket);
18250
+ let choice;
18251
+ try {
18252
+ choice = choiceOf(fds, selecting.pause, req);
18253
+ } catch (err) {
18254
+ selecting.pause.choose({ refuse: 40 });
18255
+ throw err;
18256
+ }
18257
+ selecting.pause.choose(choice);
18258
+ try {
18259
+ return servedOf(await selecting.run);
18085
18260
  } finally {
18086
- if (!shared) server.release();
18261
+ choice.done?.();
18087
18262
  }
18088
18263
  }
18089
18264
 
@@ -18251,7 +18426,9 @@ var SOCKET_OPS = [
18251
18426
  "sock-tls",
18252
18427
  "sock-tls-upgrade",
18253
18428
  "sock-tls-serve",
18254
- "sock-tls-listen"
18429
+ "sock-tls-listen",
18430
+ "sock-tls-context",
18431
+ "sock-tls-select"
18255
18432
  ];
18256
18433
  function socketAt(fds, fd) {
18257
18434
  const file = anySocketAt(fds, fd);
@@ -18332,6 +18509,12 @@ async function socketSyscall(req, proc) {
18332
18509
  const listener = from === void 0 ? {} : { listener: socketAt(fds, from) };
18333
18510
  return ok3(await serveSecure(proc, socketAt(fds, req.fd), { ...rest2, ...listener }));
18334
18511
  }
18512
+ case "sock-tls-context":
18513
+ return ok3(await contextSecure(proc, req.cert));
18514
+ case "sock-tls-select": {
18515
+ const { fd, ...choice } = req;
18516
+ return ok3(await selectSecure(fds, socketAt(fds, fd), choice));
18517
+ }
18335
18518
  case "sock-tls-listen":
18336
18519
  await listenSecure(proc, socketAt(fds, req.fd), req);
18337
18520
  return ok3({});
@@ -28442,7 +28625,7 @@ function targetOf(command) {
28442
28625
  ...command.variants ? { variants: command.variants } : {}
28443
28626
  };
28444
28627
  }
28445
- function chosen(planned, env) {
28628
+ function chosen2(planned, env) {
28446
28629
  const { target } = planned;
28447
28630
  const wasm = variantFor(target.variants, env);
28448
28631
  if (wasm === void 0) return planned;
@@ -29601,7 +29784,7 @@ var Launcher = class {
29601
29784
  delete env[TICKET_ENV];
29602
29785
  const own = env.HOSTNAME;
29603
29786
  if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
29604
- const planned = chosen(asked, env);
29787
+ const planned = chosen2(asked, env);
29605
29788
  const { target, args } = planned;
29606
29789
  let program;
29607
29790
  let exeId;