|
2 | 2 |
|
3 | 3 | **Status: Descriptive - Draft** |
4 | 4 |
|
5 | | -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/). |
6 | | - |
7 | | -DAG JOSE supports the full [IPLD Data Model](../data-model-layer/data-model.md) (within the payload). |
| 5 | +JOSE is a standard 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/). |
8 | 6 |
|
9 | 7 | ## Format |
10 | 8 |
|
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. |
| 9 | +The are two kinds of JOSE objects: 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 objects are primitives in JOSE and can be used to create JWT and JWM objects etc. The IETF RFCs specify a JSON encoding of JOSE objects. This specification maps the JSON encoding to CBOR. Upon encountering the `dag-jose` multiformat implementations can be sure that the block contains dag-cbor encoded data which matches the IPLD schema we specify below. |
| 10 | + |
| 11 | +### Mapping from the JOSE general JSON serialization to dag-jose serialization |
| 12 | + |
| 13 | +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. Libraries implementing serialization should accept all JOSE formats including the `Decoded Representation` (see below) and convert them if necessary. |
| 14 | + |
| 15 | +To map the general JSON serialization to CBOR we do the following: |
12 | 16 |
|
13 | | -### Representation |
| 17 | +- Any field which is represented as `base64url(<data>)` we map directly to `Bytes` . For fields like `header` and `protected` which are specified as the `base64url(ascii(<some json>))` that means that the value is the `ascii(<some json>)` bytes. |
| 18 | +- For JWS we specify that the `payload` property MUST be a CID, and we set the `payload` of the encoded JOSE object to `Bytes` containing the bytes of the CID. For applications where an additional network request to retrieve the linked content is undesirable then an `identity` multihash should be used. |
| 19 | +- For JWE objects the `ciphertext` must decrypt to a plaintext which is the bytes of a CID. This is for the same reason as the `payload` being a CID, and the same approach of using an `identity` multihash can be used, and most likely will be the only way to retain the confidentiality of data. |
14 | 20 |
|
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`. |
| 21 | +Below we present an IPLD schema representing the encoded JOSE objects. Note that the `EncodedJOSE` union is not in fact a valid IPLD schema as there is no valid discriminator. The actual wire format is a single struct which contains all the keys from both the `EncodedJWE` and the `EncodedJWS` structs, implementors should follow [section 9 of the JWE spec](https://tools.ietf.org/html/rfc7516#section-9) and distinguish between these two branches of the union by checking if the `payload` attribute exists, and hence you have a JWS; or the `ciphertext` attribute, hence you have a JWE. |
| 22 | + |
| 23 | +**Encoded JOSE** |
16 | 24 |
|
17 | 25 | ```ipldsch |
18 | | -type Signature struct { |
| 26 | +type EncodedSignature struct { |
19 | 27 | header optional {String:Any} |
20 | | - protected optional {String:Any} |
| 28 | + protected optional Bytes |
21 | 29 | signature Bytes |
22 | 30 | } |
23 | 31 |
|
24 | | -type JWS struct { |
25 | | - payload Any |
26 | | - signatures [Signature] |
27 | | -} |
28 | | -
|
29 | | -type Recipient struct { |
| 32 | +type EncodedRecipient struct { |
30 | 33 | encrypted_key optional Bytes |
31 | 34 | header optional {String:Any} |
32 | 35 | } |
33 | 36 |
|
34 | | -type JWE struct { |
| 37 | +type EncodedJWE struct { |
35 | 38 | aad optional Bytes |
36 | 39 | ciphertext Bytes |
37 | 40 | iv optional Bytes |
38 | | - protected optional {String:Any} |
39 | | - recipients [Recipient] |
| 41 | + protected optional Bytes |
| 42 | + recipients [EncodedRecipient] |
40 | 43 | tag optional Bytes |
41 | 44 | unprotected optional {String:Any} |
42 | 45 | } |
43 | 46 |
|
44 | | -type JOSE union { |
45 | | - | JWS jws |
46 | | - | JWE jwe |
47 | | -} representation kinded |
| 47 | +type EncodedJWS struct { |
| 48 | + signatures [EncodedSignature] |
| 49 | + payload optional Bytes |
| 50 | +} |
| 51 | +
|
| 52 | +type EncodedJOSE union { EncodedJWE | EncodedJWS } |
48 | 53 | ``` |
49 | 54 |
|
50 | | -### Serialization |
| 55 | +## Padding for encryption |
| 56 | + |
| 57 | +Applications may need to pad the plaintext when encrypting to avoid leaking the size of the plaintext. This raises the question of how the application knows what part of the decrypted plaintext is padding. In this case we use the fact that the plaintext MUST be a valid CID, implementations should parse the plaintext as a CID and discard any content beyond the multihash digest size - which we assume to be the padding. |
51 | 58 |
|
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. |
53 | 59 |
|
54 | | -The implementation of the serialization function should accept all JOSE formats including the `Decoded Representation` and convert them if necessary. |
| 60 | +## Decoded JOSE |
55 | 61 |
|
56 | | -#### General JSON Serialization |
| 62 | +Typically implementations will want to decode this format into something more useful for applications. Exactly what that will look like depends on the language of the implementation, here we use the IPLD schema language to give a somewhat language agnostic description of what the decoded representation might look like at runtime. Note that everything which is specified as `base64url(ascii(<some JSON>))` in the JOSE specs - and which we encode as `Bytes` in the wire format - is here decoded to a `String`. We also add the `link: &Any` attribute to the `DecodedJWS`, which allows applications to easily retrieve the authenticated content. |
57 | 63 |
|
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. |
| 64 | +Also note that - as with the encoded representation - the `DecodedJOSE` union is not valid IPLD schema as there is no way to discriminate between them. How exactly this would be represented will depend on the language of the implementation. For example in Typescript this would be a straightforward `type DecodedJOSE = DecodedJWE | DecodedJWS`. |
59 | 65 |
|
60 | 66 | ```ipldsch |
61 | | -type GeneralSignature struct { |
| 67 | +type DecodedSignature struct { |
62 | 68 | header optional {String:Any} |
63 | 69 | protected optional String |
64 | 70 | signature String |
65 | 71 | } |
66 | 72 |
|
67 | | -type GeneralJWS struct { |
| 73 | +type DecodedJWS struct { |
68 | 74 | payload String |
69 | | - signatures [GeneralSignature] |
| 75 | + signatures [DecodedSignature] |
| 76 | + link: &Any |
70 | 77 | } |
71 | 78 |
|
72 | | -type GeneralRecipient struct { |
| 79 | +type DecodedRecipient struct { |
73 | 80 | encrypted_key optional String |
74 | 81 | header optional {String:Any} |
75 | 82 | } |
76 | 83 |
|
77 | | -type GeneralJWE struct { |
| 84 | +type DecodedJWE struct { |
78 | 85 | aad optional String |
79 | 86 | ciphertext String |
80 | | - iv optional String |
81 | | - protected optional String |
82 | | - recipients [GeneralRecipient] |
83 | | - tag optional String |
| 87 | + iv String |
| 88 | + protected String |
| 89 | + recipients [DecodedRecipient] |
| 90 | + tag String |
84 | 91 | unprotected optional {String:Any} |
85 | 92 | } |
86 | 93 |
|
87 | | -type GeneralJOSE union { |
88 | | - | GeneralJWS jws |
89 | | - | GeneralJWE jwe |
90 | | -} representation kinded |
| 94 | +type DecodedJOSE union { DecodedJWE | DecodedJWS } |
91 | 95 | ``` |
92 | 96 |
|
93 | | -##### Serializing the Decoded Representation |
94 | | - |
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. |
96 | | - |
97 | | -###### Protected |
98 | | - |
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))`). |
100 | | - |
101 | | -###### Payload |
102 | | - |
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. |
104 | | - |
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 |
108 | | - |
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. |
110 | | - |
111 | | -## Additional information |
112 | | - |
113 | | -### Reccomended JOSE creation strategy |
114 | | - |
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). |
117 | | - |
118 | | -For JWE it is `protected` and the cleartext before it is encrypted into `ciphertext`. |
119 | | - |
120 | | -### Decryption of JWEs |
121 | | - |
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). |
123 | | - |
124 | | -### Implementations |
| 97 | +##Implementations |
125 | 98 |
|
126 | | -* [Javascript](https://github.com/oed/js-dag-jose) |
| 99 | +- [Javascript](https://github.com/oed/js-dag-jose) |
| 100 | +- [Go](https://github.com/alexjg/go-dag-jose) |
0 commit comments