Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add signature extensions to DSSE
Browse files Browse the repository at this point in the history
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 <aditya@saky.in>
adityasaky committed May 13, 2024
1 parent fba27e4 commit 88c5aaf
Showing 4 changed files with 114 additions and 11 deletions.
57 changes: 53 additions & 4 deletions envelope.md
Original file line number Diff line number Diff line change
@@ -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": "<Base64(SERIALIZED_BODY)>",
"payloadType": "<PAYLOAD_TYPE>",
"signatures": [{
"keyid": "<KEYID>",
"sig": "<Base64(SIGNATURE)>",
"extension": {
"kind": "<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

17 changes: 17 additions & 0 deletions envelope.proto
Original file line number Diff line number Diff line change
@@ -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;
}
17 changes: 17 additions & 0 deletions extensions.md
Original file line number Diff line number Diff line change
@@ -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=<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
34 changes: 27 additions & 7 deletions protocol.md
Original file line number Diff line number Diff line change
@@ -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 provide the 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
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,23 +92,28 @@ Functions:
Out of band:
- Agree on a PAYLOAD_TYPE and cryptographic details, optionally including
KEYID.
KEYID and EXTENSION.
To sign:
- Serialize the message according to PAYLOAD_TYPE. Call the result
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.

0 comments on commit 88c5aaf

Please sign in to comment.