Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace magic payloadType with explicit sigType. #13

Merged
merged 5 commits into from
Jan 8, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 32 additions & 23 deletions specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,28 @@ The signature format is a JSON message of the following form:
```

Empty fields may be omitted. [Multiple signatures](#multiple-signatures) are
allowed.
allowed. Note that an optional `signature.sigType` field may be present but
empty for compatibility with [backwards compatible signature] mode.

Parameters:

* SERIALIZED_BODY is the byte sequence to be signed.

* PAYLOAD_TYPE is a URI indicating how to interpret SERIALIZED_BODY. It
encompasses the content type (JSON, Canonical-JSON, CBOR, etc.), the
purpose, and the schema version of the payload. This obviates the need for
the `_type` field within in-toto/TUF payloads. This URI does not need to be
resolved to a remote resource, nor does such a resource need to be fetched.
Examples:
* PAYLOAD_TYPE is an authenticated(*) URI indicating how to interpret
SERIALIZED_BODY. It encompasses the content type (JSON, Canonical-JSON,
CBOR, etc.), the purpose, and the schema version of the payload. This
obviates the need for the `_type` field within in-toto/TUF payloads. This
URI does not need to be resolved to a remote resource, nor does such a
resource need to be fetched. Examples:

- https://in-toto.io/Link/v0.9
- https://in-toto.io/Layout/v0.9
- https://theupdateframework.com/Root/v1.0.5
- etc...

(*) Exception: PAYLOAD_TYPE is unauthenticated if `signature.sigType ==
"raw-json-no-payload-type"`.

* KEYID is an optional, unauthenticated hint indicating what key and algorithm
was used to sign the message. As with Sign(), details are agreed upon
out-of-band by the signer and verifier. It **MUST NOT** be used for security
Expand Down Expand Up @@ -105,6 +109,9 @@ To sign:

To verify:

- If `sigType == "raw-json-no-payload-type"`, use
[backwards compatible signature] instead. Reject if `sigType` is any other
non-empty value.
- Base64-decode `payload`; call this SERIALIZED_BODY. Reject if the decoding
fails.
- Base64-decode `sig` and verify PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY).
Expand All @@ -119,44 +126,46 @@ either, and verifiers **MUST** accept either.
### Backwards compatible signatures

To convert existing signatures from the current format to the new format,
`"backwards-compatible-json"` is added to the payload type URI to indicate that
`"raw-json-no-payload-type"` is added to the payload type URI to indicate that
the signature is over the raw payload. This allows the signatures to remain
valid while avoiding the verifier from having to use [Canonical JSON].

```json
{
"payload": "<Base64(CanonicalJson(BODY))>",
"payloadType": "<URI>/backwards-compatible-json",
"payload": "<Base64(SERIALIZED_BODY)>",
"signatures" : [{
"keyid": "<KEYID>",
"sig": "<Base64(Sign(CanonicalJson(BODY)))>"
"sigType": "raw-json-no-payload-type",
"sig" : "<Base64(Sign(SERIALIZED_BODY))>"
}]
}
```

Support for this backwards compatibility mode is optional.
Support for this backwards compatibility mode is optional and should be disabled
by default.

To sign:

- BODY **MUST** be an object type (`{...}`).
- Serialize BODY as [Canonical JSON]; call this SERIALIZED_BODY.
- The message **MUST** be an object type (`{...}`).
- Serialize the message as [Canonical JSON]; call this SERIALIZED_BODY.
- Sign SERIALIZED_BODY, base64-encode the result, and store it in `sig`.
- Store `"raw-json-no-payload-type"` in `sigType`.
- Optionally, compute a KEYID and store it in `keyid`.
- Base64-encode SERIALIZED_BODY and store it in `payload`.
- Store `"<URI>/backwards-compatible-json"` in `payloadType`.

To verify:

- If `payloadType` != `"<URI>/backwards-compatible-json"`, use the normal
verification process instead of this one.
- If `sigType != "raw-json-no-payload-type"`, use the
[normal verification process](#steps) instead of this one.
- Base64-decode `payload`; call this SERIALIZED_BODY. Reject if the decoding
fails.
- Base64-decode `sig` and verify SERIALIZED_BODY. Reject if either the
decoding or the signature verification fails.
- Parse SERIALIZED_BODY as a JSON object. Reject if the parsing fails or if
the result is not a JSON object. In particular, the first byte of
SERIALIZED_BODY **MUST** be `{`. Verifiers **MUST NOT** require SERIALIZED_BODY
to be Canonical JSON.
SERIALIZED_BODY **MUST** be `{`. Verifiers **MUST NOT** require
SERIALIZED_BODY to be Canonical JSON.
- Discard `payloadType` if present.

Backwards compatible signatures are not recommended because they lack the
authenticated payloadType indicator.
Expand Down Expand Up @@ -280,8 +289,8 @@ Rationales for specific decisions:
payloadType were not signed.
- Also, URIs don't need to be registered while Media Types do.

- Why use payloadType "backwards-compatible-json" instead of assuming
backwards compatible mode if payloadType is absent?
- Why use payloadType "raw-json-no-payload-type" instead of assuming backwards
compatible mode if payloadType is absent?

- We wanted to leave open the possibility of having an
application-specific "default" value if payloadType is unspecified,
Expand Down Expand Up @@ -337,11 +346,11 @@ To detect whether a signature is in the old or new format:
To convert an existing signature to the new format:

- `new.payload = base64encode(CanonicalJson(orig.signed))`
- `new.payloadType = "<URI>/backwards-compatible-json"`
- `new.signatures[*].sigType = "raw-json-no-payload-type"`
- `new.signatures[*].sig = base64encode(hexdecode(orig.signatures[*].sig))`
- `new.signatures[*].keyid = orig.signatures[*].keyid`

To convert a backwards compatible signature to the old format:
To convert a [backwards compatible signature] to the old format:

- `old.signed = jsonparse(base64decode(new.payload))`
- `old.signatures[*].sig = hexencode(base64decode(new.signatures[*].sig))`
Expand Down