From f0518cf7c1b5ffc61ce3d60e0b5fac305b2cc3ae Mon Sep 17 00:00:00 2001 From: Mark Lodato Date: Fri, 4 Dec 2020 17:29:48 -0500 Subject: [PATCH 1/3] Replace magic payloadType with explicit sigType. Previously the switch between normal and "backwards compatible json" mode was determined by a magic `payloadType`. The downside of this approach was that it was undiscoverable: readers would not know this magic value existed. Now this behavior is made explicit via a `signatures.sigType` field. The new string better explains the behavior, which is that the payload must be JSON and that `payloadType` is unauthenticated. --- specification.md | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/specification.md b/specification.md index 02d607e..b6c4760 100644 --- a/specification.md +++ b/specification.md @@ -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 was used to sign the message. It **must not** be used for security decisions. @@ -102,6 +106,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). @@ -122,30 +129,31 @@ valid while avoiding the verifier from having to use [Canonical JSON]. ```json { - "payload": "", - "payloadType": "/backwards-compatible-json", + "payload": "", "signatures" : [{ "keyid": "", - "sig": "" + "sigType": "raw-json-no-payload-type", + "sig" : "" }] } ``` -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 `"/backwards-compatible-json"` in `payloadType`. To verify: -- If `payloadType` != `"/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 @@ -154,6 +162,7 @@ To verify: 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. +- Discard `payloadType` if present. Backwards compatible signatures are not recommended because they lack the authenticated payloadType indicator. @@ -334,11 +343,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 = "/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))` @@ -346,6 +355,8 @@ To convert a backwards compatible signature to the old format: ## Testing +TODO: Update reference implementation with this new design. + See [reference implementation](reference_implementation.ipynb). Here is an example. From c52e58786c1fcc9d3739fe0be277c1876da5283c Mon Sep 17 00:00:00 2001 From: Mark Lodato Date: Mon, 14 Dec 2020 16:40:21 -0500 Subject: [PATCH 2/3] Remove invalid TODO. The reference implementation did not support backwards-compatible signatures anyway, so no update is needed. --- specification.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/specification.md b/specification.md index 2030272..e2d8e27 100644 --- a/specification.md +++ b/specification.md @@ -358,8 +358,6 @@ To convert a [backwards compatible signature] to the old format: ## Testing -TODO: Update reference implementation with this new design. - See [reference implementation](reference_implementation.ipynb). Here is an example. From fba29689b3e51cfe6c569e2a2e79b6d8f7fe8ab7 Mon Sep 17 00:00:00 2001 From: Mark Lodato Date: Fri, 8 Jan 2021 15:07:57 -0500 Subject: [PATCH 3/3] Replace obsolete "backwards-compatible-json". This was cruft from an earlier revision. It should have been "raw-json-no-payload-type". --- specification.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specification.md b/specification.md index e2d8e27..fc9d8b2 100644 --- a/specification.md +++ b/specification.md @@ -126,7 +126,7 @@ 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]. @@ -163,8 +163,8 @@ To verify: 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 @@ -289,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,