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
|
/// Implement UCAN KeyMaterial trait for p256
///
/// This is needed because the 'ucan-key-support' crate does not include support for this key type.
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use p256::ecdsa::signature::{Signer, Verifier};
use p256::ecdsa::{Signature, SigningKey as P256PrivateKey, VerifyingKey as P256PublicKey};
use ucan::crypto::KeyMaterial;
pub use ucan::crypto::{did::P256_MAGIC_BYTES, JwtSignatureAlgorithm};
pub fn bytes_to_p256_key(bytes: Vec<u8>) -> Result<Box<dyn KeyMaterial>> {
let public_key = P256PublicKey::try_from(bytes.as_slice())?;
Ok(Box::new(P256KeyMaterial(public_key, None)))
}
#[derive(Clone)]
pub struct P256KeyMaterial(pub P256PublicKey, pub Option<P256PrivateKey>);
#[cfg_attr(target_arch="wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl KeyMaterial for P256KeyMaterial {
fn get_jwt_algorithm_name(&self) -> String {
JwtSignatureAlgorithm::ES256.to_string()
}
async fn get_did(&self) -> Result<String> {
let bytes = [
P256_MAGIC_BYTES,
&self.0.to_encoded_point(true).to_bytes().to_vec(),
]
.concat();
Ok(format!("did:key:z{}", bs58::encode(bytes).into_string()))
}
async fn sign(&self, payload: &[u8]) -> Result<Vec<u8>> {
match self.1 {
Some(ref private_key) => {
let signature = private_key.sign(payload);
Ok(signature.to_vec())
}
None => Err(anyhow!("No private key; cannot sign data")),
}
}
async fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<()> {
let signature = Signature::try_from(signature)?;
self.0
.verify(payload, &signature)
.map_err(|error| anyhow!("Could not verify signature: {:?}", error))
}
}
#[cfg(test)]
mod tests {
use super::{bytes_to_p256_key, P256KeyMaterial, P256_MAGIC_BYTES};
use p256::ecdsa::signature::{Signer, Verifier};
use p256::ecdsa::{SigningKey as P256PrivateKey, VerifyingKey as P256PublicKey};
use ucan::{
builder::UcanBuilder,
crypto::{did::DidParser, KeyMaterial},
ucan::Ucan,
};
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
async fn it_can_sign_and_verify_a_ucan() {
let private_key = P256PrivateKey::random(&mut p256::elliptic_curve::rand_core::OsRng);
let public_key = P256PublicKey::from(&private_key);
let key_material = P256KeyMaterial(public_key, Some(private_key));
let token_string = UcanBuilder::default()
.issued_by(&key_material)
.for_audience(key_material.get_did().await.unwrap().as_str())
.with_lifetime(60)
.build()
.unwrap()
.sign()
.await
.unwrap()
.encode()
.unwrap();
let mut did_parser = DidParser::new(&[(P256_MAGIC_BYTES, bytes_to_p256_key)]);
let ucan = Ucan::try_from_token_string(&token_string).unwrap();
ucan.check_signature(&mut did_parser).await.unwrap();
}
}
|