@@ -8,6 +8,8 @@ use thiserror::Error;
8
8
#[ cfg( any( feature = "internal" , feature = "secrets" ) ) ]
9
9
use uuid:: Uuid ;
10
10
11
+ use bitwarden_crypto:: CryptoError ;
12
+
11
13
#[ cfg( any( feature = "internal" , feature = "secrets" ) ) ]
12
14
use crate :: key_management:: { KeyIds , SymmetricKeyId } ;
13
15
use crate :: { error:: UserIdAlreadySetError , MissingPrivateKeyError , VaultLockedError } ;
@@ -28,6 +30,12 @@ pub enum EncryptionSettingsError {
28
30
#[ error( "Invalid private key" ) ]
29
31
InvalidPrivateKey ,
30
32
33
+ #[ error( "Invalid signing key" ) ]
34
+ InvalidSigningKey ,
35
+
36
+ #[ error( "Invalid security state" ) ]
37
+ InvalidSecurityState ,
38
+
31
39
#[ error( transparent) ]
32
40
MissingPrivateKey ( #[ from] MissingPrivateKeyError ) ,
33
41
@@ -48,51 +56,86 @@ impl EncryptionSettings {
48
56
user_key : SymmetricCryptoKey ,
49
57
private_key : EncString ,
50
58
signing_key : Option < EncString > ,
51
- _security_state : Option < SignedSecurityState > ,
59
+ security_state : Option < SignedSecurityState > ,
52
60
store : & KeyStore < KeyIds > ,
53
61
) -> Result < ( ) , EncryptionSettingsError > {
54
- use bitwarden_crypto:: {
55
- AsymmetricCryptoKey , CoseSerializable , CryptoError , KeyDecryptable , SigningKey ,
56
- } ;
62
+ use bitwarden_crypto:: { AsymmetricCryptoKey , KeyDecryptable } ;
57
63
use log:: warn;
58
64
59
- use crate :: key_management:: { AsymmetricKeyId , SigningKeyId , SymmetricKeyId } ;
60
-
61
- let private_key = {
62
- let dec: Vec < u8 > = private_key. decrypt_with_key ( & user_key) ?;
63
-
64
- // FIXME: [PM-11690] - Temporarily ignore invalid private keys until we have a recovery
65
- // process in place.
66
- AsymmetricCryptoKey :: from_der ( & dec)
67
- . map_err ( |_| {
68
- warn ! ( "Invalid private key" ) ;
69
- } )
70
- . ok ( )
65
+ use crate :: key_management:: { AsymmetricKeyId , SymmetricKeyId } ;
71
66
72
- // Some(
73
- // AsymmetricCryptoKey::from_der(&dec)
74
- // .map_err(|_| EncryptionSettingsError::InvalidPrivateKey)?,
75
- // )
67
+ // This is an all-or-nothing check. The server cannot pretend a signing key or security state to be missing, because they are *always* present when the
68
+ // user key is an XChaCha20Poly1305Key. Thus, the server or network cannot lie about the presence of these, because otherwise the entire user account will
69
+ // fail to decrypt.
70
+ let is_v2_user = if let SymmetricCryptoKey :: XChaCha20Poly1305Key ( _) = user_key {
71
+ true
72
+ } else {
73
+ false
76
74
} ;
77
- let signing_key = signing_key
78
- . map ( |key| {
79
- let dec: Vec < u8 > = key. decrypt_with_key ( & user_key) ?;
80
- SigningKey :: from_cose ( dec. as_slice ( ) ) . map_err ( Into :: < CryptoError > :: into)
81
- } )
82
- . transpose ( ) ?;
83
75
84
- // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
85
- #[ allow( deprecated) ]
86
- {
87
- let mut ctx = store. context_mut ( ) ;
88
- ctx. set_symmetric_key ( SymmetricKeyId :: User , user_key) ?;
89
- if let Some ( private_key) = private_key {
76
+ if is_v2_user {
77
+ // For v2 users, we mandate the signing key and security state to be present
78
+ // The private key must also be valid.
79
+
80
+ use bitwarden_crypto:: { security_state:: SecurityState , CoseSerializable , SigningKey } ;
81
+
82
+ // Both of these are required for v2 users
83
+ let signing_key = signing_key. ok_or ( EncryptionSettingsError :: Crypto (
84
+ CryptoError :: SecurityDowngrade ( "Signing key is required for v2 users" . to_string ( ) ) ,
85
+ ) ) ?;
86
+ let security_state = security_state. ok_or ( EncryptionSettingsError :: Crypto (
87
+ CryptoError :: SecurityDowngrade (
88
+ "Security state is required for v2 users" . to_string ( ) ,
89
+ ) ,
90
+ ) ) ?;
91
+
92
+ // Everything MUST decrypt.
93
+ let signing_key: Vec < u8 > = signing_key. decrypt_with_key ( & user_key) ?;
94
+ let signing_key = SigningKey :: from_cose ( & signing_key)
95
+ . map_err ( |_| EncryptionSettingsError :: InvalidSigningKey ) ?;
96
+ let private_key: Vec < u8 > = private_key. decrypt_with_key ( & user_key) ?;
97
+ let private_key = AsymmetricCryptoKey :: from_der ( & private_key)
98
+ . map_err ( |_| EncryptionSettingsError :: InvalidPrivateKey ) ?;
99
+ let _security_state: SecurityState = security_state
100
+ . verify_and_unwrap ( & signing_key. to_verifying_key ( ) )
101
+ . map_err ( |_| EncryptionSettingsError :: InvalidSecurityState ) ?;
102
+
103
+ #[ allow( deprecated) ]
104
+ {
105
+ use crate :: key_management:: SigningKeyId ;
106
+
107
+ let mut ctx = store. context_mut ( ) ;
108
+ ctx. set_symmetric_key ( SymmetricKeyId :: User , user_key) ?;
90
109
ctx. set_asymmetric_key ( AsymmetricKeyId :: UserPrivateKey , private_key) ?;
91
- }
92
-
93
- if let Some ( signing_key) = signing_key {
94
110
ctx. set_signing_key ( SigningKeyId :: UserSigningKey , signing_key) ?;
95
111
}
112
+ } else {
113
+ let private_key = {
114
+ let dec: Vec < u8 > = private_key. decrypt_with_key ( & user_key) ?;
115
+
116
+ // FIXME: [PM-11690] - Temporarily ignore invalid private keys until we have a recovery
117
+ // process in place.
118
+ AsymmetricCryptoKey :: from_der ( & dec)
119
+ . map_err ( |_| {
120
+ warn ! ( "Invalid private key" ) ;
121
+ } )
122
+ . ok ( )
123
+
124
+ // Some(
125
+ // AsymmetricCryptoKey::from_der(&dec)
126
+ // .map_err(|_| EncryptionSettingsError::InvalidPrivateKey)?,
127
+ // )
128
+ } ;
129
+
130
+ // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
131
+ #[ allow( deprecated) ]
132
+ {
133
+ let mut ctx = store. context_mut ( ) ;
134
+ ctx. set_symmetric_key ( SymmetricKeyId :: User , user_key) ?;
135
+ if let Some ( private_key) = private_key {
136
+ ctx. set_asymmetric_key ( AsymmetricKeyId :: UserPrivateKey , private_key) ?;
137
+ }
138
+ }
96
139
}
97
140
98
141
Ok ( ( ) )
0 commit comments