ic_agent/identity/
mod.rs

1//! Types and traits dealing with identity across the Internet Computer.
2use std::sync::Arc;
3
4use crate::{agent::EnvelopeContent, export::Principal};
5
6pub(crate) mod anonymous;
7pub(crate) mod basic;
8pub(crate) mod delegated;
9pub(crate) mod error;
10pub(crate) mod prime256v1;
11pub(crate) mod secp256k1;
12
13#[doc(inline)]
14pub use anonymous::AnonymousIdentity;
15#[doc(inline)]
16pub use basic::BasicIdentity;
17#[doc(inline)]
18pub use delegated::DelegatedIdentity;
19#[doc(inline)]
20pub use error::DelegationError;
21#[doc(inline)]
22pub use ic_transport_types::{Delegation, SignedDelegation};
23#[doc(inline)]
24pub use prime256v1::Prime256v1Identity;
25#[doc(inline)]
26pub use secp256k1::Secp256k1Identity;
27
28#[cfg(feature = "pem")]
29#[doc(inline)]
30pub use error::PemError;
31
32/// A cryptographic signature, signed by an [Identity].
33#[derive(Clone, Debug)]
34pub struct Signature {
35    /// This is the DER-encoded public key.
36    pub public_key: Option<Vec<u8>>,
37    /// The signature bytes.
38    pub signature: Option<Vec<u8>>,
39    /// A list of delegations connecting `public_key` to the key that signed `signature`, and in that order.
40    pub delegations: Option<Vec<SignedDelegation>>,
41}
42
43/// An `Identity` produces [`Signatures`](Signature) for requests or delegations. It knows or
44/// represents the [`Principal`] of the sender.
45///
46/// [`Agents`](crate::Agent) are assigned a single `Identity` object, but there can be multiple
47/// identities used.
48pub trait Identity: Send + Sync {
49    /// Returns a sender, ie. the Principal ID that is used to sign a request.
50    ///
51    /// Only one sender can be used per request.
52    fn sender(&self) -> Result<Principal, String>;
53
54    /// Produce the public key commonly returned in [`Signature`].
55    ///
56    /// Should only return `None` if `sign` would do the same.
57    fn public_key(&self) -> Option<Vec<u8>>;
58
59    /// Sign a request ID derived from a content map.
60    ///
61    /// Implementors should call `content.to_request_id().signable()` for the actual bytes that need to be signed.
62    fn sign(&self, content: &EnvelopeContent) -> Result<Signature, String>;
63
64    /// Sign a delegation to let another key be used to authenticate [`sender`](Identity::sender).
65    ///
66    /// Not all `Identity` implementations support this operation, though all `ic-agent` implementations other than `AnonymousIdentity` do.
67    ///
68    /// Implementors should call `content.signable()` for the actual bytes that need to be signed.
69    fn sign_delegation(&self, content: &Delegation) -> Result<Signature, String> {
70        let _ = content; // silence unused warning
71        Err(String::from("unsupported"))
72    }
73
74    /// Sign arbitrary bytes.
75    ///
76    /// Not all `Identity` implementations support this operation, though all `ic-agent` implementations do.
77    fn sign_arbitrary(&self, content: &[u8]) -> Result<Signature, String> {
78        let _ = content; // silence unused warning
79        Err(String::from("unsupported"))
80    }
81
82    /// A list of signed delegations connecting [`sender`](Identity::sender)
83    /// to [`public_key`](Identity::public_key), and in that order.
84    fn delegation_chain(&self) -> Vec<SignedDelegation> {
85        vec![]
86    }
87}
88
89macro_rules! delegating_impl {
90    ($implementor:ty, $name:ident => $self_expr:expr) => {
91        impl Identity for $implementor {
92            fn sender(&$name) -> Result<Principal, String> {
93                $self_expr.sender()
94            }
95
96            fn public_key(&$name) -> Option<Vec<u8>> {
97                $self_expr.public_key()
98            }
99
100            fn sign(&$name, content: &EnvelopeContent) -> Result<Signature, String> {
101                $self_expr.sign(content)
102            }
103
104            fn sign_delegation(&$name, content: &Delegation) -> Result<Signature, String> {
105                $self_expr.sign_delegation(content)
106            }
107
108            fn sign_arbitrary(&$name, content: &[u8]) -> Result<Signature, String> {
109                $self_expr.sign_arbitrary(content)
110            }
111
112            fn delegation_chain(&$name) -> Vec<SignedDelegation> {
113                $self_expr.delegation_chain()
114            }
115        }
116    };
117}
118
119delegating_impl!(Box<dyn Identity>, self => **self);
120delegating_impl!(Arc<dyn Identity>, self => **self);
121delegating_impl!(&dyn Identity, self => *self);