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

Add support for signature extensions #61

Merged
Merged
Show file tree
Hide file tree
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
57 changes: 53 additions & 4 deletions envelope.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
adityasaky marked this conversation as resolved.
Show resolved Hide resolved
[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.
JustinCappos marked this conversation as resolved.
Show resolved Hide resolved
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.
adityasaky marked this conversation as resolved.
Show resolved Hide resolved
* 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

Expand Down
17 changes: 17 additions & 0 deletions envelope.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
Expand Down Expand Up @@ -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 |
adityasaky marked this conversation as resolved.
Show resolved Hide resolved


[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
Expand Up @@ -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
Expand All @@ -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
adityasaky marked this conversation as resolved.
Show resolved Hide resolved

* SERIALIZED_BODY: Arbitrary byte sequence to be signed.

Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down