Skip to content

Adding verifiability proposal #1330

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
Binary file added cloudevents/extensions/verifiability-flow.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
269 changes: 269 additions & 0 deletions cloudevents/extensions/verifiability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
# CloudEvents Verifiability Extension

This proposal introduces a transport protocol agnostic design for verifiable
CloudEvents. It allows producers of CloudEvents to sign the events that they
send and consumers to cryptographically verify the *authenticity and the
integrity* of the events that they receive. Through this process consumers can
be sure that events were in fact produced by the claimed producer
(authenticity), and that the events were received exactly as they were sent,
and not modified in transit (integrity).

The threats addressed by this proposal are those of malicious actors
impersonating CloudEvent producers and of malicious actors modifying messages
in transit.

This proposal only applies to individual events. It does not give consumers any
guarantees about the completeness of the event stream or the order of events.

The threats of malicious actors removing or hiding items from the event stream
as well as swapping their order are not addressed by this proposal. Neither are
the possibilities of messages accidentally getting lost or delivered in the
wrong order. Both can be addressed by producers through means of adding the
necessary information inside the event payloads.

Further, this proposal only aims at *verifiability*. It does not aim to enable
*confidentiality*. Consequently, it does not address the threat of unauthorized
parties reading CloudEvents that were not meant for them.

## Notational Conventions

As with the main [CloudEvents specification](../spec.md), the key words "MUST",
"MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT",
"RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as
described in [RFC 2119](https://tools.ietf.org/html/rfc2119).

However, the scope of these key words is limited to when this extension is
used. For example, an attribute being marked as "REQUIRED" does not mean
it needs to be in all CloudEvents, rather it needs to be included only when
this extension is being used.

## Attributes

### `verificationmaterial` (Verification Material)

- **Type:** `String`
- **Description:**
The material consumers use to verify a CloudEvent. For example, this could
be a signature of the event generated using a private key. Consumers would
use the producer’s public key to verify the signature.

Producers SHOULD avoid relying on canonicalization to minimize the attack
surface. Verification material SHOULD be transported in a detached format
when possible to avoid canonicalization issues.
- **Constraints:**
- REQUIRED
- MUST be base64-encoded
- If present, the `verificationmaterialtype` attribute MUST also be present
- MUST be transported in the same message as the event
- MUST NOT appear more than once in the message (duplication of the attribute
MUST cause failure)
- If `verificationmaterialtype` is missing, the implementation MUST fail
- If the verification material is invalid (e.g., does not match the received
event), the implementation MUST fail
- If the verification material is of an unknown type, the implementation
SHOULD fail

### `verificationmaterialtype` (Verification Material Type)

- **Type:** `String`
- **Description:**
Indicates the type of verification material. This high-level category
informs consumers how to interpret and process the verification material. It
can include implementation-specific details such as subtype, version
information, etc.
- **Constraints:**
- REQUIRED
- If present, the `verificationmaterial` attribute MUST also be present
- Producers and consumers MUST agree on the material type to ensure
successful verification
- MUST NOT appear more than once in the message (duplication of the attribute
MUST cause failure)
- If `verificationmaterial` is missing, the implementation MUST fail
- If the material type is unknown to the implementation, it MUST fail


## Usage

When this extension is used, producers MUST set both the `verificationmaterial`
and `verificationmaterialtype` attributes. Consumers can choose whether to
perform verification and how to proceed if verification fails.

## Assumptions

This proposal contains a few key assumptions:

1. SDKs will verify as early as possible which depends on the
verification implementation.
2. Users manage their secrets, e.g. public key infrastructure (PKI).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on why these assumptions are being made? It'll help people understand the overall proposal.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In particular, when option 1 is chosen, does it impact assumption 1 ?


## Design

Verifiability in CloudEvents consists of two steps:

1. The producer of an event adds verification material to the message
2. The consumer of an event MAY use the verification material to verify the
authenticity and integrity of the event


The specifics of what the verification material looks like and how the
verification is performed depends on the *verifiability implementation*.

For example, in a public/private key based implementation the producer of an
event would add a signature based on their private key as the verification
material, and the consumer of an event could use the corresponding public key
to check if the signature matches the event.

The flow looks like this:

![Flow](./verifiability-flow.jpg)

*Option 1*: useful for verifiability implementations outside of the CE SDK. The
CE SDK merely passes on messages and is not involved in producing verification
material or performing verifications and has no knowledge about the secrets
that the verification is based on (e.g. private keys). Appropriate for tools in
a closed ecosystem like an enterprise system(s) with special requirements that
are not suitable for the CE SDK.

*Option 2*: useful for verifiability implementations that are directly
supported by the CE SDK. The CE SDK has to be provided with the secrets (e.g.
private key for producer and public key for consumers) and will create the
verification material on the producer side and also perform the verification on
the consumer side. This is the appropriate choice for any type of tool that is
used by other entities, for example open source.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth mentioning that each side of the interaction could choose a different option?
I'm assuming neither side would need to know what choice the other side made, right? It becomes an impl/deployment choice.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. So yes, let me clarify that.


**Notes:** If an intermediary party modifies an event, they are considered the
producer of a new event. They MUST create an updated verification material and
the consumer(s) MUST recognize them as a trustworthy producer.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth calling out that the intermediary is also a consumer that needs to verify the incoming message before it does it's own verifiability creation processing, right?

Which begs the question... do we need to worry about nested verification scenarios?

e.g. client and receiving app do their own verify logic, but then the sdks do as well and neither know about each other. Is this a user error or something we should consider in the design to ensure a proper separation of concerns?

Copy link
Author

@xibz xibz Apr 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which begs the question... do we need to worry about nested verification scenarios?

That’s a great question, and an important one to scope clearly.

This proposal intentionally avoids prescribing nested verification logic. The goal is simplicity and clarity: if an intermediary verifies and re-signs an event, downstream consumers can safely assume that all prior verification steps were completed successfully.

If certain use cases require retaining and re-validating upstream signatures (e.g. for compliance or traceability), they can implement that at the application level. However, I believe this behavior is out of scope for the core proposal, and handling it by default could introduce unnecessary complexity for most users.

e.g. client and receiving app do their own verify logic, but then the sdks do as well and neither know about each other. Is this a user error or something we should consider in the design to ensure a proper separation of concerns?

Ideally, verification logic should be explicit and predictable, not something silently enforced at multiple layers (e.g. SDK and application both independently verifying without coordination). That said, I view this as a matter of implementation discipline and documentation, not something that needs to be deeply enforced in the spec.

When the SDKs include built-in verification, that should be clearly documented and ideally exposed as a configurable behavior. Likewise, applications integrating with such SDKs should understand where verification happens to avoid redundant or conflicting logic.

This is not a user error per se, but it is a UX and documentation consideration for implementers of SDKs, not something the event format itself needs to control.

Let me know if I understood that last question right

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This proposal intentionally avoids prescribing nested verification logic. The goal is simplicity and clarity: if an intermediary verifies and re-signs an event, downstream consumers can safely assume that all prior verification steps were completed successfully.

only if we trust the "man in the middle".

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, you're right that this assumes the intermediary is trusted once it re-signs.

This proposal offers a baseline model where each hop that re-signs effectively vouches for the previous event state. That model works well for many common deployment scenarios where intermediaries are under control of the same org or within a trusted boundary.

That said, if an implementation operates in a zero-trust or cross-organizational context, then yes—nested signature chains could be introduced to preserve and verify the original event alongside any transformations. I think that should remain an implementation detail, not a requirement of this extension.

I can certainly note this as a pattern for advanced use cases, but our aim is to keep the spec as simple and flexible as possible without precluding stronger models.


The choice between Option 1 and Option 2 can be made independently by each
system. For example, a producer might follow Option 1 while a consumer uses
Option 2, depending on their requirements and trust boundaries.

## Verifiability Implementation Proposals

A proposal for adding a verifiability implementation to the CE SDK **MUST:**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels a bit odd to use RFC2119 keywords for things sdk authors need to do (here and below).
I'm ok with really strong language (e.g. "it is expected that implementations do ..."), but whether people follow our advice is out of scope for us. All we can mandate is what goes on the wire.


* provide specs on how to implement verification
* provide test vectors
* provide a verification coverage table (see Verification coverage table)

Test vectors ensure that implementations are consistent which does NOT affect
verifiability.

A proposal for adding a verifiability implementation to the CE SDK **SHOULD:**

* provide information about how they handle attributes, and if relevant, normalization

## Example

To illustrate, let’s walk through how to implement a verification
implementation

### Verification Implementation

This is an example message containing a CloudEvent directly from the spec. It
happens to be an HTTP structured mode message in JSON format. Our goal is to
come up with the most insecure but also most concise verification
implementation imaginable: one based on a reversed digest which we will call
`rev`! The `rev` implementation will only verify whether or not the
payload, `data`, is valid and not whether the other context attributes are
valid, for the sake of simplicity.

Here is how a message containing that CloudEvent might look:

```
content-length: 209
content-type: application/json

{
"specversion" : "1.0",
"type" : "com.example.someevent",
"source" : "/mycontext",
"subject": null,
"id" : "D234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"data" : "I'm just a string"
}
```

In order to make this event verifiable, the reversed value of the 'data' field
is computed and base64-encoded: `Z25pcnRzIGEgdHN1aiBtJ0kK`.
This value will then be base64 encoded and added as the `verificationmaterial`
context attribute:

```
content-length: 209
content-type: application/json

{
"specversion" : "1.0",
"type" : "com.example.someevent",
"source" : "/mycontext",
"subject": null,
"id" : "D234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"data" : "I'm just a string",
"verificationmaterial": "Z25pcnRzIGEgdHN1aiBtJ0kK",
"verificationmaterialtype": "rev"
}
```

A consumer then receives this message and in order to verify, they would look
at the `verificationmaterialtype` attribute to determine whether it knows how
to perform the verification. The consumer sees that verification material’s
type is `rev`, so they will compute the `rev` of the payload to verify the
CloudEvent contained in the message:

```
$ echo -n "I'm just a string" | rev
gnirts a tsuj m'I
```

The consumer can then confirm that the verification material matches the rev
output and conclude that the CloudEvent’s authenticity and integrity are
"guaranteed".

Now, since we want to make our fantasy verification implementation into a
proposal to be included in the CE SDK, we will need to define test vectors and
a verification coverage table.

### Test Vectors

An example test vector is defined below:

```
[
"input": {
{
"specversion" : "1.0",
"type" : "com.example.someevent",
"source" : "/mycontext",
"subject": null,
"id" : "D234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"data" : "I'm just a string"
}
},
"expectedVerificationMaterialType": "rev",
"expectedVerificationMaterial": "Z25pcnRzIGEgdHN1aiBtJ0kK"
]
```

SDKs and implementers can then use the vectors to ensure that any
implementation is correct and verifiable across different languages and
systems.

### Verification Coverage Table

The table below outlines which parts of a CloudEvent for our imaginary `rev`
based verification implementation would cover:

|Verifiable information |binary-mode |structured-mode |comment |
|--- |--- |--- |--- |
|data/payload |✅ |✅ | |
|mandatory context attributes |❌ |❌ |The `rev` verification implementation only looks at the payload, not at any context attributes. |
|permissive context attributes |❌ |❌ |
|extension attributes |❌ |❌ |

Again, `rev` was chosen because it makes for an easily readable example. It is
wildly insecure and not suitable for actual verifiability.
3 changes: 3 additions & 0 deletions cloudevents/languages/he/extensions/verifiability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CloudEvents Verifiability Extension
מסמך זה טרם תורגם. בבקשה תשתמשו [בגרסה האנגלית של המסמך](../../../extensions/verifiability.md) לבינתיים.

7 changes: 7 additions & 0 deletions cloudevents/languages/zh-CN/extensions/verifiability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# CloudEvents Verifiability Extension

本文档尚未被翻译,请先阅读英文[原版文档](../../../extensions/verifiability.md) 。

如果您迫切地需要此文档的中文翻译,请[提交一个issue](https://github.com/cloudevents/spec/issues) ,
我们会尽快安排专人进行翻译。

Loading