<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.internetcomputer.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Roman.kashitsyn</id>
	<title>Internet Computer Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.internetcomputer.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Roman.kashitsyn"/>
	<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/wiki/Special:Contributions/Roman.kashitsyn"/>
	<updated>2026-04-30T17:03:16Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=HTTP_asset_certification&amp;diff=1662</id>
		<title>HTTP asset certification</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=HTTP_asset_certification&amp;diff=1662"/>
		<updated>2022-02-02T13:39:35Z</updated>

		<summary type="html">&lt;p&gt;Roman.kashitsyn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;HTTP asset certification is a protocol that allows canisters to certify bodies of responses to GET HTTP requests.&lt;br /&gt;
The receiver of such responses can use the IC public key to authenticate the body of the response.&lt;br /&gt;
The protocol relies on [https://smartcontracts.org/docs/interface-spec/index.html#system-api-certified-data Certified data] feature of the IC.&lt;br /&gt;
&lt;br /&gt;
== Canister protocol ==&lt;br /&gt;
&lt;br /&gt;
A canister must follow the following protocol to certify assets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
An example of such a tree:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
*root*&lt;br /&gt;
└── http_assets&lt;br /&gt;
    ├── index.html -&amp;gt; SHA256(body)&lt;br /&gt;
    ├── ...&lt;br /&gt;
    └── /css/styles.css -&amp;gt; SHA256(body)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Compute the root hash of the tree and call [https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports &amp;lt;code&amp;gt;ic0.certified_data_set&amp;lt;/code&amp;gt;] with the bytes of the hash as the argument.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Add a [[#IC-Certificate header]] to each certified HTTP response.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Validator protocol ==&lt;br /&gt;
&lt;br /&gt;
The validator follows the following steps to validate the certificate of resource at path &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; served by canister &amp;lt;code&amp;gt;CANISTER_ID&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Hash the body of the HTTP response, obtaining hash &amp;lt;code&amp;gt;DATA_HASH&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Check that the response contains the &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; header.&lt;br /&gt;
* Decode the &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt; from the value of the &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; header.&lt;br /&gt;
* 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.&lt;br /&gt;
* Check that &amp;lt;code&amp;gt;lookup(/http_assets/PATH, tree) = Found(DATA_HASH)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Check that &amp;lt;code&amp;gt;lookup(/canister/CANISTER_ID/certified_data, certificate.tree) = Found(reconstruct(tree))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== IC-Certificate header ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt;, both of which are Byte Sequences:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IC-Certficate: certificate=:&amp;lt;base64(c)&amp;gt;:, tree=:&amp;lt;base64(t)&amp;gt;:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; is the a CBOR-encoded certificate (see [https://smartcontracts.org/docs/interface-spec/index.html#certification-encoding Interface Specification: Encoding of certificates]).&lt;br /&gt;
* &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; is a Hash Tree, CBOR-encoded according the CDDL &amp;lt;code&amp;gt;#6.55799(hash-tree)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;hash-tree&amp;lt;/code&amp;gt; is the corresponding [https://smartcontracts.org/docs/interface-spec/index.html#api-cddl CDDL production in the Interface Specification].&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; must be a valid [https://smartcontracts.org/docs/interface-spec/index.html#_certificate Internet Specification: Certificate] with&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lookup(/canister/&amp;lt;canister_id&amp;gt;/certified_data, certificate.tree)&lt;br /&gt;
    = Found (reconstruct(tree))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt; exposes the relevant nodes in the &amp;lt;code&amp;gt;/http_assets&amp;lt;/code&amp;gt; subtree to allow the client to lookup the request path to get the expected body hash.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
For this example, we fetched &amp;lt;code&amp;gt;/index.html&amp;lt;/code&amp;gt; resource of the Internet Identity canister (canister id &amp;lt;code&amp;gt;rdmx6-jaaaa-aaaaa-aaadq-cai&amp;lt;/code&amp;gt;) available at https://rdmx6-jaaaa-aaaaa-aaadq-cai.raw.ic0.app/index.html.&lt;br /&gt;
The SHA-256 hash of the resource at the moment of fetching is &amp;lt;code&amp;gt;478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d&amp;lt;/code&amp;gt;.&lt;br /&gt;
The response contained the following header:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
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==:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can extract the following data from the header value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ROOT HASH: 0b2d843df534ac8ed2331fe2782deb71d23a08d9b4019a8fa695ec7fde93de36&lt;br /&gt;
TREE HASH: 594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a&lt;br /&gt;
SIGNATURE: a45cddad72f1f96fec450b37e4b8932aad90dca657d6f2f0f3889c33c74f1638f238ae1d93206619dd1e9d8104c5d020&lt;br /&gt;
CERTIFICATE TIME: 2022-02-02T08:23:24.851277509+00:00&lt;br /&gt;
CERTIFICATE TREE:&lt;br /&gt;
HashTree {&lt;br /&gt;
    root: Fork(&lt;br /&gt;
        Fork(&lt;br /&gt;
            Fork(&lt;br /&gt;
                Label(&amp;quot;canister&amp;quot;, Fork(&lt;br /&gt;
                    Fork(&lt;br /&gt;
                        Pruned(8b9d8a4a03c07d6044aeb7ee895b95484c517dc7944d038a18fc313002c46cc7),&lt;br /&gt;
                        Fork(&lt;br /&gt;
                            Pruned(c8245873c33fba0b7c1bb0bc44f61aca7fa5e2c7418fc82f168b732442e7437d),&lt;br /&gt;
                            Fork(&lt;br /&gt;
                                Pruned(35ffe50767d485ebbc38b2c8ce8be26fddc87b5903737b31a686dbaf07e443a5),&lt;br /&gt;
                                Label(0x00000000000000070101, Fork(&lt;br /&gt;
                                    Fork(&lt;br /&gt;
                                        Label(&amp;quot;certified_data&amp;quot;, Leaf(0x594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a)),&lt;br /&gt;
                                        Pruned(fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938),&lt;br /&gt;
                                    ),&lt;br /&gt;
                                    Pruned(4a8239252d290aeb073f89e1ea1efcd1e6ebf7ad44d25567164170cc5e6965a7),&lt;br /&gt;
                                )),&lt;br /&gt;
                            ),&lt;br /&gt;
                        ),&lt;br /&gt;
                    ),&lt;br /&gt;
                    Pruned(70a89d3c41a23e814c3d87c4c8d1ac0d16169abcb58865f41cd504a0a8480137),&lt;br /&gt;
                )),&lt;br /&gt;
                Pruned(474cdd29464e31c9b9107365e5379edd75aa6ead6002bc141b3676147e2b5ad9),&lt;br /&gt;
            ),&lt;br /&gt;
            Pruned(4e4c0970dae1d1e27d16eb49727ead87d7826ccd8a5e7968c5e77469cc6640d7),&lt;br /&gt;
        ),&lt;br /&gt;
        Fork(&lt;br /&gt;
            Pruned(3a48d1fc213d49307103104f7d72c2b5930edba8787b90631f343b3aa68a5f0a),&lt;br /&gt;
            Label(&amp;quot;time&amp;quot;, Leaf(0xc59db5ebb6cffae716)),&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
}&lt;br /&gt;
TREE:&lt;br /&gt;
HashTree {&lt;br /&gt;
    root: Fork(&lt;br /&gt;
        Label(&amp;quot;http_assets&amp;quot;, Fork(&lt;br /&gt;
            Pruned(382d006733e55bdebf0884c30641f73a64b75ec2f4b13aa3f3b7edb1304146b0),&lt;br /&gt;
            Fork(&lt;br /&gt;
                Label(&amp;quot;/index.html&amp;quot;, Leaf(0x478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d)),&lt;br /&gt;
                Pruned(b1d8bf127c9c0ec9d0645318dcf2d2970d551ea22c3ca84608fbc6fe1d158859),&lt;br /&gt;
            ),&lt;br /&gt;
        )),&lt;br /&gt;
        Pruned(2a67edf2a05480f6cfa36cb15bb5c573fb08b41c5f71e752b1dfca8f7018620c),&lt;br /&gt;
    ),&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* The protocol supports only one resource per path. This does not work well with content negotiation protocol.&lt;br /&gt;
* The protocol does not support certification of HTTP statuses and headers. Only resource bodies can be certified. &lt;br /&gt;
&lt;br /&gt;
== Canisters using HTTP asset certification ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/dfinity/internet-identity/blob/7ff3dd51dd98c7b1b43d83950c9f31ea7159103d/src/internet_identity/src/main.rs#L775 Internet Identity canister]&lt;br /&gt;
* [https://github.com/dfinity/nns-dapp/blob/49126394df77b9583e508277fc736eda51de47be/rs/src/assets.rs#L123 NNS frontend]&lt;br /&gt;
* [https://githug.com/dfinity/certified-assets Certified assets canister]&lt;br /&gt;
&lt;br /&gt;
== Validators ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/dfinity/ic/tree/master/typescript/service-worker Certifying Service Worker]&lt;br /&gt;
* [https://github.com/dfinity/icx-proxy/blob/b0de0437fe6806a96d942465e5ee284c23b812e8/src/main.rs#L470 ICX proxy]&lt;/div&gt;</summary>
		<author><name>Roman.kashitsyn</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=HTTP_asset_certification&amp;diff=1656</id>
		<title>HTTP asset certification</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=HTTP_asset_certification&amp;diff=1656"/>
		<updated>2022-02-02T10:43:01Z</updated>

		<summary type="html">&lt;p&gt;Roman.kashitsyn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;HTTP asset certification is a protocol that allows canisters to certify bodies of responses to GET HTTP requests.&lt;br /&gt;
The receiver of such responses can use the IC public key to authenticate the body of the response.&lt;br /&gt;
The protocol relies on [https://smartcontracts.org/docs/interface-spec/index.html#system-api-certified-data Certified data] feature of the IC.&lt;br /&gt;
&lt;br /&gt;
== Canister protocol ==&lt;br /&gt;
&lt;br /&gt;
A canister must follow the following protocol to certify assets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
An example of such a tree:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
*root*&lt;br /&gt;
└── http_assets&lt;br /&gt;
    ├── index.html -&amp;gt; SHA256(body)&lt;br /&gt;
    ├── ...&lt;br /&gt;
    └── /css/styles.css -&amp;gt; SHA256(body)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Compute the root hash of the tree and call [https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports &amp;lt;code&amp;gt;ic0.certified_data_set&amp;lt;/code&amp;gt;] with the bytes of the hash as the argument.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Add a [[#IC-Certificate header]] to each certified HTTP response.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Validator protocol ==&lt;br /&gt;
&lt;br /&gt;
The validator follows the following steps to validate the certificate of resource at path &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; served by canister &amp;lt;code&amp;gt;CANISTER_ID&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Hash the body of the HTTP response, obtaining hash &amp;lt;code&amp;gt;DATA_HASH&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Check that the response contains the &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; header.&lt;br /&gt;
* Decode the &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt; from the value of the &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; header.&lt;br /&gt;
* 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.&lt;br /&gt;
* Check that &amp;lt;code&amp;gt;lookup(/http_assets/PATH, tree) = Found(DATA_HASH)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Check that &amp;lt;code&amp;gt;lookup(/canister/CANISTER_ID/certified_data, certificate.tree) = Found(reconstruct(tree))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== IC-Certificate header ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt;, both of which are Byte Sequences:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IC-Certficate: certificate=:&amp;lt;base64(c)&amp;gt;:, tree=:&amp;lt;base64(t)&amp;gt;:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; is the a CBOR-encoded certificate (see [https://smartcontracts.org/docs/interface-spec/index.html#certification-encoding Interface Specification: Encoding of certificates]).&lt;br /&gt;
* &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; is a Hash Tree, CBOR-encoded according the CDDL &amp;lt;code&amp;gt;#6.55799(hash-tree)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;hash-tree&amp;lt;/code&amp;gt; is the corresponding [https://smartcontracts.org/docs/interface-spec/index.html#api-cddl CDDL production in the Interface Specification].&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; must be a valid [https://smartcontracts.org/docs/interface-spec/index.html#_certificate Internet Specification: Certificate] with&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lookup(/canister/&amp;lt;canister_id&amp;gt;/certified_data, certificate.tree)&lt;br /&gt;
    = Found (reconstruct(tree))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt; exposes the relevant nodes in the &amp;lt;code&amp;gt;/http_assets&amp;lt;/code&amp;gt; subtree to allow the client to lookup the request path to get the expected body hash.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
For this example, we fetched &amp;lt;code&amp;gt;/index.html&amp;lt;/code&amp;gt; resource of the Internet Identity canister (canister id &amp;lt;code&amp;gt;rdmx6-jaaaa-aaaaa-aaadq-cai&amp;lt;/code&amp;gt;) available at https://rdmx6-jaaaa-aaaaa-aaadq-cai.raw.ic0.app/index.html.&lt;br /&gt;
The SHA-256 hash of the resource at the moment of fetching is &amp;lt;code&amp;gt;478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d&amp;lt;/code&amp;gt;.&lt;br /&gt;
The response contained the following header:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
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==:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can extract the following data from the header value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ROOT HASH: 0b2d843df534ac8ed2331fe2782deb71d23a08d9b4019a8fa695ec7fde93de36&lt;br /&gt;
TREE HASH: 594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a&lt;br /&gt;
SIGNATURE: a45cddad72f1f96fec450b37e4b8932aad90dca657d6f2f0f3889c33c74f1638f238ae1d93206619dd1e9d8104c5d020&lt;br /&gt;
CERTIFICATE TIME: 2022-02-02T08:23:24.851277509+00:00&lt;br /&gt;
CERTIFICATE TREE:&lt;br /&gt;
HashTree {&lt;br /&gt;
    root: Fork(&lt;br /&gt;
        Fork(&lt;br /&gt;
            Fork(&lt;br /&gt;
                Label(&amp;quot;canister&amp;quot;, Fork(&lt;br /&gt;
                    Fork(&lt;br /&gt;
                        Pruned(8b9d8a4a03c07d6044aeb7ee895b95484c517dc7944d038a18fc313002c46cc7),&lt;br /&gt;
                        Fork(&lt;br /&gt;
                            Pruned(c8245873c33fba0b7c1bb0bc44f61aca7fa5e2c7418fc82f168b732442e7437d),&lt;br /&gt;
                            Fork(&lt;br /&gt;
                                Pruned(35ffe50767d485ebbc38b2c8ce8be26fddc87b5903737b31a686dbaf07e443a5),&lt;br /&gt;
                                Label(&amp;quot;&amp;quot;, Fork(&lt;br /&gt;
                                    Fork(&lt;br /&gt;
                                        Label(&amp;quot;certified_data&amp;quot;, Leaf(0x594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a)),&lt;br /&gt;
                                        Pruned(fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938),&lt;br /&gt;
                                    ),&lt;br /&gt;
                                    Pruned(4a8239252d290aeb073f89e1ea1efcd1e6ebf7ad44d25567164170cc5e6965a7),&lt;br /&gt;
                                )),&lt;br /&gt;
                            ),&lt;br /&gt;
                        ),&lt;br /&gt;
                    ),&lt;br /&gt;
                    Pruned(70a89d3c41a23e814c3d87c4c8d1ac0d16169abcb58865f41cd504a0a8480137),&lt;br /&gt;
                )),&lt;br /&gt;
                Pruned(474cdd29464e31c9b9107365e5379edd75aa6ead6002bc141b3676147e2b5ad9),&lt;br /&gt;
            ),&lt;br /&gt;
            Pruned(4e4c0970dae1d1e27d16eb49727ead87d7826ccd8a5e7968c5e77469cc6640d7),&lt;br /&gt;
        ),&lt;br /&gt;
        Fork(&lt;br /&gt;
            Pruned(3a48d1fc213d49307103104f7d72c2b5930edba8787b90631f343b3aa68a5f0a),&lt;br /&gt;
            Label(&amp;quot;time&amp;quot;, Leaf(0xc59db5ebb6cffae716)),&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
}&lt;br /&gt;
TREE:&lt;br /&gt;
HashTree {&lt;br /&gt;
    root: Fork(&lt;br /&gt;
        Label(&amp;quot;http_assets&amp;quot;, Fork(&lt;br /&gt;
            Pruned(382d006733e55bdebf0884c30641f73a64b75ec2f4b13aa3f3b7edb1304146b0),&lt;br /&gt;
            Fork(&lt;br /&gt;
                Label(&amp;quot;/index.html&amp;quot;, Leaf(0x478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d)),&lt;br /&gt;
                Pruned(b1d8bf127c9c0ec9d0645318dcf2d2970d551ea22c3ca84608fbc6fe1d158859),&lt;br /&gt;
            ),&lt;br /&gt;
        )),&lt;br /&gt;
        Pruned(2a67edf2a05480f6cfa36cb15bb5c573fb08b41c5f71e752b1dfca8f7018620c),&lt;br /&gt;
    ),&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* The protocol supports only one resource per path. This does not work well with content negotiation protocol.&lt;br /&gt;
* The protocol does not support certification of HTTP statuses and headers. Only resource bodies can be certified. &lt;br /&gt;
&lt;br /&gt;
== Canisters using HTTP asset certification ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/dfinity/internet-identity/blob/7ff3dd51dd98c7b1b43d83950c9f31ea7159103d/src/internet_identity/src/main.rs#L775 Internet Identity canister]&lt;br /&gt;
* [https://github.com/dfinity/nns-dapp/blob/49126394df77b9583e508277fc736eda51de47be/rs/src/assets.rs#L123 NNS frontend]&lt;br /&gt;
* [https://githug.com/dfinity/certified-assets Certified assets canister]&lt;br /&gt;
&lt;br /&gt;
== Validators ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/dfinity/ic/tree/master/typescript/service-worker Certifying Service Worker]&lt;br /&gt;
* [https://github.com/dfinity/icx-proxy/blob/b0de0437fe6806a96d942465e5ee284c23b812e8/src/main.rs#L470 ICX proxy]&lt;/div&gt;</summary>
		<author><name>Roman.kashitsyn</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=HTTP_asset_certification&amp;diff=1655</id>
		<title>HTTP asset certification</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=HTTP_asset_certification&amp;diff=1655"/>
		<updated>2022-02-02T09:54:08Z</updated>

		<summary type="html">&lt;p&gt;Roman.kashitsyn: An overview of the first version of the HTTP asset certification protocol.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;HTTP asset certification is a protocol that allows canisters to certify bodies of responses to GET HTTP requests.&lt;br /&gt;
The receiver of such responses can use the IC public key to authenticate the body of the response.&lt;br /&gt;
The protocol relies on [https://smartcontracts.org/docs/interface-spec/index.html#system-api-certified-data Certified data] feature of the IC.&lt;br /&gt;
&lt;br /&gt;
== Canister protocol ==&lt;br /&gt;
&lt;br /&gt;
A canister must follow the following protocol to certify assets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
An example of such a tree:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
*root*&lt;br /&gt;
└── http_assets&lt;br /&gt;
    ├── index.html -&amp;gt; SHA256(body)&lt;br /&gt;
    ├── ...&lt;br /&gt;
    └── /css/styles.css -&amp;gt; SHA256(body)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Compute the root hash of the tree and call [https://smartcontracts.org/docs/interface-spec/index.html#system-api-imports &amp;lt;code&amp;gt;ic0.certified_data_set&amp;lt;/code&amp;gt;] with the bytes of the hash as the argument.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Add a [[#IC-Certificate header]] to each certified HTTP response.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Validator protocol ==&lt;br /&gt;
&lt;br /&gt;
The validator follows the following steps to validate the certificate of resource at path &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; served by canister &amp;lt;code&amp;gt;CANISTER_ID&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* Hash the body of the HTTP response, obtaining hash &amp;lt;code&amp;gt;DATA_HASH&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Check that the response contains the &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; header.&lt;br /&gt;
* Decode the &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt; from the value of the &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; header.&lt;br /&gt;
* Check the validity of the certificate as described in the [https://smartcontracts.org/docs/interface-spec/index.html#certification Interface Specification: Certification].&lt;br /&gt;
* Check that &amp;lt;code&amp;gt;lookup(/http_assets/PATH, tree) = Found(DATA_HASH)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Check that &amp;lt;code&amp;gt;lookup(/canister/CANISTER_ID/certified_data, certificate.tree) = Found(reconstruct(tree))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== IC-Certificate header ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;IC-Certificate&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt;, both of which are Byte Sequences:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IC-Certficate: certificate=:&amp;lt;base64(c)&amp;gt;:, tree=:&amp;lt;base64(t)&amp;gt;:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; is the a CBOR-encoded certificate (see [https://smartcontracts.org/docs/interface-spec/index.html#certification-encoding Interface Specification: Encoding of certificates]).&lt;br /&gt;
* &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; is a Hash Tree, CBOR-encoded according the CDDL &amp;lt;code&amp;gt;#6.55799(hash-tree)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;hash-tree&amp;lt;/code&amp;gt; is the corresponding [https://smartcontracts.org/docs/interface-spec/index.html#api-cddl CDDL production in the Interface Specification].&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;certificate&amp;lt;/code&amp;gt; must be a valid [https://smartcontracts.org/docs/interface-spec/index.html#_certificate Internet Specification: Certificate] with&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lookup(/canister/&amp;lt;canister_id&amp;gt;/certified_data, certificate.tree)&lt;br /&gt;
    = Found (reconstruct(tree))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;tree&amp;lt;/code&amp;gt; exposes the relevant nodes in the &amp;lt;code&amp;gt;/http_assets&amp;lt;/code&amp;gt; subtree to allow the client to lookup the request path to get the expected body hash.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
For this example, we fetched &amp;lt;code&amp;gt;/index.html&amp;lt;/code&amp;gt; resource of the Internet Identity canister (canister id &amp;lt;code&amp;gt;rdmx6-jaaaa-aaaaa-aaadq-cai&amp;lt;/code&amp;gt;) available at https://rdmx6-jaaaa-aaaaa-aaadq-cai.raw.ic0.app/index.html.&lt;br /&gt;
The SHA-256 hash of the resource at the moment of fetching is &amp;lt;code&amp;gt;478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d&amp;lt;/code&amp;gt;.&lt;br /&gt;
The response contained the following header:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
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==:&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can extract the following data from the header value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ROOT HASH: 0b2d843df534ac8ed2331fe2782deb71d23a08d9b4019a8fa695ec7fde93de36&lt;br /&gt;
TREE HASH: 594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a&lt;br /&gt;
SIGNATURE: a45cddad72f1f96fec450b37e4b8932aad90dca657d6f2f0f3889c33c74f1638f238ae1d93206619dd1e9d8104c5d020&lt;br /&gt;
CERTIFICATE TIME: 2022-02-02T08:23:24.851277509+00:00&lt;br /&gt;
CERTIFICATE TREE:&lt;br /&gt;
HashTree {&lt;br /&gt;
    root: Fork(&lt;br /&gt;
        Fork(&lt;br /&gt;
            Fork(&lt;br /&gt;
                Label(&amp;quot;canister&amp;quot;, Fork(&lt;br /&gt;
                    Fork(&lt;br /&gt;
                        Pruned(8b9d8a4a03c07d6044aeb7ee895b95484c517dc7944d038a18fc313002c46cc7),&lt;br /&gt;
                        Fork(&lt;br /&gt;
                            Pruned(c8245873c33fba0b7c1bb0bc44f61aca7fa5e2c7418fc82f168b732442e7437d),&lt;br /&gt;
                            Fork(&lt;br /&gt;
                                Pruned(35ffe50767d485ebbc38b2c8ce8be26fddc87b5903737b31a686dbaf07e443a5),&lt;br /&gt;
                                Label(&amp;quot;&amp;quot;, Fork(&lt;br /&gt;
                                    Fork(&lt;br /&gt;
                                        Label(&amp;quot;certified_data&amp;quot;, Leaf(0x594b75d308d68a7c746805b2acd122ff447b55eba16a50cc8c60c4af321b673a)),&lt;br /&gt;
                                        Pruned(fd5b59459758c8afecaf7285da359e4b5adb945fb86a3c1f0efd996c21a96938),&lt;br /&gt;
                                    ),&lt;br /&gt;
                                    Pruned(4a8239252d290aeb073f89e1ea1efcd1e6ebf7ad44d25567164170cc5e6965a7),&lt;br /&gt;
                                )),&lt;br /&gt;
                            ),&lt;br /&gt;
                        ),&lt;br /&gt;
                    ),&lt;br /&gt;
                    Pruned(70a89d3c41a23e814c3d87c4c8d1ac0d16169abcb58865f41cd504a0a8480137),&lt;br /&gt;
                )),&lt;br /&gt;
                Pruned(474cdd29464e31c9b9107365e5379edd75aa6ead6002bc141b3676147e2b5ad9),&lt;br /&gt;
            ),&lt;br /&gt;
            Pruned(4e4c0970dae1d1e27d16eb49727ead87d7826ccd8a5e7968c5e77469cc6640d7),&lt;br /&gt;
        ),&lt;br /&gt;
        Fork(&lt;br /&gt;
            Pruned(3a48d1fc213d49307103104f7d72c2b5930edba8787b90631f343b3aa68a5f0a),&lt;br /&gt;
            Label(&amp;quot;time&amp;quot;, Leaf(0xc59db5ebb6cffae716)),&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
}&lt;br /&gt;
TREE:&lt;br /&gt;
HashTree {&lt;br /&gt;
    root: Fork(&lt;br /&gt;
        Label(&amp;quot;http_assets&amp;quot;, Fork(&lt;br /&gt;
            Pruned(382d006733e55bdebf0884c30641f73a64b75ec2f4b13aa3f3b7edb1304146b0),&lt;br /&gt;
            Fork(&lt;br /&gt;
                Label(&amp;quot;/index.html&amp;quot;, Leaf(0x478afb8206ca0b566a7f138e623accd169fa822602d2f6d717fb67d1045f4f0d)),&lt;br /&gt;
                Pruned(b1d8bf127c9c0ec9d0645318dcf2d2970d551ea22c3ca84608fbc6fe1d158859),&lt;br /&gt;
            ),&lt;br /&gt;
        )),&lt;br /&gt;
        Pruned(2a67edf2a05480f6cfa36cb15bb5c573fb08b41c5f71e752b1dfca8f7018620c),&lt;br /&gt;
    ),&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* The protocol supports only one resource per path. This does not work well with content negotiation protocol.&lt;br /&gt;
* The protocol does not support certification of HTTP statuses and headers. Only resource bodies can be certified. &lt;br /&gt;
&lt;br /&gt;
== Canisters using HTTP asset certification ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/dfinity/internet-identity/blob/7ff3dd51dd98c7b1b43d83950c9f31ea7159103d/src/internet_identity/src/main.rs#L775 Internet Identity canister]&lt;br /&gt;
* [https://github.com/dfinity/nns-dapp/blob/49126394df77b9583e508277fc736eda51de47be/rs/src/assets.rs#L123 NNS frontend]&lt;br /&gt;
* [https://githug.com/dfinity/certified-assets Certified assets canister]&lt;/div&gt;</summary>
		<author><name>Roman.kashitsyn</name></author>
	</entry>
</feed>