1use anyhow::{anyhow, Result};
2use async_trait::async_trait;
3
4use rsa::{
5 pkcs1::{DecodeRsaPublicKey, EncodeRsaPublicKey},
6 Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey,
7};
8
9use sha2::{Digest, Sha256};
10use ucan::crypto::{JwtSignatureAlgorithm, KeyMaterial};
11
12pub use ucan::crypto::did::RSA_MAGIC_BYTES;
13
14pub fn bytes_to_rsa_key(bytes: Vec<u8>) -> Result<Box<dyn KeyMaterial>> {
15 println!("Trying to parse RSA key...");
16 let public_key = RsaPublicKey::from_pkcs1_der(&bytes)?;
18
19 Ok(Box::new(RsaKeyMaterial(public_key, None)))
20}
21
22#[derive(Clone)]
23pub struct RsaKeyMaterial(pub RsaPublicKey, pub Option<RsaPrivateKey>);
24
25#[cfg_attr(target_arch="wasm32", async_trait(?Send))]
26#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
27impl KeyMaterial for RsaKeyMaterial {
28 fn get_jwt_algorithm_name(&self) -> String {
29 JwtSignatureAlgorithm::RS256.to_string()
30 }
31
32 async fn get_did(&self) -> Result<String> {
33 let bytes = match self.0.to_pkcs1_der() {
34 Ok(document) => [RSA_MAGIC_BYTES, document.as_bytes()].concat(),
35 Err(error) => {
36 warn!("Could not get RSA public key bytes for DID: {:?}", error);
38 Vec::new()
39 }
40 };
41 Ok(format!("did:key:z{}", bs58::encode(bytes).into_string()))
42 }
43
44 async fn sign(&self, payload: &[u8]) -> Result<Vec<u8>> {
45 let mut hasher = Sha256::new();
46 hasher.update(payload);
47 let hashed = hasher.finalize();
48
49 match &self.1 {
50 Some(private_key) => {
51 let padding = Pkcs1v15Sign::new::<Sha256>();
52 let signature = private_key.sign(padding, hashed.as_ref())?;
53 info!("SIGNED!");
54 Ok(signature)
55 }
56 None => Err(anyhow!("No private key; cannot sign data")),
57 }
58 }
59
60 async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
61 let mut hasher = Sha256::new();
62 hasher.update(payload);
63 let hashed = hasher.finalize();
64 let padding = Pkcs1v15Sign::new::<Sha256>();
65
66 self.0
67 .verify(padding, hashed.as_ref(), signature)
68 .map_err(|error| anyhow!(error))
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::{bytes_to_rsa_key, RsaKeyMaterial, RSA_MAGIC_BYTES};
75
76 use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey, RsaPublicKey};
77 use ucan::{
78 builder::UcanBuilder,
79 crypto::{did::DidParser, KeyMaterial},
80 ucan::Ucan,
81 };
82
83 #[cfg(target_arch = "wasm32")]
84 use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
85
86 #[cfg(target_arch = "wasm32")]
87 wasm_bindgen_test_configure!(run_in_browser);
88
89 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
90 #[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
91 async fn it_can_sign_and_verify_a_ucan() {
92 let private_key =
93 RsaPrivateKey::from_pkcs8_der(include_bytes!("./fixtures/rsa_key.pk8")).unwrap();
94 let public_key = RsaPublicKey::from(&private_key);
95
96 let key_material = RsaKeyMaterial(public_key, Some(private_key));
97 let token_string = UcanBuilder::default()
98 .issued_by(&key_material)
99 .for_audience(key_material.get_did().await.unwrap().as_str())
100 .with_lifetime(60)
101 .build()
102 .unwrap()
103 .sign()
104 .await
105 .unwrap()
106 .encode()
107 .unwrap();
108
109 let mut did_parser = DidParser::new(&[(RSA_MAGIC_BYTES, bytes_to_rsa_key)]);
110
111 let ucan = Ucan::try_from(token_string).unwrap();
112 ucan.check_signature(&mut did_parser).await.unwrap();
113 }
114}