@@ -32,13 +32,16 @@ The signature format is a JSON message of the following form:
32
32
"payload" : " <Base64(SERIALIZED_BODY)>" ,
33
33
"payloadType" : " <PAYLOAD_TYPE>" ,
34
34
"signatures" : [{
35
- … ,
35
+ "keyid" : " <KEYID> " ,
36
36
"sig" : " <Base64(Sign(PAE([UTF8(PAYLOAD_TYPE), SERIALIZED_BODY])))>"
37
- }, … ]
37
+ }]
38
38
}
39
39
```
40
40
41
- where:
41
+ Empty fields may be omitted. [ Multiple signatures] ( #multiple-signatures ) are
42
+ allowed.
43
+
44
+ Parameters:
42
45
43
46
* SERIALIZED_BODY is the byte sequence to be signed.
44
47
@@ -54,6 +57,14 @@ where:
54
57
- https://theupdateframework.com/Root/v1.0.5
55
58
- etc...
56
59
60
+ * KEYID is an optional, unauthenticated hint indicating what key and algorithm
61
+ was used to sign the message. As with Sign(), details are agreed upon
62
+ out-of-band by the signer and verifier. It ** MUST NOT** be used for security
63
+ decisions; it may only be used to narrow the selection of possible keys to
64
+ try.
65
+
66
+ Functions:
67
+
57
68
* PAE() is the
58
69
[ PASETO Pre-Authentication Encoding] ( https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Common.md#authentication-padding ) ,
59
70
where parameters ` type ` and ` body ` are byte sequences:
63
74
le64(n) := 64-bit little-endian encoding of `n`, where 0 <= n < 2^63
64
75
```
65
76
66
- * Sign() is an arbitrary digital signature format. Details must be agreed upon
77
+ * Sign() is an arbitrary digital signature format. Details are agreed upon
67
78
out-of-band by the signer and verifier. This specification places no
68
79
restriction on the signature algorithm or format.
69
80
@@ -81,6 +92,7 @@ To sign:
81
92
- Serialize BODY according to PAYLOAD_TYPE. Call the result SERIALIZED_BODY.
82
93
- Sign PAE([UTF8(PAYLOAD_TYPE), SERIALIZED_BODY]), base64-encode the result,
83
94
and store it in `sig`.
95
+ - Optionally, compute a KEYID and store it in `keyid`.
84
96
- Base64-encode SERIALIZED_BODY and store it in `payload`.
85
97
- Store PAYLOAD_TYPE in `payloadType`.
86
98
@@ -94,33 +106,34 @@ To verify:
94
106
fails.
95
107
96
108
Either standard or URL-safe base64 encodings are allowed. Signers may use
97
- either, and verifiers must accept either.
109
+ either, and verifiers **MUST** accept either.
98
110
99
111
### Backwards compatible signatures
100
112
101
113
To convert existing signatures from the current format to the new format,
102
- `"backwards-compatible-json"` must be added to the payload type URI to indicate
103
- that the signature is over the raw payload. This allows the signatures to remain
114
+ `"backwards-compatible-json"` is added to the payload type URI to indicate that
115
+ the signature is over the raw payload. This allows the signatures to remain
104
116
valid while avoiding the verifier from having to use [Canonical JSON].
105
117
106
118
```json
107
119
{
108
120
"payload": "<Base64(CanonicalJson(BODY))>",
109
121
"payloadType": "<URI>/backwards-compatible-json",
110
122
"signatures" : [{
111
- … ,
112
- "sig" : "<Base64(Sign(CanonicalJson(BODY)))>"
113
- }, … ]
123
+ "keyid": "<KEYID>" ,
124
+ "sig": "<Base64(Sign(CanonicalJson(BODY)))>"
125
+ }]
114
126
}
115
127
```
116
128
117
129
Support for this backwards compatibility mode is optional.
118
130
119
131
To sign:
120
132
121
- - BODY ** must ** be an object type (` {...} ` ).
133
+ - BODY ** MUST ** be an object type (` {...} ` ).
122
134
- Serialize BODY as [ Canonical JSON] ; call this SERIALIZED_BODY.
123
135
- Sign SERIALIZED_BODY, base64-encode the result, and store it in ` sig ` .
136
+ - Optionally, compute a KEYID and store it in ` keyid ` .
124
137
- Base64-encode SERIALIZED_BODY and store it in ` payload ` .
125
138
- Store ` "<URI>/backwards-compatible-json" ` in ` payloadType ` .
126
139
@@ -134,16 +147,35 @@ To verify:
134
147
decoding or the signature verification fails.
135
148
- Parse SERIALIZED_BODY as a JSON object. Reject if the parsing fails or if
136
149
the result is not a JSON object. In particular, the first byte of
137
- SERIALIZED_BODY must be ` { ` . Verifiers ** must not ** require SERIALIZED_BODY
150
+ SERIALIZED_BODY ** MUST ** be ` { ` . Verifiers ** MUST NOT ** require SERIALIZED_BODY
138
151
to be Canonical JSON.
139
152
140
153
Backwards compatible signatures are not recommended because they lack the
141
154
authenticated payloadType indicator.
142
155
143
156
This scheme is safe from rollback attacks because the first byte of
144
- SERIALIZED_BODY must be 0x7b (` { ` ) in backwards compatibility mode and 0x02 in
157
+ SERIALIZED_BODY is 0x7b (` { ` ) in backwards compatibility mode and 0x02 in
145
158
regular mode.
146
159
160
+ ### Multiple signatures
161
+
162
+ A file may have more than one signature, which is equivalent to separate files
163
+ with individual signatures.
164
+
165
+ ``` json
166
+ {
167
+ "payload" : " <Base64(SERIALIZED_BODY)>" ,
168
+ "payloadType" : " <PAYLOAD_TYPE>" ,
169
+ "signatures" : [{
170
+ "keyid" : " <KEYID_1>" ,
171
+ "sig" : " <SIG_1>"
172
+ }, {
173
+ "keyid" : " <KEYID_2>" ,
174
+ "sig" : " <SIG_2>"
175
+ }]
176
+ }
177
+ ```
178
+
147
179
### Optional changes to wrapper
148
180
149
181
The standard wrapper is JSON with an explicit ` payloadType ` . Optionally,
@@ -278,9 +310,9 @@ used by TUF and in-toto has a BODY that is a regular JSON object and a signature
278
310
{
279
311
"signed" : <BODY>,
280
312
"signatures" : [{
281
- … ,
313
+ "keyid" : " <KEYID> " ,
282
314
"sig" : " <Hex(Sign(CanonicalJson(BODY)))>"
283
- }, … ]
315
+ }]
284
316
}
285
317
```
286
318
@@ -299,11 +331,13 @@ To convert an existing signature to the new format:
299
331
- ` new.payload = base64encode(CanonicalJson(orig.signed)) `
300
332
- ` new.payloadType = "<URI>/backwards-compatible-json" `
301
333
- ` new.signatures[*].sig = base64encode(hexdecode(orig.signatures[*].sig)) `
334
+ - ` new.signatures[*].keyid = orig.signatures[*].keyid `
302
335
303
336
To convert a backwards compatible signature to the old format:
304
337
305
338
- ` old.signed = jsonparse(base64decode(new.payload)) `
306
339
- ` old.signatures[*].sig = hexencode(base64decode(new.signatures[*].sig)) `
340
+ - ` old.signatures[*].keyid = new.signatures[*].keyid `
307
341
308
342
## Testing
309
343
0 commit comments