mirror of
https://github.com/vacp2p/specs.git
synced 2026-01-07 22:44:07 -05:00
Reword
This commit is contained in:
@@ -6,9 +6,7 @@
|
||||
|
||||
Authors: [@MarcoPolo]
|
||||
|
||||
[@MarcoPolo]: https://github.com/MarcoPolo
|
||||
|
||||
Interest Group: Same as [HTTP](README.md)
|
||||
Interest Group: [@sukunrt], [@achingbrain]
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -22,33 +20,34 @@ scheme is called `libp2p-PeerID`.
|
||||
|
||||
| Param Name | Description |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| origin | The server name used in the TLS connection (SNI) |
|
||||
| origin | The server name used in the TLS connection (SNI). |
|
||||
| challenge-server | The random base64 encoded value the client generates to challenge the server to prove its identity |
|
||||
| challenge-client | The random base64 encoded value the server generates to challenge the client to prove its identity |
|
||||
| sig | the signature over some set of fields |
|
||||
| client-peer-id | A client's peer id |
|
||||
| server-peer-id | A server's peer id |
|
||||
| public-key | A peer's public key |
|
||||
| sig | A base64 encoded signature. |
|
||||
| peer-id | The peer id of the node that set this parameter. Encoding defined by the [Peer ID spec]. |
|
||||
| public-key | A base64 encoded value of peer's public key. The key itself is encoded per the [Peer ID spec]. |
|
||||
| opaque | An base64 encoded opaque to the client blob generated by the server. If a client receives this it must return it. A server may use this to authenticate statelessly. For example, it could store the challenge-client and a expiry time. |
|
||||
|
||||
Params are encoded per [RFC 9110 auth-param's ABNF](https://datatracker.ietf.org/doc/html/rfc9110#name-collected-abnf). Generally it'll be something like: `origin=example.com, challenge-server=base64EncodedVal`
|
||||
Params are encoded per [RFC 9110 auth-param's ABNF](https://datatracker.ietf.org/doc/html/rfc9110#name-collected-abnf). Generally it'll be something like: `origin="example.com", challenge-server=base64EncodedVal`
|
||||
|
||||
## Signing
|
||||
|
||||
Signatures sign some set of parameters. The parameters are sorted
|
||||
alphabetically, prepended with a varint length prefix, and concatenated together
|
||||
to form the data to be signed. The signing algorithm is defined by the key type
|
||||
used. Refer to the [PeerID
|
||||
spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md) for
|
||||
used. Refer to the [Peer ID
|
||||
spec] for
|
||||
specifics on the signing algorithm. The set of parameters is prefixed with the auth scheme "libp2p-PeerID"
|
||||
|
||||
As an example, if we wanted to sign the parameters `origin=example.com,
|
||||
challenger-server=base64String` we would first structure the parameters as:
|
||||
As an example, if we wanted to sign the parameters `origin="example.com",
|
||||
challenge-client=base64String` we would first structure the parameters as a byte
|
||||
slice containing:
|
||||
```
|
||||
libp2p-PeerID<varintprefix>challenge-server=<base64String><varintprefix>origin=example.com
|
||||
libp2p-PeerID<varintprefix>challenge-client=<base64String><varintprefix>origin="example.com"
|
||||
```
|
||||
|
||||
See the test vectors below for more examples. (todo)
|
||||
Then sign the resulting byte slice. See the test vectors below for a
|
||||
examples.
|
||||
|
||||
|
||||
## Base64 Encoding
|
||||
@@ -58,132 +57,72 @@ from [RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5). The
|
||||
reason this is not a multibase is to aid clients or servers who can not or
|
||||
prefer not to import a multibase dependency.
|
||||
|
||||
## Mutual Client and Server Peer ID Authentication Overview
|
||||
## Mutual Client and Server Peer ID
|
||||
|
||||
1. The client makes a request to the autentication URI.
|
||||
2. The server responds with the header `WWW-Authenticate: libp2p-PeerID
|
||||
challenge-client=<base64-encoded-challenge>, opaque=...`. The challenge MUST
|
||||
be indistinguishable from random data.
|
||||
3. The client sends a request to the same URI and sets the `Authorization`
|
||||
[header](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.6.2) header
|
||||
to the following:
|
||||
The following protocol allows both the client and server to authenticate each
|
||||
other's peer id by having them each sign a challenge issued by the other. The
|
||||
protocol operates as follows:
|
||||
|
||||
1. The client makes a POST request to the authentication URI.
|
||||
2. The server responds with status code 401 (Unauthorized) and set the header:
|
||||
```
|
||||
libp2p-PeerID peer-id="<encoded-peer-id-bytes>", opaque=... challenge-server="<base64-encoded-challenge-server>", sig="<base64-signature-bytes>"
|
||||
WWW-Authenticate: libp2p-PeerID challenge-client=<base64-encoded-challenge>, opaque=<base64-encoded-opaque-value>
|
||||
```
|
||||
The signature is the client signing the parameters `challenge-client` and `origin`.
|
||||
4. The server authenticates the signature, and responds by setting the `Authentication-Info` response header to the
|
||||
following:
|
||||
```
|
||||
libp2p-PeerID peer-id="<encoded-peer-id-bytes>",sig="<base64-signature-bytes>"
|
||||
```
|
||||
The signature is the server signing the parameters `challenge-server`,
|
||||
`origin`, and `client` (`client` is the client's string encoded peer id)
|
||||
5. The client authenticates the signature. At this point both the client and
|
||||
server have authenticated each other.
|
||||
|
||||
|
||||
## Mutual Client and Server Peer ID Authentication Detailed
|
||||
|
||||
(todo reword this)
|
||||
|
||||
<!-- 1. The server initiates the authentication by responding to a request that must
|
||||
be authenticated with the response header `WWW-Authenticate: libp2p-PeerID
|
||||
challenge-client="<base64-encoded-challenge>`. The challenge MUST be
|
||||
indistinguishable from random data. The Server MAY randomly generate this
|
||||
data, or MAY use an server-encrypted value. If using random data the
|
||||
server SHOULD store the challenge temporarily until the authentication is
|
||||
done. The challenge SHOULD be at least 32 bytes.
|
||||
|
||||
2. The client sends a request and sets the `Authorization`
|
||||
[header](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.6.2) header
|
||||
to the following:
|
||||
The opaque parameter is opaque to client. The client MUST return the opaque
|
||||
parameter back to the server. The server MAY use the opaque parameter to
|
||||
encode state.
|
||||
3. The client makes another POST request to the authentication URI and sets the header:
|
||||
```
|
||||
libp2p-PeerID peer-id="<encoded-peer-id-bytes>",[challenge-server="<base64-encoded-challenge-server>",]sig="<base64-signature-bytes>"]
|
||||
Authorization: libp2p-PeerID peer-id=<string-representation-of-client-peer-id>, opaque=<opaque-from-server>, challenge-server=<base64-encoded-challenge-server>, sig=<base64-signature-bytes>
|
||||
```
|
||||
|
||||
* The `challenge-server` parameter is optional. The client should set it if
|
||||
the client wants to authenticate the server.
|
||||
* The peer-id is encoded per the string encoding described in the [peer-ids spec](../peer-ids/peer-ids.md).
|
||||
* The signature is over the concatenated result of:
|
||||
```
|
||||
<varint-length> + "origin=" + server-name +
|
||||
[<varint-length> + "challenge-server=" + base64-encoded-client-chosen-challenge-server + ]
|
||||
<varint-length> + "challenge-client=" + base64-encoded-challenge
|
||||
```
|
||||
* Strings are UTF-8 encoded.
|
||||
* If the challenge server was omitted in the `Authorization` header it MUST
|
||||
be omitted in the signature.
|
||||
* If provided, the client-chosen `challenge-server` MUST be randomly generated.
|
||||
* The client-chosen `challenge-server` SHOULD be at least 32 bytes.
|
||||
* The client MUST use the same server-name as what is used for the TLS
|
||||
session.
|
||||
* If the client _only_ wants to authenticate the server and the server does
|
||||
not need to authenticate the client, the client can omit the
|
||||
`challenge-client` from the parameters and signature on its initial request
|
||||
(since it did not receive a `challenge-client`). If a resource requires
|
||||
client authentication, the server MUST return `401 Unauthorized` if a
|
||||
client attempts to authenticate without a `challenge-client`.
|
||||
* Example on building the message to sign:
|
||||
```
|
||||
origin=example.com
|
||||
client-challenge=qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=
|
||||
challenge=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
```
|
||||
|
||||
Message To Sign in hex with comments
|
||||
```
|
||||
12 // (18 bytes)
|
||||
6f726967696e3d6578616d706c652e636f6d // (origin=example.com)
|
||||
|
||||
3d // (61 bytes)
|
||||
636c69656e742d6368616c6c656e67653d7171717171717171717171717171717171717171717171717171717171717171717171717171717171716f3d // (client-challenge=qq...o=)
|
||||
|
||||
36 // (54 bytes)
|
||||
6368616c6c656e67653d414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d // (challenge=AA...A=)
|
||||
```
|
||||
|
||||
All together:
|
||||
```
|
||||
Message To Sign in hex:
|
||||
126f726967696e3d6578616d706c652e636f6d3d636c69656e742d6368616c6c656e67653d7171717171717171717171717171717171717171717171717171717171717171717171717171717171716f3d366368616c6c656e67653d414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d
|
||||
```
|
||||
2. The server MUST verify the signature using the server name used in the TLS
|
||||
The `sig` param represents a signature over the parameters:
|
||||
- `origin`
|
||||
- `challenge-client` in its base64 encoded form.
|
||||
4. The server MUST verify the signature using the server name used in the TLS
|
||||
session. The server MUST return 401 Unauthorized if the server fails to
|
||||
validate the signature.
|
||||
3. If the signature is valid, the server has authenticated the client's peer id
|
||||
and MAY fulfill the request according to application logic. If the request is
|
||||
fulfilled, the server sets the `Authentication-Info` response header to the
|
||||
following:
|
||||
```
|
||||
libp2p-PeerID peer-id="<encoded-peer-id-bytes>",sig="<base64-signature-bytes>"
|
||||
```
|
||||
* The signature is over the concatenated result of:
|
||||
```
|
||||
<varint-length> + "origin=" + server-name +
|
||||
[<varint-length> + "challenge-server=" + base64-encoded-client-chosen-challenge-server + ]
|
||||
<varint-length> + "client=" + <encoded-client-peer-id-bytes>
|
||||
```
|
||||
* Strings are UTF-8 encoded.
|
||||
* Optionally, the server MAY include a libp2p-Bearer
|
||||
token in the
|
||||
`Authentication-Info` response header. This allows clients to avoid a
|
||||
future iteration of this authentication protocol. If clients see a bearer
|
||||
token, they SHOULD store it for future use. For example, an
|
||||
`Authentication-Info` header with a bearer token would look like:
|
||||
```
|
||||
libp2p-PeerID peer-id="<encoded-peer-id-bytes>",sig="<base64-signature-bytes>",bearer-token="<token>".
|
||||
```
|
||||
4. The client can then authenticate the server with the the signature from
|
||||
`Authentication-info`. -->
|
||||
validate the signature. If the signature is valid, the server has
|
||||
authenticated the client's peer id. The server MUST respond with status code
|
||||
200 (OK) and set the headers:
|
||||
```
|
||||
Authentication-Info: libp2p-PeerID peer-id=<server-peer-id-string>, sig=<base64-signature-bytes>
|
||||
Authorization: libp2p-Bearer <base64-encoded-opaque-blob>
|
||||
```
|
||||
The `sig` param represents a signature over the parameters:
|
||||
- `origin`
|
||||
- `challenge-server` in its base64 encoded form.
|
||||
- `client` the string representation of the client's Peer ID.
|
||||
|
||||
## Authentication Endpoint
|
||||
The `libp2p-Bearer` token allows the client to make peer id authenticated
|
||||
requests. The value is opaque to the client, and the server may use it to
|
||||
store authentication state such as:
|
||||
- The client's Peer ID.
|
||||
- The `origin` parameter.
|
||||
- The token creation date (to allow tokens to expire).
|
||||
5. The client MUST verify the signature. After verification the client has
|
||||
authenticated the server's peer id. The client MUST send the `libp2p-Bearer`
|
||||
token for Peer ID authenticated requests.
|
||||
|
||||
## libp2p Bearer token
|
||||
|
||||
The libp2p Bearer token is a token given to the client from the server that
|
||||
allows the client (the bearer) to make Peer ID authenticated requests to the
|
||||
server. Once the client receives this token after the Mutual Authentication
|
||||
protocol, the client should save it and use it for future authenticated
|
||||
requests.
|
||||
|
||||
The server SHOULD return a 401 Unauthorized and follow the above Mutual
|
||||
authentication protocol when it wants the client to request a new libp2p Bearer
|
||||
token.
|
||||
|
||||
## Authentication URI Endpoint
|
||||
|
||||
Because the client needs to make a request to authenticate the server, and the
|
||||
client may not want to make the real request before authenticating the server,
|
||||
the server MAY provide an authentication endpoint. This authentication endpoint
|
||||
is like any other application protocol, and it shows up in `.well-known/libp2p`,
|
||||
is like any other application protocol, and it shows up in `.well-known/libp2p/protocols`,
|
||||
but it only does the authentication flow. The client and server SHOULD NOT send
|
||||
any data besides what is defined in the above authentication flows. The protocol
|
||||
any data besides what is defined in the above authentication flow. The protocol
|
||||
id for the authentication endpoint is `/http-peer-id-auth/1.0.0`.
|
||||
|
||||
|
||||
@@ -201,5 +140,61 @@ then this authentication scheme can not protect the client from a mitm attack.
|
||||
|
||||
## Test Vectors
|
||||
|
||||
### Definitions used
|
||||
|
||||
- zero key: An ED25519 key initialized with zero bytes.
|
||||
- zero peer id: A peer ID derived from the zero key.
|
||||
- client key: An ED25519 key with the following marshalled key (refer to the [Peer ID spec] for how to unmarshal): `080112407e0830617c4a7de83925dfb2694556b12936c477a0e1feb2e148ec9da60fee7d1ed1e8fae2c4a144b8be8fd4b47bf3d3b34b871c3cacf6010f0e42d474fce27e`
|
||||
- client peer ID: A peer id derived from the client key.
|
||||
|
||||
### Walkthrough
|
||||
|
||||
Included is a concrete example of running the protocol. The client uses the Peer ID defined above, and the server uses the zero key.
|
||||
|
||||
|
||||
|
||||
1. The clients sends the initial request.
|
||||
2. The server responds with the header:
|
||||
```
|
||||
WWW-Authenticate: libp2p-PeerID challenge-client=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=, opaque=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
```
|
||||
3. The client sends another request with the header:
|
||||
```
|
||||
Authorization: libp2p-PeerID peer-id=12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq, opaque=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=, challenge-server=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=, sig=MKoR8Shzr6VmQ675dErKh_gGGUsGaO8zXnZ8Cx8bIKiQlYBhqazUG8w4lG3_Wd5IfSz5P1HLfXtVb_fg_dsxDw==
|
||||
```
|
||||
4. The server responds with the header:
|
||||
```
|
||||
Authentication-Info: libp2p-PeerID peer-id=12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN, sig=m0OkSsO9YGcqfZ_XVTbiRwTtM4ds8434D9aod22Mmo3Wm0vBvxHOd71glC-uEez6g5gjA580KkGc9DOIvP47BQ==
|
||||
Authorization: libp2p-Bearer <base64-encoded-bearer-token>
|
||||
```
|
||||
|
||||
|
||||
The following table lists out all parameters and intermediate values used in the walkthrough above.
|
||||
|
||||
| Parameter | value |
|
||||
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| origin | example.com |
|
||||
| challenge-client | `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=` |
|
||||
| challenge-server | `BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=` |
|
||||
| client peer id | `12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq` |
|
||||
| server's peer id | The zero key `12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN` |
|
||||
| The server's opaque blob | Could be anything. In this example we'll use `CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=`. |
|
||||
| What the client will sign (percent encoded) | `libp2p-PeerID=challenge-client=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=%12origin=%22example.com%22` |
|
||||
| The client's signature | `MKoR8Shzr6VmQ675dErKh_gGGUsGaO8zXnZ8Cx8bIKiQlYBhqazUG8w4lG3_Wd5IfSz5P1HLfXtVb_fg_dsxDw==` |
|
||||
| The client's Authorization header | `Authorization: libp2p-PeerID peer-id=12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq, opaque=CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=, challenge-server=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=, sig=MKoR8Shzr6VmQ675dErKh_gGGUsGaO8zXnZ8Cx8bIKiQlYBhqazUG8w4lG3_Wd5IfSz5P1HLfXtVb_fg_dsxDw==` |
|
||||
| What the server will sign (percent encoded) | `libp2p-PeerID=challenge-server=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=%3Bclient=12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq%14origin=%22example.com%22` |
|
||||
| The server's signature | `m0OkSsO9YGcqfZ_XVTbiRwTtM4ds8434D9aod22Mmo3Wm0vBvxHOd71glC-uEez6g5gjA580KkGc9DOIvP47BQ==` |
|
||||
| The server's Authentication-Info header | `Authentication-Info: libp2p-PeerID peer-id=12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN, sig=m0OkSsO9YGcqfZ_XVTbiRwTtM4ds8434D9aod22Mmo3Wm0vBvxHOd71glC-uEez6g5gjA580KkGc9DOIvP47BQ==` |
|
||||
|
||||
|
||||
TODOS:
|
||||
- [ ]: Rename origin to hostname
|
||||
|
||||
TODO (marco): include a couple examples of what is signed, exchanged, and
|
||||
resulting signature.
|
||||
|
||||
[Peer ID spec]: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md
|
||||
|
||||
[@MarcoPolo]: https://github.com/MarcoPolo
|
||||
[@sukunrt]: https://github.com/sukunrt
|
||||
[@achingbrain]: https://github.com/achingbrain
|
||||
|
||||
Reference in New Issue
Block a user