Skip to main content

rust_ev_crypto_primitives/
direct_trust.rs

1// Copyright © 2023 Denis Morel
2
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11// details.
12//
13// You should have received a copy of the GNU General Public License and
14// a copy of the GNU General Public License along with this program. If not, see
15// <https://www.gnu.org/licenses/>.
16
17//! Module implementing the direct trust
18
19use super::basic_crypto_functions::{
20    BasisCryptoError, CertificateExtension, Keystore as SslKeystore, SigningCertificate,
21};
22use std::{
23    fs, io,
24    path::{Path, PathBuf},
25};
26use thiserror::Error;
27
28#[derive(Error, Debug)]
29#[error(transparent)]
30/// Error in direct_trust
31pub struct DirectTrustError(#[from] DirectTrustErrorRepr);
32
33#[derive(Error, Debug)]
34enum DirectTrustErrorRepr {
35    #[error("Error reading password file {path}")]
36    ReadPassword { path: PathBuf, source: io::Error },
37    #[error("Error creating the keystore from the file {path}")]
38    KeystoreFromFile {
39        path: PathBuf,
40        source: BasisCryptoError,
41    },
42    #[error("Error creating the keystore from the directory {path}")]
43    KeystoreFromDir {
44        path: PathBuf,
45        source: BasisCryptoError,
46    },
47    #[error("Error getting the public certificate {authority} from the keystore")]
48    PublicCertificate {
49        authority: String,
50        source: BasisCryptoError,
51    },
52    #[error("Error getting the private certificate from the keystore")]
53    PrivateCertificate { source: BasisCryptoError },
54}
55
56/// Struct representing a direct trust
57pub struct Keystore {
58    keystore: SslKeystore,
59}
60
61impl Keystore {
62    /// Read a direct trust keystore from pkcs12
63    pub fn from_pkcs12(
64        keystore_path: &Path,
65        password_file_path: &Path,
66    ) -> Result<Self, DirectTrustError> {
67        let pwd = fs::read_to_string(password_file_path).map_err(|e| {
68            DirectTrustErrorRepr::ReadPassword {
69                path: password_file_path.to_path_buf(),
70                source: e,
71            }
72        })?;
73        Ok(Keystore {
74            keystore: SslKeystore::from_pkcs12(keystore_path, &pwd).map_err(|e| {
75                DirectTrustErrorRepr::KeystoreFromFile {
76                    path: keystore_path.to_path_buf(),
77                    source: e,
78                }
79            })?,
80        })
81    }
82
83    /// Read a direct trust keystore from a directory, where the public key certificates are stored
84    pub fn from_directory(
85        keystore_path: &Path,
86        extension: &CertificateExtension,
87    ) -> Result<Self, DirectTrustError> {
88        let mut ks = SslKeystore::from_directory(keystore_path).map_err(|e| {
89            DirectTrustErrorRepr::KeystoreFromDir {
90                path: keystore_path.to_path_buf(),
91                source: e,
92            }
93        })?;
94        ks.set_certificate_extension(extension);
95        Ok(Self { keystore: ks })
96    }
97
98    /// Read the public certificate with the authority given as parameter
99    pub fn public_certificate(
100        &self,
101        authority: &str,
102    ) -> Result<DirectTrustCertificate, DirectTrustError> {
103        let cert = self
104            .keystore
105            .get_public_certificate(&String::from(authority))
106            .map_err(|e| DirectTrustErrorRepr::PublicCertificate {
107                authority: authority.to_string(),
108                source: e,
109            })?;
110        Ok(DirectTrustCertificate { cert })
111    }
112
113    /// Read the secret key and associated certificate
114    ///
115    /// Return an error if no secret key found in the keystore
116    pub fn secret_key_certificate(&self) -> Result<DirectTrustCertificate, DirectTrustError> {
117        let cert = self
118            .keystore
119            .get_secret_certificate()
120            .map_err(|e| DirectTrustErrorRepr::PrivateCertificate { source: e })?;
121        Ok(DirectTrustCertificate { cert })
122    }
123}
124
125/// Struct representing a direct trust certificate
126#[derive(Clone)]
127pub struct DirectTrustCertificate {
128    cert: SigningCertificate,
129}
130
131impl DirectTrustCertificate {
132    /// Get authority of the certificate
133    pub fn authority(&self) -> &str {
134        self.cert.authority()
135    }
136
137    /// Get the certificate of the authority
138    pub fn signing_certificate(&self) -> &SigningCertificate {
139        &self.cert
140    }
141}
142
143#[cfg(test)]
144mod test {
145    use super::*;
146    use std::path::PathBuf;
147
148    const VERIFIER_KEYSTORE_FILE_NAME: &str = "public_keys_keystore_verifier.p12";
149    const VERIFIER_PASSWORD_FILE_NAME: &str = "public_keys_keystore_verifier_pw.txt";
150    const CANTON_KEYSTORE_FILE_NAME: &str = "signing_keystore_canton.p12";
151    const CANTON_PASSWORD_FILE_NAME: &str = "signing_pw_canton.txt";
152
153    fn get_location() -> PathBuf {
154        Path::new("./").join("test_data").join("direct-trust")
155    }
156
157    #[test]
158    fn test_create_pkcs12() {
159        let dt = Keystore::from_pkcs12(
160            &get_location().join(Path::new(VERIFIER_KEYSTORE_FILE_NAME)),
161            &get_location().join(Path::new(VERIFIER_PASSWORD_FILE_NAME)),
162        )
163        .unwrap();
164        assert!(dt.public_certificate("canton").is_ok());
165        assert!(dt.public_certificate("toto").is_err());
166        assert!(dt.secret_key_certificate().is_err());
167        let dt = Keystore::from_pkcs12(
168            &get_location().join(Path::new(CANTON_KEYSTORE_FILE_NAME)),
169            &get_location().join(Path::new(CANTON_PASSWORD_FILE_NAME)),
170        )
171        .unwrap();
172        assert!(dt.secret_key_certificate().is_ok());
173        let dt_err = Keystore::from_pkcs12(
174            Path::new("./toto"),
175            &get_location().join(Path::new(VERIFIER_PASSWORD_FILE_NAME)),
176        );
177        assert!(dt_err.is_err());
178    }
179
180    #[test]
181    fn test_create_dir() {
182        let dt =
183            Keystore::from_directory(&get_location(), &CertificateExtension::default()).unwrap();
184        //let dt = DirectTrustCertificate::new(, &CertificateAuthority::Canton);
185        assert!(dt.public_certificate("canton").is_ok());
186        assert!(dt.public_certificate("toto").is_err());
187        let dt_err =
188            Keystore::from_directory(Path::new("./toto"), &CertificateExtension::default());
189        assert!(dt_err.is_err());
190    }
191}