feat: DSSE signing extension#1371
Conversation
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add a simple workflow based on GitHub super-linter to validate our markdown. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add a CloudEvents binding document. The CloudEvents Binding for CDEvents defines how CDEvents are mapped to CloudEvents headers and body. Add a primer document. The primer document gives an overview of the CDEvents spec, it's architecture, goals and design decisions. Both documents are only stubs for now. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Import the draft spec as-is from github.com/cdfoundation/sig-events, except for minor lint and spelling fixes. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add a tool to generate and manage the TOC of various docs. We might want to add a CI job that checks that the TOC is up to date once we start adding specs. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Explain relations to CloudEvents Signed-off-by: Mattias Linnér <mattias.linner@ericsson.com>
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add a roadmap doc for cdevents that include the mission and vision for the project too. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Include the work on reference implementations, or "adapters" that will be required to produce / consume cdevents in various platforms. Relocate the use cases to the primer.md document. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
According to the CloudEvents spec, https://github.com/cloudevents/spec/blob/v1.0.1/spec.md the event type SHOULD be prefixed with a reverse-DNS name. The prefix domain dictates the organisation which defines the semantics of the event type. Since CDEvents owns the `cdevents.dev` domain, and has a website hosted on that domain, we should use that domain in the event types as well. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Restructure a the spec root page, add more sections and introduce the initial terminology, including subjects and predicates. This provides the basis for restructuring the vocabulary and defining the schemas that will be used to build the SDKs. Partially addresses: cloudevents#12 Related to: cloudevents#11 Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add a link to CONTRIBUTING.md and improve the README.md to include links to the various documents. Remove the code of conduct that is now hosted in the .github repo. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add syntax details for attributes in CDEvents Expand the definition of mandatory attributes by adding syntax details and examples. Introduce the "version" as a mandatory attribute. Add the subject as an optional attribute as discussed in the WG. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com> Co-authored-by: Emil Bäckmark <emil.backmark@ericsson.com> Co-authored-by: Mattias Linnér <mattias.linner@ericsson.com>
Add an introduction to CDEvents explaining what it is and what it provides. Co-authored-by: Emil Bäckmark <emil.backmark@ericsson.com>
Introduce objects and subjects Add the type system including objects. Define subjects in the core protocol stage and rework the spec accordingly. Add the general cloudevents binding specification. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Format source code events same as core Reformat the source code version control stage page to match what done for the core stage. No spec changes. Part of cloudevents#13 Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
* Add service published event to the spec This is WRT the issue cdfoundation/sig-events#111 add distinction for when to use Deployed vs Published events
* Format the CI and CD stage spec Format the CI and CD stage spec. Complete the SCM spec with the available part of the data model. Fix some linting issues. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com> Co-authored-by: Emil Bäckmark <emil.backmark@ericsson.com>
* Remove binary mode from CDEvents As discussed in the WG, we're not going to have a CDEvents binary mode, so remove it from the specification. Organise links in the cloudevents binding doc. Update the TOC. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
* Add support for third party data in the spec Add a new field. Organise the spec document so that it's clear which are the three root elements of a CDEvent and how the spec document itself is structured. Fixes: cloudevents#60 Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com> Co-authored-by: Emil Bäckmark <emil.backmark@ericsson.com>
* Add jsonschema for a few of the events Add initial jsonschemas for all of the events. These json schemas are automatically generated through the go types defined in the new cdevents/go-sdk, using the library github.com/invopop/jsonschema, see cdevents/sdk-go#6 for details. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add the white paper as PDF to the repo, including a paragraph about it in the primer.md Document that decision decisions are included in primer.md, and add a pull request template to remind PR authors about it Fixes cloudevents#17 Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
Add details about the specification versioning, the event versioning and the schemas. Update the spec version to 0.1.0-draft as starting in-progress version. Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com> Co-authored-by: Emil Bäckmark <emil.backmark@ericsson.com>
Bumps [rojopolis/spellcheck-github-actions](https://github.com/rojopolis/spellcheck-github-actions) from 0.59.0 to 0.60.0. - [Release notes](https://github.com/rojopolis/spellcheck-github-actions/releases) - [Changelog](https://github.com/rojopolis/spellcheck-github-actions/blob/master/CHANGELOG.md) - [Commits](rojopolis/spellcheck-github-actions@0.59.0...0.60.0) --- updated-dependencies: - dependency-name: rojopolis/spellcheck-github-actions dependency-version: 0.60.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
* feat(schema): Add approval events Introduces three new event types to model the lifecycle of an approval request in a CI/CD pipeline or workflow. Many CI/CD systems require a formal decision point before execution can continue, like a deployment to production, a release cut, or a regulated change proceeding through a pipeline. The decision may come from a human approver, an automated policy engine, an external compliance system, or any other entity capable of authorizing progression. There is currently no canonical CDEvents representation for this pattern, leaving teams to model approvals through customData or out of band mechanisms with no shared traversal or governance model. **approval.created**: emitted when an approval request is initiated. Captures the requestor and references to the approval details and the resource being gated. **approval.updated**: emitted when a non-terminal decision is recorded or when the resource target of the approval changes. Supports flows where multiple decisions may be recorded before a terminal state is reached, whether from humans, automated systems, or a combination. **approval.closed**: emitted when the approval reaches a terminal state. Captures the final decision, the responder, and the terminal status: Approved, Rejected, Cancelled, or Expired. All three events share a common core: - `approvalDetailsUrl`: reference URL to the approval request page - `resourceTargetUrl`: reference URL to the resource being gated approval.created adds: - `requestor`: the entity that initiated the approval request approval.updated and approval.closed add: - `responder`: the entity that recorded a decision (URN format) - `decision`: the decision selected by the responder approval.closed additionally adds: - `status`: example terminal state: approved, rejected, cancelled, expired - Deployment gates requiring sign-off before production rollout - Automated policy checks that must authorize pipeline progression - Regulated change management pipelines requiring auditable approval records - Multistage release workflows where approvals gate progression between environments - Compliance workflows requiring documented authorization before sensitive operations - External system integrations where a thirdparty tool must approve before execution continues * fixup! feat(schema): Add approval events Signed-off-by: xibz <bjp@apple.com> * fixup! feat(schema): Add approval events Signed-off-by: xibz <bjp@apple.com> --------- Signed-off-by: xibz <bjp@apple.com>
Sync oss-mirror to main
Signed-off-by: xibz <bjp@apple.com>
Signed-off-by: xibz <bjp@apple.com>
Signed-off-by: xibz <bjp@apple.com>
This commit changes releases to be tag based given the branch is constantly being stomped over during the resync Signed-off-by: xibz <bjp@apple.com>
* Bump ajv from 8.18.0 to 8.20.0 in /tools Bumps [ajv](https://github.com/ajv-validator/ajv) from 8.18.0 to 8.20.0. - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](ajv-validator/ajv@v8.18.0...v8.20.0) --- updated-dependencies: - dependency-name: ajv dependency-version: 8.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * feat(rio): add rio.yml Signed-off-by: xibz <bjp@apple.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: xibz <bjp@apple.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit changes releases to be tag based given the branch is constantly being stomped over during the resync Signed-off-by: xibz <bjp@apple.com>
Signed-off-by: xibz <bjp@apple.com>
Signed-off-by: xibz <bjp@apple.com>
…vents#15) Signed-off-by: xibz <bjp@apple.com>
| end-sha: | ||
| description: 'Ending SHA? (latest HEAD)' | ||
|
|
||
| permissions: |
There was a problem hiding this comment.
Can you rebase? These are not part of your PR
| attributes alongside the event data. | ||
| verify those signatures. The verification material is transported in an | ||
| extension attribute alongside the event data. | ||
|
|
| 8. recompute `core_digest` from the event according to steps 3-4 of the signing [Protocol](#protocol) and compare it to the `core` byte sequence from step 6.2 | ||
| 1. if the values are not equal, the event has been modified in transit and MUST be discarded | ||
| 11. the event is returned as verified successfully. | ||
| 9. if the `ext` field is present (step 6.3) and the consumer wishes to verify extension attributes, recompute `ext_digest` from the event using the `signedextattrs` list from step 6.4 according to step 5 of the signing [Protocol](#protocol) and compare it to the `ext` byte sequence from step 6.3 |
There was a problem hiding this comment.
Please wrap entire doc at 80 chars
| data. Users handle either a complete unverified event or a verified event with | ||
| only verified values—never a mixture of both. | ||
| Upon verification of a CloudEvent, implementations MUST return a new event | ||
| containing only verified data. If only core verification was performed (step 8), |
There was a problem hiding this comment.
So, if there are CE extensions but they're not verified, they're silently dropped?
Is this what we want instead of rejecting the event? I'm wondering if the presence of extra stuff is sign that someone is trying to mess with things and we need to play it safe.
There was a problem hiding this comment.
I'm concerned about this too. I'd far rather be able to keep everything, but make it easy to determine which extensions were signed and which weren't.
|
Some errors from the tooling: You may want to squash and rebase |
| to modify and re-sign events, it explicitly does not aim to provide a | ||
| cryptographic audit trail of event modifications. | ||
|
|
||
| As a general principle, this extension aims to avoid cryptographic agility in |
There was a problem hiding this comment.
I'm not sure what "cryptographic agility" is - is that a term most folks in the relevant audience would understand? (It's entirely possible.)
|
|
||
| ``` | ||
| { | ||
| "core": "<Base64(core_digest)>", |
There was a problem hiding this comment.
Can we capitalize these for consistency with VERIFICATION_MATERIAL, KEY_ID and SIGNATURE? Aside from anything else, that makes it easier to tell that they're not expected to be attribute names.
| This extension defines the following attribute: | ||
|
|
||
| ### dssematerial | ||
| - Type: `String` |
There was a problem hiding this comment.
It's not clear to me why this is a string and specified as base64. If the intention is to transport arbitrary bytes, I think it should be of type Binary, which would happen to be base64-encoded in the JSON CloudEvents format, but not necessarily in other formats.
I think it would be better to make it Binary, and explicitly state that logically it's a string, but binary is used to avoid the restrictions on the String type. Alternatively, would it be reasonable to put the JSON on a single line and have it as a string without any additional encoding? I suspect the only character disallowed in https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#type-system that causes a problem at the moment is for the line break.
| 5. if the list from step 2 is not empty: | ||
| 1. create an empty byte sequence for the ext digest | ||
| 2. for each extension attribute in the list from step 2 (in the given order, from lowest to highest index) | ||
| 1. compute the SHA256 digest of the extension attribute's value and append it to the byte sequence. Non-string attribute values MUST be serialized to their [CloudEvents string representation](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#type-system) before hashing. *(if the attribute is not present on the event, use the digest of the empty byte sequence)* |
There was a problem hiding this comment.
I think we need more clarity here. Effectively I'd suggest a whole separate section about how each type is hashed, and then use that for both the core and extension attributes.
(I'd also suggest that when hashing a binary value, there's no point in converting it to base64 first - likewise we could use simple encodings for Integer and Boolean values.)
| 2. if verification fails, the event MUST be discarded | ||
| 8. recompute `core_digest` from the event according to steps 3-4 of the signing [Protocol](#protocol) and compare it to the `core` byte sequence from step 6.2 | ||
| 1. if the values are not equal, the event has been modified in transit and MUST be discarded | ||
| 9. if the `ext` field is present (step 6.3) and the consumer wishes to verify extension attributes, recompute `ext_digest` from the event using the `signedextattrs` list from step 6.4 according to step 5 of the signing [Protocol](#protocol) and compare it to the `ext` byte sequence from step 6.3 |
There was a problem hiding this comment.
This is where I think we need to be clear that the verifier must know the types of the extension attributes in order to verify them. The overall result of verification could be:
- Verified both core and extensions
- Verified core, there were no signed extensions
- Verified code, can't verify extensions due to at least one extension attribute's type not being known
- Verification failed (one of the signatures doesn't match)
| data. Users handle either a complete unverified event or a verified event with | ||
| only verified values—never a mixture of both. | ||
| Upon verification of a CloudEvent, implementations MUST return a new event | ||
| containing only verified data. If only core verification was performed (step 8), |
There was a problem hiding this comment.
I'm concerned about this too. I'd far rather be able to keep everything, but make it easy to determine which extensions were signed and which weren't.
| * *In [CloudEvent's official Protocol Buffers format](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/cloudevents.proto#L57), the `time` Context Attribute is encoded as a `google.protobuf.Timestamp` and hence does not include time zone information (which RFC 3339 would allow). For interoperability with CloudEvent setups using the Protocol Buffers format, time zone information is ignored in the signing and verification process.* | ||
| * *The signature covers the exact byte representation of the event data. Intermediaries that deserialize and reserialize event data (e.g., reformatting JSON whitespace or reordering keys) will invalidate the signature. Implementations that route signed events MUST preserve the original byte sequence of the event data.* | ||
|
|
||
| ## Verification Walkthrough |
There was a problem hiding this comment.
I've stopped reviewing at this point as I suspect changes above will affect the text below.
| This is how to sign a CloudEvent using DSSE: | ||
|
|
||
| 1. choose a signing key | ||
| 2. choose the list of "signed extension attributes" (the list MUST adhere to the constraints defined in the [`dssematerial`](#dssematerial) attribute definition: no repetitions, no Context Attribute names, and no `dssematerial`) |
There was a problem hiding this comment.
Note either here or elsewhere that extension attributes with a known value but not a known type (which could happen in some SDK implementations if this is an event which has been received and is being propagated) cannot be signed.
| - Attribute names MUST NOT contain repetitions | ||
| - Attribute names MUST NOT include any [core context attribute](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#context-attributes) name (`id`, `source`, `specversion`, `type`, `datacontenttype`, `dataschema`, `subject`, `time`) | ||
| - Attribute names MUST NOT include `dssematerial` (the verification material attribute) | ||
| - Extension attribute values MUST be of a supported CloudEvents type (`Boolean`, `Integer`, `String`, `Binary`, `URI`, `URI-reference`, or `Timestamp`) |
There was a problem hiding this comment.
I'm not sure what this means - there's no concept of an attribute which exists but isn't of a supported type.
If this is intended to mean that the signer knows the type of the attribute, that's slightly different. I think I'd probably talk about that separate from this bullet list though.
| normalized to UTC ("Zulu") time with second precision. | ||
| - `CEString(v)` is the CloudEvents canonical string encoding of an extension | ||
| attribute value, as defined in step 5.2.1 of the [Signing Protocol](#signing-protocol) | ||
| (`Boolean`, `Integer`, `String`, `Binary`, `URI`, `URI-reference`, `Timestamp`). |
There was a problem hiding this comment.
Not sure what this list is intended for, but I think we can just remove the line (and move the period to the line above)
There was a problem hiding this comment.
It's mostly cause security typically wants things to be VERY clear. No way to interpret anything.
| - `CEString(v)` is the CloudEvents canonical string encoding of an extension | ||
| attribute value, as defined in step 5.2.1 of the [Signing Protocol](#signing-protocol) | ||
| (`Boolean`, `Integer`, `String`, `Binary`, `URI`, `URI-reference`, `Timestamp`). | ||
| - `event.data` is hashed as its raw byte representation — no UTF-8 wrapping |
There was a problem hiding this comment.
Hmm... this could be tricky. I've been focused on the representations of the attributes, but data is a whole other tricky story. What is the "raw byte representation" of an in-memory CloudEvent which has a JSON object as its data? If this is intended to be "the bytes that appear in the serialized form" then that gets us back to implementation difficulties.
(Historically, attributes have been relatively straightforward - we've had many, many discussions about the nature of data, particularly for event formats which can represents certain data types in a different way, e.g. where the data for a JSON-formatted event is itself a JSON object...)
There was a problem hiding this comment.
This only applies to event.data, not to context attributes. Context attributes use semantic canonicalization (Option 3 from our email thread), which you described as having “really significant benefits: Signature doesn’t change based on format, Much simpler implementation than either 1 or 2”, and that’s what the spec implements for all typed attributes (UTF8(s) for strings, RFC3339(UTC(t)) for timestamps, etc.).
For event.data, raw bytes are unavoidable: there is no CE type system for event data, so we cannot apply semantic canonicalization. The note at lines 327–328 calls this out explicitly, any intermediary that reserializes event data (whitespace changes, key reordering) must re-sign. This is the same trade-off you acknowledged in the email when discussing Option 2: “That’s ‘only’ inefficient rather than particularly difficult, but it does mean that support for this extension needs to be built into every event formatter.” We avoided that for attributes via Option 3; for data there is no equivalent.
| - `Binary`: Base64 encoding per RFC 4648 | ||
| - `URI`: the absolute URI string per RFC 3986 Section 4.3 | ||
| - `URI-reference`: the URI-reference string per RFC 3986 Section 4.1 | ||
| - `Timestamp`: RFC 3339 Zulu format with second precision (normalized to UTC as described in step 8) |
There was a problem hiding this comment.
Again, I'd separate out "here's how you hash a value" (on a per type basis) from the uses of it. That way you don't need any repetition, and key implementation details (e.g. how to hash a timestamp value) aren't buried in the list.
| 1. compute the SHA256 digest of the extension attribute's value and append it to the byte sequence. Extension attribute values MUST be serialized using their CloudEvents canonical string encoding before hashing: | ||
| - `Boolean`: "true" or "false" (case-sensitive) | ||
| - `Integer`: decimal representation without leading zeros, fraction, or exponent (per RFC 7159 Section 6) | ||
| - `String`: the string value as-is |
There was a problem hiding this comment.
A string value can't be hashed, as hashing is an operation on binary data. I suspect we want to say you hash the UTF-8-encoded form of the string.
|
|
||
| *Notes:* | ||
|
|
||
| * *In [CloudEvent's type system](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#type-system) a `Timestamp`'s string encoding is [RFC 3339](https://tools.ietf.org/html/rfc3339). This means that verification of the `time` Context Attribute can only be done with second precision, even though an SDK might allow passing in a timestamp with nanosecond precision.* |
There was a problem hiding this comment.
It's not RFC3339 which limits us to second precision - it's interoperability. We don't know what degree of precision any given consumer will use, so it's simplest to truncate to the second.
There was a problem hiding this comment.
Good call out. I remember there's a timestamp RFC that is specifically second precisions, but I may be misremembering or blurring RFCs.
But good callout
|
|
||
| * *In [CloudEvent's type system](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#type-system) a `Timestamp`'s string encoding is [RFC 3339](https://tools.ietf.org/html/rfc3339). This means that verification of the `time` Context Attribute can only be done with second precision, even though an SDK might allow passing in a timestamp with nanosecond precision.* | ||
| * *In [CloudEvent's official Protocol Buffers format](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/cloudevents.proto#L57), the `time` Context Attribute is encoded as a `google.protobuf.Timestamp` and hence does not include time zone information (which RFC 3339 would allow). For interoperability with CloudEvent setups using the Protocol Buffers format, time zone information is ignored in the signing and verification process.* | ||
| * *The signature covers the exact byte representation of the event data. Intermediaries that deserialize and reserialize event data (e.g., reformatting JSON whitespace or reordering keys) will invalidate the signature. Deployments requiring end-to-end verifiability SHOULD avoid such intermediaries or accept re-signing at trust boundaries.* |
There was a problem hiding this comment.
This comes back to what "the exact byte representation of the event data" is, and how tricky that could be for implementations...
There was a problem hiding this comment.
Same answer as above
This applies only to event.data, not to context attributes. For context attributes the spec uses semantic canonicalization (Option 3 from our March 11 discussion), which you preferred precisely because it avoids the wire-bytes implementation pain you described: “often the bytes that were on the wire aren’t known by the time you’re dealing with the parsed representation... the JSON event formatter reads the whole body as a document. At that point, the original bytes on the wire have gone.”
For event.data we cannot apply the same trick, there is no CE type for data. Signing requires stable bytes, and the spec documents the consequence clearly (lines 327–328): intermediaries that reserialize data must resign. SDK authors should sign as close to the wire as possible. Happy to add a note in the spec making this explicit for SDK implementors.
There was a problem hiding this comment.
Right - sorry for missing this before. I think in many cases this may make implementation close to infeasible, unfortunately.
For example in https://github.com/cloudevents/sdk-csharp/blob/main/src/CloudNative.CloudEvents.SystemTextJson/JsonEventFormatter.cs#L138 (and similar event formatters) the first thing that's done is to read the event as a JSON document. At that point, we simply don't have the original bytes. So to read the wire data, we'd probably have to maintain our own very low-level JSON parser in order to get the raw bytes.
I hate to be a downer, but I think for at least a lot of languages, this will simply break any layered architecture of the SDK. It may be feasible in some other languages of course.
There was a problem hiding this comment.
For event.data I want to acknowledge you raised this in our March email too, and at the time you said "That feels somewhat reasonable as a spec, but a real pain to implement in an SDK." We proceeded on that basis, and the spec documents the consequence clearly. So I dont think it was missed, per se.
On the C# SDK example: the formatter reading the whole JSON document before the raw bytes are available is a real constraint, but the solution is to capture the bytes during parsing rather than after. System.Text.Json exposes raw UTF-8 bytes for a value node via GetRawText() or an equivalent reader-level API, no custom low-level parser needed. The SDK would need to thread this through the signing path, which is additional work, but it's the same class of work any checksum/integrity system requires.
The alternative, defining a canonical serialization for event.data, would require specifying rules for every possible content type (JSON, XML, binary, protobuf, etc.), which is far out of scope. Raw bytes is the only content-type-agnostic option.
Producers typically sign before serialization where raw bytes are always available. For SDKs that receive-and-propagate, capturing bytes at the formatter layer is the right integration point. We can capture that in the spec if needed
There was a problem hiding this comment.
but the solution is to capture the bytes during parsing rather than after. System.Text.Json exposes raw UTF-8 bytes for a value node via GetRawText() or an equivalent reader-level API, no custom low-level parser needed.
I may have chosen a bad example - it's possible that we can do this for System.Text.Json without very many changes. I think I'd need to check it really carefully for every format - for example, in protobuf it may be feasible due to parsing effectively preserving everything we need.
At the very least, I think it'll mean work on a "per language, per format" basis, and in a way which makes the implementation significantly more complex. That may well be unavoidable, and I acknowledge that there's probably no better approach - but with our current state of SDKs being "it's hard to find maintainers at all" that may well mean we end up with an extension that is very spottily implemented :(
There was a problem hiding this comment.
As someone who used to maintain SDKs, I understand the pain :(.
I will have to check with legal, but we may be able to help with some implementations, e.g., golang, java, python.
C# is a little out of skillset though ><. At this point it seems like figuring out the best path to get this implemented.
I will have a commit that updates the other points, e.g., the duplicated canonicalization stuff, type lists, etc, soon
| called `dssematerial` (see [Attributes](#attributes) section below). | ||
|
|
||
| The `dssematerial` binary value MUST be the UTF-8 encoding of a proper DSSE | ||
| envelope: |
There was a problem hiding this comment.
DSSE JSON envelope (like below)
| 5. compute the SHA256 digest of the event's [`datacontenttype`](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#datacontenttype) Context Attribute in UTF8 and append it to the byte sequence *(if the attribute is not set, use the digest of the empty byte sequence)* | ||
| 6. compute the SHA256 digest of the event's [`dataschema`](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#dataschema) Context Attribute in UTF8 and append it to the byte sequence *(if the attribute is not set, use the digest of the empty byte sequence)* | ||
| 7. compute the SHA256 digest of the event's [`subject`](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#subject) Context Attribute in UTF8 and append it to the byte sequence *(if the attribute is not set, use the digest of the empty byte sequence)* | ||
| 8. compute the SHA256 digest of the event's [`time`](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#time) Context Attribute normalized to RFC 3339 Zulu format with second precision (no subsecond component) and append it to the byte sequence (if the attribute is not set, use the digest of the empty byte sequence) |
There was a problem hiding this comment.
"Zulu" is mentioned once in RFC3339, but it will be helpful to show a formatted datetime example of what you mean here and also link to the RFC. That's a good potential source of hours of debugging fun if one misses this detail.
| *Notes:* | ||
|
|
||
| * *In [CloudEvent's type system](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#type-system) a `Timestamp`'s string encoding is [RFC 3339](https://tools.ietf.org/html/rfc3339). This means that verification of the `time` Context Attribute can only be done with second precision, even though an SDK might allow passing in a timestamp with nanosecond precision.* | ||
| * *In [CloudEvent's official Protocol Buffers format](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/cloudevents.proto#L57), the `time` Context Attribute is encoded as a `google.protobuf.Timestamp` and hence does not include time zone information (which RFC 3339 would allow). For interoperability with CloudEvent setups using the Protocol Buffers format, time zone information is ignored in the signing and verification process.* |
There was a problem hiding this comment.
We should assume that all timezone-less datetime values are UTC.
clemensv
left a comment
There was a problem hiding this comment.
I am in favor of merging this once the remaining raised issues are addressed, which all seem editorial. The mechanism is clearly explained.
Introduces the verifiability extension, enabling producers to cryptographically sign CloudEvents and consumers to verify authenticity and integrity using DSSE (Dead Simple Signing Envelope) v1.0.2. Key design points: - Canonical value serialization per CloudEvents type for format-neutral signatures (no wire-bytes requirement for context attributes) - Optional signing of extension attributes via signedextattrs - Consumer behavior configuration matrix (strict/passthrough/core-only) - Proxy guidance: SHOULD re-sign when modifying signed fields - SDK phased rollout: JSON format first, additional formats by vote - Timestamp normalization to RFC 3339 Zulu with second precision Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Proposed Changes
feat: Add DSSE-based cryptographic signing for CloudEvents verification
Implements verifiable CloudEvents using DSSE (Dead Simple Signing Envelope) to ensure event authenticity and integrity across untrusted transport layers.
Key features:
Technical approach:
This enables cryptographic proof that events:
Does NOT address: event ordering, completeness, replay attacks, or confidentiality
Fixes #1302
Release Note