@ai-ecoverse/slicc-kernel 1.135.7 → 1.136.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/README.md CHANGED
@@ -468,7 +468,7 @@ The module's default export (or its `main` export) is called with a context and
468
468
  - **`servername`** must be a host name (letters, digits and `-` in labels of at most 63, at most 253 in all, one trailing dot allowed) or an IP literal, else `EINVAL` before anything is dialled. An IP literal sends no SNI and must match an iPAddress subjectAltName.
469
469
  - **The `tls` property** is the handshake's: `{ path: 'kernel', substitutes: false, verified, protocol: 'TLSv1.3' or 'TLSv1.2', alpnProtocol (the agreed protocol, or false), authorized, authorizationError?, servername, peerCertificates, cipher, clientCertificate, sni, hostnameChecked, hostnameMatches? }`.
470
470
  - `peerCertificates` is the server's chain as DER, leaf first.
471
- - `verified` is the kernel's own verdict on the session, whatever the caller's flags: the chain verifies against the kernel's **bundled roots** (never a `ca` the caller passed, which only decides `authorized`) and the leaf names `servername`, which is a host name, not an IP literal. `rejectUnauthorized: false`, `checkHostname: false` and `sni: false` don't change it; a custom `ca` makes it false even when the chain would pass both. Sealed substitution in an A2 session is gated on it ([#1090](https://github.com/ai-ecoverse/slicc-kernel/issues/1090)).
471
+ - `verified` is the kernel's own verdict on the session, whatever the caller's flags: the chain verifies against the kernel's **bundled roots** (never a `ca` the caller passed, which only decides `authorized`) and the leaf names `servername`, which is a host name, not an IP literal. `rejectUnauthorized: false`, `checkHostname: false` and `sni: false` don't change it; a custom `ca` makes it false even when the chain would pass both. Sealed substitution in an A2 session is gated on it, or on a vault anchor (below; [#1090](https://github.com/ai-ecoverse/slicc-kernel/issues/1090)). `verifiedBy` is `'bundled'` when `verified` is true, otherwise `'none'`. It's never a claim the kernel can't back at connect. The vault's requests use the vault's own names for the same verdicts: `'roots'` where `conn.tls` says `'bundled'`, and `'anchored'` for a vault anchor.
472
472
  - `cipher` is the negotiated suite as Node's `getCipher()` gives it: `{ name, standardName, version }`, where `name` is OpenSSL's (`ECDHE-RSA-AES128-GCM-SHA256`) and `standardName` IANA's. As in Node, `version` is the suite's own version, not the session's: `TLSv1.0` for a CBC-SHA suite on a TLS 1.2 session.
473
473
  - `clientCertificate` says whether a client certificate was offered. `sni` says whether the server name was sent: it's false with `sni: false` and for an IP-literal `servername`, which TLS never sends.
474
474
  - `hostnameChecked` says whether the kernel checked the leaf against `servername`. `hostnameMatches` says whether it names it.
@@ -492,8 +492,8 @@ The module's default export (or its `main` export) is called with a context and
492
492
  - **The caller must then check the server's identity itself**, as slicc-jsh does with Node's `checkServerIdentity` and `peerCertificates[0]`; pass it only when the program supplied one.
493
493
  - With `rejectUnauthorized: false` it's `EINVAL`.
494
494
  - **STARTTLS:** `net.connect({ socket: conn, host, tls })` upgrades an open plain connection to an uplink destination in place, as Node's `tls.connect({ socket })` does. It resolves with a connection whose streams now carry the decrypted bytes and whose `tls` is the session. Don't hold a pending read on the plain connection while it upgrades. Pass `host` (or `tls.servername`): the plain connection only knows the address it reached, so without a name the certificate is checked against that IP, and a certificate for the host name fails.
495
- - **Sealed values in an A2 session** ([#1090](https://github.com/ai-ecoverse/slicc-kernel/issues/1090)) are substituted only at a credential position, only in a session the kernel verified itself, and only as the vault allows. `substitutes` is true when all of these hold:
496
- - `verified` is true;
495
+ - **Sealed values in an A2 session** ([#1090](https://github.com/ai-ecoverse/slicc-kernel/issues/1090)) are substituted only at a credential position, only in a session the kernel verified itself (by its bundled roots, or by a vault anchor), and only as the vault allows. `substitutes` means the session **may** substitute: a placeholder at a recognized position will be offered to the vault, and whether a value comes back is the vault's and the anchor check's decision. It's true when all of these hold:
496
+ - `verified` is true, or the engine can verify a chain on its own (wasm-tls-engine 4.2.0-5's `tls_chain_verify`) and the server name isn't an IP literal, so a vault anchor may verify the session (below);
497
497
  - ALPN didn't agree `h2`;
498
498
  - a vault is connected;
499
499
  - the uplink said which exit the connection leaves by (`UplinkConn.exit`: `tailscale` or `device:<id>`, the only exits an uplink connection takes). Without one, or with any other value, nothing is substituted.
@@ -511,6 +511,11 @@ The module's default export (or its `main` export) is called with a context and
511
511
  - **Requirements:** only the plain GS2 header (`n,,`) and the bare RFC 5802 messages; at most 100000 iterations.
512
512
 
513
513
  Anything else goes out as written: the startup, an MD5 (`R` 5) answer, every later message, and a frame over 16 KiB. A server whose `pg_hba` asks for MD5 gets the placeholder, and refuses.
514
+ - **Vault anchors** (§3.19.6) are for private-CA services such as managed pg and corporate APIs.
515
+ - **The request:** at the first credential position, before it asks for any value, the kernel asks the vault `sessionAnchors { stamp, session, host, port, protocol, exit }`. That request carries no value. The vault answers with the CAs (`anchors`, DER) and SPKI pins (`pins`, sha256) of the session rules for that host, port, protocol and exit.
516
+ - **The check:** the kernel re-verifies the server's chain against a store holding **only** that answer, never the program's `ca`, with the same checks as a session. An anchor that issues must be a CA. A non-CA anchor, or a pin on the leaf, matches only the exact presented leaf, and the name must still match. A pin on an issuer makes that certificate of the chain the anchor.
517
+ - **The result:** a match makes the session's `sessionMaterialize` say `verifiedBy: 'anchored'`, with `anchor` set to the anchor DER's sha256 or the pin itself. Without one, a session the bundled roots verified asks as before. A rule with anchors refuses those unless it says `roots = true`. Otherwise nothing is asked. `conn.tls` is reported at connect, before this check, so an anchorable session shows `verified: false`, `verifiedBy: 'none'` and `substitutes: true` (eligible). In v1 the anchored verdict isn't reported to the program. The secret's owner sees it: every `sessionMaterialize` names how the session was trusted (`verifiedBy: 'roots'`, or `'anchored'` with the matching anchor's sha256 or pin), and the vault records that with the substitution.
518
+ - **Not supported:** name constraints on an anchor, which Mbed TLS can't parse when critical, so such an anchor never verifies.
514
519
  - **What goes out:** the placeholders the vault answers with a value of at least 8 bytes go out as that value (`Basic` decoded, substituted and re-encoded). Everything else goes out as written:
515
520
  - the request line and the body;
516
521
  - other headers;