ic_agent/identity/
basic.rs1use crate::{agent::EnvelopeContent, export::Principal, Identity, Signature};
2
3#[cfg(feature = "pem")]
4use crate::identity::error::PemError;
5
6use ed25519_consensus::SigningKey;
7use simple_asn1::{
8 oid, to_der,
9 ASN1Block::{BitString, ObjectIdentifier, Sequence},
10};
11
12use std::fmt;
13
14use super::Delegation;
15
16pub struct BasicIdentity {
20 private_key: KeyCompat,
21 der_encoded_public_key: Vec<u8>,
22}
23
24impl fmt::Debug for BasicIdentity {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 f.debug_struct("BasicIdentity")
27 .field("der_encoded_public_key", &self.der_encoded_public_key)
28 .finish_non_exhaustive()
29 }
30}
31
32impl BasicIdentity {
33 #[cfg(feature = "pem")]
35 pub fn from_pem_file<P: AsRef<std::path::Path>>(file_path: P) -> Result<Self, PemError> {
36 Self::from_pem(std::fs::File::open(file_path)?)
37 }
38
39 #[cfg(feature = "pem")]
41 pub fn from_pem<R: std::io::Read>(pem_reader: R) -> Result<Self, PemError> {
42 use der::{asn1::OctetString, Decode, ErrorKind, SliceReader, Tag, TagNumber};
43 use pkcs8::PrivateKeyInfo;
44
45 let bytes: Vec<u8> = pem_reader.bytes().collect::<Result<_, _>>()?;
46 let pem = pem::parse(bytes)?;
47 let pki_res = PrivateKeyInfo::decode(&mut SliceReader::new(pem.contents())?);
48 let mut truncated;
49 let pki = match pki_res {
50 Ok(pki) => pki,
51 Err(e) => {
52 if e.kind()
53 == (ErrorKind::Noncanonical {
54 tag: Tag::ContextSpecific {
55 constructed: true,
56 number: TagNumber::new(1),
57 },
58 })
59 {
60 truncated = pem.into_contents();
62 if truncated[48..52] != *b"\xA1\x23\x03\x21" {
63 return Err(e.into());
64 }
65 truncated.truncate(48);
67 truncated[1] = 46;
68 truncated[4] = 0;
69 PrivateKeyInfo::decode(&mut SliceReader::new(&truncated)?).map_err(|_| e)?
70 } else {
71 return Err(e.into());
72 }
73 }
74 };
75 let decoded_key = OctetString::from_der(pki.private_key)?; let private_key = SigningKey::try_from(decoded_key.as_bytes())?;
77 Ok(BasicIdentity::from_signing_key(private_key))
78 }
79
80 pub fn from_signing_key(key: SigningKey) -> Self {
82 let public_key = key.verification_key();
83 let der_encoded_public_key = der_encode_public_key(public_key.as_bytes().to_vec());
84
85 Self {
86 private_key: KeyCompat::Standard(key),
87 der_encoded_public_key,
88 }
89 }
90
91 #[cfg(feature = "ring")]
93 pub fn from_key_pair(key_pair: ring::signature::Ed25519KeyPair) -> Self {
94 use ring::signature::KeyPair;
95 let der_encoded_public_key = der_encode_public_key(key_pair.public_key().as_ref().to_vec());
96 Self {
97 private_key: KeyCompat::Ring(key_pair),
98 der_encoded_public_key,
99 }
100 }
101}
102
103enum KeyCompat {
104 Standard(SigningKey),
105 #[cfg(feature = "ring")]
106 Ring(ring::signature::Ed25519KeyPair),
107}
108
109impl KeyCompat {
110 fn sign(&self, payload: &[u8]) -> Vec<u8> {
111 match self {
112 Self::Standard(k) => k.sign(payload).to_bytes().to_vec(),
113 #[cfg(feature = "ring")]
114 Self::Ring(k) => k.sign(payload).as_ref().to_vec(),
115 }
116 }
117}
118
119impl Identity for BasicIdentity {
120 fn sender(&self) -> Result<Principal, String> {
121 Ok(Principal::self_authenticating(&self.der_encoded_public_key))
122 }
123
124 fn public_key(&self) -> Option<Vec<u8>> {
125 Some(self.der_encoded_public_key.clone())
126 }
127
128 fn sign(&self, content: &EnvelopeContent) -> Result<Signature, String> {
129 self.sign_arbitrary(&content.to_request_id().signable())
130 }
131
132 fn sign_delegation(&self, content: &Delegation) -> Result<Signature, String> {
133 self.sign_arbitrary(&content.signable())
134 }
135
136 fn sign_arbitrary(&self, content: &[u8]) -> Result<Signature, String> {
137 let signature = self.private_key.sign(content);
138 Ok(Signature {
139 signature: Some(signature),
140 public_key: self.public_key(),
141 delegations: None,
142 })
143 }
144}
145
146fn der_encode_public_key(public_key: Vec<u8>) -> Vec<u8> {
147 let id_ed25519 = oid!(1, 3, 101, 112);
150 let algorithm = Sequence(0, vec![ObjectIdentifier(0, id_ed25519)]);
151 let subject_public_key = BitString(0, public_key.len() * 8, public_key);
152 let subject_public_key_info = Sequence(0, vec![algorithm, subject_public_key]);
153 to_der(&subject_public_key_info).unwrap()
154}