alpine/crypto/
identity.rs1use std::fs::File;
2use std::io::BufReader;
3
4use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey};
5use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
6use ed25519_dalek::{Signer, Verifier};
7use thiserror::Error;
8
9#[derive(Clone)]
11pub struct NodeCredentials {
12 pub signing: SigningKey,
13 pub verifying: VerifyingKey,
14}
15
16#[derive(Debug, Error)]
17pub enum IdentityError {
18 #[error("failed to parse PEM: {0}")]
19 Pem(String),
20 #[error("missing key material in PEM")]
21 MissingKey,
22}
23
24impl NodeCredentials {
25 pub fn load_signing_pem(path: &str) -> Result<SigningKey, IdentityError> {
26 let file = File::open(path).map_err(|e| IdentityError::Pem(e.to_string()))?;
27 let mut reader = BufReader::new(file);
28 let key_der = rustls_pemfile::pkcs8_private_keys(&mut reader)
29 .next()
30 .ok_or(IdentityError::MissingKey)?
31 .map_err(|e| IdentityError::Pem(format!("pkcs8 parse: {}", e)))?;
32 SigningKey::from_pkcs8_der(key_der.secret_pkcs8_der())
33 .map_err(|e| IdentityError::Pem(e.to_string()))
34 }
35
36 pub fn load_verifying_pem(path: &str) -> Result<VerifyingKey, IdentityError> {
37 let file = File::open(path).map_err(|e| IdentityError::Pem(e.to_string()))?;
38 let mut reader = BufReader::new(file);
39 let cert = rustls_pemfile::certs(&mut reader)
40 .next()
41 .ok_or(IdentityError::MissingKey)?
42 .map_err(|e| IdentityError::Pem(format!("cert parse: {}", e)))?;
43 VerifyingKey::from_public_key_der(cert.as_ref())
44 .map_err(|e| IdentityError::Pem(e.to_string()))
45 }
46
47 pub fn sign(&self, data: &[u8]) -> Signature {
48 self.signing.sign(data)
49 }
50
51 pub fn verify(&self, data: &[u8], sig: &Signature) -> bool {
52 self.verifying.verify(data, sig).is_ok()
53 }
54}