use super::{DelegatedTokenOps, SignedDelegationProof, crypto, keys, verify};
use crate::{
InternalError,
cdk::types::Principal,
dto::auth::{DelegationCert, DelegationProof},
ops::{
auth::DelegationValidationError,
ic::{IcOps, ecdsa::EcdsaOps},
},
};
impl DelegatedTokenOps {
pub(crate) async fn sign_delegation_cert(
cert: DelegationCert,
) -> Result<SignedDelegationProof, InternalError> {
let local = IcOps::canister_self();
if cert.root_pid != local {
return Err(DelegationValidationError::InvalidRootAuthority {
expected: local,
found: cert.root_pid,
}
.into());
}
let key_name = keys::delegated_tokens_key_name()?;
crate::perf!("resolve_signing_key_name");
let hash = crypto::cert_hash(&cert);
crate::perf!("hash_cert");
let derivation_path = keys::root_derivation_path();
crate::perf!("build_root_derivation_path");
let sig = EcdsaOps::sign_bytes(&key_name, derivation_path, hash).await?;
crate::perf!("sign_cert");
Ok(SignedDelegationProof {
proof: DelegationProof {
cert,
cert_sig: sig,
},
cert_hash: hash,
})
}
pub(crate) async fn local_shard_public_key_sec1(
shard_pid: Principal,
) -> Result<Vec<u8>, InternalError> {
if let Some(shard_public_key) =
crate::ops::storage::auth::DelegationStateOps::shard_public_key(shard_pid)
{
return Ok(shard_public_key);
}
let key_name = keys::delegated_tokens_key_name()?;
let shard_public_key =
EcdsaOps::public_key_sec1(&key_name, keys::shard_derivation_path(shard_pid), shard_pid)
.await?;
crate::ops::storage::auth::DelegationStateOps::set_shard_public_key(
shard_pid,
shard_public_key.clone(),
);
Ok(shard_public_key)
}
pub async fn cache_public_keys_for_cert(cert: &DelegationCert) -> Result<(), InternalError> {
Self::cache_public_keys_for_cert_with_optional_shard(cert, None).await
}
pub async fn cache_public_keys_for_cert_with_optional_shard(
cert: &DelegationCert,
shard_public_key: Option<Vec<u8>>,
) -> Result<(), InternalError> {
let key_name = keys::delegated_tokens_key_name()?;
keys::ensure_root_public_key_cached(&key_name, cert.root_pid).await?;
if let Some(shard_public_key) = shard_public_key {
crate::ops::storage::auth::DelegationStateOps::set_shard_public_key(
cert.shard_pid,
shard_public_key,
);
} else {
keys::ensure_shard_public_key_cached(&key_name, cert.shard_pid).await?;
}
Ok(())
}
pub(crate) async fn fetch_missing_shard_public_key_for_cert(
cert: &DelegationCert,
) -> Result<Option<Vec<u8>>, InternalError> {
let key_name = keys::delegated_tokens_key_name()?;
keys::fetch_missing_shard_public_key(&key_name, cert.shard_pid).await
}
pub(super) fn verify_delegation_structure(
proof: &DelegationProof,
expected_root: Option<Principal>,
) -> Result<(), InternalError> {
if proof.cert.expires_at <= proof.cert.issued_at {
return Err(DelegationValidationError::CertInvalidWindow {
issued_at: proof.cert.issued_at,
expires_at: proof.cert.expires_at,
}
.into());
}
if let Some(expected) = expected_root
&& proof.cert.root_pid != expected
{
return Err(DelegationValidationError::InvalidRootAuthority {
expected,
found: proof.cert.root_pid,
}
.into());
}
Ok(())
}
pub(super) fn verify_delegation_signature(
proof: &DelegationProof,
) -> Result<(), InternalError> {
verify::verify_delegation_signature(proof)
}
pub fn verify_delegation_proof(
proof: &DelegationProof,
authority_pid: Principal,
) -> Result<(), InternalError> {
Self::verify_delegation_structure(proof, Some(authority_pid))?;
Self::verify_delegation_signature(proof)?;
Ok(())
}
}