@synoi/sraid 0.2.0 → 0.4.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 +156 -50
- package/SPEC.md +2 -2
- package/dist/attestation.d.ts +8 -49
- package/dist/attestation.d.ts.map +1 -1
- package/dist/attestation.js +15 -46
- package/dist/attestation.js.map +1 -1
- package/dist/capability.d.ts +59 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +44 -0
- package/dist/capability.js.map +1 -0
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -18
- package/dist/index.js.map +1 -1
- package/dist/internal/attestation-core.d.ts +85 -0
- package/dist/internal/attestation-core.d.ts.map +1 -0
- package/dist/internal/attestation-core.js +78 -0
- package/dist/internal/attestation-core.js.map +1 -0
- package/dist/internal/base64-browser.d.ts +31 -0
- package/dist/internal/base64-browser.d.ts.map +1 -0
- package/dist/internal/base64-browser.js +39 -0
- package/dist/internal/base64-browser.js.map +1 -0
- package/dist/internal/base64-validate.d.ts +19 -0
- package/dist/internal/base64-validate.d.ts.map +1 -0
- package/dist/internal/base64-validate.js +33 -0
- package/dist/internal/base64-validate.js.map +1 -0
- package/dist/internal/base64.d.ts +7 -5
- package/dist/internal/base64.d.ts.map +1 -1
- package/dist/internal/base64.js +7 -19
- package/dist/internal/base64.js.map +1 -1
- package/dist/internal/content-core.d.ts +68 -0
- package/dist/internal/content-core.d.ts.map +1 -0
- package/dist/internal/content-core.js +87 -0
- package/dist/internal/content-core.js.map +1 -0
- package/dist/internal/ed25519-browser.d.ts +33 -0
- package/dist/internal/ed25519-browser.d.ts.map +1 -0
- package/dist/internal/ed25519-browser.js +79 -0
- package/dist/internal/ed25519-browser.js.map +1 -0
- package/dist/internal/mldsa-browser.d.ts +27 -0
- package/dist/internal/mldsa-browser.d.ts.map +1 -0
- package/dist/internal/mldsa-browser.js +35 -0
- package/dist/internal/mldsa-browser.js.map +1 -0
- package/dist/internal/sha256-browser.d.ts +17 -0
- package/dist/internal/sha256-browser.d.ts.map +1 -0
- package/dist/internal/sha256-browser.js +27 -0
- package/dist/internal/sha256-browser.js.map +1 -0
- package/dist/lineage.js +0 -0
- package/dist/lineage.js.map +1 -1
- package/dist/oid.d.ts +2 -52
- package/dist/oid.d.ts.map +1 -1
- package/dist/oid.js +9 -71
- package/dist/oid.js.map +1 -1
- package/dist/types.d.ts +4 -30
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts +2 -17
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +0 -57
- package/dist/validate.js.map +1 -1
- package/dist/verify-browser.d.ts +80 -0
- package/dist/verify-browser.d.ts.map +1 -0
- package/dist/verify-browser.js +157 -0
- package/dist/verify-browser.js.map +1 -0
- package/package.json +22 -3
- package/src/attestation.ts +29 -88
- package/src/capability.ts +69 -0
- package/src/index.ts +27 -36
- package/src/internal/attestation-core.ts +122 -0
- package/src/internal/base64-browser.ts +39 -0
- package/src/internal/base64-validate.ts +31 -0
- package/src/internal/base64.ts +7 -16
- package/src/internal/content-core.ts +88 -0
- package/src/internal/ed25519-browser.ts +85 -0
- package/src/internal/mldsa-browser.ts +39 -0
- package/src/internal/sha256-browser.ts +28 -0
- package/src/lineage.ts +0 -0
- package/src/oid.ts +10 -73
- package/src/types.ts +23 -31
- package/src/validate.ts +1 -64
- package/src/verify-browser.ts +185 -0
- package/dist/authority.d.ts +0 -351
- package/dist/authority.d.ts.map +0 -1
- package/dist/authority.js +0 -563
- package/dist/authority.js.map +0 -1
- package/src/authority.ts +0 -849
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,IAAI,EACJ,WAAW,EACX,OAAO,EACP,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,IAAI,EACJ,WAAW,EACX,OAAO,EACP,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAGhG,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,gBAAgB,CAAA;AAKvB,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAMlE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAK5D,OAAO,EACL,iBAAiB,EACjB,GAAG,EACH,WAAW,EACX,aAAa,EACb,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,UAAU,EACV,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGrE,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @synoi/sraid — public surface.
|
|
3
3
|
*
|
|
4
|
-
* SRAID
|
|
4
|
+
* SRAID is the object-identity layer: it defines what a signed object IS and
|
|
5
|
+
* how anyone re-derives and verifies its identity offline.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* L4 Apps
|
|
7
|
+
* Scope, precisely:
|
|
8
|
+
* IN canonical serializer, OID computation, hybrid Ed25519 + ML-DSA-65
|
|
9
|
+
* attestation verification, lineage resolution, shape validators.
|
|
10
|
+
* OUT storage, transport, key resolution, revocation, policy, enforcement.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* It verifies SIGNATURES, not IDENTITIES: `signer_kid` is an opaque string
|
|
13
|
+
* this package never resolves, and nothing here checks revocation. Deciding
|
|
14
|
+
* whether a key was trusted at signing time is a caller/directory concern.
|
|
15
15
|
*/
|
|
16
16
|
// Canonical serializer — byte-identical to synoi-gateway + @synoi/vault.
|
|
17
17
|
export { canonicalize } from './canonicalize.js';
|
|
@@ -28,19 +28,27 @@ export { verifyMlDsa65, isNativeMlDsaAvailable } from './mldsa.js';
|
|
|
28
28
|
// bytes; `evictKeyFromCaches(keyId)` drops that entry from every cache so a
|
|
29
29
|
// rotated or compromised key cannot be served stale on a later verify.
|
|
30
30
|
export { evictKeyFromCaches } from './internal/key-cache.js';
|
|
31
|
-
//
|
|
31
|
+
// DSSE attestation — PAE type-binding, hybrid Ed25519 + ML-DSA-65 both
|
|
32
32
|
// required. The preferred signing path (replaces the legacy bare-bytes
|
|
33
33
|
// SignatureEnvelope; closes the cross-type confusion gap SRAID F7 / A4).
|
|
34
34
|
export { verifyAttestation, pae, ALG_ED25519, ALG_ML_DSA_65, } from './attestation.js';
|
|
35
|
-
//
|
|
35
|
+
// Lineage (Merkle-DAG) — unify the `supersedes` string with the identity-bound
|
|
36
|
+
// `prev`/`links` edges; latest-wins resolution over a version set.
|
|
36
37
|
export { lineageLinks, supersededOids, latestWins, } from './lineage.js';
|
|
37
|
-
//
|
|
38
|
+
// Propagating sensitivity — coarse, opaque tier + monotone max() carry-forward.
|
|
38
39
|
export { SENSITIVITY_TIERS, SENSITIVITY_DEFAULT, isSensitivityTier, sensitivityRank, sensitivityMax, sensitivityCarryForward, sensitivityMonotoneCheck, } from './sensitivity.js';
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Always reports revocation_checked/existence_checked false (no live claim).
|
|
43
|
-
export { verifyDelegationChain, MAX_DELEGATION_DEPTH, } from './authority.js';
|
|
40
|
+
// Capability matching + the live-grant-status contract. The leaf primitive a
|
|
41
|
+
// grant store needs: pure string logic, no crypto, no I/O, no live claim.
|
|
42
|
+
export { capabilityCovers } from './capability.js';
|
|
44
43
|
// Shape validators.
|
|
45
|
-
export { validateCdro,
|
|
44
|
+
export { validateCdro, validateSignatureEnvelope, validateAttestationEnvelope, validateAuthorityBlock, validateLineageLink, } from './validate.js';
|
|
45
|
+
// MOVED IN 0.4.0 — the grant and delegation-chain VERIFIERS (`verifyAuthority`,
|
|
46
|
+
// `verifyDelegationChain`, `MAX_DELEGATION_DEPTH`) are authorization policy,
|
|
47
|
+
// not object identity, and are no longer exported from this entry. They live
|
|
48
|
+
// at the `@synoi/sraid/authority` subpath, unchanged and still verify-only.
|
|
49
|
+
//
|
|
50
|
+
// `capabilityCovers`, `AuthorityResolver` and `GrantStatus` did NOT move: they
|
|
51
|
+
// are the leaf primitive and the contract, and are exported above.
|
|
52
|
+
//
|
|
53
|
+
// REMOVED IN 0.4.0 — `validateSro`, `SRO`, `SROBody`. See CHANGELOG 0.4.0.
|
|
46
54
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAeH,yEAAyE;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,oEAAoE;AACpE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAEhG,8EAA8E;AAC9E,OAAO,EACL,eAAe,GAGhB,MAAM,gBAAgB,CAAA;AAEvB,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAElE,wEAAwE;AACxE,yEAAyE;AACzE,4EAA4E;AAC5E,uEAAuE;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,uEAAuE;AACvE,uEAAuE;AACvE,yEAAyE;AACzE,OAAO,EACL,iBAAiB,EACjB,GAAG,EACH,WAAW,EACX,aAAa,GAGd,MAAM,kBAAkB,CAAA;AAEzB,+EAA+E;AAC/E,mEAAmE;AACnE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,UAAU,GAEX,MAAM,cAAc,CAAA;AAErB,gFAAgF;AAChF,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,kBAAkB,CAAA;AAEzB,6EAA6E;AAC7E,0EAA0E;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGlD,oBAAoB;AACpB,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,eAAe,CAAA;AAEtB,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,EAAE;AACF,+EAA+E;AAC/E,mEAAmE;AACnE,EAAE;AACF,2EAA2E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/attestation-core.ts
|
|
3
|
+
*
|
|
4
|
+
* The crypto-agnostic core of the L2 DSSE attestation profile: the PAE
|
|
5
|
+
* encoding, the algorithm identifiers, the public verify input/result types,
|
|
6
|
+
* the both-required signature lookup, and the envelope-shape predicate.
|
|
7
|
+
*
|
|
8
|
+
* This is a PURE module — no crypto, no node:crypto, no Buffer — so the same
|
|
9
|
+
* PAE bytes, AND-policy shape, and type contract are shared byte-for-byte by
|
|
10
|
+
* BOTH the node default entry (attestation.ts, node:crypto verifiers) and the
|
|
11
|
+
* browser verify surface (verify-browser.ts, WebCrypto + @noble verifiers).
|
|
12
|
+
* Divergent PAE or shape logic between the two would be a signature-validity
|
|
13
|
+
* hazard; keeping it in one place removes that risk.
|
|
14
|
+
*
|
|
15
|
+
* The verify ORCHESTRATION (decode each sig, run both verifiers, gate on the
|
|
16
|
+
* AND policy) is intentionally NOT here: the node path is synchronous
|
|
17
|
+
* (node:crypto verify) and the browser path is asynchronous (WebCrypto verify),
|
|
18
|
+
* so a single shared body cannot serve both. Each entry keeps its own thin
|
|
19
|
+
* orchestration and reuses these leaf helpers.
|
|
20
|
+
*/
|
|
21
|
+
import type { AttestationEnvelope, AttestationSignature } from '../types.js';
|
|
22
|
+
/** The single supported algorithm identifiers for the JSON profile. */
|
|
23
|
+
export declare const ALG_ED25519 = "ed25519";
|
|
24
|
+
export declare const ALG_ML_DSA_65 = "ml-dsa-65";
|
|
25
|
+
/**
|
|
26
|
+
* The DSSE Pre-Authentication Encoding (PAE).
|
|
27
|
+
*
|
|
28
|
+
* Per the DSSE spec:
|
|
29
|
+
*
|
|
30
|
+
* PAE(type, body) = "DSSEv1" SP LEN(type) SP type SP LEN(body) SP body
|
|
31
|
+
*
|
|
32
|
+
* where:
|
|
33
|
+
* - SP is a single ASCII space (0x20),
|
|
34
|
+
* - LEN(x) is the ASCII-decimal byte length of x's UTF-8 encoding,
|
|
35
|
+
* - type and body are the raw UTF-8 bytes (NOT base64).
|
|
36
|
+
*
|
|
37
|
+
* Binding the payloadType (and both lengths) into the signed bytes is what
|
|
38
|
+
* makes a signature non-transferable across object types. Returns the raw
|
|
39
|
+
* bytes to be signed/verified.
|
|
40
|
+
*/
|
|
41
|
+
export declare function pae(payloadType: string, payload: string | Uint8Array): Uint8Array;
|
|
42
|
+
export interface VerifyAttestationInput {
|
|
43
|
+
/**
|
|
44
|
+
* The DSSE attestation envelope to verify. Its `payloadType` is bound into
|
|
45
|
+
* the PAE; its `payload` is the canonical UTF-8 string that was signed.
|
|
46
|
+
*/
|
|
47
|
+
envelope: AttestationEnvelope;
|
|
48
|
+
/** Raw 32-byte Ed25519 public key. */
|
|
49
|
+
ed25519_pub: Uint8Array;
|
|
50
|
+
/** Raw ML-DSA-65 public key bytes. */
|
|
51
|
+
ml_dsa_pub: Uint8Array;
|
|
52
|
+
/**
|
|
53
|
+
* Optional. If supplied, the verifier asserts the envelope's `payloadType`
|
|
54
|
+
* equals this value before verifying signatures — an explicit type-pinning
|
|
55
|
+
* check on top of the structural PAE binding. A mismatch fails with
|
|
56
|
+
* `payload-type-mismatch`.
|
|
57
|
+
*/
|
|
58
|
+
expectedPayloadType?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface VerifyAttestationResult {
|
|
61
|
+
/** True only when BOTH required signatures verified over the same PAE. */
|
|
62
|
+
valid: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Human-readable failure reasons. Empty when valid. Possible values:
|
|
65
|
+
* 'envelope-malformed', 'payload-type-mismatch', 'missing-ed25519',
|
|
66
|
+
* 'missing-ml-dsa-65', 'ed25519-malformed', 'ml-dsa-malformed',
|
|
67
|
+
* 'ed25519-invalid', 'ml-dsa-invalid'.
|
|
68
|
+
*/
|
|
69
|
+
reasons: string[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Structural well-formedness of an attestation envelope: a non-null object with
|
|
73
|
+
* a non-empty string `payloadType`, a string `payload`, and an array
|
|
74
|
+
* `signatures`. A false result maps to the `envelope-malformed` reason. This is
|
|
75
|
+
* the SINGLE definition of envelope shape, shared by the node and browser
|
|
76
|
+
* verifiers so they reject the same inputs.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isWellFormedEnvelope(env: unknown): env is AttestationEnvelope;
|
|
79
|
+
/**
|
|
80
|
+
* Find the first well-formed signature entry for `alg` (a `{ alg, sig }` object
|
|
81
|
+
* whose `sig` is a string). Returns undefined when absent; the AND policy in
|
|
82
|
+
* each verifier turns a missing pair member into a `missing-*` reason.
|
|
83
|
+
*/
|
|
84
|
+
export declare function findSig(sigs: readonly AttestationSignature[], alg: string): AttestationSignature | undefined;
|
|
85
|
+
//# sourceMappingURL=attestation-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation-core.d.ts","sourceRoot":"","sources":["../../src/internal/attestation-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAE5E,uEAAuE;AACvE,eAAO,MAAM,WAAW,YAAY,CAAA;AACpC,eAAO,MAAM,aAAa,cAAc,CAAA;AAExC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAYjF;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,sCAAsC;IACtC,WAAW,EAAE,UAAU,CAAA;IACvB,sCAAsC;IACtC,UAAU,EAAE,UAAU,CAAA;IACtB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,KAAK,EAAE,OAAO,CAAA;IACd;;;;;OAKG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,mBAAmB,CAS7E;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,SAAS,oBAAoB,EAAE,EACrC,GAAG,EAAE,MAAM,GACV,oBAAoB,GAAG,SAAS,CAOlC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/attestation-core.ts
|
|
3
|
+
*
|
|
4
|
+
* The crypto-agnostic core of the L2 DSSE attestation profile: the PAE
|
|
5
|
+
* encoding, the algorithm identifiers, the public verify input/result types,
|
|
6
|
+
* the both-required signature lookup, and the envelope-shape predicate.
|
|
7
|
+
*
|
|
8
|
+
* This is a PURE module — no crypto, no node:crypto, no Buffer — so the same
|
|
9
|
+
* PAE bytes, AND-policy shape, and type contract are shared byte-for-byte by
|
|
10
|
+
* BOTH the node default entry (attestation.ts, node:crypto verifiers) and the
|
|
11
|
+
* browser verify surface (verify-browser.ts, WebCrypto + @noble verifiers).
|
|
12
|
+
* Divergent PAE or shape logic between the two would be a signature-validity
|
|
13
|
+
* hazard; keeping it in one place removes that risk.
|
|
14
|
+
*
|
|
15
|
+
* The verify ORCHESTRATION (decode each sig, run both verifiers, gate on the
|
|
16
|
+
* AND policy) is intentionally NOT here: the node path is synchronous
|
|
17
|
+
* (node:crypto verify) and the browser path is asynchronous (WebCrypto verify),
|
|
18
|
+
* so a single shared body cannot serve both. Each entry keeps its own thin
|
|
19
|
+
* orchestration and reuses these leaf helpers.
|
|
20
|
+
*/
|
|
21
|
+
/** The single supported algorithm identifiers for the JSON profile. */
|
|
22
|
+
export const ALG_ED25519 = 'ed25519';
|
|
23
|
+
export const ALG_ML_DSA_65 = 'ml-dsa-65';
|
|
24
|
+
/**
|
|
25
|
+
* The DSSE Pre-Authentication Encoding (PAE).
|
|
26
|
+
*
|
|
27
|
+
* Per the DSSE spec:
|
|
28
|
+
*
|
|
29
|
+
* PAE(type, body) = "DSSEv1" SP LEN(type) SP type SP LEN(body) SP body
|
|
30
|
+
*
|
|
31
|
+
* where:
|
|
32
|
+
* - SP is a single ASCII space (0x20),
|
|
33
|
+
* - LEN(x) is the ASCII-decimal byte length of x's UTF-8 encoding,
|
|
34
|
+
* - type and body are the raw UTF-8 bytes (NOT base64).
|
|
35
|
+
*
|
|
36
|
+
* Binding the payloadType (and both lengths) into the signed bytes is what
|
|
37
|
+
* makes a signature non-transferable across object types. Returns the raw
|
|
38
|
+
* bytes to be signed/verified.
|
|
39
|
+
*/
|
|
40
|
+
export function pae(payloadType, payload) {
|
|
41
|
+
const enc = new TextEncoder();
|
|
42
|
+
const typeBytes = enc.encode(payloadType);
|
|
43
|
+
const bodyBytes = typeof payload === 'string' ? enc.encode(payload) : payload;
|
|
44
|
+
const prefix = enc.encode(`DSSEv1 ${typeBytes.length} ${payloadType} ${bodyBytes.length} `);
|
|
45
|
+
const out = new Uint8Array(prefix.length + bodyBytes.length);
|
|
46
|
+
out.set(prefix, 0);
|
|
47
|
+
out.set(bodyBytes, prefix.length);
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Structural well-formedness of an attestation envelope: a non-null object with
|
|
52
|
+
* a non-empty string `payloadType`, a string `payload`, and an array
|
|
53
|
+
* `signatures`. A false result maps to the `envelope-malformed` reason. This is
|
|
54
|
+
* the SINGLE definition of envelope shape, shared by the node and browser
|
|
55
|
+
* verifiers so they reject the same inputs.
|
|
56
|
+
*/
|
|
57
|
+
export function isWellFormedEnvelope(env) {
|
|
58
|
+
return (env !== null &&
|
|
59
|
+
typeof env === 'object' &&
|
|
60
|
+
typeof env.payloadType === 'string' &&
|
|
61
|
+
env.payloadType.length > 0 &&
|
|
62
|
+
typeof env.payload === 'string' &&
|
|
63
|
+
Array.isArray(env.signatures));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Find the first well-formed signature entry for `alg` (a `{ alg, sig }` object
|
|
67
|
+
* whose `sig` is a string). Returns undefined when absent; the AND policy in
|
|
68
|
+
* each verifier turns a missing pair member into a `missing-*` reason.
|
|
69
|
+
*/
|
|
70
|
+
export function findSig(sigs, alg) {
|
|
71
|
+
for (const s of sigs) {
|
|
72
|
+
if (s && typeof s === 'object' && s.alg === alg && typeof s.sig === 'string') {
|
|
73
|
+
return s;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=attestation-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation-core.js","sourceRoot":"","sources":["../../src/internal/attestation-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,uEAAuE;AACvE,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAA;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAA;AAExC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,GAAG,CAAC,WAAmB,EAAE,OAA4B;IACnE,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAA;IAC7B,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACzC,MAAM,SAAS,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAE7E,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CACvB,UAAU,SAAS,CAAC,MAAM,IAAI,WAAW,IAAI,SAAS,CAAC,MAAM,GAAG,CACjE,CAAA;IACD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;IAC5D,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAClB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACjC,OAAO,GAAG,CAAA;AACZ,CAAC;AAiCD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAY;IAC/C,OAAO,CACL,GAAG,KAAK,IAAI;QACZ,OAAO,GAAG,KAAK,QAAQ;QACvB,OAAQ,GAA2B,CAAC,WAAW,KAAK,QAAQ;QAC3D,GAA2B,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QACnD,OAAQ,GAA2B,CAAC,OAAO,KAAK,QAAQ;QACxD,KAAK,CAAC,OAAO,CAAE,GAA2B,CAAC,UAAU,CAAC,CACvD,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CACrB,IAAqC,EACrC,GAAW;IAEX,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC7E,OAAO,CAAC,CAAA;QACV,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/base64-browser.ts
|
|
3
|
+
*
|
|
4
|
+
* Strict standard-base64 (RFC 4648 §4, with `=` padding) decode for the
|
|
5
|
+
* BROWSER verify surface.
|
|
6
|
+
*
|
|
7
|
+
* INTERNAL: not exported from any public entry.
|
|
8
|
+
*
|
|
9
|
+
* Why a separate decoder: the node decoder (./base64.ts `decodeBase64Strict`)
|
|
10
|
+
* finishes with `Buffer.from(s, 'base64')`. `Buffer` is a NODE global that does
|
|
11
|
+
* not exist in a browser / service-worker / Chrome-extension context — and,
|
|
12
|
+
* crucially, it is NOT a `node:` specifier, so an esbuild `node:`-reference scan
|
|
13
|
+
* would NOT catch it. A `Buffer`-based decode would bundle clean yet throw
|
|
14
|
+
* `ReferenceError: Buffer is not defined` at runtime. This decoder is
|
|
15
|
+
* Buffer-free: it reuses the pure `assertBase64` validation (regex/length/
|
|
16
|
+
* padding only, from ./base64-validate.js — NOT ./base64.js, whose graph pulls
|
|
17
|
+
* in the `Buffer` decode) and decodes via the standard `atob` global, which IS
|
|
18
|
+
* available in browsers, dedicated/shared workers, and MV3 extension service
|
|
19
|
+
* workers.
|
|
20
|
+
*
|
|
21
|
+
* Same strict contract as the node path: throws Error('base64-malformed') on
|
|
22
|
+
* any deviation (illegal char, bad length, bad padding) rather than silently
|
|
23
|
+
* truncating, so a malformed signature is rejected loudly, never decoded to a
|
|
24
|
+
* short prefix that then "verifies" against something unintended.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Strictly decode standard base64 to raw bytes using only browser-safe globals.
|
|
28
|
+
* Throws Error('base64-malformed') on any non-conforming input.
|
|
29
|
+
*/
|
|
30
|
+
export declare function decodeBase64StrictBrowser(s: string): Uint8Array;
|
|
31
|
+
//# sourceMappingURL=base64-browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64-browser.d.ts","sourceRoot":"","sources":["../../src/internal/base64-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAM/D"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/base64-browser.ts
|
|
3
|
+
*
|
|
4
|
+
* Strict standard-base64 (RFC 4648 §4, with `=` padding) decode for the
|
|
5
|
+
* BROWSER verify surface.
|
|
6
|
+
*
|
|
7
|
+
* INTERNAL: not exported from any public entry.
|
|
8
|
+
*
|
|
9
|
+
* Why a separate decoder: the node decoder (./base64.ts `decodeBase64Strict`)
|
|
10
|
+
* finishes with `Buffer.from(s, 'base64')`. `Buffer` is a NODE global that does
|
|
11
|
+
* not exist in a browser / service-worker / Chrome-extension context — and,
|
|
12
|
+
* crucially, it is NOT a `node:` specifier, so an esbuild `node:`-reference scan
|
|
13
|
+
* would NOT catch it. A `Buffer`-based decode would bundle clean yet throw
|
|
14
|
+
* `ReferenceError: Buffer is not defined` at runtime. This decoder is
|
|
15
|
+
* Buffer-free: it reuses the pure `assertBase64` validation (regex/length/
|
|
16
|
+
* padding only, from ./base64-validate.js — NOT ./base64.js, whose graph pulls
|
|
17
|
+
* in the `Buffer` decode) and decodes via the standard `atob` global, which IS
|
|
18
|
+
* available in browsers, dedicated/shared workers, and MV3 extension service
|
|
19
|
+
* workers.
|
|
20
|
+
*
|
|
21
|
+
* Same strict contract as the node path: throws Error('base64-malformed') on
|
|
22
|
+
* any deviation (illegal char, bad length, bad padding) rather than silently
|
|
23
|
+
* truncating, so a malformed signature is rejected loudly, never decoded to a
|
|
24
|
+
* short prefix that then "verifies" against something unintended.
|
|
25
|
+
*/
|
|
26
|
+
import { assertBase64 } from './base64-validate.js';
|
|
27
|
+
/**
|
|
28
|
+
* Strictly decode standard base64 to raw bytes using only browser-safe globals.
|
|
29
|
+
* Throws Error('base64-malformed') on any non-conforming input.
|
|
30
|
+
*/
|
|
31
|
+
export function decodeBase64StrictBrowser(s) {
|
|
32
|
+
assertBase64(s);
|
|
33
|
+
const bin = atob(s);
|
|
34
|
+
const out = new Uint8Array(bin.length);
|
|
35
|
+
for (let i = 0; i < bin.length; i++)
|
|
36
|
+
out[i] = bin.charCodeAt(i);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=base64-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64-browser.js","sourceRoot":"","sources":["../../src/internal/base64-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,CAAS;IACjD,YAAY,CAAC,CAAC,CAAC,CAAA;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IAC/D,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/base64-validate.ts
|
|
3
|
+
*
|
|
4
|
+
* Pure strict standard-base64 (RFC 4648 §4, with `=` padding) VALIDATION.
|
|
5
|
+
*
|
|
6
|
+
* INTERNAL: not exported from any public entry.
|
|
7
|
+
*
|
|
8
|
+
* This is the Buffer-free, node:crypto-free half of base64 handling, split out
|
|
9
|
+
* so the browser decoder (./base64-browser.ts) can validate without importing
|
|
10
|
+
* ./base64.ts (whose `decodeBase64Strict` uses the node `Buffer` global — safe
|
|
11
|
+
* in node, a runtime `ReferenceError` in a browser). The node decoder re-uses
|
|
12
|
+
* this same validator, so both paths reject exactly the same inputs.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Validate strict standard base64. Throws Error('base64-malformed') on any
|
|
16
|
+
* non-conforming input.
|
|
17
|
+
*/
|
|
18
|
+
export declare function assertBase64(s: string): void;
|
|
19
|
+
//# sourceMappingURL=base64-validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64-validate.d.ts","sourceRoot":"","sources":["../../src/internal/base64-validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ5C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/base64-validate.ts
|
|
3
|
+
*
|
|
4
|
+
* Pure strict standard-base64 (RFC 4648 §4, with `=` padding) VALIDATION.
|
|
5
|
+
*
|
|
6
|
+
* INTERNAL: not exported from any public entry.
|
|
7
|
+
*
|
|
8
|
+
* This is the Buffer-free, node:crypto-free half of base64 handling, split out
|
|
9
|
+
* so the browser decoder (./base64-browser.ts) can validate without importing
|
|
10
|
+
* ./base64.ts (whose `decodeBase64Strict` uses the node `Buffer` global — safe
|
|
11
|
+
* in node, a runtime `ReferenceError` in a browser). The node decoder re-uses
|
|
12
|
+
* this same validator, so both paths reject exactly the same inputs.
|
|
13
|
+
*/
|
|
14
|
+
// Standard base64 alphabet; `=` only as 1-2 trailing pad chars. Total length
|
|
15
|
+
// must be a multiple of 4.
|
|
16
|
+
const STD_B64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
17
|
+
/**
|
|
18
|
+
* Validate strict standard base64. Throws Error('base64-malformed') on any
|
|
19
|
+
* non-conforming input.
|
|
20
|
+
*/
|
|
21
|
+
export function assertBase64(s) {
|
|
22
|
+
if (typeof s !== 'string')
|
|
23
|
+
throw new Error('base64-malformed');
|
|
24
|
+
if (s.length % 4 !== 0)
|
|
25
|
+
throw new Error('base64-malformed');
|
|
26
|
+
if (!STD_B64.test(s))
|
|
27
|
+
throw new Error('base64-malformed');
|
|
28
|
+
// `=` may appear only in the final 1-2 positions. The regex `={0,2}` anchored
|
|
29
|
+
// at end already guarantees pad chars are contiguous and trailing, but a pad
|
|
30
|
+
// char earlier in the body would have been rejected by the alphabet class —
|
|
31
|
+
// so an in-body `=` cannot pass STD_B64. No extra check needed.
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=base64-validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64-validate.js","sourceRoot":"","sources":["../../src/internal/base64-validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,6EAA6E;AAC7E,2BAA2B;AAC3B,MAAM,OAAO,GAAG,wBAAwB,CAAA;AAExC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC9D,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC3D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACzD,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,gEAAgE;AAClE,CAAC"}
|
|
@@ -14,12 +14,14 @@
|
|
|
14
14
|
*
|
|
15
15
|
* Canonical inputs carry no surrounding whitespace, so no trim is applied;
|
|
16
16
|
* leading/trailing whitespace is itself a rejection.
|
|
17
|
+
*
|
|
18
|
+
* The strict VALIDATION (alphabet/length/padding) lives in the pure, Buffer-
|
|
19
|
+
* free ./base64-validate.ts so the browser decoder can share it; this module
|
|
20
|
+
* adds the node `Buffer`-based decode on top and re-exports `assertBase64` so
|
|
21
|
+
* existing importers of `./base64.js` are unchanged.
|
|
17
22
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* non-conforming input.
|
|
21
|
-
*/
|
|
22
|
-
export declare function assertBase64(s: string): void;
|
|
23
|
+
import { assertBase64 } from './base64-validate.js';
|
|
24
|
+
export { assertBase64 };
|
|
23
25
|
/**
|
|
24
26
|
* Strictly decode standard base64 to raw bytes. Throws
|
|
25
27
|
* Error('base64-malformed') on any non-conforming input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/internal/base64.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/internal/base64.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAGxD"}
|
package/dist/internal/base64.js
CHANGED
|
@@ -14,26 +14,14 @@
|
|
|
14
14
|
*
|
|
15
15
|
* Canonical inputs carry no surrounding whitespace, so no trim is applied;
|
|
16
16
|
* leading/trailing whitespace is itself a rejection.
|
|
17
|
+
*
|
|
18
|
+
* The strict VALIDATION (alphabet/length/padding) lives in the pure, Buffer-
|
|
19
|
+
* free ./base64-validate.ts so the browser decoder can share it; this module
|
|
20
|
+
* adds the node `Buffer`-based decode on top and re-exports `assertBase64` so
|
|
21
|
+
* existing importers of `./base64.js` are unchanged.
|
|
17
22
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const STD_B64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
21
|
-
/**
|
|
22
|
-
* Validate strict standard base64. Throws Error('base64-malformed') on any
|
|
23
|
-
* non-conforming input.
|
|
24
|
-
*/
|
|
25
|
-
export function assertBase64(s) {
|
|
26
|
-
if (typeof s !== 'string')
|
|
27
|
-
throw new Error('base64-malformed');
|
|
28
|
-
if (s.length % 4 !== 0)
|
|
29
|
-
throw new Error('base64-malformed');
|
|
30
|
-
if (!STD_B64.test(s))
|
|
31
|
-
throw new Error('base64-malformed');
|
|
32
|
-
// `=` may appear only in the final 1-2 positions. The regex `={0,2}` anchored
|
|
33
|
-
// at end already guarantees pad chars are contiguous and trailing, but a pad
|
|
34
|
-
// char earlier in the body would have been rejected by the alphabet class —
|
|
35
|
-
// so an in-body `=` cannot pass STD_B64. No extra check needed.
|
|
36
|
-
}
|
|
23
|
+
import { assertBase64 } from './base64-validate.js';
|
|
24
|
+
export { assertBase64 };
|
|
37
25
|
/**
|
|
38
26
|
* Strictly decode standard base64 to raw bytes. Throws
|
|
39
27
|
* Error('base64-malformed') on any non-conforming input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base64.js","sourceRoot":"","sources":["../../src/internal/base64.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"base64.js","sourceRoot":"","sources":["../../src/internal/base64.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,YAAY,CAAC,CAAC,CAAC,CAAA;IACf,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;AACjD,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/content-core.ts
|
|
3
|
+
*
|
|
4
|
+
* The CDRO OID content-core projection: the normative strip-set and the
|
|
5
|
+
* field-removal function that together define WHAT bytes an OID is computed
|
|
6
|
+
* over. This is a PURE module — no hashing, no node:crypto, no Buffer — so it
|
|
7
|
+
* is safe to import from both the node default entry (via oid.ts) and the
|
|
8
|
+
* browser verify surface (via verify-browser.ts) without dragging node
|
|
9
|
+
* builtins into a browser bundle.
|
|
10
|
+
*
|
|
11
|
+
* This is the SINGLE NORMATIVE SOURCE of the CDRO OID projection (ADR_019).
|
|
12
|
+
* oid.ts re-exports these symbols and layers the SHA-256 hashing on top; every
|
|
13
|
+
* other surface (GAP SDKs, the gateway signer, IMPLEMENTING.md) derives from
|
|
14
|
+
* THIS set, never re-lists it.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The detached-signature / envelope fields removed by `cdroContentCore`
|
|
18
|
+
* before hashing. This is the SINGLE NORMATIVE strip-set for the CDRO OID
|
|
19
|
+
* projection (ADR_019 decision 1); every other surface (GAP SDKs, the
|
|
20
|
+
* gateway signer, IMPLEMENTING.md) derives from THIS set, never re-lists it.
|
|
21
|
+
*
|
|
22
|
+
* The set is defined SEMANTICALLY: it is "every field produced BY the signer
|
|
23
|
+
* after canonicalization, plus the OID output itself." Concretely:
|
|
24
|
+
*
|
|
25
|
+
* oid — the projection OUTPUT (cannot be an input to itself).
|
|
26
|
+
* signature — legacy hybrid SignatureEnvelope (attaches after hash).
|
|
27
|
+
* ml_dsa_signature — detached PQ signature (attaches after hash).
|
|
28
|
+
* signature_key_id — signer-stamped key id (produced by the signer).
|
|
29
|
+
* signature_algorithm — signer-stamped alg id (produced by the signer).
|
|
30
|
+
* attestation — DSSE AttestationEnvelope (attaches after hash).
|
|
31
|
+
*
|
|
32
|
+
* EVERYTHING ELSE IS KEPT and hashed into the OID, including in particular:
|
|
33
|
+
* - `gap_version` — IN identity so a protocol downgrade is OID-detectable.
|
|
34
|
+
* - `supersedes` — IN identity because the SRAID Merkle-DAG head-proves-
|
|
35
|
+
* history property requires every lineage edge inside the
|
|
36
|
+
* hash. Superseding mints a NEW object; it never mutates
|
|
37
|
+
* the old one's bytes, so keeping it here is safe and
|
|
38
|
+
* makes the lineage edge tamper-evident.
|
|
39
|
+
* - `type`, `sraid_version`, `tenant_id`, `created_at_ms`, `created_by`,
|
|
40
|
+
* `body`, `authority`, `sensitivity`, `prev`, `links`, and any other
|
|
41
|
+
* content field.
|
|
42
|
+
*
|
|
43
|
+
* This is the ONE projection that yields the SAME OID whether the object is
|
|
44
|
+
* pre- or post-attestation: attaching an `attestation` (or `signature`,
|
|
45
|
+
* `ml_dsa_signature`, `signature_key_id`, `signature_algorithm`) after hashing
|
|
46
|
+
* is stripped back out here, so `cdroOid(obj)` is invariant across signing.
|
|
47
|
+
*
|
|
48
|
+
* It is FROZEN so no caller can mutate the normative set at runtime.
|
|
49
|
+
*/
|
|
50
|
+
export declare const CDRO_ENVELOPE_FIELDS: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Build the OID content core of a full CDRO: the object with EXACTLY the six
|
|
53
|
+
* detached-signature / envelope fields in `CDRO_ENVELOPE_FIELDS` removed at
|
|
54
|
+
* the top level, and everything else kept.
|
|
55
|
+
*
|
|
56
|
+
* This is the mechanism that makes the L4 `authority` block, the L3 lineage
|
|
57
|
+
* edges (`prev`, `links`, `supersedes`), the propagating `sensitivity` tier,
|
|
58
|
+
* and `gap_version` tamper-evident: they are hashed into identity by
|
|
59
|
+
* construction, so a field cannot be added, stripped, re-pointed, or
|
|
60
|
+
* downgraded without producing a different OID (and invalidating the
|
|
61
|
+
* signature, which is computed over these same bytes). Because `prev`/`links`/
|
|
62
|
+
* `supersedes` OIDs are inside the hash, a node's OID transitively commits its
|
|
63
|
+
* whole reachable history (the Merkle-DAG "head proves history" property).
|
|
64
|
+
*
|
|
65
|
+
* Returns a plain object suitable for `canonicalize` / `oidOf`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function cdroContentCore(cdro: unknown): Record<string, unknown>;
|
|
68
|
+
//# sourceMappingURL=content-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-core.d.ts","sourceRoot":"","sources":["../../src/internal/content-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAOhD,CAAA;AAIF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUtE"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synoi/sraid — internal/content-core.ts
|
|
3
|
+
*
|
|
4
|
+
* The CDRO OID content-core projection: the normative strip-set and the
|
|
5
|
+
* field-removal function that together define WHAT bytes an OID is computed
|
|
6
|
+
* over. This is a PURE module — no hashing, no node:crypto, no Buffer — so it
|
|
7
|
+
* is safe to import from both the node default entry (via oid.ts) and the
|
|
8
|
+
* browser verify surface (via verify-browser.ts) without dragging node
|
|
9
|
+
* builtins into a browser bundle.
|
|
10
|
+
*
|
|
11
|
+
* This is the SINGLE NORMATIVE SOURCE of the CDRO OID projection (ADR_019).
|
|
12
|
+
* oid.ts re-exports these symbols and layers the SHA-256 hashing on top; every
|
|
13
|
+
* other surface (GAP SDKs, the gateway signer, IMPLEMENTING.md) derives from
|
|
14
|
+
* THIS set, never re-lists it.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The detached-signature / envelope fields removed by `cdroContentCore`
|
|
18
|
+
* before hashing. This is the SINGLE NORMATIVE strip-set for the CDRO OID
|
|
19
|
+
* projection (ADR_019 decision 1); every other surface (GAP SDKs, the
|
|
20
|
+
* gateway signer, IMPLEMENTING.md) derives from THIS set, never re-lists it.
|
|
21
|
+
*
|
|
22
|
+
* The set is defined SEMANTICALLY: it is "every field produced BY the signer
|
|
23
|
+
* after canonicalization, plus the OID output itself." Concretely:
|
|
24
|
+
*
|
|
25
|
+
* oid — the projection OUTPUT (cannot be an input to itself).
|
|
26
|
+
* signature — legacy hybrid SignatureEnvelope (attaches after hash).
|
|
27
|
+
* ml_dsa_signature — detached PQ signature (attaches after hash).
|
|
28
|
+
* signature_key_id — signer-stamped key id (produced by the signer).
|
|
29
|
+
* signature_algorithm — signer-stamped alg id (produced by the signer).
|
|
30
|
+
* attestation — DSSE AttestationEnvelope (attaches after hash).
|
|
31
|
+
*
|
|
32
|
+
* EVERYTHING ELSE IS KEPT and hashed into the OID, including in particular:
|
|
33
|
+
* - `gap_version` — IN identity so a protocol downgrade is OID-detectable.
|
|
34
|
+
* - `supersedes` — IN identity because the SRAID Merkle-DAG head-proves-
|
|
35
|
+
* history property requires every lineage edge inside the
|
|
36
|
+
* hash. Superseding mints a NEW object; it never mutates
|
|
37
|
+
* the old one's bytes, so keeping it here is safe and
|
|
38
|
+
* makes the lineage edge tamper-evident.
|
|
39
|
+
* - `type`, `sraid_version`, `tenant_id`, `created_at_ms`, `created_by`,
|
|
40
|
+
* `body`, `authority`, `sensitivity`, `prev`, `links`, and any other
|
|
41
|
+
* content field.
|
|
42
|
+
*
|
|
43
|
+
* This is the ONE projection that yields the SAME OID whether the object is
|
|
44
|
+
* pre- or post-attestation: attaching an `attestation` (or `signature`,
|
|
45
|
+
* `ml_dsa_signature`, `signature_key_id`, `signature_algorithm`) after hashing
|
|
46
|
+
* is stripped back out here, so `cdroOid(obj)` is invariant across signing.
|
|
47
|
+
*
|
|
48
|
+
* It is FROZEN so no caller can mutate the normative set at runtime.
|
|
49
|
+
*/
|
|
50
|
+
export const CDRO_ENVELOPE_FIELDS = Object.freeze([
|
|
51
|
+
'oid',
|
|
52
|
+
'signature',
|
|
53
|
+
'ml_dsa_signature',
|
|
54
|
+
'signature_key_id',
|
|
55
|
+
'signature_algorithm',
|
|
56
|
+
'attestation',
|
|
57
|
+
]);
|
|
58
|
+
const CDRO_ENVELOPE_FIELD_SET = new Set(CDRO_ENVELOPE_FIELDS);
|
|
59
|
+
/**
|
|
60
|
+
* Build the OID content core of a full CDRO: the object with EXACTLY the six
|
|
61
|
+
* detached-signature / envelope fields in `CDRO_ENVELOPE_FIELDS` removed at
|
|
62
|
+
* the top level, and everything else kept.
|
|
63
|
+
*
|
|
64
|
+
* This is the mechanism that makes the L4 `authority` block, the L3 lineage
|
|
65
|
+
* edges (`prev`, `links`, `supersedes`), the propagating `sensitivity` tier,
|
|
66
|
+
* and `gap_version` tamper-evident: they are hashed into identity by
|
|
67
|
+
* construction, so a field cannot be added, stripped, re-pointed, or
|
|
68
|
+
* downgraded without producing a different OID (and invalidating the
|
|
69
|
+
* signature, which is computed over these same bytes). Because `prev`/`links`/
|
|
70
|
+
* `supersedes` OIDs are inside the hash, a node's OID transitively commits its
|
|
71
|
+
* whole reachable history (the Merkle-DAG "head proves history" property).
|
|
72
|
+
*
|
|
73
|
+
* Returns a plain object suitable for `canonicalize` / `oidOf`.
|
|
74
|
+
*/
|
|
75
|
+
export function cdroContentCore(cdro) {
|
|
76
|
+
if (cdro === null || typeof cdro !== 'object' || Array.isArray(cdro)) {
|
|
77
|
+
throw new TypeError('cdroContentCore: argument must be a CDRO object');
|
|
78
|
+
}
|
|
79
|
+
const core = {};
|
|
80
|
+
for (const [k, v] of Object.entries(cdro)) {
|
|
81
|
+
if (CDRO_ENVELOPE_FIELD_SET.has(k))
|
|
82
|
+
continue;
|
|
83
|
+
core[k] = v;
|
|
84
|
+
}
|
|
85
|
+
return core;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=content-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-core.js","sourceRoot":"","sources":["../../src/internal/content-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB,MAAM,CAAC,MAAM,CAAC;IACnE,KAAK;IACL,WAAW;IACX,kBAAkB;IAClB,kBAAkB;IAClB,qBAAqB;IACrB,aAAa;CACd,CAAC,CAAA;AAEF,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAA;AAElF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,SAAS,CAAC,iDAAiD,CAAC,CAAA;IACxE,CAAC;IACD,MAAM,IAAI,GAA4B,EAAE,CAAA;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;QACrE,IAAI,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAQ;QAC5C,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACb,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|