Skip to content

Commit

Permalink
Fix issuer certification (#2130)
Browse files Browse the repository at this point in the history
* Fix issuer certification

Also adds a test to check that the certification is valid.

* Revert unrelated line change

* Fix test comment
  • Loading branch information
Frederik Rothenberger authored Dec 11, 2023
1 parent 2959010 commit bc97e5b
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 5 deletions.
91 changes: 91 additions & 0 deletions demos/vc_issuer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions demos/vc_issuer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ include_dir = "0.7"
[dev-dependencies]
assert_matches = "1.5.0"
ic-test-state-machine-client = "3"
ic-response-verification = "1.3"
canister_tests = { path = "../../src/canister_tests" }
8 changes: 5 additions & 3 deletions demos/vc_issuer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,9 +394,11 @@ fn add_adult(adult_id: Principal) -> String {
pub fn http_request(req: HttpRequest) -> HttpResponse {
let parts: Vec<&str> = req.url.split('?').collect();
let path = parts[0];
let sigs = SIGNATURES.with_borrow(|sigs| pruned(sigs.root_hash()));
let maybe_asset = ASSETS
.with_borrow(|assets| assets.certified_asset(path, req.certificate_version, Some(sigs)));
let sigs_root_hash =
SIGNATURES.with_borrow(|sigs| pruned(labeled_hash(LABEL_SIG, &sigs.root_hash())));
let maybe_asset = ASSETS.with_borrow(|assets| {
assets.certified_asset(path, req.certificate_version, Some(sigs_root_hash))
});

let mut headers = static_headers();
match maybe_asset {
Expand Down
69 changes: 67 additions & 2 deletions demos/vc_issuer/tests/issue_credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@
use assert_matches::assert_matches;
use candid::{CandidType, Deserialize, Principal};
use canister_sig_util::{extract_raw_root_pk_from_der, CanisterSigPublicKey};
use canister_tests::api::http_request;
use canister_tests::api::internet_identity::vc_mvp as ii_api;
use canister_tests::framework::{env, get_wasm_path, principal_1, test_principal, II_WASM};
use canister_tests::framework::{env, get_wasm_path, principal_1, test_principal, time, II_WASM};
use canister_tests::{flows, match_value};
use ic_cdk::api::management_canister::provisional::CanisterId;
use ic_response_verification::types::{Request, Response, VerificationInfo};
use ic_response_verification::verify_request_response_pair;
use ic_test_state_machine_client::{call_candid, call_candid_as};
use ic_test_state_machine_client::{query_candid_as, CallError, StateMachine};
use identity_core::common::Value;
use identity_jose::jwt::JwtClaims;
use internet_identity_interface::http_gateway::{HttpRequest, HttpResponse};
use internet_identity_interface::internet_identity::types::vc_mvp::{
GetIdAliasRequest, GetIdAliasResponse, PrepareIdAliasRequest, PrepareIdAliasResponse,
};
use internet_identity_interface::internet_identity::types::FrontendHostname;
use lazy_static::lazy_static;
use serde_bytes::ByteBuf;
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::UNIX_EPOCH;
use std::time::{Duration, UNIX_EPOCH};
use vc_util::issuer_api::{
ArgumentValue, CredentialSpec, GetCredentialRequest, GetCredentialResponse,
Icrc21ConsentMessageResponse, Icrc21ConsentPreferences, Icrc21Error,
Expand Down Expand Up @@ -699,3 +704,63 @@ fn should_configure() {
let issuer_id = install_canister(&env, VC_ISSUER_WASM.clone());
api::configure(&env, issuer_id, &DUMMY_ISSUER_INIT).expect("API call failed");
}

/// Verifies that the expected assets is delivered and certified.
#[test]
fn issuer_canister_serves_http_assets() -> Result<(), CallError> {
fn verify_response_certification(
env: &StateMachine,
canister_id: CanisterId,
request: HttpRequest,
http_response: HttpResponse,
min_certification_version: u16,
) -> VerificationInfo {
verify_request_response_pair(
Request {
method: request.method,
url: request.url,
headers: request.headers,
body: request.body.into_vec(),
},
Response {
status_code: http_response.status_code,
headers: http_response.headers,
body: http_response.body.into_vec(),
},
canister_id.as_slice(),
time(env) as u128,
Duration::from_secs(300).as_nanos(),
&env.root_key(),
min_certification_version as u8,
)
.unwrap_or_else(|e| panic!("validation failed: {e}"))
}

let env = env();
let canister_id = install_canister(&env, VC_ISSUER_WASM.clone());

// for each asset and certification version, fetch the asset, check the HTTP status code, headers and certificate.

for certification_version in 1..=2 {
let request = HttpRequest {
method: "GET".to_string(),
url: "/".to_string(),
headers: vec![],
body: ByteBuf::new(),
certificate_version: Some(certification_version),
};
let http_response = http_request(&env, canister_id, &request)?;
assert_eq!(http_response.status_code, 200);

let result = verify_response_certification(
&env,
canister_id,
request,
http_response,
certification_version,
);
assert_eq!(result.verification_version, certification_version);
}

Ok(())
}

0 comments on commit bc97e5b

Please sign in to comment.