Address PR comments

This commit is contained in:
Marco Munizaga
2024-08-21 12:41:50 -07:00
parent f97e5966f6
commit a1091a4371

View File

@@ -18,21 +18,21 @@ scheme is called `libp2p-PeerID`.
## Parameters
| Param Name | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hostname | 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 | 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. |
| Param Name | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hostname | The server name used in the TLS connection (SNI). |
| challenge-server | The random quoted string value the client generates to challenge the server to prove its identity |
| challenge-client | The random quoted string value the server generates to challenge the client to prove its identity |
| 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 value 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: `hostname="example.com", challenge-server=base64EncodedVal`
Params are encoded per [RFC 9110 auth-param's ABNF](https://datatracker.ietf.org/doc/html/rfc9110#name-cmaollected-abnf). Generally it'll be something like: `hostname="example.com", challenge-server="challenge-string"`
## Signing
Signatures sign some set of parameters. The parameters are sorted
Signatures sign some set of parameters prefixed by the string `libp2p-PeerID`. 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 [Peer ID
@@ -40,10 +40,10 @@ 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 `hostname="example.com",
challenge-client=base64String` we would first structure the parameters as a byte
challenge-client="<challenge-string>"` we would first structure the parameters as a byte
slice containing:
```
libp2p-PeerID<varintprefix>challenge-client=<base64String><varintprefix>hostname="example.com"
libp2p-PeerID<varintprefix>challenge-client="<challenge-string>"<varintprefix>hostname="example.com"
```
Then sign the resulting byte slice. See the test vectors below for a
@@ -52,55 +52,56 @@ examples.
## Base64 Encoding
The base64 encoding follows Base 64 Encoding with URL and Filename Safe Alphabet
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.
The base64 encoding follows Base 64 Encoding with URL and Filename Safe
Alphabet from [RFC
4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5). Padding MAY be
omitted. 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
## Mutual Client and Server Peer ID Authentication
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
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.
1. The client makes an HTTP request to an authenticated resource.
2. The server responds with status code 401 (Unauthorized) and set the header:
```
WWW-Authenticate: libp2p-PeerID challenge-client=<base64-encoded-challenge>, opaque=<base64-encoded-opaque-value>
WWW-Authenticate: libp2p-PeerID challenge-client="<challenge-string>", opaque="<base64-encoded-opaque-value>"
```
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:
3. The client makes another HTTP request to the same authenticated resource and sets the header:
```
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>
Authorization: libp2p-PeerID peer-id="<string-representation-of-client-peer-id>", opaque="<opaque-from-server>", challenge-server="<challenge-string>"[,encoded-public-key="<base64-encoded-public-key-bytes>" ], sig="<base64-signature-bytes>"
```
The `encoded-public-key` param is optional and represents the client's public key. This is only needed when the client's public key is not included in the PeerID (e.g. not using the "identity" multihash).
The `sig` param represents a signature over the parameters:
- `hostname`
- `challenge-client` in its base64 encoded form.
- `challenge-client`
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. 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:
authenticated the client's Peer ID. The server SHOULD proceed to serve the HTTP request. The server MUST set the following response headers:
```
Authentication-Info: libp2p-PeerID peer-id=<server-peer-id-string>, sig=<base64-signature-bytes>
Authorization: libp2p-Bearer <base64-encoded-opaque-blob>
Authentication-Info: libp2p-PeerID peer-id="<server-peer-id-string>", sig="<base64-signature-bytes>", libp2p-Bearer <base64-encoded-opaque-blob>
```
The `sig` param represents a signature over the parameters:
- `hostname`
- `challenge-server` in its base64 encoded form.
- `client` the string representation of the client's Peer ID.
- `challenge-server`
- `client-pubkey` the bytes of the client's public key
The `libp2p-Bearer` token allows the client to make peer id authenticated
The `libp2p-Bearer` token allows the client to make future 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 `hostname` 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`
authenticated the server's Peer ID. The client MUST send the `libp2p-Bearer`
token for Peer ID authenticated requests.
## libp2p Bearer token
@@ -131,21 +132,23 @@ id for the authentication endpoint is `/http-peer-id-auth/1.0.0`.
* Implementations MUST only authenticate over a secured connection (i.e. TLS).
* Implementations SHOULD limit the maximum length of any variable length field.
## Note on web PKI
## Security Considerations
Protection against man-in-the-middle (mitm) type attacks is through web PKI. If
the client is in an environment where web PKI can not be fully trusted (e.g. an
Protection against man-in-the-middle (mitm) type attacks is through Web PKI. If
the client is in an environment where Web PKI can not be fully trusted (e.g. an
enterprise network with a custom enterprise root CA installed on the client),
then this authentication scheme can not protect the client from a mitm attack.
This authentication scheme is also not secure in cases where you do not own your domain name or the certificate. If someone else can get a valid certificate for your domain, you may be vulnerable to 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.
- 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.
- client Peer ID: A Peer ID derived from the client key.
### Walkthrough
@@ -156,35 +159,34 @@ Included is a concrete example of running the protocol. The client uses the Peer
1. The clients sends the initial request.
2. The server responds with the header:
```
WWW-Authenticate: libp2p-PeerID challenge-client=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=, opaque=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
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=F5OBYbbMXoIVJNWrW0UANi7rrbj4GCB6kcEceQjajLTMvC-_jpBF9MFlxiaNYXOEiPQqeo_S56YUSNinwl0ZCQ==
Authorization: libp2p-PeerID peer-id=12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq, opaque="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", challenge-server="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", sig="F5OBYbbMXoIVJNWrW0UANi7rrbj4GCB6kcEceQjajLTMvC-_jpBF9MFlxiaNYXOEiPQqeo_S56YUSNinwl0ZCQ=="
```
4. The server responds with the header:
```
Authentication-Info: libp2p-PeerID peer-id=12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN, sig=btLFqW200aDTQqpkKetJJje7V-iDknXygFqPsfiegNsboXeYDiQ6Rqcpezz1wfr8j9h83QkN9z78cAWzKzV_AQ==
Authorization: libp2p-Bearer <base64-encoded-bearer-token>
Authentication-Info: libp2p-PeerID peer-id="12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN", sig="btLFqW200aDTQqpkKetJJje7V-iDknXygFqPsfiegNsboXeYDiQ6Rqcpezz1wfr8j9h83QkN9z78cAWzKzV_AQ==", libp2p-Bearer <base64-encoded-bearer-token>
```
The following table lists out all parameters and intermediate values used in the walkthrough above.
| Parameter | value |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hostname | 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=%16hostname=%22example.com%22` |
| The client's signature | `F5OBYbbMXoIVJNWrW0UANi7rrbj4GCB6kcEceQjajLTMvC-_jpBF9MFlxiaNYXOEiPQqeo_S56YUSNinwl0ZCQ==` |
| The client's Authorization header | `Authorization: libp2p-PeerID peer-id=12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq, opaque=CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=, challenge-server=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=, sig=F5OBYbbMXoIVJNWrW0UANi7rrbj4GCB6kcEceQjajLTMvC-_jpBF9MFlxiaNYXOEiPQqeo_S56YUSNinwl0ZCQ==` |
| What the server will sign (percent encoded) | `libp2p-PeerID=challenge-server=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=%3Bclient=12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq%16hostname=%22example.com%22` |
| The server's signature | `btLFqW200aDTQqpkKetJJje7V-iDknXygFqPsfiegNsboXeYDiQ6Rqcpezz1wfr8j9h83QkN9z78cAWzKzV_AQ==` |
| The server's Authentication-Info header | `Authentication-Info: libp2p-PeerID peer-id=12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN, sig=btLFqW200aDTQqpkKetJJje7V-iDknXygFqPsfiegNsboXeYDiQ6Rqcpezz1wfr8j9h83QkN9z78cAWzKzV_AQ==` |
| Parameter | value |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hostname | 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) | `todo` |
| The client's signature | `todo` |
| The client's Authorization header | `Authorization: libp2p-PeerID peer-id="12D3KooWBtg3aaRMjxwedh83aGiUkwSxDwUZkzuJcfaqUmo7R3pq", opaque="CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=", challenge-server="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", sig="F5OBYbbMXoIVJNWrW0UANi7rrbj4GCB6kcEceQjajLTMvC-_jpBF9MFlxiaNYXOEiPQqeo_S56YUSNinwl0ZCQ=="` |
| What the server will sign (percent encoded) | `todo` |
| The server's signature | `todo` |
| The server's Authentication-Info header | `Authentication-Info: libp2p-PeerID peer-id="12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN", sig="btLFqW200aDTQqpkKetJJje7V-iDknXygFqPsfiegNsboXeYDiQ6Rqcpezz1wfr8j9h83QkN9z78cAWzKzV_AQ==", libp2p-Bearer <some-opaque-value>` |
[Peer ID spec]: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md