mirror of
https://github.com/vacp2p/specs.git
synced 2026-01-08 23:08:09 -05:00
5.3 KiB
5.3 KiB
libp2p AutoTLS
| Lifecycle Stage | Maturity | Status | Latest Revision |
|---|---|---|---|
| ?? | ?????????????? | Active | r0, 2025-04-30 |
Authors: @gmelodie
See the lifecycle document for context about the maturity level and spec status.
Table of Contents
Introduction
TODO
General Flow
- Start libp2p client with public IPv4 (or IPv6) and support for
identifyprotocol (standard fornim-libp2p) - Get
PeerIDas a base36 of the CID of the multihash with thelibp2p-key(0x72) multicodec:- Transform PeerID into a multihash
mh - Transform
mhinto av1CID with the0x72multicodec (libp2p-key) - Base36 encode the
cid.data.buffer(not regular base36! this one needs multibase base36, which is the same as regular base36 but doesn't trims leading zeroes and starts with akorK) to getb36peerid
- Transform PeerID into a multihash
- Generate an RSA key
mykey - Register an account on the ACME server (production server for Let's Encrypt or just the staging server for testing)
- Send a GET request to the
directoryendpoint, and extract thenewAccountvalue from the JSON response, which will be the registration URL we'll use - Signed POST request to registration URL with the following
payload:{"termsOfServiceAgreed": true}. The actual POST body is signed using JWT with anmykeyandnonce(gotten fromdirectory["newNonce"]), so the final body of any ACME request should look like:Obs: the response to the account registration contains a{ "payload": token.claims.toBase64, "protected": token.header.toBase64, "signature": base64UrlEncode(token.signature), }kidin thelocationfield that should be saved and used in following requests to ACME server
- Send a GET request to the
- Request a certificate for the
*.{b36peerid}.libp2p.directdomain from the ACME server by issuing a POST request using the same JWT signature scheme (and another newnoncefromdirectory["newNonce"]) but withkidinstead ofjwkfield and the following payload:{ "type": "dns", "value": "*.{b36peerid}.libp2p.direct" } - From the ACME server response, get the entry with
"type"of"dns-01"and derive theKey Authorizationfor it:sha256.digest((dns01Challenge["token"] + "." + thumbprint(key))- JWK thumbprint:
base64encode(sha256.digest({"e": key.e, "kty": "RSA", "n": key.n})), but you can use other key types too
- JWK thumbprint:
- Send challenge to AutoTLS broker/server https://registration.libp2p.direct/, which requires a PeerID Auth scheme:
- Send GET request to the
v1/_acme-challengeendpoint and getwww-authenticatefield from the response header, and extract the values of three strings that it contains:challenge-client,public-keyandopaque - Generate random string with around 42 characters as a
challengeServerof our own - Get
peer-pubkeyandpeer-privkeykeys of our libp2ppeer, which are not necessarily the same keys we're using to talk to ACME server sig =(obs:varintis a protobuf varint field that encodes the length of thekey=valuestring)
sig = base64URL( peer-privkey.sign( bytes(varint + "challenge-client={challenge-client}") + bytes(varint + "hostname={hostname}") + bytes(varint + "server-public-key={publicKey}") ) )headers ={ "Content-Type": "application/json", "User-Agent": "nim-libp2p", "authorization": "libp2p-PeerID public-key=\"{clientPublicKeyB64}\", opaque=\"{opaque}\", challenge-server=\"{challengeServer}\", sig=\"{sig}\"" }- Send POST to
v1/_acme-challengeendpoint usingpayloadas body andheaders - Get the
bearertoken from theauthentication-infoheader of the response, which should be used for following requests from this client.
- Send GET request to the
- Check that the AutoTLS server has added the
_acme-challenge.{b36peerid}.libp2p.directTXTand thedashed-public-ip-address.{b36peerid}.libp2p.directADNS resource records. - Notify ACME server of challenge completion so it can lookup the DNS resource records.
- Get URL from
dns01challenge["url"] - Send an empty signed JSON payload (
{}) to the ACME server using thekidobtained from the ACME registration step and get the response from the server (completedResponse). - From
completedResponse, theurlfield from the JSON body byGETting it, again withkidsigning.
- Get URL from
- Wait for ACME server to finish testing the domain.
- The response from the polling will contain a
statusfield that will bependingwhile ACME is still testing the challenge, andvalidorinvalidwhen it's done.
- The response from the polling will contain a
- Download certificate from ACME server.