brass_aphid_wire_decryption/decryption/
key_manager.rs1use brass_aphid_wire_messages::iana;
2
3use crate::{
4 decryption::{key_space::KeySpace, Mode},
5 key_log::NssLog,
6};
7use std::{
8 collections::HashMap,
9 ffi::c_void,
10 fmt::Debug,
11 pin::Pin,
12 sync::{Arc, Mutex},
13};
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
16struct TlsKeys {
17 pub client_handshake_traffic_secret: Option<Vec<u8>>,
19 pub server_handshake_traffic_secret: Option<Vec<u8>>,
20 pub client_application_traffic_secret: Option<Vec<u8>>,
21 pub server_application_traffic_secret: Option<Vec<u8>>,
22 pub master_secret: Option<Vec<u8>>,
24}
25
26impl TlsKeys {
27 fn update_from_nss_log(&mut self, keys: NssLog) -> anyhow::Result<()> {
28 match keys.label.as_str() {
29 "CLIENT_HANDSHAKE_TRAFFIC_SECRET" => {
30 self.client_handshake_traffic_secret = Some(keys.secret);
31 }
32 "SERVER_HANDSHAKE_TRAFFIC_SECRET" => {
33 self.server_handshake_traffic_secret = Some(keys.secret);
34 }
35 "CLIENT_TRAFFIC_SECRET_0" => {
36 self.client_application_traffic_secret = Some(keys.secret);
37 }
38 "SERVER_TRAFFIC_SECRET_0" => {
39 self.server_application_traffic_secret = Some(keys.secret);
40 }
41 "CLIENT_RANDOM" => {
42 self.master_secret = Some(keys.secret);
43 }
44 _ => {}
45 }
46 Ok(())
47 }
48}
49
50#[derive(Debug, Clone)]
63pub struct KeyManager(Pin<Arc<Mutex<HashMap<Vec<u8>, TlsKeys>>>>);
64
65impl Default for KeyManager {
66 fn default() -> Self {
67 Self::new()
68 }
69}
70
71impl KeyManager {
72 pub fn new() -> Self {
73 let value = Arc::pin(Mutex::new(HashMap::new()));
74 Self(value)
75 }
76
77 pub fn enable_s2n_logging(&self, config: &mut s2n_tls::config::Builder) {
78 unsafe {
79 config
80 .set_key_log_callback(
81 Some(Self::s2n_tls_key_log_cb),
82 self as *const KeyManager as *mut c_void,
83 )
84 .unwrap();
85 }
86 }
87
88 unsafe extern "C" fn s2n_tls_key_log_cb(
89 ctx: *mut std::ffi::c_void,
90 _conn: *mut s2n_tls_sys::s2n_connection,
91 logline: *mut u8,
92 len: usize,
93 ) -> std::ffi::c_int {
94 let handle = &mut *(ctx as *mut Self);
95 let logline = core::slice::from_raw_parts(logline, len);
96
97 handle.parse_key_log_line(logline);
99
100 0
101 }
102
103 pub fn parse_key_log_line(&self, line: &[u8]) {
105 let line = String::from_utf8(line.to_vec()).unwrap();
106 let key = NssLog::from_log_line(&line).unwrap();
107 self.register_key(key);
108 }
109
110 pub fn register_key(&self, key: NssLog) {
111 tracing::debug!("received key {key:?}");
112 self.0
113 .lock()
114 .unwrap()
115 .entry(key.client_random.clone())
116 .or_default()
117 .update_from_nss_log(key)
118 .unwrap();
119 }
120
121 pub fn handshake_space(
123 &self,
124 mode: Mode,
125 client_random: &[u8],
126 cipher: iana::Cipher,
127 ) -> Option<KeySpace> {
128 let key = self.0.lock().unwrap().get(client_random)?.clone();
129 let secret = match mode {
130 Mode::Client => key.client_handshake_traffic_secret?,
131 Mode::Server => key.server_handshake_traffic_secret?,
132 };
133 let space = KeySpace::handshake_traffic_secret(secret, cipher);
134 Some(space)
135 }
136
137 pub fn first_application_space(
142 &self,
143 mode: Mode,
144 client_random: &[u8],
145 cipher: iana::Cipher,
146 ) -> Option<KeySpace> {
147 let key = self.0.lock().unwrap().get(client_random)?.clone();
148 let secret = match mode {
149 Mode::Client => key.client_application_traffic_secret?,
150 Mode::Server => key.server_application_traffic_secret?,
151 };
152 let space = KeySpace::first_traffic_secret(secret, cipher);
153 Some(space)
154 }
155}
156
157impl rustls::KeyLog for KeyManager {
158 fn log(&self, label: &str, client_random: &[u8], secret: &[u8]) {
159 let key = NssLog {
160 label: label.to_string(),
161 client_random: client_random.to_vec(),
162 secret: secret.to_vec(),
163 };
164 self.register_key(key)
165 }
166}