Difference between revisions of "HTTP asset certification"

From Internet Computer Wiki
Jump to: navigation, search
Line 135: Line 135:
 
* [https://github.com/dfinity/internet-identity/blob/7ff3dd51dd98c7b1b43d83950c9f31ea7159103d/src/internet_identity/src/main.rs#L775 Internet Identity canister]
 
* [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/nns-dapp/blob/49126394df77b9583e508277fc736eda51de47be/rs/src/assets.rs#L123 NNS frontend]
* [https://githug.com/dfinity/certified-assets Certified assets canister]
+
* [https://github.com/dfinity/certified-assets Certified assets canister]
  
 
== Validators ==
 
== Validators ==

Revision as of 11:06, 1 July 2022

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 Certified data feature of the IC.

Canister protocol

A canister must follow the following protocol to certify assets:

  • Construct a hash tree that maps paths of HTTP resources to SHA-256 hashes of their bodies. An example of such a tree:
    *root*
    └── http_assets
        ├── index.html -> SHA256(body)
        ├── ...
        └── /css/styles.css -> SHA256(body)
    
  • Compute the root hash of the tree and call ic0.certified_data_set with the bytes of the hash as the argument.
  • Add a #IC-Certificate header to each certified HTTP response.

Validator protocol

The validator follows the following steps to validate the certificate of resource at path PATH served by canister CANISTER_ID:

  • Hash the body of the HTTP response, obtaining hash DATA_HASH.
  • Check that the response contains the IC-Certificate header.
  • Decode the certificate and the tree from the value of the IC-Certificate header.
  • Check the validity of the certificate as described in the Interface Specification: Certification. This step requires knowing the IC root key.
  • Check that lookup(/http_assets/PATH, tree) = Found(DATA_HASH)
  • Check that lookup(/canister/CANISTER_ID/certified_data, certificate.tree) = Found(reconstruct(tree)).

IC-Certificate header

The IC-Certificate header is a Structure Header (as per RFC proposal) with is a dictionary with with members certificate and tree, both of which are Byte Sequences:

IC-Certificate: certificate=:<base64(c)>:, tree=:<base64(t)>:

where

The certificate must be a valid Internet Specification: Certificate with

lookup(/canister/<canister_id>/certified_data, certificate.tree)
    = Found (reconstruct(tree))

The tree exposes the relevant nodes in the /http_assets subtree to allow the client to lookup the request path to get the expected body hash.

Example

For this example, we fetched /index.html resource of the Internet Identity canister (canister id rdmx6-jaaaa-aaaaa-aaadq-cai) 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 478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d. The response contained the following header:

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==:

We can extract the following data from the header value:

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),
    ),
}

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

Validators