|
|
(59 intermediate revisions by 4 users not shown) |
Line 1: |
Line 1: |
− | HTTP asset certification is a protocol that allows canisters to certify bodies of responses to GET HTTP requests.
| + | This content has moved to the learn hub ([https://learn.internetcomputer.org/hc/en-us/articles/34276431179412-Asset-Certification Asset Certification] and [https://learn.internetcomputer.org/hc/en-us/articles/34211943471892-HTTP-Gateway-Protocol HTTP Gateway Protocol]) and the [https://internetcomputer.org/docs/references/http-gateway-protocol-spec HTTP Gateway Protocol Specification]. |
− | The receiver of such responses can use the IC public key to authenticate the body of the response.
| |
− | The protocol relies on [https://smartcontracts.org/docs/interface-spec/index.html#system-api-certified-data Certified data] feature of the IC.
| |
− | | |
− | == Canister protocol ==
| |
− | | |
− | A canister must follow the following protocol to certify assets:
| |
− | | |
− | <ul>
| |
− | <li>
| |
− | Construct a [https://smartcontracts.org/docs/interface-spec/index.html#_certificate hash tree] that maps paths of HTTP resources to SHA-256 hashes of their bodies.
| |
− | An example of such a tree:
| |
− | <pre>
| |
− | *root*
| |
− | └── http_assets
| |
− | ├── index.html -> SHA256(body)
| |
− | ├── ...
| |
− | └── /css/styles.css -> SHA256(body)
| |
− | </pre>
| |
− | </li>
| |
− | <li>
| |
− | Compute the root hash of the tree and call [https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports <code>ic0.certified_data_set</code>] with the bytes of the hash as the argument.
| |
− | </li>
| |
− | <li>
| |
− | Add a [[#IC-Certificate header]] to each certified HTTP response.
| |
− | </li>
| |
− | </ul>
| |
− | | |
− | == Validator protocol ==
| |
− | | |
− | The validator follows the following steps to validate the certificate of resource at path <code>PATH</code> served by canister <code>CANISTER_ID</code>:
| |
− | | |
− | * Hash the body of the HTTP response, obtaining hash <code>DATA_HASH</code>.
| |
− | * Check that the response contains the <code>IC-Certificate</code> header.
| |
− | * Decode the <code>certificate</code> and the <code>tree</code> from the value of the <code>IC-Certificate</code> header.
| |
− | * Check the validity of the certificate as described in the [https://smartcontracts.org/docs/interface-spec/index.html#certification Interface Specification: Certification]. This step requires knowing the IC root key.
| |
− | * Check that <code>lookup(/http_assets/PATH, tree) = Found(DATA_HASH)</code>
| |
− | * Check that <code>lookup(/canister/CANISTER_ID/certified_data, certificate.tree) = Found(reconstruct(tree))</code>.
| |
− | | |
− | == IC-Certificate header ==
| |
− | | |
− | The <code>IC-Certificate</code> header is a Structure Header (as per [https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-header-structure RFC proposal]) with is a dictionary with with members <code>certificate</code> and <code>tree</code>, both of which are Byte Sequences:
| |
− | | |
− | <pre>
| |
− | IC-Certficate: certificate=:<base64(c)>:, tree=:<base64(t)>:
| |
− | </pre>
| |
− | | |
− | where
| |
− | | |
− | * <code>c</code> is the a CBOR-encoded certificate (see [https://smartcontracts.org/docs/interface-spec/index.html#certification-encoding Interface Specification: Encoding of certificates]).
| |
− | * <code>t</code> is a Hash Tree, CBOR-encoded according the CDDL <code>#6.55799(hash-tree)</code> where <code>hash-tree</code> is the corresponding [https://smartcontracts.org/docs/interface-spec/index.html#api-cddl CDDL production in the Interface Specification].
| |
− | | |
− | The <code>certificate</code> must be a valid [https://smartcontracts.org/docs/interface-spec/index.html#_certificate Internet Specification: Certificate] with
| |
− | | |
− | <pre>
| |
− | lookup(/canister/<canister_id>/certified_data, certificate.tree)
| |
− | = Found (reconstruct(tree))
| |
− | </pre>
| |
− | | |
− | The <code>tree</code> exposes the relevant nodes in the <code>/http_assets</code> subtree to allow the client to lookup the request path to get the expected body hash.
| |
− | | |
− | === Example ===
| |
− | | |
− | For this example, we fetched <code>/index.html</code> resource of the Internet Identity canister (canister id <code>rdmx6-jaaaa-aaaaa-aaadq-cai</code>) available at https://rdmx6-jaaaa-aaaaa-aaadq-cai.raw.ic0.app/index.html.
| |
− | The SHA-256 hash of the resource at the moment of fetching is <code>478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d</code>.
| |
− | The response contained the following header:
| |
− | | |
− | <pre>
| |
− | IC-Certificate: certificate=:2dn3omR0cmVlgwGDAYMBgwJIY2FuaXN0ZXKDAYMBggRYIIudikoDwH1gRK637olblUhMUX3HlE0Dihj8MTACxGzHgwGCBFggyCRYc8M/ugt8G7C8RPYayn+l4sdBj8gvFotzJELnQ32DAYIEWCA1/+UHZ9SF67w4ssjOi+Jv3ch7WQNzezGmhtuvB+RDpYMCSgAAAAAAAAAHAQGDAYMBgwJOY2VydGlmaWVkX2RhdGGCA1ggWUt10wjWinx0aAWyrNEi/0R7VeuhalDMjGDErzIbZzqCBFgg/VtZRZdYyK/sr3KF2jWeS1rblF+4ajwfDv2ZbCGpaTiCBFggSoI5JS0pCusHP4nh6h780ebr961E0lVnFkFwzF5pZaeCBFggcKidPEGiPoFMPYfEyNGsDRYWmry1iGX0HNUEoKhIATeCBFggR0zdKUZOMcm5EHNl5Tee3XWqbq1gArwUGzZ2FH4rWtmCBFggTkwJcNrh0eJ9FutJcn6th9eCbM2KXnloxed0acxmQNeDAYIEWCA6SNH8IT1JMHEDEE99csK1kw7bqHh7kGMfNDs6popfCoMCRHRpbWWCA0nFnbXrts/65xZpc2lnbmF0dXJlWDCkXN2tcvH5b+xFCzfkuJMqrZDcplfW8vDziJwzx08WOPI4rh2TIGYZ3R6dgQTF0CA=:, tree=:2dn3gwGDAktodHRwX2Fzc2V0c4MBggRYIDgtAGcz5VvevwiEwwZB9zpkt17C9LE6o/O37bEwQUawgwGDAksvaW5kZXguaHRtbIIDWCBHivuCBsoLVmp/E45iOszRafqCJgLS9tcX+2fRBF9PDYIEWCCx2L8SfJwOydBkUxjc8tKXDVUeoiw8qEYI+8b+HRWIWYIEWCAqZ+3yoFSA9s+jbLFbtcVz+wi0HF9x51Kx38qPcBhiDA==:
| |
− | </pre>
| |
− | | |
− | We can extract the following data from the header value:
| |
− | | |
− | <pre>
| |
− | ROOT HASH: 0b2d843df534ac8ed2331fe2782deb71d23a08d9b4019a8fa695ec7fde93de36
| |
− | TREE HASH: 594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a
| |
− | SIGNATURE: a45cddad72f1f96fec450b37e4b8932aad90dca657d6f2f0f3889c33c74f1638f238ae1d93206619dd1e9d8104c5d020
| |
− | CERTIFICATE TIME: 2022-02-02T08:23:24.851277509+00:00
| |
− | CERTIFICATE TREE:
| |
− | HashTree {
| |
− | root: Fork(
| |
− | Fork(
| |
− | Fork(
| |
− | Label("canister", Fork(
| |
− | Fork(
| |
− | Pruned(8b9d8a4a03c07d6044aeb7ee895b95484c517dc7944d038a18fc313002c46cc7),
| |
− | Fork(
| |
− | Pruned(c8245873c33fba0b7c1bb0bc44f61aca7fa5e2c7418fc82f168b732442e7437d),
| |
− | Fork(
| |
− | Pruned(35ffe50767d485ebbc38b2c8ce8be26fddc87b5903737b31a686dbaf07e443a5),
| |
− | Label(0x00000000000000070101, Fork(
| |
− | Fork(
| |
− | Label("certified_data", Leaf(0x594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a)),
| |
− | Pruned(fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938),
| |
− | ),
| |
− | Pruned(4a8239252d290aeb073f89e1ea1efcd1e6ebf7ad44d25567164170cc5e6965a7),
| |
− | )),
| |
− | ),
| |
− | ),
| |
− | ),
| |
− | Pruned(70a89d3c41a23e814c3d87c4c8d1ac0d16169abcb58865f41cd504a0a8480137),
| |
− | )),
| |
− | Pruned(474cdd29464e31c9b9107365e5379edd75aa6ead6002bc141b3676147e2b5ad9),
| |
− | ),
| |
− | Pruned(4e4c0970dae1d1e27d16eb49727ead87d7826ccd8a5e7968c5e77469cc6640d7),
| |
− | ),
| |
− | Fork(
| |
− | Pruned(3a48d1fc213d49307103104f7d72c2b5930edba8787b90631f343b3aa68a5f0a),
| |
− | Label("time", Leaf(0xc59db5ebb6cffae716)),
| |
− | ),
| |
− | ),
| |
− | }
| |
− | TREE:
| |
− | HashTree {
| |
− | root: Fork(
| |
− | Label("http_assets", Fork(
| |
− | Pruned(382d006733e55bdebf0884c30641f73a64b75ec2f4b13aa3f3b7edb1304146b0),
| |
− | Fork(
| |
− | Label("/index.html", Leaf(0x478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d)),
| |
− | Pruned(b1d8bf127c9c0ec9d0645318dcf2d2970d551ea22c3ca84608fbc6fe1d158859),
| |
− | ),
| |
− | )),
| |
− | Pruned(2a67edf2a05480f6cfa36cb15bb5c573fb08b41c5f71e752b1dfca8f7018620c),
| |
− | ),
| |
− | }
| |
− | </pre>
| |
− | | |
− | == Limitations ==
| |
− | | |
− | * The protocol supports only one resource per path. This does not work well with content negotiation protocol.
| |
− | * The protocol does not support certification of HTTP statuses and headers. Only resource bodies can be certified.
| |
− | | |
− | == Canisters using HTTP asset certification ==
| |
− | | |
− | * [https://github.com/dfinity/internet-identity/blob/7ff3dd51dd98c7b1b43d83950c9f31ea7159103d/src/internet_identity/src/main.rs#L775 Internet Identity canister]
| |
− | * [https://github.com/dfinity/nns-dapp/blob/49126394df77b9583e508277fc736eda51de47be/rs/src/assets.rs#L123 NNS frontend]
| |
− | * [https://githug.com/dfinity/certified-assets Certified assets canister]
| |
− | | |
− | == Validators ==
| |
− | | |
− | * [https://github.com/dfinity/ic/tree/master/typescript/service-worker Certifying Service Worker]
| |
− | * [https://github.com/dfinity/icx-proxy/blob/b0de0437fe6806a96d942465e5ee284c23b812e8/src/main.rs#L470 ICX proxy]
| |