KSA Core — statements, data model, canonical encoding and cipher suites¶
Specification SPEC-0002 · version 0.1.0 · draft
Abstract¶
This document specifies the KSA statement: a signed assertion by one key about one target. It defines the data model every statement is built from, a single deterministic binary encoding, the envelope that carries a statement with its signature, the cipher suites that fix the exact bytes signed, the registered statement kinds, and the procedure a verifier follows to establish that one statement is well-formed and was signed by the key it names. Whether a verified statement should be believed is out of scope here; that is trust evaluation (SPEC-0004).
Status of this document¶
Draft for review in the m-of-n project. The base of this specification is the
sponsor's FKSA core v0.2.1, adopted by ADR-0003; Appendix C lists every
difference. Nothing in this draft is final until its version leaves 0.x.
Table of contents¶
- Introduction · 2. Conventions and terminology · 3. Overview · 4. Data model and canonical encoding · 5. The signed statement envelope · 6. Cipher suites ·
- Statement structure · 8. Statement kinds · 9. Verifying one statement ·
- Key store · 11. Human-review form · 12. Registries · 13. Security considerations · 14. Privacy considerations · 15. References · Appendix A. Test vectors · Appendix B. CDDL · Appendix C. Changes from FKSA v0.2.1
1. Introduction¶
KSA (Key-centric Semantic Attestations) is a protocol of statements: signed messages in which a key says something about a target. Every exchange that asserts or transfers trust — publishing a key, making a claim about an artifact, delegating authority, reviewing, revoking — is a statement with one shared structure.
This document fixes three things exactly, because everything else depends on them:
- the bytes that are signed, so that any two conforming implementations produce and verify identical signatures;
- the bytes that are hashed, so that statements and definitions can be referenced by digest without ambiguity;
- the order of verification: a signature is checked over the bytes as received, before those bytes are decoded.
The meaning of the values inside a statement — what a type is, which values it permits, how it renders for a person — is defined by definitions (SPEC-0003). How statements combine into a decision is trust evaluation (SPEC-0004).
2. Conventions and terminology¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
| term | meaning |
|---|---|
| key | a public key under a cipher suite: an opaque octet string whose layout the suite fixes |
| kid | key identifier: the 32-octet SHA-256 digest of the key's encoding (§4.5) |
| persona | a principal identified by a key (SPEC-0001 §3). On the wire a persona appears only as kids |
| statement | the signed object of §7: a kind, a suite, a speaker (says), a target (this), a validity window and a kind-specific body |
| TBS | "to be signed": the canonical encoding (§4) of a statement |
| envelope | the array that carries a TBS with its signature (§5) |
| statement digest | SHA-256 of the TBS (§6.3); how one statement refers to another |
| definition | a hash-identified document that defines types, templates and processes (SPEC-0003) |
| DefinitionId | SHA-256 of a definition body's canonical encoding (SPEC-0003 §4) |
| verifier | an implementation that performs the procedure of §9 |
Byte strings are written as lowercase hexadecimal. ‖ denotes concatenation.
3. Overview¶
┌────────────────────── envelope (§5) ───────────────────────┐
│ suite │ says (kid) │ TBS (bytes, exactly as signed) │ sig │ ? pub │
└────────────────────────────┬───────────────────────────────┘
│ decoded only after the signature verifies
▼
statement (§7): kind · suite · says · this · valid · body
A producer builds a statement, encodes it canonically (§4) to obtain the TBS,
signs DS ‖ TBS under its suite (§6), and transmits the envelope. A verifier
reads the envelope, resolves the key named by says, verifies the signature
over the received TBS, and only then decodes the TBS with a validating decoder
and checks its structure (§9).
Three properties follow:
- No canonicalisation during verification. The verifier never re-encodes. It checks that the received bytes are already canonical (§4.3); if they are not, the statement is rejected — never repaired.
- Domain separation. Every signature covers a suite-specific label (§6.4), so a KSA signature cannot be replayed as a signature in another protocol, or in FKSA, and vice versa.
- Content addressing. A statement is referred to by the SHA-256 of its TBS; a definition by the SHA-256 of its body. Both are stable across transports.
4. Data model and canonical encoding¶
4.1 Data model¶
Every TBS and every definition body MUST consist only of the following values.
| type | rule |
|---|---|
| integer | in the range −(2^53 − 1) … 2^53 − 1 inclusive |
| byte string | any length, subject to §13.6 |
| text string | valid UTF-8. Preserved byte-exact; MUST NOT be normalised (no Unicode normalisation, no case folding, no whitespace trimming) by any producer or verifier |
| boolean | true or false |
| array | ordered; order is significant and signed |
| map | keys are unsigned integers in protocol structures (§7, SPEC-0003 §5) and text strings inside values and language maps; no duplicate keys |
The following MUST NOT appear anywhere in a TBS or definition body: floating-point
numbers, null, undefined, any other simple value, CBOR tags (major type 6),
and indefinite-length items.
4.2 Deterministic encoding¶
A TBS or definition body MUST be encoded as CBOR [RFC8949] satisfying the core deterministic encoding requirements of [RFC8949] §4.2.1, restricted to the data model of §4.1:
- every integer, length and count uses the shortest possible head (preferred serialization);
- every array, map, byte string and text string has a definite length;
- the keys of every map are sorted in bytewise lexicographic order of their deterministic encodings;
- no tags, no floating-point values, and no simple values other than
true(0xf5) andfalse(0xf4).
This is the encoding called KSA-CBOR in this specification and in SPEC-0003. It is the single canonical encoding for every signed or hashed object (ADR-0003 D2).
4.3 Validating decoder¶
A verifier MUST decode a TBS (and a definition body, SPEC-0003 §4) with a decoder that rejects any input that is not exactly the KSA-CBOR encoding of some value in the data model. In particular it MUST reject:
- a head longer than necessary (e.g.
0x1817for the integer 23); - an indefinite-length item;
- map keys not in sorted order, or a duplicated key;
- a tag, a floating-point value,
null,undefined, or any simple value other thantrueandfalse; - an integer outside the range of §4.1;
- a text string that is not valid UTF-8;
- bytes remaining after the top-level item.
Rejection MUST NOT be replaced by repair: a decoder MUST NOT re-sort, re-encode or otherwise normalise and then accept. Every check above can be made in a single forward pass without re-encoding (mofn#78).
4.4 Time¶
A time is an integer T derived from s, the number of seconds since
2026-01-01T00:00:00Z (negative before it):
- if
s mod 86400 = 0:T = 2·(s / 86400) + 1(odd: the day form); - otherwise:
T = 2·s(even: the seconds form).
To decode: an odd T gives s = ((T − 1) / 2) · 86400; an even T gives
s = T / 2. An even T whose s is a multiple of 86400 MUST be rejected, so
every instant has exactly one encoding. Leap seconds are not represented.
In the human-review form (§11) a time is written exactly as
YYYY-MM-DDTHH:MM:SSZ: upper-case T and Z, no fraction, no offset, seconds
00–59. Any other spelling MUST be rejected, not normalised.
4.5 Identifiers¶
| identifier | definition | size |
|---|---|---|
| kid | SHA-256 of the key's public-key encoding under its suite (§6) | 32 octets |
| statement digest | SHA-256 of the statement's TBS, under the statement's own suite | 32 octets |
| DefinitionId | SHA-256 of the definition body's KSA-CBOR encoding (SPEC-0003 §4) | 32 octets |
Identifiers MUST appear in full in every TBS and every definition body. A transport MAY abbreviate them on the wire, provided the receiver reconstructs the full TBS before verification (§13.7).
5. The signed statement envelope¶
A statement is transmitted as a signed statement: a KSA-CBOR array of four or five elements.
signed-statement = [ suite, says, tbs, sig, ? pub ]
| # | element | type | authenticated? |
|---|---|---|---|
| 0 | suite |
unsigned integer | no — a hint; checked against the TBS in step V6 |
| 1 | says |
kid (32-octet byte string) | no — a hint; checked against the TBS in step V6 |
| 2 | tbs |
byte string: the TBS exactly as signed | yes |
| 3 | sig |
byte string: the signature over DS ‖ tbs (§6) |
— |
| 4 | pub |
byte string: the speaker's public-key encoding | no — OPTIONAL; checked against says in V3 |
The envelope exists so that a verifier can verify before it decodes.
suite and says tell it which key and which algorithm to use; tbs is
verified as received; only then is it decoded. pub lets a verifier check a
statement from a key it does not yet hold — REQUIRED for the bootstrap kinds
(key-publish, and self when it carries a key), OPTIONAL otherwise.
A producer MUST place the canonical TBS in tbs and MUST set suite and says
to the values inside it. An envelope is not itself hashed or signed; the
statement digest is computed over tbs only.
Why not sign the statement "minus its signature field", as FKSA does? Because a verifier would have to decode, remove a field, and re-encode before it could check the signature — canonicalising during verification, exposing its decoder to unauthenticated input, and creating a second encoder whose output must match the producer's byte for byte. Carrying the signed bytes intact removes all three (ARCH-0001 R-O-05).
6. Cipher suites¶
6.1 What a suite defines¶
A cipher suite is an immutable registry entry (§12.3). Each entry MUST define:
| item | meaning |
|---|---|
| suite code | an unsigned integer; never reused |
| name | a stable text name |
| key algorithm | the signature algorithm and its parameters |
| public-key encoding | the exact octets of a public key — the input to kid |
| signature input | the exact octets signed: DS ‖ TBS, with its DS label (§6.4) |
| signature encoding | the exact octets of sig |
| verification rules | including any strictness beyond the base algorithm |
| digest | the hash used for statement digests and kids |
A statement's suite is inside its TBS and is therefore covered by its signature. A verifier MUST report a statement under an unregistered or unsupported suite as unverifiable (§9), which is distinct from invalid.
6.2 Suite codes¶
| code | name | status |
|---|---|---|
| 0 | — | reserved; never valid |
| 1 | ksa-ed25519-sha256 |
default (§6.3) |
| 2 | ksa-p256-sha256 |
reserved; not yet specified |
| 3–7 | — | reserved: classical suites |
| 8 | ksa-mldsa65-sha256 |
provisional (§6.5) |
| 9–15 | — | reserved: post-quantum and hybrid suites |
| 16–255 | — | Specification Required (§12) |
| 256–65535 | — | experimental and private use; MUST NOT be used outside a closed deployment |
6.3 Suite 1 — ksa-ed25519-sha256¶
- Key algorithm: Ed25519, PureEdDSA [RFC8032].
- Public-key encoding: the 32-octet encoding of [RFC8032] §5.1.2.
kid = SHA-256(public key). - Signature input:
DS ‖ TBS, whereDSis the labelKSA-STMT-SIG-v1followed by one zero octet (16 octets; hex4b53412d53544d542d5349472d763100). The TBS octets are signed directly, not a digest of them. - Signature encoding: the 64-octet
R ‖ Sof [RFC8032] §5.1.6. - Statement digest: SHA-256(TBS), without
DS. - Strict key rules. A verifier MUST reject a public key — when it is ingested (§10) and again before any verification under it — if its encoding is non-canonical (the encoded y ≥ p, with p = 2^255 − 19, or x = 0 with the sign bit set), if it does not decode to a curve point, or if it decodes to a point of small order ([8]A is the identity; this covers all eight points of the torsion subgroup, including the identity).
- Strict signature rules. A verifier MUST reject a signature if S ≥ L, where L = 2^252 + 27742317777372353535851937790883648493; if R is non-canonical or not on the curve; or if R is of small order. Only then does it evaluate the verification equation of [RFC8032] §5.1.7. A library verify function that accepts small-order keys or S ≥ L MUST NOT be relied on alone; implementations SHOULD use one documented to enforce these rules.
6.4 Domain-separation labels¶
A DS label is a fixed ASCII string followed by one zero octet. It is prepended to the bytes being signed and is never transmitted.
| label | signs |
|---|---|
KSA-STMT-SIG-v1\0 |
a KSA statement, in every suite that prepends a label |
KSA-POP-SIG-v1\0 |
a proof of possession over a presentation (SPEC-0001 §8) |
KSA-<OBJECT>-SIG-v<n>\0 |
any future signed object; each MUST register its own label, and reusing another's is forbidden |
The labels differ from FKSA's (FKSA-STMT-SIG-v0\0) on purpose: a statement in
one protocol cannot verify as a statement in the other.
For suites whose algorithm has a context parameter (ML-DSA), the label without its zero octet is passed as that context, and is not prepended (§6.5).
6.5 Suite 8 — ksa-mldsa65-sha256 (provisional)¶
- Key algorithm: ML-DSA-65 [FIPS204], pure (not HashML-DSA).
- Public-key encoding: the 1952-octet encoding of [FIPS204].
kid = SHA-256(public key). - Signature input: the TBS, with context string
ctx = "KSA-STMT-SIG-v1"(15 octets). - Signature encoding: the 3309-octet signature of [FIPS204].
- Statement digest: SHA-256(TBS).
Provisional: no test vectors are published for it yet, and it MUST NOT be the only suite a wallet offers until they are. It is specified now because a statement verified decades after signing must survive the post-quantum transition (ARCH survey R-001 §10).
7. Statement structure¶
7.1 Fields¶
A statement is a KSA-CBOR map with these keys. Absent optional fields MUST be omitted; they MUST NOT be present with an empty or placeholder value.
| key | name | type | presence |
|---|---|---|---|
| 1 | kind |
unsigned integer (§8) | REQUIRED |
| 2 | suite |
unsigned integer (§6.2) | REQUIRED |
| 3 | says |
kid — the speaker | REQUIRED |
| 4 | this |
target (§7.2) | REQUIRED except as §8 allows |
| 5 | valid |
validity (§7.3) | RECOMMENDED; REQUIRED for rotate and revoke |
| 6 | body |
map — kind-specific (§8) | REQUIRED |
The statement map is closed: a key not listed above MUST cause rejection. Every map inside a statement defined by this specification is closed in the same way. KSA has no namespaced extension fields: all extensibility is through attributes whose types are defined in definitions (§7.4; ADR-0003 D1), so an unrecognised field is always an error.
7.2 Targets¶
this names what the statement is about. It is an array whose first element is
a target type.
| type | form | names |
|---|---|---|
| 1 key | [1, kid] |
a key — a persona |
| 2 digest | [2, digest-alg, bytes] |
an object identified by its digest; digest-alg 1 = SHA-256 (32 octets) |
| 3 statement | [3, statement-digest] |
another statement |
| 4 definition | [4, DefinitionId] |
a definition |
| 5 locator | [5, text] |
a resource identified by a URI; weaker than a digest, and SHOULD be used only where no digest exists |
| 6 description | [6, type-ref, value] |
something identified by a typed description — the description's canonical encoding is its identity |
FKSA permits only keys as subjects. KSA permits any of the above, which is what lets a statement concern a release, a record, or another statement.
7.3 Validity¶
valid = { ? 1 not-before: time, ? 2 not-on-or-after: time, ? 3 issued: time }
A statement is valid at time t if and only if not-before ≤ t when
not-before is present and t < not-on-or-after when not-on-or-after is
present. A missing bound is unbounded on that side.
issued is the speaker's statement of when it signed. It is REQUIRED for
rotate and revoke, and RECOMMENDED for every other kind, because rotation
semantics depend on it (SPEC-0004 §7). Whether a statement is valid at a given
time is evaluated by trust evaluation, not by single-statement verification (§9).
7.4 Attributes and type references¶
type-ref = { 1 definition: DefinitionId, 2 label: text }
attribute = { 1 type: type-ref, 2 value: value }
attribute-range = { 1 type: type-ref, ? 3 range: value }
A type reference names a type by the hash of the definition that defines it
and a label local to that definition. Inside a statement, definition is
REQUIRED. (Inside a definition it MAY be omitted to mean "this definition";
SPEC-0003 §5.2.)
An attribute assigns a value; an attribute range states a set of values —
the scope of a trust statement or of a delegation constraint. An attribute range
with no range means the unbounded range of its type. Whether a value is an
acceptable assignment, whether a range is well-formed, and whether one range is
within another are defined by the type's base kind (SPEC-0003 §6). Supplying a
range where an assignment is required, or the reverse, is a type error.
8. Statement kinds¶
8.1 Registry of kinds¶
| code | kind | this |
purpose |
|---|---|---|---|
| 1 | key-publish |
MUST be [1, says] |
publish the speaker's public key |
| 2 | self |
MUST be [1, says] |
the speaker's public claims about itself |
| 3 | speaks |
MUST be [1, says] |
the definitions the speaker can produce and understand |
| 4 | attestation |
any target | assign attributes to the target |
| 5 | trust |
[1, kid], or absent in the threshold form |
extend trust to a key about a range of attributes |
| 6 | revoke |
MUST be [1, says] |
withdraw one of the speaker's own statements |
| 7 | rotate |
[1, new-kid], not equal to says |
name the speaker key's successor |
| 8 | define |
MUST be [4, DefinitionId] |
publish a definition, as its author |
| 9 | review |
[3, statement-digest] or [2, …] |
give an opinion on a statement or object |
| 10 | approve |
[3, statement-digest] or [2, …] |
authorise a statement or object |
| 11 | aggregate |
any target except [1, …] |
the result of a published process (SPEC-0005) |
A verifier MUST reject a statement whose kind is not registered.
8.2 key-publish (1)¶
body = { 1 key: public-key }
public-key = { 1 alg: key-alg, 2 pub: bytes }
kid(body.key) MUST equal says. The envelope MUST carry pub, and it MUST
equal body.key.pub. A verified key-publish is one of the two ways a key
enters a key store (§10).
8.3 self (2)¶
body = { ? 1 key: public-key, ? 2 label: text, ? 3 uses: [+ usage],
? 4 created: time, ? 5 controller: controller-kind }
The speaker's public self-description. label is a display string, not a
binding. uses lists usage codes (§12.7). controller states what kind of
entity controls the key (§12.8) — a self-claim, worth what a self-claim is
worth; SPEC-0004 §5 says how stronger evidence is weighed. If key is present
the rules of §8.2 apply to it. Private notes about a key (SPEC-0001 §5.4) are
never carried in a self statement.
8.4 speaks (3)¶
body = { 1 definitions: [+ DefinitionId] }
The speaker claims it can produce and understand statements using these
definitions. A relying party SHOULD check that an attester speaks a definition
before relying on its attestations under it; whether a missing speaks is a
warning or a failure is policy (SPEC-0004 §9).
8.5 attestation (4)¶
body = { 1 has: [+ attribute], ? 3 template: type-ref }
The speaker asserts that the target has each attribute. Each attribute's value
MUST be a valid assignment for its type (SPEC-0003 §6). template, when present,
names the template the statement was issued from (SPEC-0003 §7); a statement
that names a template MUST conform to it, and conformance is checked by trust
evaluation, where the definition is available.
8.6 trust (5)¶
body = { 1 about: [+ attribute-range],
? 2 may-delegate: delegation-constraints,
? 3 trusts: [2* kid], ? 4 threshold: uint }
delegation-constraints = { ? 1 depth: uint, ? 2 ranges: [+ attribute-range],
? 3 allow-keys: [+ kid], ? 4 exclude-keys: [+ kid],
? 5 not-on-or-after: time }
The speaker extends trust to a key about a range of attributes. In the
threshold form, this is absent, trusts lists two or more keys, and
threshold is an integer n with 1 ≤ n ≤ the number of keys: the trust is
extended to any n of them acting together (SPEC-0004 §6.4). Otherwise this
MUST be present and trusts and threshold MUST be absent.
about MUST NOT be empty: unlimited trust is written as an attribute range with
no range for each type concerned. Without may-delegate, trust is one hop:
the trusted key may attest, but trust statements it issues are not followed.
With it, depth counts further hops; ranges is an allow-list that every
further delegation must fall within; allow-keys and exclude-keys constrain
who may be delegated to; not-on-or-after caps validity, and the earlier bound
wins. SPEC-0004 §6 is normative for how these are applied.
8.7 revoke (6)¶
body = { 1 revokes: statement-digest }
Withdraws the statement with that digest. Only that statement's speaker may
revoke it (ADR-0003 D5); a revoke naming a statement by another speaker has
no effect. Revocation takes effect at valid.not-before.
8.8 rotate (7)¶
body = { ? 1 note: text }
Signed by the old key (says), naming the new key (this). valid.issued is
REQUIRED. A rotate does not bind the new key's public key; the new key MUST be
published by its own key-publish. SPEC-0004 §7 defines how statements before
and after a rotation are evaluated.
8.9 define (8)¶
body = { 1 name: text, 2 version: text, ? 3 supersedes: DefinitionId }
Publishes the definition named by this as the speaker's. The speaker MUST
equal the definition body's definer (SPEC-0003 §4); a verifier holding the
definition MUST check this, and name and version MUST equal the body's.
supersedes names an earlier definition this one replaces; it is honoured only
if the earlier definition has the same definer (SPEC-0003 §8.3).
8.10 review (9) and approve (10)¶
review-body = { 1 has: [+ attribute], ? 2 comment: text, ? 3 template: type-ref }
approve-body = { ? 1 has: [+ attribute], ? 2 comment: text, ? 3 template: type-ref }
A review is an opinion; its attributes (e.g. an outcome) are typed by a definition. An approval is an authorization: it counts towards a requirement only if its speaker is entitled to approve, which SPEC-0004 and SPEC-0005 determine. A review never satisfies an approval requirement.
8.11 aggregate (11)¶
body = { 1 process: process-ref, 2 inputs: [+ statement-digest], 3 result: bool }
process-ref = { 1 definition: DefinitionId, 2 label: text }
The outcome of evaluating a published process over the cited input statements. An aggregate is believed only if it recomputes (SPEC-0005 §6).
9. Verifying one statement¶
9.1 Results¶
| result | meaning |
|---|---|
| verified | the statement is well-formed and was signed by the key named by says |
| invalid | it is malformed, or its signature does not verify; it MUST NOT be used |
| unverifiable | it may be valid, but this verifier cannot tell: unsupported suite, or no key for says |
An invalid statement carries a reason code (§12.9).
9.2 Procedure¶
A verifier MUST perform these steps in this order, stopping at the first that fails.
| step | check | on failure |
|---|---|---|
| V1 envelope | the input decodes, under §4.3, as an array of 4 or 5 elements of types (uint, 32-octet bytes, bytes, bytes, ? bytes) with no trailing bytes | invalid envelope |
| V2 suite | suite is registered and supported |
unverifiable suite |
| V3 key | obtain the public key: from the key store by (suite, says); or, if the envelope carries pub, from pub after checking kid(pub) = says. Apply the suite's strict key rules (§6.3) |
unverifiable unknown-key if none; invalid key if the strict rules or the kid check fail |
| V4 signature | verify sig over the suite's signature input built from the received tbs, under the suite's strict signature rules |
invalid signature |
| V5 canonical | decode tbs with the validating decoder of §4.3 |
invalid encoding |
| V6 agreement | the decoded suite and says equal the envelope's |
invalid envelope-mismatch |
| V7 structure | the statement and every map in it conform to §7 and §8 and Appendix B: closed maps, registered kind, required fields present, this as the kind requires, every type-ref carries a definition |
invalid structure |
| V8 kind rules | the kind-specific checks of §8 that need only this statement (e.g. key-publish: kid(body.key) = says; rotate: this ≠ [1, says]; trust: target and threshold form) |
invalid kind-rule |
| V9 result | the statement is verified; its digest is SHA-256(tbs) |
— |
Checks that need other statements, definitions or time — revocation, validity at a time, whether a type exists, whether a value is in range, authorization — are not part of single-statement verification. They are trust evaluation (SPEC-0004).
10. Key store¶
A verifier keeps a key store mapping (suite, kid) to a public key. It MUST add a binding only from:
- a verified
key-publish, or a verifiedselfthat carries a key, whose key hashes to itssays; or - an out-of-band import — for example a scanned code or a file — followed by the same check that the kid is the SHA-256 of the key.
Before storing, the suite's strict key rules MUST be applied. A key MUST NOT be
added because a statement merely names it, because it appears as an envelope
pub on a statement of another kind, or because a rotate names it.
A key in the key store is known, not trusted. Trust is decided by trust evaluation, per context (SPEC-0004).
11. Human-review form¶
Statements and definitions have a YAML form for people to read and review. It is never signed or hashed: the signed object is always the KSA-CBOR encoding. A conforming tool converts between the two one-to-one.
This is test vector TV-4 (Appendix A) in human-review form:
kind: attestation
suite: ksa-ed25519-sha256
says: '0x21fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9'
this: {digest: {alg: sha-256, value: '0x48dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba7'}}
valid:
not before: "2026-10-06T00:00:00Z"
not on or after: "2026-11-01T00:00:00Z"
issued: "2026-10-06T10:30:00Z"
body:
has:
- type: {definition: '0x517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a7175', label: build-provenance}
value: reproducible
Rules (adopted from FKSA §2.1):
- Field names are the names of §7–§8, with
-written as a space. - Byte strings are quoted text:
'0x'followed by lowercase hexadecimal. - Times are quoted text in the exact form of §4.4. A YAML loader MUST NOT resolve YAML timestamps.
- Integers are decimal only:
0, or an optional-followed by a non-zero digit and further digits. Hexadecimal, octal, binary, a leading+, leading zeros,-0,_separators and sexagesimal forms MUST be rejected, whether implicit or tagged. - Floats,
nulland YAML-only types MUST be rejected. - The human form MAY carry annotations whose keys begin with
_; they are discarded before encoding and never signed.
12. Registries¶
Every registry in this section is append-only. A code or name, once assigned, MUST NOT be reassigned or reused; a withdrawn entry becomes "reserved, never assigned". Code 0 is reserved in every numeric registry. "Specification Required" means: added by a revision of this specification accepted through an ADR. Registering an entry MUST NOT change the canonical bytes of any existing statement.
12.1 Statement kinds — §8.1¶
12.2 Target types — §7.2¶
12.3 Cipher suites — §6.2¶
12.4 Key algorithms (public-key.alg)¶
| code | algorithm | suites |
|---|---|---|
| 1 | Ed25519 | 1 |
| 2 | ECDSA P-256 (reserved) | 2 |
| 8 | ML-DSA-65 (provisional) | 8 |
12.5 Digest algorithms (target type 2)¶
| code | algorithm | length |
|---|---|---|
| 1 | SHA-256 | 32 |
| 2 | SHA-384 | 48 |
| 3 | SHA-512 | 64 |
12.6 DS labels — §6.4¶
12.7 Usage codes (self.uses)¶
| code | usage | code | usage | |
|---|---|---|---|---|
| 1 | statements | 4 | ||
| 2 | tls | 5 | payments | |
| 3 | ipsec | 6 | transport (SPEC-0001 §8) |
Usage codes are declarative. Wallets SHOULD vary their interface by usage — payments SHOULD require stronger confirmation — and enforcement at evaluation time is policy (SPEC-0004 §9).
12.8 Controller kinds (self.controller)¶
| code | controller |
|---|---|
| 1 | person |
| 2 | organisation |
| 3 | service or script |
| 4 | AI agent |
| 5 | software implementation |
| 6 | hardware device |
12.9 Verification reason codes — §9.2¶
envelope, suite, unknown-key, key, signature, encoding,
envelope-mismatch, structure, kind-rule.
13. Security considerations¶
13.1 Canonicalisation¶
Signing a re-encoded form invites two encoders to disagree and lets a verifier's decoder run on unauthenticated input. KSA signs and verifies the received bytes (§5) and rejects any non-canonical encoding (§4.3), so there is exactly one encoding of each statement and no repair path.
13.2 Cross-protocol use¶
A signature binds its DS label (§6.4). A key that is also used in another protocol cannot have a KSA signature replayed there, or a signature from there replayed as KSA, provided that protocol also domain-separates. Wallets SHOULD NOT use one key in more than one protocol even so (SPEC-0001 §5.3).
13.3 Malleability¶
Without the strict rules of §6.3, Ed25519 admits more than one valid signature on a message (S + L) and keys of small order that verify forged signatures. Statements are content-addressed by the digest of their TBS, not of their signature, so signature malleability cannot change a statement's identity — but the strict rules are still REQUIRED, because some downstream systems key on signatures.
13.4 Key substitution¶
kid is the hash of the full public key, so two keys
cannot share a kid without a SHA-256 collision. Identifiers MUST NOT be truncated
in signed or hashed bytes.
13.5 Unknown suites and kinds¶
An unknown suite is unverifiable, never silently accepted; an unknown kind or field is invalid. A verifier MUST NOT skip what it does not understand (ARCH-0002 P5).
13.6 Resource limits¶
A verifier MUST accept a TBS of at least 65 536 octets
and nesting depth of at least 16, and MAY reject larger or deeper inputs as
encoding. It MUST bound the work it performs on any input before V4 succeeds.
13.7 Abbreviated transport forms¶
A transport that abbreviates identifiers (§4.5) MUST NOT be trusted to reconstruct them; the reconstructed TBS is verified in full, and an abbreviation that reconstructs to the wrong bytes simply fails V4.
13.8 Replay¶
A statement is a durable assertion; replaying it is not an attack on it. Freshness, where needed, comes from validity windows and from a proof of possession bound to a presentation and a nonce (SPEC-0001 §8).
13.9 Time¶
Validity depends on the evaluator's clock. SPEC-0004 §8 says how a time is chosen.
14. Privacy considerations¶
Statements are designed to be shown to others. A kid is a stable identifier and
links every statement made with that key; personas that need to be unlinkable
MUST use separate keys. self.label and self.controller are published. Trust
statements reveal relationships; SPEC-0004 §4 keeps trust anchors local unless
their owner chooses to publish them.
15. References¶
15.1 Normative¶
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
- [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, May 2017.
- [RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital Signature Algorithm (EdDSA)", RFC 8032, January 2017.
- [RFC8949] Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", STD 94, RFC 8949, December 2020.
- [FIPS180-4] NIST, "Secure Hash Standard (SHS)", FIPS 180-4, August 2015.
- [FIPS204] NIST, "Module-Lattice-Based Digital Signature Standard", FIPS 204, August 2024.
15.2 Informative¶
- [RFC8610] Birkholz, H., Vigano, C. and C. Bormann, "Concise Data Definition Language (CDDL)", RFC 8610, June 2019.
- [RFC8785] Rundgren, A., Jordan, B. and S. Erdtman, "JSON Canonicalization Scheme (JCS)", RFC 8785, June 2020.
- [FKSA] Lambert, P., "FKSA Core Specification v0.2.1", sponsor draft, October 2026.
- [ADR-0003] "KSA adopts the FKSA core", m-of-n, October 2026.
- [ARCH-0001], [ARCH-0002], [ARCH-0003] — the design record for this specification.
Appendix A. Test vectors¶
Generated by spec/vectors/ksa-core/generate.py with the cryptography and
cbor2 libraries; every positive vector is encoded by two independent encoders
that agree byte for byte, and every signature verifies with a third, separate
check. Machine-readable form: spec/vectors/ksa-core/vectors.json. A conforming
verifier MUST return verified for every positive vector and invalid at
the stated step for every negative vector.
Keys¶
| name | seed | public key | kid = SHA-256(pub) |
|---|---|---|---|
| alice | 9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60 |
d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a |
21fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9 |
| bob | 4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb |
3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c |
39f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f |
| carol | 94f0d20c5f4157e44463f03fae4d9c93c59da7c42af17014481faf7ab80c5009 |
be2809c0673894dc058c0f06f32d870c2a95b671d9df62074fcb19c0c203bf6b |
c7b66369c87c115e8f8ab2fd27540d1a8a28cc475aab29b58ba0caf47910e207 |
| bob2 | cfe6d5ee21b7bf722007ceb061436f23285c43dd9366d51d5d9cd978be007061 |
05da6bf466928fa468b1ecb00413a356c33502b70dc0620020fe98315cd1dfd8 |
9dcd2b600a6996b68623f46e19c60b6eb076c4a707df022e8479ef1d191b91f6 |
Domain-separation label (hex): 4b53412d53544d542d5349472d763100
DV-1 — definition supply-chain v1, definer Alice¶
DefinitionId = SHA-256(body) = 517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a7175
a401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9026c737570706c792d636861696e03613105838201a701706275696c642d70726f76656e616e6365020103a262656e704275696c642070726f76656e616e6365626573781e50726f636564656e636961206465206c6120636f6d70696c616369c3b36e04a262656e781b486f772074686520617274696661637420776173206275696c742e626573781f43c3b36d6f20736520636f6d70696cc3b320656c2061727465666163746f2e0683a3016c726570726f64756369626c6502a262656e6c526570726f64756369626c656265736c526570726f64756369626c6503a262656e78296275696c7420726570726f64756369626c792066726f6d207075626c697368656420736f75726365736265737838636f6d70696c61646f20646520666f726d6120726570726f64756369626c65206465736465206675656e746573207075626c696361646173a30168617474657374656402a162656e68417474657374656403a162656e781d6275696c7420627920616e20617474657374656420706970656c696e65a3016a756e766572696669656402a162656e6a556e766572696669656403a162656e736f726967696e206e6f7420766572696669656408020981a2016a70726f76656e616e636502a162656e782e446f6573207468652070726f76656e616e6365206e616d6520746865206578706563746564206275696c6465723f8201a601676f7574636f6d65020103a162656e6e526576696577206f7574636f6d6504a162656e781a57686174206120726576696577657220636f6e636c756465642e0683a30167617070726f766502a162656e67417070726f766503a162656e7819726561647920746f207075626c697368206173206275696c74a301676368616e67657302a162656e6f52657175657374206368616e67657303a162656e78196e6f742072656164793b206368616e676573206e6565646564a3016672656a65637402a162656e6652656a65637403a162656e756d757374206e6f74206265207075626c697368656408008202a7017372656c656173652d6174746573746174696f6e020403a10181020481a201a102706275696c642d70726f76656e616e636502f5051a00278d0008a262656e78327b736179737d20617474657374732074686174207b746869737d20776173207b6275696c642d70726f76656e616e63657d2e62657378337b736179737d2061746573746967756120717565207b746869737d20667565207b6275696c642d70726f76656e616e63657d2e09a162656e7352656c65617365206174746573746174696f6e
TV-1 — key-publish: Alice publishes her Ed25519 key; this = says = SHA-256(pub); the envelope carries pub¶
- signer: alice
- statement digest = SHA-256(TBS):
66127ad345e8575fcb7d626b4171e6f26e94cc4bb24dfa6478fbebd24f6f89ed - TBS:
a60101020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119022b031a02dc210006a101a20101025820d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a - signature over DS ‖ TBS:
87401657335ec9c1754ea381abc7c0b084c80583afce4e4ef9e21c01b8bc77e029480bfafc51a456109f3ed9541a0c9fa54c1c39f3bb56bfa9c4ea6c570ef101 - envelope
[suite, says, tbs, sig, ? pub]:8501582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b95882a60101020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119022b031a02dc210006a101a20101025820d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a584087401657335ec9c1754ea381abc7c0b084c80583afce4e4ef9e21c01b8bc77e029480bfafc51a456109f3ed9541a0c9fa54c1c39f3bb56bfa9c4ea6c570ef1015820d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a - expected: accept
TV-2 — self: label Alice, uses [statements], controller person (a self-claim)¶
- signer: alice
- statement digest = SHA-256(TBS):
91877221d7ea2743d9d802bce179aaaac9ff1e818d07a4a2d42ef7cee35efb8b - TBS:
a60102020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119022b031a02dc210006a30265416c6963650381010501 - signature over DS ‖ TBS:
3ff5e983aeefc3d5d451aa05493d843e6a22eaeefeefea2066fd4e5bf40b86f974cfc626c97a03bb8b2e4cb7b70aefb3199595d0b2c597881ff5f56ae4a0630c - envelope
[suite, says, tbs, sig, ? pub]:8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b95867a60102020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119022b031a02dc210006a30265416c696365038101050158403ff5e983aeefc3d5d451aa05493d843e6a22eaeefeefea2066fd4e5bf40b86f974cfc626c97a03bb8b2e4cb7b70aefb3199595d0b2c597881ff5f56ae4a0630c - expected: accept
TV-3 — define: Alice publishes definition DV-1 by its DefinitionId¶
- signer: alice
- statement digest = SHA-256(TBS):
2d200d1936d1d69945774e0c02662f25263fe4a07b11636643cfd0336fbaa97c - TBS:
a60108020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b90482045820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717505a20119022d031a02ddff2006a2016c737570706c792d636861696e026131 - signature over DS ‖ TBS:
8e08134764f37f17a2042ef965a74e5d46464db9d154772a78cb8a1c8e4bd3c4809709efef19b94bf621ca9cf6510b73f90585d3cb5a704b6303801b27513f06 - envelope
[suite, says, tbs, sig, ? pub]:8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9586ca60108020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b90482045820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717505a20119022d031a02ddff2006a2016c737570706c792d636861696e02613158408e08134764f37f17a2042ef965a74e5d46464db9d154772a78cb8a1c8e4bd3c4809709efef19b94bf621ca9cf6510b73f90585d3cb5a704b6303801b27513f06 - expected: accept
TV-4 — attestation about an ARTIFACT digest (not a key): build-provenance = reproducible¶
- signer: alice
- statement digest = SHA-256(TBS):
c539ace6b96e917b73074266f4ec46c69d07348c8d75d1660cbbaa6a1aaf6922 - TBS:
a60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b904830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295006a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e6365026c726570726f64756369626c65 - signature over DS ‖ TBS:
8f30ee4ef039d81813703a2b629bb60e5abfc5b82a07432594a2add6fb77d24ccb9a41d744022af89e5ce0ead553131929e2f66fbd1c2ec1869b2c4c91319c0f - envelope
[suite, says, tbs, sig, ? pub]:8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b958a8a60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b904830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295006a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e6365026c726570726f64756369626c6558408f30ee4ef039d81813703a2b629bb60e5abfc5b82a07432594a2add6fb77d24ccb9a41d744022af89e5ce0ead553131929e2f66fbd1c2ec1869b2c4c91319c0f - expected: accept
TV-5 — trust: Carol trusts Alice about build-provenance in {reproducible, attested}; may delegate depth 1 within {reproducible}¶
- signer: carol
- statement digest = SHA-256(TBS):
723436bf3ca419bc57fdea0f2b6518f65d280d04c1928b618e9f70a58ce785e6 - TBS:
a601050201035820c7b66369c87c115e8f8ab2fd27540d1a8a28cc475aab29b58ba0caf47910e207048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119022d031a02de376006a20181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e636503826c726570726f64756369626c6568617474657374656402a301010281a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e636503816c726570726f64756369626c650519029d - signature over DS ‖ TBS:
be4ed1ab94e2cc7ee4cef5af3936334a5bc5307b8c47e07b0e847b4e7b83e973cee0ec8b787626aae9c55d24c1d2812fd42473297a9763d384a980d62f773b0c - envelope
[suite, says, tbs, sig, ? pub]:84015820c7b66369c87c115e8f8ab2fd27540d1a8a28cc475aab29b58ba0caf47910e20758fea601050201035820c7b66369c87c115e8f8ab2fd27540d1a8a28cc475aab29b58ba0caf47910e207048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119022d031a02de376006a20181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e636503826c726570726f64756369626c6568617474657374656402a301010281a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e636503816c726570726f64756369626c650519029d5840be4ed1ab94e2cc7ee4cef5af3936334a5bc5307b8c47e07b0e847b4e7b83e973cee0ec8b787626aae9c55d24c1d2812fd42473297a9763d384a980d62f773b0c - expected: accept
TV-6 — review: Bob reviews statement TV-4 (target is a statement digest): outcome approve¶
- signer: bob
- statement digest = SHA-256(TBS):
2f983d3949a31904a1ca69c22f77d42de3dafe5fb415cd577770a9dc49cd153e - TBS:
a60109020103582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f0482035820c539ace6b96e917b73074266f4ec46c69d07348c8d75d1660cbbaa6a1aaf692205a3011a02de538002190249031a02de538006a20181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502676f7574636f6d650267617070726f766502782570726f76656e616e6365206e616d657320746865206578706563746564206275696c646572 - signature over DS ‖ TBS:
c44ebdbb53321947f14d0fa3ecdcfbe543a2cdbeb52a42ce5402a32b4a4a20cf09ff11c4e966e508d53e353ec27f21a3d088e54c01f36be6d679cb2eb4f3cc0b - envelope
[suite, says, tbs, sig, ? pub]:8401582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f58c3a60109020103582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f0482035820c539ace6b96e917b73074266f4ec46c69d07348c8d75d1660cbbaa6a1aaf692205a3011a02de538002190249031a02de538006a20181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502676f7574636f6d650267617070726f766502782570726f76656e616e6365206e616d657320746865206578706563746564206275696c6465725840c44ebdbb53321947f14d0fa3ecdcfbe543a2cdbeb52a42ce5402a32b4a4a20cf09ff11c4e966e508d53e353ec27f21a3d088e54c01f36be6d679cb2eb4f3cc0b - expected: accept
TV-7 — revoke: Alice revokes TV-4 by digest, effective 2026-10-21¶
- signer: alice
- statement digest = SHA-256(TBS):
ff6ea7c3945253db6eceb654775c432214d44b7e7414f33ae366e108eda5a766 - TBS:
a60106020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119024b031a0302cd0006a1015820c539ace6b96e917b73074266f4ec46c69d07348c8d75d1660cbbaa6a1aaf6922 - signature over DS ‖ TBS:
01c19179c78a6b07811281b2661f40c2c6aff34899f91a990b6d0be0a19f5cca38bf31a9e31a62591384cf4493792b7438b935fd5d17515dc8017cd6b0e7b001 - envelope
[suite, says, tbs, sig, ? pub]:8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9587ea60106020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9048201582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b905a20119024b031a0302cd0006a1015820c539ace6b96e917b73074266f4ec46c69d07348c8d75d1660cbbaa6a1aaf6922584001c19179c78a6b07811281b2661f40c2c6aff34899f91a990b6d0be0a19f5cca38bf31a9e31a62591384cf4493792b7438b935fd5d17515dc8017cd6b0e7b001 - expected: accept
TV-8 — rotate: Bob's old key names its successor; valid.issued orders statements around the rotation¶
- signer: bob
- statement digest = SHA-256(TBS):
2e5a65d97ae602151edf080639d4683fd3e3169a00ea44a1cdaf8048a7eac479 - TBS:
a60107020103582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f04820158209dcd2b600a6996b68623f46e19c60b6eb076c4a707df022e8479ef1d191b91f605a201190249031a0301434006a101706c6170746f70207265696e7374616c6c - signature over DS ‖ TBS:
d03a7aee59a7e03d6d3d17df3b424d67bddef5b372aab58604cb2adb778a26bbdc0c9b87ae2f70bd26d05f23018375a4f0167ea2b2157b6f6c3e7304dd2e3f04 - envelope
[suite, says, tbs, sig, ? pub]:8401582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f586da60107020103582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f04820158209dcd2b600a6996b68623f46e19c60b6eb076c4a707df022e8479ef1d191b91f605a201190249031a0301434006a101706c6170746f70207265696e7374616c6c5840d03a7aee59a7e03d6d3d17df3b424d67bddef5b372aab58604cb2adb778a26bbdc0c9b87ae2f70bd26d05f23018375a4f0167ea2b2157b6f6c3e7304dd2e3f04 - expected: accept
Negative vectors¶
N-1 — reject at V5 canonical decode¶
TBS map keys are not in deterministic order; the signature over those bytes is valid.
8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b958a8a60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b906a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e6365026c726570726f64756369626c6504830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295058408712c0fb82a423a79da9d0e02676cf6426b343a6482af0c2ad9cb5cd28d5f89a15dbcfa18e7d7eeddf123225fcfaef8bfd143792495d75540393365e60558e0b
N-2 — reject at V4 signature¶
TBS altered after signing.
8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b958a8a60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b904830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295006a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e6365026c726570726f64756369626c6458408f30ee4ef039d81813703a2b629bb60e5abfc5b82a07432594a2add6fb77d24ccb9a41d744022af89e5ce0ead553131929e2f66fbd1c2ec1869b2c4c91319c0f
N-3 — reject at V6 outer/inner agreement¶
outer says (Bob) does not equal inner says (Alice).
8401582039f713d0a644253f04529421b9f51b9b08979d08295959c4f3990ee617f5139f58a8a60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b904830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295006a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e6365026c726570726f64756369626c6558407a0fc00a0ced5c69f263838ccbed020ce1d22abe6a7059525e4afd3b2d3a04db2def0bfafa7a177e8f0fa4115168a6e59afbdd612dca81753d5709785222380f
N-4 — reject at V3 strict key check¶
public key is a small-order point (the identity); MUST be rejected before any verification.
8501582001d0fabd251fcbbe2b93b4b927b26ad2a1a99077152e45ded1e678afa45dbec55876a50101020103582001d0fabd251fcbbe2b93b4b927b26ad2a1a99077152e45ded1e678afa45dbec5048201582001d0fabd251fcbbe2b93b4b927b26ad2a1a99077152e45ded1e678afa45dbec506a101a20101025820010000000000000000000000000000000000000000000000000000000000000058400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058200100000000000000000000000000000000000000000000000000000000000000
N-5 — reject at V4 strict signature¶
signature S >= L (malleated); MUST be rejected even though R and the equation may verify.
8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b958a8a60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b904830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295006a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e6365026c726570726f64756369626c6558408f30ee4ef039d81813703a2b629bb60e5abfc5b82a07432594a2add6fb77d24cb86e37345f653c5075f9d78db44df22d29e2f66fbd1c2ec1869b2c4c91319c1f
N-6 — reject at V5 canonical decode¶
TBS contains a floating-point value; outside the KSA data model.
8401582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b9589ea60104020103582021fe31dfa154a261626bf854046fd2271b7bed4b6abe45aa58877ef47f9721b904830201582048dfc39586b0c4f9e905b3b60f59a30b7c0c7408e44f7cb4df2a09fbf3e67ba705a30119022d02190261031a02de295006a10181a201a2015820517007656a617b3b5ab7cc376275a46ad88d14594f6846df88a34f2c8b3a717502706275696c642d70726f76656e616e636502f93e005840b2b03f999c33b988e29f03162d44813dc36235f8de8cc002dd76f8fc7fbeccf9e864c20f591da1ea73df2c725f40df103ac50f3221d88a6e20127e409692230a
Appendix B. CDDL¶
signed-statement = [
suite: suite-code,
says: kid,
tbs: bstr .cbor statement, ; the octets exactly as signed
sig: bstr,
? pub: bstr ; unauthenticated; REQUIRED for key-publish
]
statement = {
1 => kind-code,
2 => suite-code,
3 => kid, ; says
? 4 => target, ; this
? 5 => validity,
6 => body
}
kind-code = 1..11
suite-code = uint
kid = bstr .size 32
digest = bstr .size 32
definition-id = bstr .size 32
time = int
target = [1, kid] ; key
/ [2, digest-alg, bstr] ; object digest
/ [3, digest] ; statement
/ [4, definition-id] ; definition
/ [5, tstr] ; locator (URI)
/ [6, type-ref, value] ; description
digest-alg = 1..3
validity = { ? 1 => time, ? 2 => time, ? 3 => time } ; not-before, not-on-or-after, issued
type-ref = { 1 => definition-id, 2 => label }
process-ref = { 1 => definition-id, 2 => label }
label = tstr
attribute = { 1 => type-ref, 2 => value }
attribute-range = { 1 => type-ref, ? 3 => value }
value = int / bool / bstr / tstr / [* value] / { * tstr => value }
public-key = { 1 => key-alg, 2 => bstr }
key-alg = 1 / 2 / 8
body = key-publish-body / self-body / speaks-body / attestation-body / trust-body
/ revoke-body / rotate-body / define-body / review-body / approve-body / aggregate-body
key-publish-body = { 1 => public-key }
self-body = { ? 1 => public-key, ? 2 => tstr, ? 3 => [+ uint], ? 4 => time, ? 5 => uint }
speaks-body = { 1 => [+ definition-id] }
attestation-body = { 1 => [+ attribute], ? 3 => type-ref } ; 3: template
trust-body = { 1 => [+ attribute-range], ? 2 => delegation-constraints,
? 3 => [2* kid], ? 4 => uint }
delegation-constraints = { ? 1 => uint, ? 2 => [+ attribute-range],
? 3 => [+ kid], ? 4 => [+ kid], ? 5 => time }
revoke-body = { 1 => digest }
rotate-body = { ? 1 => tstr }
define-body = { 1 => tstr, 2 => tstr, ? 3 => definition-id } ; 3: supersedes
review-body = { 1 => [+ attribute], ? 2 => tstr, ? 3 => type-ref }
approve-body = { ? 1 => [+ attribute], ? 2 => tstr, ? 3 => type-ref }
aggregate-body = { 1 => process-ref, 2 => [+ digest], 3 => bool }
The CDDL describes structure. The kind-specific constraints of §8 and the encoding rules of §4 are additional and normative.
Appendix C. Changes from FKSA v0.2.1¶
| FKSA v0.2.1 | KSA Core 0.1 | why |
|---|---|---|
signature over the statement minus signed, re-encoded |
envelope carries TBS as signed; verify before decode (§5) | ARCH-0001 R-O-05 |
this is always a kid |
targets: key, digest, statement, definition, locator, description (§7.2) | attestations about artifacts and statements |
ns:name extension fields; open/closed contexts |
closed maps; extensibility only through definition-typed attributes (§7.1) | ADR-0003 D1 |
| schema id: URN or SHA-256 of JCS | DefinitionId = SHA-256 of KSA-CBOR; no URNs (SPEC-0003) |
ADR-0003 D1, D2 |
| schema documents unsigned (open Q12) | definitions published by a signed define statement |
SPEC-0003 §8 |
DS label FKSA-STMT-SIG-v0\0 |
KSA-STMT-SIG-v1\0 |
the two protocols cannot replay each other |
valid.issued reserved |
issued registered; REQUIRED for rotate and revoke |
rotation ordering (FKSA RW-3) |
ask is a statement kind |
ask is an evaluation query (SPEC-0004 §10), not a statement | it is never signed |
| kinds: key-publish, self, speaks, attestation, trust, revoke, rotate | adds define, review, approve, aggregate | definitions, review and processes |
self.uses text tokens |
usage codes (§12.7); self.controller added (§12.8) |
controller kinds |
suite 1 ed25519-cbor-sha256, suite 16 JCS legacy |
suite 1 ksa-ed25519-sha256; no legacy JCS suite; suite 8 ML-DSA-65 provisional |
one encoding; post-quantum path |
speaks handles (wire-only) |
not adopted in the core | a transport optimisation, not a protocol element |
| unchanged | data model, time encoding, strict Ed25519 rules, kid rule, key-store rule, delegation constraints, revocation by issuer and digest, decimal-only human-review integers | the best of FKSA |