@@ -33,13 +33,16 @@ The signature format is a JSON message of the following form:
33
33
"payload" : " <Base64(SERIALIZED_BODY)>" ,
34
34
"payloadType" : " <PAYLOAD_TYPE>" ,
35
35
"signatures" : [{
36
- … ,
36
+ "keyid" : " <KEYID> " ,
37
37
"sig" : " <Base64(Sign(PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY)))>"
38
- }, … ]
38
+ }]
39
39
}
40
40
```
41
41
42
- where:
42
+ Empty fields may be omitted. [ Multiple signatures] ( #multiple-signatures ) are
43
+ allowed.
44
+
45
+ Parameters:
43
46
44
47
* SERIALIZED_BODY is the byte sequence to be signed.
45
48
@@ -55,6 +58,11 @@ where:
55
58
- https://theupdateframework.com/Root/v1.0.5
56
59
- etc...
57
60
61
+ * KEYID is an optional, unauthenticated hint indicating what key was used to
62
+ sign the message. It ** must not** be used for security decisions.
63
+
64
+ Functions:
65
+
58
66
* PAE() is the
59
67
[ PASETO Pre-Authentication Encoding] ( https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Common.md#authentication-padding ) ,
60
68
where parameters ` type ` and ` body ` are byte sequences:
@@ -88,6 +96,7 @@ To sign:
88
96
SERIALIZED_BODY.
89
97
- Sign PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY), base64-encode the result, and
90
98
store it in `sig`.
99
+ - Optionally, compute a KEYID and store it in `keyid`.
91
100
- Base64-encode SERIALIZED_BODY and store it in `payload`.
92
101
- Store PAYLOAD_TYPE in `payloadType`.
93
102
@@ -116,9 +125,9 @@ valid while avoiding the verifier from having to use [Canonical JSON].
116
125
"payload": "<Base64(CanonicalJson(BODY))>",
117
126
"payloadType": "<URI>/backwards-compatible-json",
118
127
"signatures" : [{
119
- … ,
120
- "sig" : "<Base64(Sign(CanonicalJson(BODY)))>"
121
- }, … ]
128
+ "keyid": "<KEYID>" ,
129
+ "sig": "<Base64(Sign(CanonicalJson(BODY)))>"
130
+ }]
122
131
}
123
132
```
124
133
@@ -129,6 +138,7 @@ To sign:
129
138
- BODY ** must** be an object type (` {...} ` ).
130
139
- Serialize BODY as [ Canonical JSON] ; call this SERIALIZED_BODY.
131
140
- Sign SERIALIZED_BODY, base64-encode the result, and store it in ` sig ` .
141
+ - Optionally, compute a KEYID and store it in ` keyid ` .
132
142
- Base64-encode SERIALIZED_BODY and store it in ` payload ` .
133
143
- Store ` "<URI>/backwards-compatible-json" ` in ` payloadType ` .
134
144
@@ -152,6 +162,25 @@ This scheme is safe from rollback attacks because the first byte of
152
162
SERIALIZED_BODY must be 0x7b (` { ` ) in backwards compatibility mode and 0x02 in
153
163
regular mode.
154
164
165
+ ### Multiple signatures
166
+
167
+ A file may have more than one signature, which is equivalent to separate files
168
+ with individual signatures.
169
+
170
+ ``` json
171
+ {
172
+ "payload" : " <Base64(SERIALIZED_BODY)>" ,
173
+ "payloadType" : " <PAYLOAD_TYPE>" ,
174
+ "signatures" : [{
175
+ "keyid" : " <KEYID_1>" ,
176
+ "sig" : " <SIG_1>"
177
+ }, {
178
+ "keyid" : " <KEYID_2>" ,
179
+ "sig" : " <SIG_2>"
180
+ }]
181
+ }
182
+ ```
183
+
155
184
### Optional changes to wrapper
156
185
157
186
The standard wrapper is JSON with an explicit ` payloadType ` . Optionally,
@@ -286,9 +315,9 @@ over the [Canonical JSON] serialization of BODY.
286
315
{
287
316
"signed" : <BODY>,
288
317
"signatures" : [{
289
- … ,
318
+ "keyid" : " <KEYID> " ,
290
319
"sig" : " <Hex(Sign(CanonicalJson(BODY)))>"
291
- }, … ]
320
+ }]
292
321
}
293
322
```
294
323
@@ -307,11 +336,13 @@ To convert an existing signature to the new format:
307
336
- ` new.payload = base64encode(CanonicalJson(orig.signed)) `
308
337
- ` new.payloadType = "<URI>/backwards-compatible-json" `
309
338
- ` new.signatures[*].sig = base64encode(hexdecode(orig.signatures[*].sig)) `
339
+ - ` new.signatures[*].keyid = orig.signatures[*].keyid `
310
340
311
341
To convert a backwards compatible signature to the old format:
312
342
313
343
- ` old.signed = jsonparse(base64decode(new.payload)) `
314
344
- ` old.signatures[*].sig = hexencode(base64decode(new.signatures[*].sig)) `
345
+ - ` old.signatures[*].keyid = new.signatures[*].keyid `
315
346
316
347
## Testing
317
348
0 commit comments