bitwarden_organization_crypto/
organization_private_key.rs1use bitwarden_crypto::{
8 CryptoError, EncString, KeySlotIds, KeyStoreContext, PublicKey, UnsignedSharedKey,
9};
10use thiserror::Error;
11
12use crate::trust_proof::{CryptographicProof, TrustProof};
13
14#[derive(Debug, Error)]
16pub enum OrganizationPrivateKeyUnwrapError {
17 #[error("The organization's private key could not be unwrapped with the organization key")]
20 UnwrapFailed,
21}
22
23#[derive(Debug, Error)]
25pub enum OrganizationPublicKeyError {
26 #[error("The organization's private key does not exist in the key store context")]
28 MissingPrivateKey,
29}
30
31pub struct OrganizationPrivateKey<Ids: KeySlotIds> {
33 private_key_id: Ids::Private,
34}
35
36impl<Ids: KeySlotIds> OrganizationPrivateKey<Ids> {
37 pub fn unwrap_with_organization_key(
41 organization_key: Ids::Symmetric,
42 wrapped_organization_private_key: &EncString,
43 ctx: &mut KeyStoreContext<Ids>,
44 ) -> Result<Self, OrganizationPrivateKeyUnwrapError> {
45 let private_key_id = ctx
46 .unwrap_private_key(organization_key, wrapped_organization_private_key)
47 .map_err(|_| OrganizationPrivateKeyUnwrapError::UnwrapFailed)?;
48
49 Ok(Self { private_key_id })
50 }
51
52 pub fn from_context(private_key_id: Ids::Private, ctx: &KeyStoreContext<Ids>) -> Option<Self> {
55 ctx.has_private_key(private_key_id)
56 .then_some(Self { private_key_id })
57 }
58
59 pub fn public_key(
61 &self,
62 ctx: &KeyStoreContext<Ids>,
63 ) -> Result<PublicKey, OrganizationPublicKeyError> {
64 ctx.get_public_key(self.private_key_id)
65 .map_err(|_| OrganizationPublicKeyError::MissingPrivateKey)
66 }
67
68 pub fn trust_proof(&self) -> TrustProof<Ids> {
70 TrustProof::CryptographicallyTrusted(CryptographicProof::OwnPrivateKey(self.private_key_id))
71 }
72
73 pub(crate) fn decapsulate_key(
76 &self,
77 encapsulated_key: &UnsignedSharedKey,
78 ctx: &mut KeyStoreContext<Ids>,
79 ) -> Result<Ids::Symmetric, CryptoError> {
80 encapsulated_key.decapsulate(self.private_key_id, ctx)
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use bitwarden_crypto::{
87 KeyStore, PublicKeyEncryptionAlgorithm, SpkiPublicKeyBytes,
88 SymmetricKeyAlgorithm::Aes256CbcHmac,
89 };
90 use bitwarden_encoding::B64;
91
92 use super::*;
93 use crate::test_support::{
94 TEST_VECTOR_V1_WRAPPED_PRIVATE_KEY, TestIds, TestPrivateKey, TestSymmKey,
95 load_v1_test_vectors, unwrap_v1_organization_private_key,
96 };
97
98 const TEST_VECTOR_ORGANIZATION_PUBLIC_KEY: &str = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoNoakr8gAXszoM1FQ1kz3rCXbd/ROcb8JQveiAmYuSCvA3Wx8zLqmYo0Jq6C3gPGxCHLVI4pYA6Pt0M59AlvK4jOiGwSPh1Wt6M+HlGUuBkW3Q3fJ0OwwKDT0WwzuZlmateoxg1Jq91jaVevc7bfsJMD8YFIY/c5nWTWIs5HG/v8ZwQMrdqAO/f7O3SJ4SvetkZqQynbTAL7AfPSVhIQt85mxyvkcAsqnwnmqjmlZsSXas2Ghp9v/5Y1eyLEgNUHyFghrNqbm99LTWnwgUVPhx8ALPkI2H8r4MMEPidZ1vEFURpL513nvFYTqfe2Vzg6JUXNu0w8ikFZh/6CNeXLTQIDAQAB";
100
101 #[test]
102 fn test_unwrapping_with_the_wrong_organization_key_fails() {
103 let key_store = KeyStore::<TestIds>::default();
104 let mut ctx = key_store.context_mut();
105 let wrapped_private_key = load_v1_test_vectors(&mut ctx);
106 let other_organization_key = ctx.make_symmetric_key(Aes256CbcHmac);
107
108 let result = OrganizationPrivateKey::unwrap_with_organization_key(
109 other_organization_key,
110 &wrapped_private_key,
111 &mut ctx,
112 );
113
114 assert!(matches!(
115 result,
116 Err(OrganizationPrivateKeyUnwrapError::UnwrapFailed)
117 ));
118 }
119
120 #[test]
121 fn test_public_key_in_another_context_fails() {
122 let key_store = KeyStore::<TestIds>::default();
123 let mut ctx = key_store.context_mut();
124 let wrapped_private_key = load_v1_test_vectors(&mut ctx);
125 let organization_private_key = OrganizationPrivateKey::unwrap_with_organization_key(
126 TestSymmKey::Organization,
127 &wrapped_private_key,
128 &mut ctx,
129 )
130 .unwrap();
131 let other_key_store = KeyStore::<TestIds>::default();
132 let other_ctx = other_key_store.context();
133
134 let result = organization_private_key.public_key(&other_ctx);
135
136 assert!(matches!(
137 result,
138 Err(OrganizationPublicKeyError::MissingPrivateKey)
139 ));
140 }
141
142 #[test]
143 fn test_unwrapping_a_wrapped_value_that_is_not_a_private_key_fails() {
144 let key_store = KeyStore::<TestIds>::default();
145 let mut ctx = key_store.context_mut();
146 load_v1_test_vectors(&mut ctx);
147 let symmetric_key = ctx.make_symmetric_key(Aes256CbcHmac);
148 let wrapped_symmetric_key = ctx
149 .wrap_symmetric_key(TestSymmKey::Organization, symmetric_key)
150 .unwrap();
151
152 let result = OrganizationPrivateKey::unwrap_with_organization_key(
153 TestSymmKey::Organization,
154 &wrapped_symmetric_key,
155 &mut ctx,
156 );
157
158 assert!(matches!(
159 result,
160 Err(OrganizationPrivateKeyUnwrapError::UnwrapFailed)
161 ));
162 }
163
164 #[test]
165 fn test_persisted_private_key_is_the_organization_private_key() {
166 let key_store = KeyStore::<TestIds>::default();
167 {
168 let mut ctx = key_store.context_mut();
169 let wrapped_private_key = load_v1_test_vectors(&mut ctx);
170 let private_key_id = ctx
171 .unwrap_private_key(TestSymmKey::Organization, &wrapped_private_key)
172 .unwrap();
173 ctx.persist_private_key(private_key_id, TestPrivateKey::Organization)
174 .unwrap();
175 }
176 let ctx = key_store.context();
177
178 let organization_private_key =
179 OrganizationPrivateKey::from_context(TestPrivateKey::Organization, &ctx).unwrap();
180
181 let expected = SpkiPublicKeyBytes::from(
182 B64::try_from(TEST_VECTOR_ORGANIZATION_PUBLIC_KEY)
183 .unwrap()
184 .as_bytes()
185 .to_vec(),
186 );
187 assert_eq!(
188 organization_private_key
189 .public_key(&ctx)
190 .unwrap()
191 .to_der()
192 .unwrap(),
193 expected
194 );
195 }
196
197 #[test]
198 fn test_private_key_missing_from_the_context_is_no_organization_private_key() {
199 let key_store = KeyStore::<TestIds>::default();
200 let ctx = key_store.context();
201
202 let result = OrganizationPrivateKey::from_context(TestPrivateKey::Organization, &ctx);
203
204 assert!(result.is_none());
205 }
206
207 #[test]
208 fn test_unwrapping_with_a_missing_organization_key_fails() {
209 let key_store = KeyStore::<TestIds>::default();
210 let mut ctx = key_store.context_mut();
211 let wrapped_private_key: EncString = TEST_VECTOR_V1_WRAPPED_PRIVATE_KEY.parse().unwrap();
212
213 let result = OrganizationPrivateKey::unwrap_with_organization_key(
214 TestSymmKey::Organization,
215 &wrapped_private_key,
216 &mut ctx,
217 );
218
219 assert!(matches!(
220 result,
221 Err(OrganizationPrivateKeyUnwrapError::UnwrapFailed)
222 ));
223 }
224
225 #[test]
226 fn test_trust_proof_verifies_the_organization_public_key() {
227 let key_store = KeyStore::<TestIds>::default();
228 let mut ctx = key_store.context_mut();
229 let organization_private_key = unwrap_v1_organization_private_key(&mut ctx);
230 let organization_public_key = organization_private_key.public_key(&ctx).unwrap();
231
232 let result = organization_private_key
233 .trust_proof()
234 .verify(&organization_public_key, &ctx);
235
236 assert!(matches!(result, Ok(())));
237 }
238
239 #[test]
240 fn test_decapsulating_a_key_encapsulated_to_the_organization_public_key_opens_the_key() {
241 let key_store = KeyStore::<TestIds>::default();
242 let mut ctx = key_store.context_mut();
243 let organization_private_key = unwrap_v1_organization_private_key(&mut ctx);
244 let symmetric_key = ctx.make_symmetric_key(Aes256CbcHmac);
245 let encapsulated_key = UnsignedSharedKey::encapsulate(
246 symmetric_key,
247 &organization_private_key.public_key(&ctx).unwrap(),
248 &ctx,
249 )
250 .unwrap();
251
252 let decapsulated_key = organization_private_key
253 .decapsulate_key(&encapsulated_key, &mut ctx)
254 .unwrap();
255
256 ctx.assert_symmetric_keys_equal(symmetric_key, decapsulated_key);
257 }
258
259 #[test]
260 fn test_decapsulating_with_a_non_matching_private_key_fails() {
261 let key_store = KeyStore::<TestIds>::default();
262 let mut ctx = key_store.context_mut();
263 let organization_private_key = unwrap_v1_organization_private_key(&mut ctx);
264 let other_private_key = ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
265 let symmetric_key = ctx.make_symmetric_key(Aes256CbcHmac);
266 let encapsulated_key = UnsignedSharedKey::encapsulate(
267 symmetric_key,
268 &ctx.get_public_key(other_private_key).unwrap(),
269 &ctx,
270 )
271 .unwrap();
272
273 let result = organization_private_key.decapsulate_key(&encapsulated_key, &mut ctx);
274
275 assert!(matches!(result, Err(CryptoError::KeyDecrypt)));
276 }
277
278 #[test]
279 fn test_decapsulating_in_another_context_fails() {
280 let key_store = KeyStore::<TestIds>::default();
281 let mut ctx = key_store.context_mut();
282 let organization_private_key = unwrap_v1_organization_private_key(&mut ctx);
283 let symmetric_key = ctx.make_symmetric_key(Aes256CbcHmac);
284 let encapsulated_key = UnsignedSharedKey::encapsulate(
285 symmetric_key,
286 &organization_private_key.public_key(&ctx).unwrap(),
287 &ctx,
288 )
289 .unwrap();
290 let other_key_store = KeyStore::<TestIds>::default();
291 let mut other_ctx = other_key_store.context_mut();
292
293 let result = organization_private_key.decapsulate_key(&encapsulated_key, &mut other_ctx);
294
295 assert!(matches!(result, Err(CryptoError::MissingKeyId(_))));
296 }
297
298 #[test]
299 #[ignore = "Manual test to generate test vectors"]
300 fn generate_test_vectors() {
301 let key_store = KeyStore::<TestIds>::default();
302 let mut ctx = key_store.context_mut();
303 let wrapped_private_key = load_v1_test_vectors(&mut ctx);
304 let organization_private_key = OrganizationPrivateKey::unwrap_with_organization_key(
305 TestSymmKey::Organization,
306 &wrapped_private_key,
307 &mut ctx,
308 )
309 .unwrap();
310
311 let public_key = organization_private_key.public_key(&ctx).unwrap();
312
313 println!(
314 "const TEST_VECTOR_ORGANIZATION_PUBLIC_KEY: &str = \"{}\";",
315 B64::from(public_key.to_der().unwrap())
316 );
317 }
318
319 #[test]
320 fn test_organization_private_key_test_vector() {
321 let key_store = KeyStore::<TestIds>::default();
322 let mut ctx = key_store.context_mut();
323 let wrapped_private_key = load_v1_test_vectors(&mut ctx);
324
325 let organization_private_key = OrganizationPrivateKey::unwrap_with_organization_key(
326 TestSymmKey::Organization,
327 &wrapped_private_key,
328 &mut ctx,
329 )
330 .unwrap();
331
332 let expected = SpkiPublicKeyBytes::from(
333 B64::try_from(TEST_VECTOR_ORGANIZATION_PUBLIC_KEY)
334 .unwrap()
335 .as_bytes()
336 .to_vec(),
337 );
338 assert_eq!(
339 organization_private_key
340 .public_key(&ctx)
341 .unwrap()
342 .to_der()
343 .unwrap(),
344 expected
345 );
346 }
347}