Difference between revisions of "HTTP asset certification"

From Internet Computer Wiki
Jump to: navigation, search
(Removed content and replaced it with links where the information resides today.)
Tags: Replaced Visual edit
(54 intermediate revisions by 3 users not shown)
Line 1: Line 1:
== Motivation ==
+
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].
Users can send two types of messages to the Internet Computer: Query Calls and Update Calls.
 
 
 
HTTP asset certification is a protocol that allows canisters to certify bodies of responses to GET HTTP requests.
 
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]) is a dictionary with members <code>certificate</code> and <code>tree</code>, both of which are Byte Sequences:
 
 
 
<pre>
 
IC-Certificate: certificate=:<base64(c)>:, tree=:<base64(t)>:
 
</pre>
 
 
 
where
 
 
 
* <code>c</code> is the 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://github.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]
 

Revision as of 17:59, 23 June 2025

This content has moved to the learn hub (Asset Certification and HTTP Gateway Protocol) and the HTTP Gateway Protocol Specification.