matc/
certmanager.rs

1//! Certificate manager trait and default file based implementation
2
3use std::sync::Arc;
4
5use anyhow::{Context, Result};
6
7use crate::{cert_x509, util::cryptoutil};
8
9pub trait CertManager: Send + Sync {
10    fn get_ca_cert(&self) -> Result<Vec<u8>>;
11    fn get_ca_key(&self) -> Result<p256::SecretKey>;
12    fn get_ca_public_key(&self) -> Result<Vec<u8>>;
13    fn get_user_cert(&self, id: u64) -> Result<Vec<u8>>;
14    fn get_user_key(&self, id: u64) -> Result<p256::SecretKey>;
15    fn get_fabric_id(&self) -> u64;
16}
17
18/// Example implementation of [CertManager] trait.
19/// It stores keys and certificates in PEM files in specified directory.
20pub struct FileCertManager {
21    fabric_id: u64,
22    path: String,
23}
24
25impl FileCertManager {
26    pub fn new(fabric_id: u64, path: &str) -> Arc<Self> {
27        Arc::new(Self {
28            fabric_id,
29            path: path.to_owned(),
30        })
31    }
32    pub fn load(path: &str) -> Result<Arc<Self>> {
33        let fname = format!("{}/metadata.pem", path);
34        let fabric_str =
35            std::fs::read_to_string(&fname).context(format!("can't read from {}", fname))?;
36        let fabric_id = fabric_str.parse::<u64>()?;
37        Ok(Arc::new(Self {
38            fabric_id,
39            path: path.to_owned(),
40        }))
41    }
42    fn user_key_fname(&self, id: u64) -> String {
43        format!("{}/{}-private.pem", self.path, id)
44    }
45    fn ca_key_fname(&self) -> String {
46        format!("{}/ca-private.pem", self.path)
47    }
48    fn user_cert_fname(&self, id: u64) -> String {
49        format!("{}/{}-cert.pem", self.path, id)
50    }
51    fn ca_cert_fname(&self) -> String {
52        format!("{}/ca-cert.pem", self.path)
53    }
54    fn metadata_fname(&self) -> String {
55        format!("{}/metadata.pem", self.path)
56    }
57}
58
59const CA_NODE_ID: u64 = 1;
60
61/*fn extract_fabric_id(fname: &str) -> Result<u64> {
62    let x509_raw = cryptoutil::read_data_from_pem(fname)?;
63    let x509 = x509_cert::Certificate::from_der(&x509_raw)?;
64    let subject = x509.tbs_certificate.subject;
65    for rdn in subject.0 {
66        for av in rdn.0.as_slice() {
67            if av.oid == const_oid::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.37244.1.5") {
68                let valstr = av.value.decode_as::<String>()?;
69                return Ok(u64::from_str_radix(&valstr, 16)?)
70            }
71        }
72    };
73    Err(anyhow::anyhow!("can't extract fabric id"))
74}*/
75
76impl FileCertManager {
77    /// Initialize CA. Create directory, generate CA key and certificate and store them in specified directory.
78    /// Directory must not exist before calling this function. If it exists function will fail.
79    pub fn bootstrap(&self) -> Result<()> {
80        std::fs::create_dir(&self.path)?;
81
82        let secret_key = p256::SecretKey::random(&mut rand::thread_rng());
83        let data = cryptoutil::secret_key_to_rfc5915(&secret_key)?;
84        let pem = pem::Pem::new("EC PRIVATE KEY", data);
85        std::fs::write(self.ca_key_fname(), pem::encode(&pem).as_bytes())?;
86        let node_public_key = secret_key.public_key().to_sec1_bytes();
87
88        let x509 = cert_x509::encode_x509(
89            &node_public_key,
90            CA_NODE_ID,
91            self.fabric_id,
92            CA_NODE_ID,
93            &secret_key,
94            true,
95        )?;
96        cryptoutil::write_pem("CERTIFICATE", &x509, &self.ca_cert_fname())?;
97        std::fs::write(self.metadata_fname(), format!("{}", self.fabric_id))?;
98        Ok(())
99    }
100
101    /// Create key and certificate for specified node identifier.
102    /// This can be used as credentials for admin(and any additional) user controlling devices.
103    pub fn create_user(&self, id: u64) -> Result<()> {
104        let ca_private = self.get_ca_key()?;
105        let secret_key = p256::SecretKey::random(&mut rand::thread_rng());
106        let data = cryptoutil::secret_key_to_rfc5915(&secret_key)?;
107        let pem = pem::Pem::new("EC PRIVATE KEY", data);
108        std::fs::write(self.user_key_fname(id), pem::encode(&pem).as_bytes())?;
109        let node_public_key = secret_key.public_key().to_sec1_bytes();
110
111        let x509 = cert_x509::encode_x509(
112            &node_public_key,
113            id,
114            self.fabric_id,
115            CA_NODE_ID,
116            &ca_private,
117            false,
118        )?;
119        cryptoutil::write_pem("CERTIFICATE", &x509, &self.user_cert_fname(id))?;
120        Ok(())
121    }
122}
123
124impl CertManager for FileCertManager {
125    fn get_ca_cert(&self) -> Result<Vec<u8>> {
126        cryptoutil::read_data_from_pem(&self.ca_cert_fname())
127    }
128
129    fn get_ca_key(&self) -> Result<p256::SecretKey> {
130        cryptoutil::read_private_key_from_pem(&self.ca_key_fname())
131    }
132
133    fn get_user_cert(&self, id: u64) -> Result<Vec<u8>> {
134        cryptoutil::read_data_from_pem(&self.user_cert_fname(id))
135    }
136
137    fn get_user_key(&self, id: u64) -> Result<p256::SecretKey> {
138        cryptoutil::read_private_key_from_pem(&self.user_key_fname(id))
139    }
140
141    fn get_ca_public_key(&self) -> Result<Vec<u8>> {
142        Ok(self.get_ca_key()?.public_key().to_sec1_bytes().to_vec())
143    }
144
145    fn get_fabric_id(&self) -> u64 {
146        self.fabric_id
147    }
148}