shared/application/key/
signing_key_service.rs1use chrono::Utc;
2
3use crate::error::Result;
4
5use crate::config::AlgorithmConfig;
6use crate::domain::model::{SigningKey, SigningKeys};
7use crate::intern::key::KeyService;
8use crate::utils::crypto::JwtSigner;
9
10impl KeyService {
11 fn generate_keypair(&self) -> (String, String) {
12 self.crypto.openssl.gen_prv_pub_key()
13 }
14 fn build_signingkey(&self, private: &str, public: &str) -> Result<SigningKey> {
15 let algorithm = &self.configuration.auth.jwt()?.algorithm;
16 let kty = match algorithm {
17 AlgorithmConfig::EdDSA => "OKP",
18 AlgorithmConfig::ES256 | AlgorithmConfig::ES384 => "EC",
19 AlgorithmConfig::RS256
20 | AlgorithmConfig::RS384
21 | AlgorithmConfig::RS512
22 | AlgorithmConfig::PS256
23 | AlgorithmConfig::PS384
24 | AlgorithmConfig::PS512 => "RSA",
25 };
26
27 let encrypted_private_key = self.crypto.clone().aes.encrypt(private)?;
28 let kid = super::support::jwk_thumbprint_rsa(public);
29
30 Ok(SigningKey::new(&encrypted_private_key, public)
31 .with_algorithm(algorithm.as_str())
32 .with_kid(&kid)
33 .with_kty(kty))
34 }
35
36 #[tracing::instrument(name = "crypto.insert_signing_keys", skip(self))]
37 pub async fn save_new_key(&self) -> Result<String> {
38 let (private, public) = self.generate_keypair();
39 let key = self.build_signingkey(&private, &public)?;
40
41 self.signing_key_repository.insert(key).await
42 }
43
44 #[tracing::instrument(name = "crypto.find_signing_key", skip(self))]
45 pub async fn load_active_key(&self) -> Result<(String, SigningKey)> {
46 let key = self.signing_key_repository.find().await?;
47
48 let private_key = self
49 .crypto
50 .clone()
51 .aes
52 .decrypt(&key.encrypted_private_key)?;
53
54 Ok((private_key, key))
55 }
56
57 #[tracing::instrument(name = "crypto.find_signing_key", skip(self))]
58 pub async fn find_signing_keys(&self) -> Result<Vec<SigningKeys>> {
59 let signing_keys = self.signing_key_repository.find_valid_keys().await?;
60 let mut data: Vec<SigningKeys> = Vec::new();
61
62 for key in signing_keys {
63 let private_key = self
64 .crypto
65 .clone()
66 .aes
67 .decrypt(&key.encrypted_private_key)?;
68 data.push(SigningKeys { private_key, key })
69 }
70
71 Ok(data)
72 }
73
74 #[tracing::instrument(name = "crypto.find_all_keys", skip(self))]
75 pub async fn list_keys(&self) -> Result<Vec<SigningKey>> {
76 self.signing_key_repository.find_all().await
77 }
78
79 #[tracing::instrument(name = "crypto.rotate_signing_key", skip(self))]
80 pub async fn rotate_signing_key(&self) -> Result<(SigningKey, SigningKey)> {
81 let max_token_ttl = self.configuration.auth.jwt()?.refresh_token_expires_in;
83 let retired_key = self
84 .signing_key_repository
85 .retire_oldkey(max_token_ttl)
86 .await?;
87
88 self.save_new_key().await?;
90 let (private, active_key) = self.load_active_key().await?;
91
92 let jwt = JwtSigner::new(&private, &active_key, self.configuration.auth.jwt()?);
94 self.crypto.rotate_jwt(jwt);
95
96 Ok((retired_key, active_key))
97 }
98
99 #[tracing::instrument(name = "signing_key.prune", skip(self))]
100 pub async fn prune(&self) -> Result<Vec<SigningKey>> {
101 let keys = self.list_keys().await?;
102
103 let mut removed_keys: Vec<SigningKey> = Vec::new();
104 for key in keys {
105 let expired = key.expires_at.map(|dt| Utc::now() > dt).unwrap_or(false);
106 if key.status == "revoked" || expired {
107 let id = key.id()?;
108 self.signing_key_repository.delete(id).await?;
109
110 removed_keys.push(key);
111 }
112 }
113
114 Ok(removed_keys)
115 }
116
117 #[tracing::instrument(name = "signing_key.revoke", skip(self))]
118 pub async fn revoke(&self, id: &str) -> Result<SigningKey> {
119 self.signing_key_repository.revoke_key(id).await
120 }
121}