rust_rcs_core/security/
mod.rs1pub mod aka;
16pub mod authentication;
17pub mod gba;
18
19use std::sync::{Arc, Mutex};
20
21use cached::{Cached, TimedSizedCache};
22
23use crate::internet::{syntax, Header};
24use crate::util::rand;
25
26use self::authentication::authentication_info::AsAuthenticationInfo;
27use self::{
28 authentication::digest::{DigestAnswerParams, DigestChallenge, DigestCredentials},
29 gba::{get_gba_realm, GbaContext},
30};
31
32pub struct CachedDigestParameter {
33 pub algorithm: Vec<u8>,
34 pub realm: Vec<u8>,
35 pub uri: Vec<u8>,
36 pub qop: Option<Vec<u8>>,
37 pub next_nonce: Vec<u8>,
38}
39
40pub struct SecurityContext {
41 cache: Arc<Mutex<TimedSizedCache<String, CachedDigestParameter>>>,
42}
43
44impl SecurityContext {
45 pub fn new() -> SecurityContext {
46 SecurityContext {
47 cache: Arc::new(Mutex::new(
48 TimedSizedCache::with_size_and_lifespan_and_refresh(32, 60 * 60, true),
49 )),
50 }
51 }
52
53 pub fn preload_auth(
54 &self,
55 gba_context: &Arc<GbaContext>,
56 host: &str,
57 cipher_id: Option<(u8, u8)>,
58 method: &[u8],
59 body_digest: Option<&[u8]>,
60 ) -> Option<DigestAnswerParams> {
61 if let Some(param) = self.cache.lock().unwrap().cache_get(host) {
62 if let Some(_) = get_gba_realm(¶m.realm) {
63 if let Some(bootstrapped_context) = gba_context.try_get_bootstrapped_context() {
64 if let Ok(credential) =
65 bootstrapped_context.get_credential(host.as_bytes(), cipher_id)
66 {
67 let cnonce = rand::create_raw_alpha_numeric_string(16);
68 let nc = bootstrapped_context.increase_and_get_use_count();
69
70 let digest_answer = DigestAnswerParams {
71 realm: syntax::unquote(¶m.realm).to_vec(),
72 algorithm: Some(param.algorithm.to_vec()),
73
74 username: credential.username,
75 uri: syntax::unquote(¶m.uri).to_vec(),
76
77 challenge: Some(DigestChallenge {
78 realm: param.realm.to_vec(),
79 nonce: param.next_nonce.to_vec(),
80 algorithm: param.algorithm.to_vec(),
81 domain: None,
82 opaque: None,
83 qop: param.qop.clone(),
84 }),
85
86 credentials: Some(DigestCredentials {
87 password: credential.password,
88 client_data: Some(method.to_vec()),
89 client_nonce: Some((cnonce, nc)),
90 entity_digest: match body_digest {
91 Some(body_digest) => Some(body_digest.to_vec()),
92 None => None,
93 },
94 extra_params: Vec::new(),
95 }),
96 };
97
98 return Some(digest_answer);
99 }
100 }
101 }
102 }
103
104 None
105 }
106
107 pub fn update_auth_info(
108 &self,
109 authentication_info_header: &Header,
110 host: &str,
111 uri: &[u8],
112 challenge: &DigestChallenge,
113 have_entity: bool,
114 ) {
115 let authentication_info = authentication_info_header
116 .get_value()
117 .as_authentication_info();
118 if let Some(next_nonce) = authentication_info.next_nonce {
119 self.cache.lock().unwrap().cache_set(
120 String::from(host),
121 CachedDigestParameter {
122 algorithm: challenge.algorithm.to_vec(),
123 realm: challenge.realm.to_vec(),
124 uri: uri.to_vec(),
125 qop: match challenge.as_challenge_param().preferred_qop(have_entity) {
126 Some(qop) => Some(qop.to_vec()),
127 None => None,
128 },
129 next_nonce: next_nonce.to_vec(),
130 },
131 );
132 }
133 }
134}