Summary

  • RFC 9804 lets abc, "abc", #616263#, 3:abc and |YWJj| denote the same three-octet string, but only canonical representation supplies the unique bytes intended for signature computation.
  • A display hint can be part of the signed canonical object, yet the RFC assigns it a presentation function, not proof of type safety, trust or authorization.
  • A defensible system preserves distinct receipts for input, parser profile, canonical output, signature, typed interpretation, policy decision and observed effect.

Five readable answers, one byte-level question

An operator receives abc. Another console shows "abc"; an archive records #616263#; a protocol trace contains 3:abc; a diagnostic tool prints |YWJj|. RFC 9804 uses these forms to make a precise point: each can represent the same three octets.

That equivalence is useful, but it does not answer the operational question: which representation crossed the signature boundary? A screenshot proves only what one renderer displayed. A copied expression proves only the characters copied. A parser success proves only that a particular implementation admitted an input. The digital signature has a narrower subject: the canonical octets of the S-expression.

RFC 9804 defines an S-expression as either an octet string or a list. It then separates four environments that are often blurred in incident records. Advanced representation is flexible human input and display. Basic transport moves a canonical object across channels that may dislike binary octets or long lines. Canonical representation gives one unique encoding for signing. In-memory representation is private to an implementation.

Canonical strings carry a decimal byte length followed by a colon and the bytes verbatim. Lists are enclosed without optional layout. A whole canonical expression may alternatively travel as Base64 inside braces. That wrapper is transport, not a second signed meaning: decoding must recover the canonical bytes.

Advanced notation is different. Tokens, quoted strings, hexadecimal and Base64 can improve inspection and entry, and whitespace can improve layout. Support is optional. An application should accept it only because its profile requires it or capability discovery established it. A receipt that says merely “S-expression accepted” omits the notation, parser version, enabled forms, depth and length limits, and application restrictions that controlled admission.

Display advice is not type authority

RFC 9804 permits an octet string to carry a display hint. The hint tells an application how to display the data and, in the RFC’s words, has no other function. If present, it is included in the canonical representation; therefore its presence and exact octets can be covered by a signature.

Signed does not mean semantically sovereign. A signed hint is evidence that the signer included that hint, not that the receiving software safely interpreted the data, that the hinted media type was true, or that policy should authorize an action. If no hint exists, applications may apply a local default; the general default is application/octet-stream. Two renderers may legitimately present the same octets differently.

Comparison policy is also application-owned. RFC 9804 recommends treating expressions as equal when both hint and data match, while allowing an application to ignore hints or adopt another rule. Consequently, an audit needs the comparison rule and its version. “Same S-expression” is otherwise underspecified.

Grammar is the first gate, not the last

General S-expression grammar can admit structures that a consuming protocol must reject. RFC 9804 explicitly allows profiles to prohibit hints or advanced forms, disallow empty strings or lists, require structure, and impose resource limits. SPKI supplies a concrete example: RFC 2693 excludes empty lists for its certificate use and requires a type string in the first position.

The evidence chain therefore begins with the exact received bytes and framing. It records the parser build and enabled grammar, the application profile and limits, and the parsed abstract object. The system then re-emits canonical octets and hashes them. Signature verification names those bytes and the key or certificate path used. No display rendering is substituted for that object.

After verification comes interpretation. RFC 2692 says the application-code author defines the meaning of an SPKI authorization. RFC 2693 describes trusted tuples and authorization reduction, but the final permission still depends on the application. The receipt must identify the type handler, policy version, principal, requested action, resource and decision. Only an execution record can show what the system attempted and what actually happened.

This produces a chain rather than a universal green check:

  1. transport bytes were received and decoded;
  2. a named grammar and application profile admitted them;
  3. parsing produced an abstract expression;
  4. canonical serialization produced a recorded byte hash;
  5. a signature was verified over that boundary;
  6. a named handler assigned meaning;
  7. a versioned policy returned an authorization result;
  8. execution produced an independently observed outcome.

A break can be localised. If two parsers disagree, compare input and canonical hashes. If signatures agree but outcomes differ, examine type and policy handling. If authorization says allow but nothing changed, inspect execution. RFC 9804 makes canonical agreement possible; it does not erase the later authority boundaries.

Sources