You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-cargo-asymmetric-tokens.md
+91-2Lines changed: 91 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -98,7 +98,7 @@ The claims within the PASETO will include at least:
98
98
- If this is a mutation: which one (publish or yank or unyank), the package, the version, the SHA256 checksum of the `.crate` file as stored in the `cksum` in the index. (`mutation`, `name`, `vers`, `cksum` keys respectively.)
99
99
100
100
The "footer" (which is part of the signature) will be a JSON string in UTF-8 and include:
101
-
- The URL where cargo got the config.json file (in the `aud` key).
101
+
- The URL where cargo got the config.json file (in the `url` key).
102
102
- If this is a registry with an HTTP index, then this is the base URL that all index queries are relative to.
103
103
- If this is a registry with a GIT index, it is the URL Cargo used to clone the index.
104
104
- The `key ID` (in the `kid` key). Which can be obtained from the public key using the [PASERK IDs](https://github.com/paseto-standard/paserk/blob/master/operations/ID.md) standard.
@@ -114,6 +114,8 @@ The registry server will validate the PASETO, and check the footer and claims:
114
114
- If the server issues challenges, that the challenge has not yet been answered.
115
115
- If the operation is a mutation, that the package, version, and hash match the request.
116
116
117
+
See the [Appendix: Token Examples](#token-examples) for a walk through of constructing some tokens.
118
+
117
119
## Credential Processes
118
120
119
121
Credential Processes as defined in [RFC 2730](https://github.com/rust-lang/rfcs/pull/2730) are outside programs cargo can call on to change where and how secrets are stored. That RFC defines `special strings` which go in the `credential-process` field to describe what data the process needs from cargo. This RFC adds `{claims}`. If used Cargo will replace it with a JSON encoded set of key value pairs that should be in the generated token. Cargo will check that the output of such a process looks like a valid PASETO v3.public token that Cargo would have generated, and that the PASETO token includes all the claims Cargo provided. The credential process may add additional claims (e.g. 2fa, TOTP), as long as they are nested in `custom`.
@@ -226,4 +228,91 @@ Storing plain text secret tokens is only a problem in practice not in theory. Ho
226
228
227
229
> Fundamentally these are all problems only because once an attacker has seen a secret token they have all that is needed to act on that user's behalf.
228
230
229
-
Without the private key an asymmetric token can only be used for the intended registry, for the intended action, and for a limited amount of time. This mitigates the risk of disclosure.
231
+
Without the private key an asymmetric token can only be used for the intended registry, for the intended action, and for a limited amount of time. This mitigates the risk of disclosure.
232
+
233
+
## Token Examples
234
+
235
+
### A Simple Read Operation
236
+
237
+
For example: If cargo needs to construct an asymmetric token for a simple read operation it will gather some basic information:
238
+
- The private key ([`PASERK` secret format](https://github.com/paseto-standard/paserk/blob/master/types/secret.md)): `"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36"`
239
+
- The current time: `"2022-02-28T18:33:24+00:00"`
240
+
- The url to the root of the index: `"https://registry.com/crate-index"`
241
+
242
+
It will then derive:
243
+
- The public key for the private key ([`PASERK` public format](https://github.com/paseto-standard/paserk/blob/master/types/public.md)): `"k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ"`
244
+
- The [`PASERK ID`](https://github.com/paseto-standard/paserk/blob/master/operations/ID.md) for the public key: `"k3.pid.QB3WNBP-5j-0XQV2MOuvuOcLlJ8uz-pmqtIZus1x3YTu"`
245
+
246
+
It will then construct a PASETO in the [v3.public format](https://github.com/paseto-standard/paseto-spec/blob/master/docs/01-Protocol-Versions/Version3.md). In this case:
- The `url` is for the index of the registry that the request is for.
258
+
- The `kid` is for a public key it has on file.
259
+
- The PASETO signature can be validated using the public key related to `kid`.
260
+
261
+
It can then decode the payload and get:
262
+
```
263
+
{"iat": "2022-02-28T18:33:24+00:00"}
264
+
```
265
+
It will check that the `iat` is within the valid time period picked by the server.
266
+
Given that there is no mutation claim, it will check that the request is a read.
267
+
(A read token can be used for multiple requests. See [Rationale and alternatives](#rationale-and-alternatives) for why.)
268
+
At this point the server has validated the PASETO, it should now go on to determining if the user associated with this public key should be allowed to read this object.
269
+
270
+
### A Complicated Publish Operation
271
+
272
+
For example: If cargo needs to construct an asymmetric token for a complicated publish operation it will gather some basic information:
273
+
- The private key ([`PASERK` secret format](https://github.com/paseto-standard/paserk/blob/master/types/secret.md)): `"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36"`
274
+
- The `private-key-subject` for that key: `"private-key-subject"`
275
+
- The current time: `"2022-02-28T18:33:24+00:00"`
276
+
- The url to the root of the index: `"https://registry-challenge-subject.com/crate-index"`
277
+
- The challenge received from the most recent 401/403: `"challenge"`
278
+
279
+
Because it's a published operation cargo will also gather:
280
+
- The crate name: `"foo"`
281
+
- The crate version: `"0.0.0"`
282
+
- The hash of the `.crate` file: `"f7dbb6acfeff1d490fba693a402456f76b344fea77a5e7cae43b5970c3332b8f"`
283
+
284
+
It will then derive:
285
+
- The public key for the private key ([`PASERK` public format](https://github.com/paseto-standard/paserk/blob/master/types/public.md)): `"k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ"`
286
+
- The [`PASERK ID`](https://github.com/paseto-standard/paserk/blob/master/operations/ID.md) for the public key: `"k3.pid.QB3WNBP-5j-0XQV2MOuvuOcLlJ8uz-pmqtIZus1x3YTu"`
287
+
288
+
It will then construct a PASETO in the [v3.public format](https://github.com/paseto-standard/paseto-spec/blob/master/docs/01-Protocol-Versions/Version3.md). In this case:
- The `iat` is within the valid time period picked by the server.
308
+
- The `sub` and `kid` is for a public key it has on file.
309
+
- The PASETO signature can be validated using that public key.
310
+
- The `challenge` was issued by this server and has not been revoked.
311
+
312
+
Given that there is a mutation claim it will check that:
313
+
- The request is for a `publish`.
314
+
- The request is to publish a crate with the same name as `name`.
315
+
- The request is to publish a crate with the same version as `vers`.
316
+
- The request is to publish a crate with the same hash as `cksum`.
317
+
318
+
At this point the server has validated the PASETO, it should now go on to determining if the user associated with this public key should be allowed to publish this object.
0 commit comments