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 = ed25519_consensus::VerificationKey::try_from(
75                    spki.subject_public_key.raw_bytes(),
76                )
77                .map_err(|_| DelegationError::Parse)?;
78                let sig = ed25519_consensus::Signature::try_from(&delegation.signature[..])
79                    .map_err(|_| DelegationError::Parse)?;
80                vk.verify(&sig, &delegation.delegation.signable())
81                    .map_err(|_| DelegationError::BrokenChain {
82                        from: last_verified.clone(),
83                        to: Some(delegation.delegation.clone()),
84                    })?;
85            } else {
86                return Err(DelegationError::UnknownAlgorithm);
87            }
88            last_verified = &delegation.delegation.pubkey;
89        }
90        let delegated_principal = Principal::self_authenticating(last_verified);
91        if delegated_principal != to.sender().map_err(DelegationError::IdentityError)? {
92            return Err(DelegationError::BrokenChain {
93                from: last_verified.clone(),
94                to: None,
95            });
96        }
97
98        Ok(Self::new_unchecked(from_key, to, chain))
99    }
100
101    /// Creates a delegated identity that signs using `to`, for the principal corresponding to the public key `from_key`.
102    ///
103    /// `chain` must be a list of delegations connecting `from_key` to `to.public_key()`, and in that order;
104    /// otherwise, the replica will reject this delegation when used as an identity.
105    pub fn new_unchecked(
106        from_key: Vec<u8>,
107        to: Box<dyn Identity>,
108        chain: Vec<SignedDelegation>,
109    ) -> Self {
110        Self {
111            to,
112            chain,
113            from_key,
114        }
115    }
116
117    fn chain_signature(&self, mut sig: Signature) -> Signature {
118        sig.public_key = self.public_key();
119        sig.delegations
120            .get_or_insert(vec![])
121            .extend(self.chain.iter().cloned());
122        sig
123    }
124}
125
126impl Identity for DelegatedIdentity {
127    fn sender(&self) -> Result<Principal, String> {
128        Ok(Principal::self_authenticating(&self.from_key))
129    }
130    fn public_key(&self) -> Option<Vec<u8>> {
131        Some(self.from_key.clone())
132    }
133    fn sign(&self, content: &EnvelopeContent) -> Result<Signature, String> {
134        self.to.sign(content).map(|sig| self.chain_signature(sig))
135    }
136    fn sign_delegation(&self, content: &Delegation) -> Result<Signature, String> {
137        self.to
138            .sign_delegation(content)
139            .map(|sig| self.chain_signature(sig))
140    }
141    fn sign_arbitrary(&self, content: &[u8]) -> Result<Signature, String> {
142        self.to
143            .sign_arbitrary(content)
144            .map(|sig| self.chain_signature(sig))
145    }
146    fn delegation_chain(&self) -> Vec<SignedDelegation> {
147        let mut chain = self.to.delegation_chain();
148        chain.extend(self.chain.iter().cloned());
149        chain
150    }
151}