|
12 | 12 | // See the License for the specific language governing permissions and |
13 | 13 | // limitations under the License. |
14 | 14 |
|
| 15 | +use hmac::{Hmac, Mac}; |
15 | 16 | use log::info; |
16 | 17 | use orpc::common::Utils; |
17 | 18 | use orpc::{err_msg, CommonResult}; |
18 | | -use sha2::{Digest, Sha256}; |
| 19 | +use sha2::Sha256; |
19 | 20 | use std::collections::HashMap; |
20 | 21 | use std::process::{Command, Stdio}; |
21 | 22 |
|
| 23 | +type PolicyHmac = Hmac<Sha256>; |
| 24 | + |
22 | 25 | pub struct CommonUtils; |
23 | 26 |
|
24 | 27 | impl CommonUtils { |
@@ -67,18 +70,19 @@ impl CommonUtils { |
67 | 70 | if secret.trim().is_empty() { |
68 | 71 | return String::new(); |
69 | 72 | } |
70 | | - let mut hasher = Sha256::new(); |
71 | | - Self::update_signing_segment(&mut hasher, secret); |
72 | | - Self::update_signing_segment(&mut hasher, &version.to_string()); |
73 | | - Self::update_signing_segment(&mut hasher, &peer_whitelist.len().to_string()); |
| 73 | + let Ok(mut mac) = PolicyHmac::new_from_slice(secret.as_bytes()) else { |
| 74 | + return String::new(); |
| 75 | + }; |
| 76 | + Self::update_signing_segment(&mut mac, &version.to_string()); |
| 77 | + Self::update_signing_segment(&mut mac, &peer_whitelist.len().to_string()); |
74 | 78 | for peer in peer_whitelist { |
75 | | - Self::update_signing_segment(&mut hasher, peer); |
| 79 | + Self::update_signing_segment(&mut mac, peer); |
76 | 80 | } |
77 | | - Self::update_signing_segment(&mut hasher, &tenant_whitelist.len().to_string()); |
| 81 | + Self::update_signing_segment(&mut mac, &tenant_whitelist.len().to_string()); |
78 | 82 | for tenant in tenant_whitelist { |
79 | | - Self::update_signing_segment(&mut hasher, tenant); |
| 83 | + Self::update_signing_segment(&mut mac, tenant); |
80 | 84 | } |
81 | | - let digest = hasher.finalize(); |
| 85 | + let digest = mac.finalize().into_bytes(); |
82 | 86 | digest.iter().map(|v| format!("{:02x}", v)).collect() |
83 | 87 | } |
84 | 88 |
|
@@ -121,17 +125,48 @@ impl CommonUtils { |
121 | 125 | }) |
122 | 126 | } |
123 | 127 |
|
124 | | - fn update_signing_segment(hasher: &mut Sha256, value: &str) { |
125 | | - hasher.update(value.len().to_string().as_bytes()); |
126 | | - hasher.update(b":"); |
127 | | - hasher.update(value.as_bytes()); |
128 | | - hasher.update(b"\n"); |
| 128 | + fn update_signing_segment(mac: &mut PolicyHmac, value: &str) { |
| 129 | + mac.update(value.len().to_string().as_bytes()); |
| 130 | + mac.update(b":"); |
| 131 | + mac.update(value.as_bytes()); |
| 132 | + mac.update(b"\n"); |
129 | 133 | } |
130 | 134 | } |
131 | 135 |
|
132 | 136 | #[cfg(test)] |
133 | 137 | mod tests { |
134 | 138 | use super::CommonUtils; |
| 139 | + use sha2::{Digest, Sha256}; |
| 140 | + |
| 141 | + fn legacy_prefix_signature( |
| 142 | + secret: &str, |
| 143 | + version: u64, |
| 144 | + peer_whitelist: &[String], |
| 145 | + tenant_whitelist: &[String], |
| 146 | + ) -> String { |
| 147 | + fn update_segment(hasher: &mut Sha256, value: &str) { |
| 148 | + hasher.update(value.len().to_string().as_bytes()); |
| 149 | + hasher.update(b":"); |
| 150 | + hasher.update(value.as_bytes()); |
| 151 | + hasher.update(b"\n"); |
| 152 | + } |
| 153 | + let mut hasher = Sha256::new(); |
| 154 | + update_segment(&mut hasher, secret); |
| 155 | + update_segment(&mut hasher, &version.to_string()); |
| 156 | + update_segment(&mut hasher, &peer_whitelist.len().to_string()); |
| 157 | + for peer in peer_whitelist { |
| 158 | + update_segment(&mut hasher, peer); |
| 159 | + } |
| 160 | + update_segment(&mut hasher, &tenant_whitelist.len().to_string()); |
| 161 | + for tenant in tenant_whitelist { |
| 162 | + update_segment(&mut hasher, tenant); |
| 163 | + } |
| 164 | + hasher |
| 165 | + .finalize() |
| 166 | + .iter() |
| 167 | + .map(|v| format!("{:02x}", v)) |
| 168 | + .collect() |
| 169 | + } |
135 | 170 |
|
136 | 171 | #[test] |
137 | 172 | fn p2p_policy_signature_roundtrip() { |
@@ -169,4 +204,13 @@ mod tests { |
169 | 204 | &signatures |
170 | 205 | )); |
171 | 206 | } |
| 207 | + |
| 208 | + #[test] |
| 209 | + fn p2p_policy_signature_should_not_use_legacy_prefix_hash() { |
| 210 | + let peers = vec!["peer-a".to_string()]; |
| 211 | + let tenants = vec!["tenant-a".to_string(), "tenant-b".to_string()]; |
| 212 | + let hmac_signature = CommonUtils::sign_p2p_policy("secret", 7, &peers, &tenants); |
| 213 | + let legacy_signature = legacy_prefix_signature("secret", 7, &peers, &tenants); |
| 214 | + assert_ne!(hmac_signature, legacy_signature); |
| 215 | + } |
172 | 216 | } |
0 commit comments