ic_agent/identity/
delegated.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use candid::Principal;
use der::{Decode, SliceReader};
use ecdsa::signature::Verifier;
use k256::Secp256k1;
use p256::NistP256;
use pkcs8::{spki::SubjectPublicKeyInfoRef, AssociatedOid, ObjectIdentifier};
use sec1::{EcParameters, EncodedPoint};

use crate::{agent::EnvelopeContent, Signature};

use super::{error::DelegationError, Delegation, Identity, SignedDelegation};

/// An identity that has been delegated the authority to authenticate as a different principal.
pub struct DelegatedIdentity {
    to: Box<dyn Identity>,
    chain: Vec<SignedDelegation>,
    from_key: Vec<u8>,
}

impl DelegatedIdentity {
    /// Creates a delegated identity that signs using `to`, for the principal corresponding to the public key `from_key`.
    ///
    /// `chain` must be a list of delegations connecting `from_key` to `to.public_key()`, and in that order;
    /// otherwise, this function will return an error.
    pub fn new(
        from_key: Vec<u8>,
        to: Box<dyn Identity>,
        chain: Vec<SignedDelegation>,
    ) -> Result<Self, DelegationError> {
        let mut last_verified = &from_key;
        for delegation in &chain {
            let spki = SubjectPublicKeyInfoRef::decode(
                &mut SliceReader::new(&last_verified[..]).map_err(|_| DelegationError::Parse)?,
            )
            .map_err(|_| DelegationError::Parse)?;
            if spki.algorithm.oid == elliptic_curve::ALGORITHM_OID {
                let Some(params) = spki.algorithm.parameters else {
                    return Err(DelegationError::UnknownAlgorithm);
                };
                let params = params
                    .decode_as::<EcParameters>()
                    .map_err(|_| DelegationError::Parse)?;
                let curve = params
                    .named_curve()
                    .ok_or(DelegationError::UnknownAlgorithm)?;
                if curve == Secp256k1::OID {
                    let pt = EncodedPoint::from_bytes(spki.subject_public_key.raw_bytes())
                        .map_err(|_| DelegationError::Parse)?;
                    let vk = k256::ecdsa::VerifyingKey::from_encoded_point(&pt)
                        .map_err(|_| DelegationError::Parse)?;
                    let sig = k256::ecdsa::Signature::try_from(&delegation.signature[..])
                        .map_err(|_| DelegationError::Parse)?;
                    vk.verify(&delegation.delegation.signable(), &sig)
                        .map_err(|_| DelegationError::BrokenChain {
                            from: last_verified.clone(),
                            to: Some(delegation.delegation.clone()),
                        })?;
                } else if curve == NistP256::OID {
                    let pt = EncodedPoint::from_bytes(spki.subject_public_key.raw_bytes())
                        .map_err(|_| DelegationError::Parse)?;
                    let vk = p256::ecdsa::VerifyingKey::from_encoded_point(&pt)
                        .map_err(|_| DelegationError::Parse)?;
                    let sig = p256::ecdsa::Signature::try_from(&delegation.signature[..])
                        .map_err(|_| DelegationError::Parse)?;
                    vk.verify(&delegation.delegation.signable(), &sig)
                        .map_err(|_| DelegationError::BrokenChain {
                            from: last_verified.clone(),
                            to: Some(delegation.delegation.clone()),
                        })?;
                } else {
                    return Err(DelegationError::UnknownAlgorithm);
                }
            } else if spki.algorithm.oid == ObjectIdentifier::new_unwrap("1.3.101.112") {
                let vk = ed25519_consensus::VerificationKey::try_from(
                    spki.subject_public_key.raw_bytes(),
                )
                .map_err(|_| DelegationError::Parse)?;
                let sig = ed25519_consensus::Signature::try_from(&delegation.signature[..])
                    .map_err(|_| DelegationError::Parse)?;
                vk.verify(&sig, &delegation.delegation.signable())
                    .map_err(|_| DelegationError::BrokenChain {
                        from: last_verified.clone(),
                        to: Some(delegation.delegation.clone()),
                    })?;
            } else {
                return Err(DelegationError::UnknownAlgorithm);
            }
            last_verified = &delegation.delegation.pubkey;
        }
        let delegated_principal = Principal::self_authenticating(last_verified);
        if delegated_principal != to.sender().map_err(DelegationError::IdentityError)? {
            return Err(DelegationError::BrokenChain {
                from: last_verified.clone(),
                to: None,
            });
        }

        Ok(Self::new_unchecked(from_key, to, chain))
    }

    /// Creates a delegated identity that signs using `to`, for the principal corresponding to the public key `from_key`.
    ///
    /// `chain` must be a list of delegations connecting `from_key` to `to.public_key()`, and in that order;
    /// otherwise, the replica will reject this delegation when used as an identity.
    pub fn new_unchecked(
        from_key: Vec<u8>,
        to: Box<dyn Identity>,
        chain: Vec<SignedDelegation>,
    ) -> Self {
        Self {
            to,
            chain,
            from_key,
        }
    }

    fn chain_signature(&self, mut sig: Signature) -> Signature {
        sig.public_key = self.public_key();
        sig.delegations
            .get_or_insert(vec![])
            .extend(self.chain.iter().cloned());
        sig
    }
}

impl Identity for DelegatedIdentity {
    fn sender(&self) -> Result<Principal, String> {
        Ok(Principal::self_authenticating(&self.from_key))
    }
    fn public_key(&self) -> Option<Vec<u8>> {
        Some(self.from_key.clone())
    }
    fn sign(&self, content: &EnvelopeContent) -> Result<Signature, String> {
        self.to.sign(content).map(|sig| self.chain_signature(sig))
    }
    fn sign_delegation(&self, content: &Delegation) -> Result<Signature, String> {
        self.to
            .sign_delegation(content)
            .map(|sig| self.chain_signature(sig))
    }
    fn sign_arbitrary(&self, content: &[u8]) -> Result<Signature, String> {
        self.to
            .sign_arbitrary(content)
            .map(|sig| self.chain_signature(sig))
    }
    fn delegation_chain(&self) -> Vec<SignedDelegation> {
        let mut chain = self.to.delegation_chain();
        chain.extend(self.chain.iter().cloned());
        chain
    }
}