@ai-ecoverse/slicc-kernel 1.151.0 → 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.
@@ -4155,14 +4155,14 @@ var WsReader = class {
4155
4155
  }
4156
4156
  };
4157
4157
  function switchingHead(accept2, protocol = "") {
4158
- const chosen2 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
4158
+ const chosen3 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
4159
4159
  ` : "";
4160
4160
  return latin1Bytes(
4161
4161
  `HTTP/1.1 101 Switching Protocols\r
4162
4162
  Upgrade: websocket\r
4163
4163
  Connection: Upgrade\r
4164
4164
  Sec-WebSocket-Accept: ${accept2}\r
4165
- ${chosen2}\r
4165
+ ${chosen3}\r
4166
4166
  `
4167
4167
  );
4168
4168
  }
@@ -6155,6 +6155,7 @@ var KernelSocket = class _KernelSocket {
6155
6155
  return this.dial(addr, route2, secure2);
6156
6156
  }
6157
6157
  serving;
6158
+ pending;
6158
6159
  served = false;
6159
6160
  get loopbackLinked() {
6160
6161
  return this.state === "connected" && !this.switch;
@@ -6339,6 +6340,8 @@ var KernelSocket = class _KernelSocket {
6339
6340
  this.boundAt = void 0;
6340
6341
  this.serving?.release();
6341
6342
  this.serving = void 0;
6343
+ this.pending?.();
6344
+ this.pending = void 0;
6342
6345
  this.changes.wake();
6343
6346
  }
6344
6347
  static pair(net, domain, cred) {
@@ -7915,7 +7918,7 @@ function satisfies(version, range2) {
7915
7918
  }
7916
7919
 
7917
7920
  // src/version.ts
7918
- var KERNEL_VERSION = true ? "1.151.0" : "0.0.0-dev";
7921
+ var KERNEL_VERSION = true ? "1.152.0" : "0.0.0-dev";
7919
7922
  var OS_RELEASE = "6.0.0-slicc";
7920
7923
  function procVersion() {
7921
7924
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -16779,6 +16782,8 @@ var TLS_CLIENT_NO_SNI = 2;
16779
16782
  var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
16780
16783
  var TLS_SERVER_REQUEST_CERT = 1;
16781
16784
  var TLS_SERVER_REQUIRE_CERT = 2;
16785
+ var TLS_SERVER_SELECT = 4;
16786
+ var TLS_HANDSHAKE_SELECT = 2;
16782
16787
  var SCRATCH = 64 * 1024;
16783
16788
  var EOF = -1;
16784
16789
  var TlsError = class extends Error {
@@ -16846,12 +16851,15 @@ var TlsEngine = class {
16846
16851
  if (!ptr) throw this.error(this.m._tls_last_error(), "server certificate");
16847
16852
  return new TlsLeaf(this, this.m, ptr);
16848
16853
  }
16854
+ get serverSelect() {
16855
+ return typeof this.m._tls_server_select === "function";
16856
+ }
16849
16857
  serverSession(leaf, alpn, clientCa, flags2) {
16850
16858
  const open2 = this.m._tls_server_new;
16851
16859
  const wire = alpnWire(alpn);
16852
16860
  const ptr = this.withBytes(
16853
16861
  wire,
16854
- (p) => open2(leaf.ptr, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
16862
+ (p) => open2(leaf?.ptr ?? 0, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
16855
16863
  );
16856
16864
  if (!ptr) throw this.error(this.m._tls_last_error(), "tls server");
16857
16865
  return new TlsSession(this, this.m, ptr);
@@ -17050,9 +17058,35 @@ var TlsSession = class {
17050
17058
  return this.m;
17051
17059
  }
17052
17060
  handshake() {
17061
+ return this.step() === 1;
17062
+ }
17063
+ step() {
17053
17064
  const ret = this.c._tls_handshake(this.ptr);
17054
17065
  if (ret < 0) throw this.engine.error(ret, "tls handshake");
17055
- return ret === 1;
17066
+ return ret;
17067
+ }
17068
+ clientAlpn() {
17069
+ const list = this.m._tls_client_alpn;
17070
+ const out = this.engine.intoScratch((p, max) => list(this.ptr, p, max));
17071
+ if (!(out instanceof Uint8Array)) return [];
17072
+ const names2 = [];
17073
+ for (let at = 0; at < out.length; at += 1 + out[at]) {
17074
+ names2.push(new TextDecoder().decode(out.subarray(at + 1, at + 1 + out[at])));
17075
+ }
17076
+ return names2;
17077
+ }
17078
+ select(leaf, alpn) {
17079
+ const pick = this.m._tls_server_select;
17080
+ const name2 = new TextEncoder().encode(alpn ?? "");
17081
+ const ret = this.engine.withBytes(
17082
+ name2,
17083
+ (p) => pick(this.ptr, leaf?.ptr ?? 0, name2.length > 0 ? p : 0, name2.length)
17084
+ );
17085
+ if (ret !== 0) throw this.engine.error(ret, "tls select");
17086
+ }
17087
+ refuse(alert) {
17088
+ const ret = this.m._tls_server_refuse(this.ptr, alert);
17089
+ if (ret !== 0) throw this.engine.error(ret, "tls refuse");
17056
17090
  }
17057
17091
  get verifyResult() {
17058
17092
  return this.c._tls_verify_result(this.ptr);
@@ -18890,17 +18924,39 @@ function serverRefusal(err, session, first) {
18890
18924
  const text = err instanceof TlsError ? err.message : String(err);
18891
18925
  return new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
18892
18926
  }
18893
- async function serverHandshake(conn, session, inbox, first) {
18927
+ async function chosen(conn, session, select) {
18928
+ if (!select) throw new KernelError("EPROTO", "ERR_SSL_HANDSHAKE_FAILURE: no selection");
18929
+ const choice = await select({ servername: session.sni, protocols: session.clientAlpn() });
18930
+ if (choice.refuse === void 0) {
18931
+ try {
18932
+ session.select(choice.leaf, choice.alpn);
18933
+ } finally {
18934
+ choice.done?.();
18935
+ }
18936
+ return;
18937
+ }
18938
+ session.refuse(choice.refuse);
18939
+ await send(conn, session).catch(() => void 0);
18940
+ throw new KernelError(
18941
+ "EPROTO",
18942
+ `ERR_SSL_HANDSHAKE_FAILURE: the program refused the handshake (alert ${choice.refuse})`
18943
+ );
18944
+ }
18945
+ async function serverHandshake(conn, session, inbox, hooks) {
18894
18946
  for (; ; ) {
18895
- let done5;
18947
+ let step2;
18896
18948
  try {
18897
- done5 = session.handshake();
18949
+ step2 = session.step();
18898
18950
  } catch (err) {
18899
18951
  await send(conn, session).catch(() => void 0);
18900
- throw serverRefusal(err, session, first());
18952
+ throw serverRefusal(err, session, hooks.first());
18953
+ }
18954
+ if (step2 === TLS_HANDSHAKE_SELECT) {
18955
+ await chosen(conn, session, hooks.select);
18956
+ continue;
18901
18957
  }
18902
18958
  await send(conn, session);
18903
- if (done5) return;
18959
+ if (step2 === 1) return;
18904
18960
  if (!await inbox.more()) {
18905
18961
  throw new KernelError(
18906
18962
  "ECONNRESET",
@@ -18909,7 +18965,7 @@ async function serverHandshake(conn, session, inbox, first) {
18909
18965
  }
18910
18966
  }
18911
18967
  }
18912
- async function tlsServer(conn, session, clientCerts) {
18968
+ async function tlsServer(conn, session, clientCerts, select) {
18913
18969
  let first;
18914
18970
  const watched = {
18915
18971
  ...conn,
@@ -18921,7 +18977,7 @@ async function tlsServer(conn, session, clientCerts) {
18921
18977
  };
18922
18978
  const inbox = new Ciphertext(watched, session);
18923
18979
  try {
18924
- await serverHandshake(conn, session, inbox, () => first);
18980
+ await serverHandshake(conn, session, inbox, { first: () => first, select });
18925
18981
  const chain2 = session.peerChain();
18926
18982
  const code = clientCerts ? verifyCode(session.verifyResult) : void 0;
18927
18983
  const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
@@ -22126,10 +22182,35 @@ function storeOf(engine, ca) {
22126
22182
  throw new KernelError("EINVAL", `ERR_INVALID_ARG_VALUE: ca: ${err.message}`);
22127
22183
  }
22128
22184
  }
22129
- function flagsOf(req) {
22185
+ function certFlags(req) {
22130
22186
  if (!req.requestCert) return 0;
22131
22187
  return req.rejectUnauthorized === false ? TLS_SERVER_REQUEST_CERT : TLS_SERVER_REQUIRE_CERT;
22132
22188
  }
22189
+ function flagsOf(req) {
22190
+ if (!req.select) return certFlags(req);
22191
+ if (req.alpn && req.alpn.length > 0)
22192
+ throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
22193
+ return certFlags(req) | TLS_SERVER_SELECT;
22194
+ }
22195
+ async function engineOf(proc, select) {
22196
+ const engine = await supportOf(proc.net).engine();
22197
+ if (!engine.serverSessions)
22198
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
22199
+ if (select && !engine.serverSelect)
22200
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server selection");
22201
+ return engine;
22202
+ }
22203
+ async function importedLeaf(proc, own, select) {
22204
+ const cert = certBytes(own);
22205
+ let engine;
22206
+ try {
22207
+ engine = await engineOf(proc, select);
22208
+ } catch (err) {
22209
+ wipe(cert);
22210
+ throw err;
22211
+ }
22212
+ return { engine, leaf: leafOf(engine, cert) };
22213
+ }
22133
22214
  function timeoutOf(req) {
22134
22215
  const ms = req.handshakeTimeout ?? HANDSHAKE_TIMEOUT_MS;
22135
22216
  if (!Number.isInteger(ms) || ms <= 0)
@@ -22151,23 +22232,14 @@ function handshakeSignal(proc, ms) {
22151
22232
  async function serverOf(proc, req) {
22152
22233
  const own = req.cert;
22153
22234
  delete req.cert;
22154
- if (!own) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
22155
- const cert = certBytes(own);
22156
- let engine;
22157
- try {
22158
- engine = await supportOf(proc.net).engine();
22159
- if (!engine.serverSessions)
22160
- throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
22161
- } catch (err) {
22162
- wipe(cert);
22163
- throw err;
22164
- }
22165
- const leaf = leafOf(engine, cert);
22235
+ if (!own && !req.select)
22236
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
22237
+ const { engine, leaf } = own ? await importedLeaf(proc, own, req.select) : { engine: await engineOf(proc, true), leaf: void 0 };
22166
22238
  let mine;
22167
22239
  try {
22168
22240
  mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
22169
22241
  const flags2 = flagsOf(req);
22170
- const store = mine ?? (flags2 ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
22242
+ const store = mine ?? (flags2 & ~TLS_SERVER_SELECT ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
22171
22243
  return {
22172
22244
  engine,
22173
22245
  leaf,
@@ -22176,12 +22248,12 @@ async function serverOf(proc, req) {
22176
22248
  flags: flags2,
22177
22249
  timeoutMs: timeoutOf(req),
22178
22250
  release() {
22179
- leaf.release();
22251
+ leaf?.release();
22180
22252
  mine?.release();
22181
22253
  }
22182
22254
  };
22183
22255
  } catch (err) {
22184
- leaf.release();
22256
+ leaf?.release();
22185
22257
  mine?.release();
22186
22258
  throw err;
22187
22259
  }
@@ -22192,30 +22264,133 @@ async function listenSecure(proc, socket, req) {
22192
22264
  socket.serving?.release();
22193
22265
  socket.serving = server;
22194
22266
  }
22267
+ function servedOf(info) {
22268
+ return {
22269
+ path: "kernel",
22270
+ protocol: info.protocol,
22271
+ alpnProtocol: info.alpnProtocol,
22272
+ servername: info.servername,
22273
+ authorized: info.authorized,
22274
+ ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
22275
+ peerCertificates: info.peerCertificates.map(encode),
22276
+ cipher: info.cipher
22277
+ };
22278
+ }
22279
+ var selections = /* @__PURE__ */ new WeakMap();
22280
+ function pausing(signal) {
22281
+ let paused;
22282
+ const pausedAt = new Promise((resolve2) => {
22283
+ paused = resolve2;
22284
+ });
22285
+ const select = (offer) => new Promise((choose, fail2) => {
22286
+ if (signal.aborted) fail2(signal.reason);
22287
+ signal.addEventListener("abort", () => fail2(signal.reason), { once: true });
22288
+ paused({ offer, choose, fail: fail2 });
22289
+ });
22290
+ return { pausedAt, select };
22291
+ }
22195
22292
  async function serveSecure(proc, socket, req) {
22196
22293
  const shared = req.listener?.serving;
22197
22294
  if (req.listener && !shared) throw new KernelError("EINVAL", "the listener has no tls");
22198
22295
  const server = shared ?? await serverOf(proc, req);
22296
+ const { engine, leaf, alpn, store, flags: flags2 } = server;
22297
+ const limit = handshakeSignal(proc, server.timeoutMs);
22298
+ const { pausedAt, select } = pausing(limit.signal);
22299
+ const certs = (flags2 & ~TLS_SERVER_SELECT) !== 0;
22300
+ const run2 = socket.secureLink(
22301
+ (raw2) => tlsServer(
22302
+ raw2,
22303
+ engine.serverSession(leaf, alpn, store, flags2),
22304
+ certs,
22305
+ flags2 & TLS_SERVER_SELECT ? select : void 0
22306
+ ),
22307
+ limit.signal,
22308
+ (reason) => !shared && reason === timedOut
22309
+ ).finally(() => {
22310
+ limit.done();
22311
+ selections.delete(socket);
22312
+ socket.pending = void 0;
22313
+ if (!shared) server.release();
22314
+ });
22315
+ run2.catch(() => void 0);
22316
+ const first = await Promise.race([run2, pausedAt.then((pause2) => ({ pause: pause2 }))]);
22317
+ if (!("pause" in first)) return servedOf(first);
22318
+ selections.set(socket, { pause: first.pause, run: run2 });
22319
+ socket.pending = () => first.pause.fail(new KernelError("ECONNRESET"));
22320
+ return { select: first.pause.offer };
22321
+ }
22322
+ var REFUSALS = /* @__PURE__ */ new Set([112, 120, 40, 49, 80]);
22323
+ var TlsContext = class {
22324
+ leaf;
22325
+ constructor(leaf) {
22326
+ this.leaf = leaf;
22327
+ }
22328
+ close() {
22329
+ this.leaf.release();
22330
+ }
22331
+ };
22332
+ var TLS_CONTEXTS_MAX = 64;
22333
+ async function contextSecure(proc, cert) {
22334
+ if (!cert) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a context needs cert and key");
22335
+ const held = proc.fds.numbers().filter((fd) => proc.fds.get(fd).file instanceof TlsContext);
22336
+ if (held.length >= TLS_CONTEXTS_MAX) {
22337
+ wipe(certBytes(cert));
22338
+ throw new KernelError("EMFILE", `at most ${TLS_CONTEXTS_MAX} tls contexts per process`);
22339
+ }
22340
+ const { leaf } = await importedLeaf(proc, cert);
22341
+ const file = new OpenFile(new TlsContext(leaf));
22199
22342
  try {
22200
- const { engine, leaf, alpn, store, flags: flags2 } = server;
22201
- const limit = handshakeSignal(proc, server.timeoutMs);
22202
- const info = await socket.secureLink(
22203
- (raw2) => tlsServer(raw2, engine.serverSession(leaf, alpn, store, flags2), flags2 !== 0),
22204
- limit.signal,
22205
- (reason) => !shared && reason === timedOut
22206
- ).finally(limit.done);
22207
- return {
22208
- path: "kernel",
22209
- protocol: info.protocol,
22210
- alpnProtocol: info.alpnProtocol,
22211
- servername: info.servername,
22212
- authorized: info.authorized,
22213
- ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
22214
- peerCertificates: info.peerCertificates.map(encode),
22215
- cipher: info.cipher
22216
- };
22343
+ const fd = proc.fds.install(file, 3);
22344
+ proc.fds.setCloseOnExec(fd);
22345
+ return fd;
22346
+ } catch (err) {
22347
+ leaf.release();
22348
+ throw err;
22349
+ }
22350
+ }
22351
+ function contextAt(fds, fd) {
22352
+ const open2 = fds.get(fd);
22353
+ const file = open2.file;
22354
+ if (!(file instanceof TlsContext)) throw new KernelError("EBADF", "not a tls context");
22355
+ const held = open2.retain();
22356
+ let released2 = false;
22357
+ return {
22358
+ leaf: file.leaf,
22359
+ done: () => {
22360
+ if (released2) return;
22361
+ released2 = true;
22362
+ void held.release();
22363
+ }
22364
+ };
22365
+ }
22366
+ function choiceOf(fds, pause2, req) {
22367
+ if (req.refuse !== void 0) {
22368
+ if (!REFUSALS.has(req.refuse)) throw new KernelError("EINVAL", "not a refusal alert");
22369
+ return { refuse: req.refuse };
22370
+ }
22371
+ if (req.alpn !== void 0 && !pause2.offer.protocols.includes(req.alpn))
22372
+ throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_INVALID_RESULT: not offered");
22373
+ return {
22374
+ ...req.context === void 0 ? {} : contextAt(fds, req.context),
22375
+ ...req.alpn === void 0 ? {} : { alpn: req.alpn }
22376
+ };
22377
+ }
22378
+ async function selectSecure(fds, socket, req) {
22379
+ const selecting = selections.get(socket);
22380
+ if (!selecting) throw new KernelError("EINVAL", "no handshake waits for a selection");
22381
+ selections.delete(socket);
22382
+ let choice;
22383
+ try {
22384
+ choice = choiceOf(fds, selecting.pause, req);
22385
+ } catch (err) {
22386
+ selecting.pause.choose({ refuse: 40 });
22387
+ throw err;
22388
+ }
22389
+ selecting.pause.choose(choice);
22390
+ try {
22391
+ return servedOf(await selecting.run);
22217
22392
  } finally {
22218
- if (!shared) server.release();
22393
+ choice.done?.();
22219
22394
  }
22220
22395
  }
22221
22396
 
@@ -22383,7 +22558,9 @@ var SOCKET_OPS = [
22383
22558
  "sock-tls",
22384
22559
  "sock-tls-upgrade",
22385
22560
  "sock-tls-serve",
22386
- "sock-tls-listen"
22561
+ "sock-tls-listen",
22562
+ "sock-tls-context",
22563
+ "sock-tls-select"
22387
22564
  ];
22388
22565
  function socketAt(fds, fd) {
22389
22566
  const file = anySocketAt(fds, fd);
@@ -22464,6 +22641,12 @@ async function socketSyscall(req, proc) {
22464
22641
  const listener = from === void 0 ? {} : { listener: socketAt(fds, from) };
22465
22642
  return ok3(await serveSecure(proc, socketAt(fds, req.fd), { ...rest2, ...listener }));
22466
22643
  }
22644
+ case "sock-tls-context":
22645
+ return ok3(await contextSecure(proc, req.cert));
22646
+ case "sock-tls-select": {
22647
+ const { fd, ...choice } = req;
22648
+ return ok3(await selectSecure(fds, socketAt(fds, fd), choice));
22649
+ }
22467
22650
  case "sock-tls-listen":
22468
22651
  await listenSecure(proc, socketAt(fds, req.fd), req);
22469
22652
  return ok3({});
@@ -29428,7 +29611,7 @@ function targetOf(command) {
29428
29611
  ...command.variants ? { variants: command.variants } : {}
29429
29612
  };
29430
29613
  }
29431
- function chosen(planned, env) {
29614
+ function chosen2(planned, env) {
29432
29615
  const { target } = planned;
29433
29616
  const wasm = variantFor(target.variants, env);
29434
29617
  if (wasm === void 0) return planned;
@@ -30587,7 +30770,7 @@ var Launcher = class {
30587
30770
  delete env[TICKET_ENV];
30588
30771
  const own = env.HOSTNAME;
30589
30772
  if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
30590
- const planned = chosen(asked, env);
30773
+ const planned = chosen2(asked, env);
30591
30774
  const { target, args } = planned;
30592
30775
  let program;
30593
30776
  let exeId;