From d25e627f668280c997fdb051699ff0a3d287666a Mon Sep 17 00:00:00 2001 From: Aditya Sirish Date: Thu, 20 Jul 2023 13:55:51 -0400 Subject: [PATCH] Add signature extensions to DSSE This commit introduces signature extensions to the DSSE specification. A signature extension can be used to store signature-specific information in the envelope. In addition, it also introduces the Sigstore DSSE extension. Signed-off-by: Aditya Sirish --- envelope.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++---- envelope.proto | 17 +++++++++++++++ extensions.md | 17 +++++++++++++++ protocol.md | 34 +++++++++++++++++++++++------- 4 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 extensions.md diff --git a/envelope.md b/envelope.md index 757a6c7..7331895 100644 --- a/envelope.md +++ b/envelope.md @@ -2,7 +2,7 @@ May 10, 2024 -Version 1.0.1 +Version 1.1.0 This document describes the recommended data structure for storing DSSE signatures, which we call the "JSON Envelope". For the protocol/algorithm, see @@ -52,14 +52,63 @@ envelopes with individual signatures. } ``` +### Signature Extensions [experimental] + + +NOTE: The design for signature extensions is currently experimental and may +change. + +In addition to `keyid` and `sig`, a signature object may include an `extension` +field to store ecosystem specific information pertaining to the signature. +Extensions do not modify the signing workflow established in the +[DSSE protocol](protocol.md) except for actually encoding the extension +alongside the signature in the envelope. However, signers and verifiers may +exchange information about the extensions used out-of-band. + +```json +{ + "payload": "", + "payloadType": "", + "signatures": [{ + "keyid": "", + "sig": "", + "extension": { + "kind": "", + "ext": {...} + } + }] +} +``` + +`extension.kind` is a string and the `EXTENSION_KIND` value must unambiguously +identify the ecosystem or kind of the extension. This in turn identifies the +fields in the opaque object `ext`. Some well-known extensions MAY be +[registered and listed](extensions.md) with their `ext` definition alongside the +DSSE specification. + +Additionally, extensions MUST NOT contain any information such that the +signature verification fails in its presence and passes in its absence. +Essentially, if a required extension in some context is missing or if a consumer +does not recognize the extension, verification MUST fail closed. + +Finally, the opaque `ext` MUST NOT contain a DSSE envelope to avoid recursive +verification of extensions and signatures. Similarly, the `ext` MUST NOT provide +the signature bytes itself, but MUST only contain information required to verify +the signature recorded in `sig` field. + ### Parsing rules * The following fields are REQUIRED and MUST be set, even if empty: `payload`, `payloadType`, `signature`, `signature.sig`. -* The following fields are OPTIONAL and MAY be unset: `signature.keyid`. - An unset field MUST be treated the same as set-but-empty. +* The following fields are OPTIONAL and MAY be unset: `signature.keyid`, + `signature.extension`. An unset field MUST be treated the same as + set-but-empty. +* The schema for `signature.extension.ext` for some declared + `signature.extension.kind` MUST be communicated separately by producers to + consumers. * Producers, or future versions of the spec, MAY add additional fields. - Consumers MUST ignore unrecognized fields. + Consumers MUST ignore unrecognized fields. Similarly, consumers MUST ignore + extensions of an unrecognized kind. ## Other data structures diff --git a/envelope.proto b/envelope.proto index 83d7602..ba04367 100644 --- a/envelope.proto +++ b/envelope.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package io.intoto; +import "google/protobuf/struct.proto"; + // An authenticated message of arbitrary type. message Envelope { // Message to be signed. (In JSON, this is encoded as base64.) @@ -32,4 +34,19 @@ message Signature { // *Unauthenticated* hint identifying which public key was used. // OPTIONAL. string keyid = 2; + + // *Unauthenticated* field that can record additional information pertaining + // to the signature. + // OPTIONAL. + Extension extension = 3; +} + +message Extension { + // Unambiguously identifies how to interpret extension fields. + // REQUIRED. + string kind = 1; + + // Extension fields. + // REQUIRED. + google.protobuf.Struct ext = 2; } diff --git a/extensions.md b/extensions.md new file mode 100644 index 0000000..3d8691c --- /dev/null +++ b/extensions.md @@ -0,0 +1,17 @@ +# DSSE Extensions + +May 10, 2024 + +Version 1.1.0 + +This document lists the well known DSSE +[signature extensions](/envelope.md#signature-extensions). To add a signature +extension, propose a change with a unique media type for the signing ecosystem +and include a link to the format of the `ext` field. + +| Name (with link) | Kind | Notes | +|------------------|------|-------| +| [Sigstore] | `application/vnd.dev.sigstore.verificationmaterial;version=` | The X.509 certificate chain must not include the root or trusted intermediate certificates | + + +[Sigstore]: https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto diff --git a/protocol.md b/protocol.md index 20f7e45..169c7c4 100644 --- a/protocol.md +++ b/protocol.md @@ -2,7 +2,7 @@ May 10, 2024 -Version 1.0.1 +Version 1.1.0 This document describes the protocol/algorithm for creating and verifying DSSE signatures, independent of how they are transmitted or stored. For the @@ -23,6 +23,7 @@ Name | Type | Required | Authenticated SERIALIZED_BODY | bytes | Yes | Yes PAYLOAD_TYPE | string | Yes | Yes KEYID | string | No | No +EXTENSION | object | No | No * SERIALIZED_BODY: Arbitrary byte sequence to be signed. @@ -52,6 +53,20 @@ KEYID | string | No | No decisions; it may only be used to narrow the selection of possible keys to try. +* EXTENSION: Optional, unauthenticated object used to store signature-specific + information. Extensions are identified by a `kind` field that unambiguously + describes the fields for the extension. The details for each extension and + its fields must be agreed upon out-of-band by the signer and verifier, + though some well-known extensions may be [listed](extensions.md) and defined + in the DSSE specification. Note that as the extension is unauthenticated, + it MUST NOT allow the verifier to independently verify the signature. For + example, the extension MUST NOT be trusted to directly provide the leaf + public key to verify a signature. Similarly, an extension field that + contains an X.509 certificate chain MUST NOT be trusted to provide the root + certificate, but it MAY provide only intermediate certificates. + * NOTE: The design for signature extensions is currently experimental + and is subject to change. + Functions: * PAE() is the "Pre-Authentication Encoding", where parameters `type` and @@ -77,7 +92,7 @@ Functions: Out of band: - Agree on a PAYLOAD_TYPE and cryptographic details, optionally including - KEYID. + KEYID and EXTENSION. To sign: @@ -85,15 +100,20 @@ To sign: SERIALIZED_BODY. - Sign PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY). Call the result SIGNATURE. - Optionally, compute a KEYID. -- Encode and transmit SERIALIZED_BODY, PAYLOAD_TYPE, SIGNATURE, and KEYID, - preferably using the recommended [JSON envelope](envelope.md). +- Optionally, include signature specific information as an EXTENSION. +- Encode and transmit SERIALIZED_BODY, PAYLOAD_TYPE, SIGNATURE, KEYID, and + EXTENSION, preferably using the recommended [JSON envelope](envelope.md). To verify: -- Receive and decode SERIALIZED_BODY, PAYLOAD_TYPE, SIGNATURE, and KEYID, such - as from the recommended [JSON envelope](envelope.md). Reject if decoding - fails. +- Receive and decode SERIALIZED_BODY, PAYLOAD_TYPE, SIGNATURE, KEYID, and + EXTENSION such as from the recommended [JSON envelope](envelope.md). Reject + if decoding fails. - Optionally, filter acceptable public keys by KEYID. +- If EXTENSION is set, use its fields to obtain information that MAY be + required for verification. Reject any significant fields that the verifier + must establish separately, such as the public key for a signature or a root + certificate for an X.509 certificate chain. - Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY). Reject if the verification fails. - Reject if PAYLOAD_TYPE is not a supported type.