Skip to content

Commit e6ae241

Browse files
authored
Merge pull request #11 from MarkLodato/multi-signature
Fully specify all fields within `signatures`
2 parents a4af882 + db5ffd1 commit e6ae241

File tree

1 file changed

+49
-15
lines changed

1 file changed

+49
-15
lines changed

specification.md

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ The signature format is a JSON message of the following form:
3232
"payload": "<Base64(SERIALIZED_BODY)>",
3333
"payloadType": "<PAYLOAD_TYPE>",
3434
"signatures": [{
35-
,
35+
"keyid": "<KEYID>",
3636
"sig": "<Base64(Sign(PAE([UTF8(PAYLOAD_TYPE), SERIALIZED_BODY])))>"
37-
}, ]
37+
}]
3838
}
3939
```
4040

41-
where:
41+
Empty fields may be omitted. [Multiple signatures](#multiple-signatures) are
42+
allowed.
43+
44+
Parameters:
4245

4346
* SERIALIZED_BODY is the byte sequence to be signed.
4447

@@ -54,6 +57,14 @@ where:
5457
- https://theupdateframework.com/Root/v1.0.5
5558
- etc...
5659

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+
5768
* PAE() is the
5869
[PASETO Pre-Authentication Encoding](https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Common.md#authentication-padding),
5970
where parameters `type` and `body` are byte sequences:
@@ -63,7 +74,7 @@ where:
6374
le64(n) := 64-bit little-endian encoding of `n`, where 0 <= n < 2^63
6475
```
6576
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
6778
out-of-band by the signer and verifier. This specification places no
6879
restriction on the signature algorithm or format.
6980
@@ -81,6 +92,7 @@ To sign:
8192
- Serialize BODY according to PAYLOAD_TYPE. Call the result SERIALIZED_BODY.
8293
- Sign PAE([UTF8(PAYLOAD_TYPE), SERIALIZED_BODY]), base64-encode the result,
8394
and store it in `sig`.
95+
- Optionally, compute a KEYID and store it in `keyid`.
8496
- Base64-encode SERIALIZED_BODY and store it in `payload`.
8597
- Store PAYLOAD_TYPE in `payloadType`.
8698
@@ -94,33 +106,34 @@ To verify:
94106
fails.
95107
96108
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.
98110
99111
### Backwards compatible signatures
100112
101113
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
104116
valid while avoiding the verifier from having to use [Canonical JSON].
105117
106118
```json
107119
{
108120
"payload": "<Base64(CanonicalJson(BODY))>",
109121
"payloadType": "<URI>/backwards-compatible-json",
110122
"signatures" : [{
111-
,
112-
"sig" : "<Base64(Sign(CanonicalJson(BODY)))>"
113-
}, …]
123+
"keyid": "<KEYID>",
124+
"sig": "<Base64(Sign(CanonicalJson(BODY)))>"
125+
}]
114126
}
115127
```
116128

117129
Support for this backwards compatibility mode is optional.
118130

119131
To sign:
120132

121-
- BODY **must** be an object type (`{...}`).
133+
- BODY **MUST** be an object type (`{...}`).
122134
- Serialize BODY as [Canonical JSON]; call this SERIALIZED_BODY.
123135
- Sign SERIALIZED_BODY, base64-encode the result, and store it in `sig`.
136+
- Optionally, compute a KEYID and store it in `keyid`.
124137
- Base64-encode SERIALIZED_BODY and store it in `payload`.
125138
- Store `"<URI>/backwards-compatible-json"` in `payloadType`.
126139

@@ -134,16 +147,35 @@ To verify:
134147
decoding or the signature verification fails.
135148
- Parse SERIALIZED_BODY as a JSON object. Reject if the parsing fails or if
136149
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
138151
to be Canonical JSON.
139152

140153
Backwards compatible signatures are not recommended because they lack the
141154
authenticated payloadType indicator.
142155

143156
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
145158
regular mode.
146159

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+
147179
### Optional changes to wrapper
148180

149181
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
278310
{
279311
"signed": <BODY>,
280312
"signatures": [{
281-
,
313+
"keyid": "<KEYID>",
282314
"sig": "<Hex(Sign(CanonicalJson(BODY)))>"
283-
}, ]
315+
}]
284316
}
285317
```
286318

@@ -299,11 +331,13 @@ To convert an existing signature to the new format:
299331
- `new.payload = base64encode(CanonicalJson(orig.signed))`
300332
- `new.payloadType = "<URI>/backwards-compatible-json"`
301333
- `new.signatures[*].sig = base64encode(hexdecode(orig.signatures[*].sig))`
334+
- `new.signatures[*].keyid = orig.signatures[*].keyid`
302335

303336
To convert a backwards compatible signature to the old format:
304337

305338
- `old.signed = jsonparse(base64decode(new.payload))`
306339
- `old.signatures[*].sig = hexencode(base64decode(new.signatures[*].sig))`
340+
- `old.signatures[*].keyid = new.signatures[*].keyid`
307341

308342
## Testing
309343

0 commit comments

Comments
 (0)