ic_http_certification/utils/
skip_certification.rs

1use super::add_v2_certificate_header;
2use crate::{
3    DefaultCelBuilder, Hash, HttpCertificationPath, HttpResponse,
4    CERTIFICATE_EXPRESSION_HEADER_NAME,
5};
6use ic_certification::{hash_tree::leaf, labeled, HashTree};
7use ic_representation_independent_hash::hash;
8
9/// Adds the `IC-Certificate` and `IC-Certificate-Expression` headers to a given [`HttpResponse`]. These headers are used by the HTTP Gateway
10/// to verify the authenticity of query call responses. In this case, the headers are pre-configured to instruct
11/// the HTTP Gateway to skip certification verification in a secure way. Secure in this context means that
12/// the decision to skip certification is made by the canister itself, and not by the replica, API boundary nodes
13/// or any other intermediate party.
14///
15/// # Arguments
16///
17/// * `data_certificate` - A certificate used by the HTTP Gateway to verify a response.
18///    Retrieved using `ic_cdk::api::data_certificate`.
19/// * `response` - The [`HttpResponse`] to add the certificate header to.
20///   Created using [`HttpResponse::builder()`](crate::HttpResponse::builder).
21///
22/// # Examples
23///
24/// ```
25/// use ic_http_certification::{HttpResponse, DefaultCelBuilder, utils::add_skip_certification_header, CERTIFICATE_EXPRESSION_HEADER_NAME, CERTIFICATE_HEADER_NAME};
26///
27/// let mut response = HttpResponse::builder().build();
28///
29/// // this should normally be retrieved using `ic_cdk::api::data_certificate()`.
30/// let data_certificate = vec![1, 2, 3];
31///
32/// add_skip_certification_header(data_certificate, &mut response);
33///
34/// assert_eq!(
35///     response.headers(),
36///     vec![
37///         (
38///             CERTIFICATE_HEADER_NAME.to_string(),
39///             "certificate=:AQID:, tree=:2dn3gwJJaHR0cF9leHBygwJDPCo+gwJYIMMautvQsFn51GT9bfTani3Ah659C0BGjTNyJtQTszcjggNA:, expr_path=:2dn3gmlodHRwX2V4cHJjPCo+:, version=2".to_string(),
40///         ),
41///         (
42///             CERTIFICATE_EXPRESSION_HEADER_NAME.to_string(),
43///             DefaultCelBuilder::skip_certification().to_string()
44///         ),
45///     ]
46/// );
47/// ```
48pub fn add_skip_certification_header(data_certificate: Vec<u8>, response: &mut HttpResponse) {
49    add_v2_certificate_header(
50        &data_certificate,
51        response,
52        &skip_certification_asset_tree(),
53        &HttpCertificationPath::wildcard("").to_expr_path(),
54    );
55
56    response.add_header((
57        CERTIFICATE_EXPRESSION_HEADER_NAME.to_string(),
58        DefaultCelBuilder::skip_certification().to_string(),
59    ));
60}
61
62/// Returns the hash of the certified data that can be used to instruct HTTP Gateways to skip certification.
63///
64/// # Examples
65///
66/// ```ignore
67/// use ic_http_certification::utils::skip_certification_certified_data;
68/// use ic_cdk::api::set_certified_data;
69///
70/// let certified_data = skip_certification_certified_data();
71///
72/// set_certified_data(&certified_data);
73/// ```
74pub fn skip_certification_certified_data() -> Hash {
75    skip_certification_asset_tree().digest()
76}
77
78fn skip_certification_asset_tree() -> HashTree {
79    let cel_expr_hash = hash(
80        DefaultCelBuilder::skip_certification()
81            .to_string()
82            .as_bytes(),
83    );
84
85    labeled(
86        "http_expr",
87        labeled("<*>", labeled(cel_expr_hash, leaf(vec![]))),
88    )
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_skip_certification_certified_data() {
97        let certified_data = skip_certification_certified_data();
98
99        assert_eq!(
100            certified_data,
101            [
102                85, 236, 195, 28, 62, 128, 71, 252, 21, 143, 32, 234, 10, 160, 96, 154, 172, 199,
103                181, 126, 6, 234, 64, 220, 65, 134, 2, 114, 167, 214, 66, 145
104            ]
105        );
106    }
107}