Skip to content
This repository was archived by the owner on Jan 8, 2026. It is now read-only.

Commit 28edd8d

Browse files
oedalexjg
authored andcommitted
fix(dag-jose): restucture and clarify content
1 parent 9cd7771 commit 28edd8d

1 file changed

Lines changed: 92 additions & 25 deletions

File tree

block-layer/codecs/dag-jose.md

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,123 @@
44

55
JOSE is a stanard for signing and encrypting JSON objects. The various specifications for JOSE can be found in the [IETF datatracker](https://datatracker.ietf.org/wg/jose/documents/).
66

7-
DAG JOSE supports the full [IPLD Data Model](../data-model-layer/data-model.md).
7+
DAG JOSE supports the full [IPLD Data Model](../data-model-layer/data-model.md) (within the payload).
88

99
## Format
1010

11-
The are two main ways to represent a JOSE node. As a JWS ([json web signature](https://datatracker.ietf.org/doc/rfc7515/?include_text=1)) and JWE ([json web encryption](https://datatracker.ietf.org/doc/rfc7516/?include_text=1)). These two formats acts as the primitives in JOSE and can be used to create JWT and JWM objects. This specification describes how to encode JWS and JWE as an IPLD format.
11+
The are two main ways to represent a JOSE object. As a JWS ([json web signature](https://datatracker.ietf.org/doc/rfc7515/?include_text=1)) and JWE ([json web encryption](https://datatracker.ietf.org/doc/rfc7516/?include_text=1)). These two formats acts as the primitives in JOSE and can be used to create JWT and JWM objects etc. This specification describes how to encode JWS and JWE as an IPLD format.
12+
13+
### Representation
14+
15+
The layout of a decoded JOSE object is described by the IPLD schema defined below. We will refer to this layout as the `Decoded Representation`.
16+
17+
```ipldsch
18+
type Signature struct {
19+
header optional {String:Any}
20+
protected optional {String:Any}
21+
signature Bytes
22+
}
23+
24+
type JWS struct {
25+
payload Any
26+
signatures [Signature]
27+
}
28+
29+
type Recipient struct {
30+
encrypted_key optional Bytes
31+
header optional {String:Any}
32+
}
33+
34+
type JWE struct {
35+
aad optional Bytes
36+
ciphertext Bytes
37+
iv optional Bytes
38+
protected optional {String:Any}
39+
recipients [Recipient]
40+
tag optional Bytes
41+
unprotected optional {String:Any}
42+
}
43+
44+
type JOSE union {
45+
| JWS jws
46+
| JWE jwe
47+
} representation kinded
48+
```
1249

1350
### Serialization
1451

15-
Both JWS and JWE supports different serialization formats: `Compact Serialization`, `Flattened JSON Serialization`, and `General JSON Serialization`. The first two are more concise, but they only allow for one recipient. Therefore DAG JOSE always uses the `Compact Serialization` if there is just one recipient, and the `General JSON Serialization` if there are multiple recipients. This ensures maximum compatibility and compactness with minimum ambiguity.
52+
Both JWS and JWE supports three different serialization formats: `Compact Serialization`, `Flattened JSON Serialization`, and `General JSON Serialization`. The first two are more concise, but they only allow for one recipient. Therefore DAG JOSE always uses the `General Serialization` which ensures maximum compatibility with minimum ambiguity.
1653

17-
The implementation of the serialization function should accept all JOSE formats and convert them if necessary.
54+
The implementation of the serialization function should accept all JOSE formats including the `Decoded Representation` and convert them if necessary.
1855

19-
#### Ordering
56+
#### General JSON Serialization
57+
58+
Below the `General JSON Serialization` can be observed. Note that all data represented as `String` here is data that has been encoded using `base64url`. Converting `Compact Serialization` and `Flattened JSON Serialization` to the general serialization is trivial.
59+
60+
```ipldsch
61+
type GeneralSignature struct {
62+
header optional {String:Any}
63+
protected optional String
64+
signature String
65+
}
2066
21-
Codec implementors **MUST** use the specified order of JOSE properties to ensure hashes consistently match for the same block data. Since JWS and JWE have a strict set of properties this is straight forward.
67+
type GeneralJWS struct {
68+
payload String
69+
signatures [GeneralSignature]
70+
}
2271
23-
#### JWS
72+
type GeneralRecipient struct {
73+
encrypted_key optional String
74+
header optional {String:Any}
75+
}
2476
25-
The top level object has two properties which should have the order: `payload` then `signatures`. The `signatures` property contains an array of signature elements. Within each of these elements there are three properties which should have the order: `protected`, `header`, then `signature`. Important to note here is that `protected` and `header` may be absent.
77+
type GeneralJWE struct {
78+
aad optional String
79+
ciphertext String
80+
iv optional String
81+
protected optional String
82+
recipients [GeneralRecipient]
83+
tag optional String
84+
unprotected optional {String:Any}
85+
}
2686
27-
The content of the `payload`, `signature`, and `protected` properties are `base64url` encoded and therefore does not need any sorting. In contrast, the `header` property contains an unencoded JSON object and should sort object keys by their (UTF-8) encoded representation, i.e. with byte comparisons.
87+
type GeneralJOSE union {
88+
| GeneralJWS jws
89+
| GeneralJWE jwe
90+
} representation kinded
91+
```
2892

29-
Finally all whitespace should be stripped. This produces the most compact and consistent representation which will ensure that two codecs producing the same data end up with matching block hashes.
93+
##### Serializing the Decoded Representation
3094

31-
##### JWS payload
95+
When serializing a JOSE object from the `Decoded Representation` special care needs to be taken with the `payload` property as well as the `protected` properties.
3296

33-
In it's serialized format a JWS `payload` is encoded using `base64url`. The content of the payload can encode any arbitrary data. To distinguish different data formats a `cty` (Content Type) Header Parameter can be defined. However, it's not required in any way, so it's not something that can be relied upon. It's quite common that the content of the `payload` simply contains JSON. With DAG-JOSE the `payload` is extended to also support [DAG-JSON](./dag-json.md) (with *Bytes Kind* and *Link Kind*).
97+
###### Protected
3498

35-
This means that the `payload` can be represented in two different ways:
99+
The `protected` property in JWE and JWS have the type `{String:Any}`. This means that it may include data with *Link Kind* and *Bytes Kind*. These should be converted into pure JSON in the same way as it's done in [DAG-JSON](./dag-json.md). However, the properties should **not** be sorted since that would cause any integrity check on the JOSE data to fail. Once in JSON format the `protected` property should be converted into `base64url` using the method described in the JOSE spec (`BASE64URL(UTF8(data))`).
36100

37-
* `base64url` encoded ([DAG-JSON](./dag-json.md), or arbitrary data)
38-
* Deserialized DAG-JSON
101+
###### Payload
39102

40-
The serialization function should accept both of these input formats and convert them if necessary.
103+
The payload property of JWS can be of either `Bytes` or `{String:Any}` types. If the former it's simply just encoded as `base64url`. If the latter, it should be encoded in the same manner as the `protected` property.
41104

42-
Note that the JWS signature happens over `ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload))` according to the [JWS specification](https://datatracker.ietf.org/doc/rfc7515/?include_text=1), so if the `payload` contains JSON it need to be ordered in a determinitic way for the signature to always be correct. The DAG-JOSE format should not prefer any specific ordering as different JWS implementations might have different preferences. If [DAG-JSON](./dag-json.md) is used this is however completely mitigated since it uses strict ordering.
105+
Note that any change in the ordering of the properties of the payload at this point would cause potential validation of the JOSE object to fail. Good signature libraries will sort the payload before the signature is applied.
106+
107+
#### Ordering
43108

44-
##### Deserializing the payload
109+
Once the data has been converted to the `General Serialization`, codec implementors **MUST** use the same sorting algorithm as [DAG-JSON](./dag-json.md) to sort the data to ensure hashes consistently match for the same block data.
45110

46-
When the JWS is deserialized the `payload` should also be decoded using [DAG-JSON](./dag-json.md) if possible. If [DAG-JSON](./dag-json.md) is not detected, the `payload` should not be decoded. By decoding the payload, standard IPLD tools can be used to traverse the content and potential links within the signed data.
111+
## Additional information
47112

48-
#### JWE
113+
### Reccomended JOSE creation strategy
49114

50-
With JWE there are a few more properties that needs to be in the correct order: `protected`, `unprotected`, `iv`, `aad`, `ciphertext`, `tag`, then `recipients`. Within the `recipients` array each element should have the property order: `header` then `encrypted_key`. Important to note here is that only the `ciphertext` property is required, all other properties may be absent.
115+
When creating a JOSE object there are some suggested approaches of how to format the data that is being signed / encrypted / authenticated that will keep you out of trouble. The main thing to keep in mind is that signatures / data authentication could be invalidated if the order of the properties in the JOSE object changes. It's therefore a good idea to sort the properties before any signature / authentication is added. The best way to do this is simply to use the same strategy employed by [DAG-JSON](./dag-json.md), which will also convert `Link` and `Bytes` to JSON representation.
116+
For JWS the relevant properties to do this for is `protected` and `payload` since the signature is done over `ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload))` according to the [JWS specification](https://datatracker.ietf.org/doc/rfc7515/?include_text=1).
51117

52-
The content of the `protected`, `iv`, `aad`, `ciphertext`, `tag`, and `encrypted_key` properties are `base64url` encoded and therefore does not need any sorting. In contrast, the `unprotected` and `header` property contains unencoded JSON objects and should sort object keys by their (UTF-8) encoded representation, i.e. with byte comparisons.
118+
For JWE it is `protected` and the cleartext before it is encrypted into `ciphertext`.
53119

54-
Finally all whitespace should be stripped. This produces the most compact and consistent representation which will ensure that two codecs producing the same data end up with matching block hashes.
120+
### Decryption of JWEs
55121

56-
##### Decrypting the JWE
122+
Similar to the `payload` of JWS, the decrypted data of a JWE may be encoded as [DAG-JSON](./dag-json.md) as described above. The implementation of the decryption function should account for this if neccessary to allow the data be interpreted as an IPLD dag node. In the future the decryption itself could be described using an [Advanced IPLD schema layout](../../schemas/advanced-layouts.md).
57123

58-
Similar to the `payload` of JWS, the decrypted data of a JWE may be encoded as [DAG-JSON](./dag-json.md). The implementation of the decryption function should account for this if neccessary to allow the data be interpreted as an IPLD dag node.
124+
### Implementations
59125

126+
* [Javascript](https://github.com/oed/js-dag-jose)

0 commit comments

Comments
 (0)