use quoted_string::strip_dquotes; use mc_attestation_verifier::SignedTcbInfo; use p256::ecdsa::VerifyingKey; use serde_json::{json, Value}; use std::collections::HashMap; use x509_cert::Certificate; use der::DecodePem; use std::fs; use cw_client::{CliClient, CwClient}; use reqwest::Url; use quartz_tcbinfo_msgs::ExecuteMsg; type TcbInfo = Value; type Fmspc = String; type Update = String; const TCB_SIGNER: &str = include_str!("../tcb_signer.pem"); async fn get_tcbinfo(fmspc: Fmspc, update: Update) -> Value { let url = format!("https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc={fmspc}&update={update}"); let body: String = reqwest::get(url) .await .expect("url retrieval failed") .text() .await .expect("could not read https response"); let tcbinfo: Value = serde_json::from_str(&body).expect("could not convert to JSON"); tcbinfo } async fn get_fmspc_list() -> Vec { let body: String = reqwest::get("https://api.trustedservices.intel.com/sgx/certification/v4/fmspcs").await .expect("url retrieval failed") .text() .await .expect("could not read https response"); let fmspc_data: Vec = serde_json::from_str(&body).expect("could not convert to JSON"); let mut fmspc_list: Vec = Vec::new(); for item in fmspc_data.iter() { let fmspc: String = format!("{}", item["fmspc"]); fmspc_list.push(strip_dquotes(&fmspc).unwrap().to_string()); } println!("{:?}", fmspc_list); fmspc_list } async fn upsert_tcbinfo() -> Result<(), &'static str> { let data = fs::read_to_string("./standard").expect("Unable to read file"); let mut store: HashMap = serde_json::from_str(&data).unwrap(); let certificate = TCB_SIGNER.to_string(); let parsed_certificate = Certificate::from_pem(certificate.clone()).expect("failed to parse PEM"); let fmspc_list = get_fmspc_list().await; let key = VerifyingKey::from_sec1_bytes( parsed_certificate .tbs_certificate .subject_public_key_info .subject_public_key .as_bytes() .expect("Failed to parse public key"), ) .expect("Failed to decode public key"); for fmspc in fmspc_list { let tcbinfo = get_tcbinfo(fmspc.clone(), "standard".to_string()).await; verify_signature(tcbinfo.clone(), key); let store_entry = &store[&fmspc]; if *store_entry != tcbinfo { println!("updating local TCBInfo for FMSPC: {fmspc}"); store.insert(fmspc.clone(), tcbinfo.clone()); println!("updating on-chain TCBInfo for FMSPC: {fmspc}"); let testnet = Url::parse("https://rpc-falcron.pion-1.ntrn.tech").expect("couldn't parse network URL"); let contract_address = "neutron1r4m59786vmxrx866585ze5ugjx9egcyja0nuxhn2y6d7ht6680sspa89zk".parse().expect("failed to parse contract address"); let chain_id = tendermint::chain::id::Id::try_from("pion-1").expect("invalid chain id"); let sender = "ajinkya"; let client = CliClient::neutrond(testnet); let execute_msg = ExecuteMsg { tcb_info: tcbinfo.to_string(), certificate: certificate.clone(), time: None, }; let res = client.tx_execute(&contract_address, &chain_id, 400000, &sender, json!(execute_msg), "11000untrn").await; println!("done: {res:?}"); std::thread::sleep(std::time::Duration::from_secs(5)); } else { println!("TCBInfo for FMSPC: {fmspc} up to date") } } let serialized = serde_json::to_string(&store).unwrap(); fs::write("./standard", serialized).expect("Unable to write file"); Ok(()) // } // } } fn verify_signature (tcbinfo: Value, key: VerifyingKey) { let tcbinfo_str = tcbinfo.as_str(); if let Some(st) = tcbinfo_str { let signed_tcbinfo = SignedTcbInfo::try_from(st).expect("tcbinfo string parsing failed"); signed_tcbinfo.verify(Some(&key), None).expect("could not verify signature"); } else { println!("{tcbinfo:?}"); } } #[tokio::main] pub async fn main() { upsert_tcbinfo().await.expect("TCBInfo update failed"); }