ic_agent/identity/
delegated.rs

1use candid::Principal;
2use der::{Decode, SliceReader};
3use ecdsa::signature::Verifier;
4use k256::Secp256k1;
5use p256::NistP256;
6use pkcs8::{spki::SubjectPublicKeyInfoRef, AssociatedOid, ObjectIdentifier};
7use sec1::{EcParameters, EncodedPoint};
8
9use crate::{agent::EnvelopeContent, Signature};
10
11use super::{error::DelegationError, Delegation, Identity, SignedDelegation};
12
13/// An identity that has been delegated the authority to authenticate as a different principal.
14pub struct DelegatedIdentity {
15    to: Box<dyn Identity>,
16    chain: Vec<SignedDelegation>,
17    from_key: Vec<u8>,
18}
19
20impl DelegatedIdentity {
21    /// Creates a delegated identity that signs using `to`, for the principal corresponding to the public key `from_key`.
22    ///
23    /// `chain` must be a list of delegations connecting `from_key` to `to.public_key()`, and in that order;
24    /// otherwise, this function will return an error.
25    pub fn new(
26        from_key: Vec<u8>,
27        to: Box<dyn Identity>,
28        chain: Vec<SignedDelegation>,
29    ) -> Result<Self, DelegationError> {
30        let mut last_verified = &from_key;
31        for delegation in &chain {
32            let spki = SubjectPublicKeyInfoRef::decode(
33                &mut SliceReader::new(&last_verified[..]).map_err(|_| DelegationError::Parse)?,
34            )
35            .map_err(|_| DelegationError::Parse)?;
36            if spki.algorithm.oid == elliptic_curve::ALGORITHM_OID {
37                let Some(params) = spki.algorithm.parameters else {
38                    return Err(DelegationError::UnknownAlgorithm);
39                };
40                let params = params
41                    .decode_as::<EcParameters>()
42                    .map_err(|_| DelegationError::Parse)?;
43                let curve = params
44                    .named_curve()
45                    .ok_or(DelegationError::UnknownAlgorithm)?;
46                if curve == Secp256k1::OID {
47                    let pt = EncodedPoint::from_bytes(spki.subject_public_key.raw_bytes())
48                        .map_err(|_| DelegationError::Parse)?;
49                    let vk = k256::ecdsa::VerifyingKey::from_encoded_point(&pt)
50                        .map_err(|_| DelegationError::Parse)?;
51                    let sig = k256::ecdsa::Signature::try_from(&delegation.signature[..])
52                        .map_err(|_| DelegationError::Parse)?;
53                    vk.verify(&delegation.delegation.signable(), &sig)
54                        .map_err(|_| DelegationError::BrokenChain {
55                            from: last_verified.clone(),
56                            to: Some(delegation.delegation.clone()),
57                        })?;
58                } else if curve == NistP256::OID {
59                    let pt = EncodedPoint::from_bytes(spki.subject_public_key.raw_bytes())
60                        .map_err(|_| DelegationError::Parse)?;
61                    let vk = p256::ecdsa::VerifyingKey::from_encoded_point(&pt)
62                        .map_err(|_| DelegationError::Parse)?;
63                    let sig = p256::ecdsa::Signature::try_from(&delegation.signature[..])
64                        .map_err(|_| DelegationError::Parse)?;
65                    vk.verify(&delegation.delegation.signable(), &sig)
66                        .map_err(|_| DelegationError::BrokenChain {
67                            from: last_verified.clone(),
68                            to: Some(delegation.delegation.clone()),
69                        })?;
70                } else {
71                    return Err(DelegationError::UnknownAlgorithm);
72                }
73            } else if spki.algorithm.oid == ObjectIdentifier::new_unwrap("1.3.101.112") {
74                let vk =
75                    ic_ed25519::PublicKey::deserialize_raw(spki.subject_public_key.raw_bytes())
76                        .map_err(|_| DelegationError::Parse)?;
77                vk.verify_signature(&delegation.delegation.signable(), &delegation.signature[..])
78                    .map_err(|_| DelegationError::BrokenChain {
79                        from: last_verified.clone(),
80                        to: Some(delegation.delegation.clone()),
81                    })?;
82            } else {
83                return Err(DelegationError::UnknownAlgorithm);
84            }
85            last_verified = &delegation.delegation.pubkey;
86        }
87        let delegated_principal = Principal::self_authenticating(last_verified);
88        if delegated_principal != to.sender().map_err(DelegationError::IdentityError)? {
89            return Err(DelegationError::BrokenChain {
90                from: last_verified.clone(),
91                to: None,
92            });
93        }
94
95        Ok(Self::new_unchecked(from_key, to, chain))
96    }
97
98    /// Creates a delegated identity that signs using `to`, for the principal corresponding to the public key `from_key`.
99    ///
100    /// `chain` must be a list of delegations connecting `from_key` to `to.public_key()`, and in that order;
101    /// otherwise, the replica will reject this delegation when used as an identity.
102    pub fn new_unchecked(
103        from_key: Vec<u8>,
104        to: Box<dyn Identity>,
105        chain: Vec<SignedDelegation>,
106    ) -> Self {
107        Self {
108            to,
109            chain,
110            from_key,
111        }
112    }
113
114    fn chain_signature(&self, mut sig: Signature) -> Signature {
115        sig.public_key = self.public_key();
116        sig.delegations
117            .get_or_insert(vec![])
118            .extend(self.chain.iter().cloned());
119        sig
120    }
121}
122
123impl Identity for DelegatedIdentity {
124    fn sender(&self) -> Result<Principal, String> {
125        Ok(Principal::self_authenticating(&self.from_key))
126    }
127    fn public_key(&self) -> Option<Vec<u8>> {
128        Some(self.from_key.clone())
129    }
130    fn sign(&self, content: &EnvelopeContent) -> Result<Signature, String> {
131        self.to.sign(content).map(|sig| self.chain_signature(sig))
132    }
133    fn sign_delegation(&self, content: &Delegation) -> Result<Signature, String> {
134        self.to
135            .sign_delegation(content)
136            .map(|sig| self.chain_signature(sig))
137    }
138    fn sign_arbitrary(&self, content: &[u8]) -> Result<Signature, String> {
139        self.to
140            .sign_arbitrary(content)
141            .map(|sig| self.chain_signature(sig))
142    }
143    fn delegation_chain(&self) -> Vec<SignedDelegation> {
144        let mut chain = self.to.delegation_chain();
145        chain.extend(self.chain.iter().cloned());
146        chain
147    }
148}