use crate::{
admission_budget::SessionAdmissionBudget,
portable::{DecodedPortableClaims, PortableEncodingError, VerifiedPortableClaims},
};
use ic_auth_protocol_types::{PortableCredential, PortableProof};
use thiserror::Error;
pub enum PortableVerificationContext<'a> {
#[cfg(feature = "portable-signature-verification")]
Ed25519 {
claims: &'a crate::portable::PortableClaimsContext<'a>,
public_key: &'a [u8; 32],
},
#[cfg(feature = "certified-proof-verification")]
Certified(&'a crate::portable_certified::PortableCertifiedContext<'a>),
}
#[derive(Debug, Error, Eq, PartialEq)]
pub enum PortableCredentialError {
#[error("credential proof does not match the protected enrolled mechanism")]
MechanismMismatch,
#[cfg(feature = "portable-signature-verification")]
#[error(transparent)]
Ed25519(#[from] crate::portable_signature::PortableSignatureError),
#[cfg(feature = "certified-proof-verification")]
#[error(transparent)]
Certified(#[from] crate::portable_certified::PortableCertifiedError),
}
pub fn verify_credential(
budget: &mut SessionAdmissionBudget,
credential: &PortableCredential,
context: &PortableVerificationContext<'_>,
) -> Result<VerifiedPortableClaims, PortableCredentialError> {
verify_claims(
budget,
credential.claims.len(),
|| DecodedPortableClaims::decode(&credential.claims),
&credential.proof,
context,
)
}
impl crate::portable::DecodedPortableClaims {
pub fn verify(
self,
budget: &mut SessionAdmissionBudget,
proof: &PortableProof,
context: &PortableVerificationContext<'_>,
) -> Result<VerifiedPortableClaims, PortableCredentialError> {
#[cfg(feature = "certified-proof-verification")]
let encoded_len = self.encoded_len;
#[cfg(not(feature = "certified-proof-verification"))]
let encoded_len = 0;
verify_claims(budget, encoded_len, || Ok(self), proof, context)
}
}
fn verify_claims(
budget: &mut SessionAdmissionBudget,
encoded_len: usize,
decode: impl FnOnce() -> Result<DecodedPortableClaims, PortableEncodingError>,
proof: &PortableProof,
context: &PortableVerificationContext<'_>,
) -> Result<VerifiedPortableClaims, PortableCredentialError> {
#[cfg(not(feature = "certified-proof-verification"))]
let _ = encoded_len;
match (context, proof) {
#[cfg(feature = "portable-signature-verification")]
(
PortableVerificationContext::Ed25519 { claims, public_key },
PortableProof::Ed25519 { signature },
) => Ok(crate::portable_signature::verify_decoded(
budget,
decode().map_err(crate::portable_signature::PortableSignatureError::from)?,
signature,
claims,
public_key,
)?),
#[cfg(feature = "certified-proof-verification")]
(
PortableVerificationContext::Certified(context),
PortableProof::Certified {
delegation,
issuer_signature,
},
) => {
crate::portable_certified::check_bounds(
encoded_len,
delegation,
issuer_signature,
context,
)?;
Ok(crate::portable_certified::verify_decoded(
budget,
decode().map_err(crate::portable_certified::PortableCertifiedError::from)?,
delegation,
issuer_signature,
context,
)?)
}
_ => Err(PortableCredentialError::MechanismMismatch),
}
}