@@ -30,6 +30,7 @@ use self::storage::default::SQLiteStorageType;
3030use self :: storage:: plugged:: PluggedStorageType ;
3131use self :: wallet:: { Wallet , Keys , Tags } ;
3232use self :: indy_crypto:: utils:: json:: { JsonDecodable , JsonEncodable } ;
33+ use utils:: crypto:: pwhash_argon2i13:: PwhashArgon2i13 ;
3334
3435
3536#[ derive( Serialize , Deserialize , Debug ) ]
@@ -63,10 +64,10 @@ impl<'a> JsonDecodable<'a> for WalletConfig {}
6364#[ derive( Debug ) ]
6465pub struct WalletCredentials {
6566 master_key : [ u8 ; 32 ] ,
67+ rekey : Option < [ u8 ; 32 ] > ,
6668 storage_credentials : String ,
6769}
6870
69- use utils:: crypto:: pwhash_argon2i13:: PwhashArgon2i13 ;
7071
7172impl WalletCredentials {
7273 fn from_json ( json : & str , salt : & [ u8 ; PwhashArgon2i13 :: SALTBYTES ] ) -> Result < WalletCredentials , WalletError > {
@@ -79,6 +80,14 @@ impl WalletCredentials {
7980 return Err ( WalletError :: CommonError ( CommonError :: InvalidStructure ( String :: from ( "Credentials missing 'key' field" ) ) ) ) ;
8081 } ;
8182
83+ let rekey = if let Some ( key) = m. get ( "rekey" ) . and_then ( |s| s. as_str ( ) ) {
84+ let mut rekey: [ u8 ; ChaCha20Poly1305IETF :: KEYBYTES ] = [ 0 ; ChaCha20Poly1305IETF :: KEYBYTES ] ;
85+ PwhashArgon2i13 :: derive_key ( & mut rekey, key. as_bytes ( ) , salt) ?;
86+ Some ( rekey)
87+ } else {
88+ None
89+ } ;
90+
8291 let storage_credentials = serde_json:: to_string (
8392 & m. get ( "storage_credentials" )
8493 . and_then ( |storage_credentials| storage_credentials. as_object ( ) )
@@ -87,6 +96,7 @@ impl WalletCredentials {
8796
8897 Ok ( WalletCredentials {
8998 master_key,
99+ rekey,
90100 storage_credentials
91101 } )
92102 } else {
@@ -274,8 +284,7 @@ impl WalletService {
274284 let config = serde_json:: from_str :: < WalletConfig > ( & config_json)
275285 . map_err ( |err| CommonError :: InvalidState ( format ! ( "Cannot deserialize Storage Config" ) ) ) ?;
276286
277- let credentials = WalletCredentials :: from_json ( credentials, & config. salt ) ?
278- ;
287+ let credentials = WalletCredentials :: from_json ( credentials, & config. salt ) ?;
279288 let storage = storage_type. open_storage ( name,
280289 Some ( & config_json) ,
281290 & credentials. storage_credentials ) ?;
@@ -288,9 +297,13 @@ impl WalletService {
288297 Ok ( keys_vector) => keys_vector,
289298 Err ( _) => return Err ( WalletError :: AccessFailed ( "Invalid master key provided" . to_string ( ) ) ) ,
290299 } ;
300+
291301 let keys = Keys :: new ( keys_vector) ;
292302
293303 let wallet = Wallet :: new ( name, & descriptor. pool_name , storage, keys) ;
304+ if let Some ( ref rekey) = credentials. rekey {
305+ wallet. rotate_key ( & rekey[ ..] ) ?;
306+ }
294307 let wallet_handle = SequenceUtils :: get_next_id ( ) ;
295308 wallets. insert ( wallet_handle, Box :: new ( wallet) ) ;
296309
@@ -727,6 +740,14 @@ mod tests {
727740 String :: from ( r#"{"key":"my_key"}"# )
728741 }
729742
743+ fn _rekey_credentials ( ) -> String {
744+ String :: from ( r#"{"key":"my_key", "rekey": "my_new_key"}"# )
745+ }
746+
747+ fn _credentials_for_new_key ( ) -> String {
748+ String :: from ( r#"{"key": "my_new_key"}"# )
749+ }
750+
730751 fn _cleanup ( ) {
731752 let mut path = std:: env:: home_dir ( ) . unwrap ( ) ;
732753 path. push ( ".indy_client" ) ;
@@ -877,6 +898,16 @@ mod tests {
877898 wallet_service. create_wallet ( "pool1" , "test_wallet" , None , None , & _credentials ( ) ) . unwrap ( ) ;
878899 wallet_service. open_wallet ( "test_wallet" , None , & _credentials ( ) ) . unwrap ( ) ;
879900 }
901+
902+ #[ test]
903+ fn wallet_service_open_wallet_without_master_key_in_credentials_returns_error ( ) {
904+ _cleanup ( ) ;
905+
906+ let wallet_service = WalletService :: new ( ) ;
907+ wallet_service. create_wallet ( "pool1" , "test_wallet" , None , None , & _credentials ( ) ) . unwrap ( ) ;
908+ let res = wallet_service. open_wallet ( "test_wallet" , None , "{}" ) ;
909+ assert_match ! ( Err ( WalletError :: InputError ( _) ) , res) ;
910+ }
880911 //
881912 // // #[test]
882913 // // fn wallet_service_open_works_for_plugged() {
@@ -1509,4 +1540,39 @@ mod tests {
15091540 let get_pool_name_res = wallet_service. get_pool_name ( 1 ) ;
15101541 assert_match ! ( Err ( WalletError :: InvalidHandle ( _) ) , get_pool_name_res) ;
15111542 }
1543+
1544+ /**
1545+ Key rotation test
1546+ */
1547+ #[ test]
1548+ fn wallet_service_key_rotation ( ) {
1549+ _cleanup ( ) ;
1550+
1551+ let wallet_service = WalletService :: new ( ) ;
1552+ wallet_service. create_wallet ( "pool1" , "test_wallet" , None , None , & _credentials ( ) ) . unwrap ( ) ;
1553+ let wallet_handle = wallet_service. open_wallet ( "test_wallet" , None , & _credentials ( ) ) . unwrap ( ) ;
1554+
1555+ wallet_service. add_record ( wallet_handle, "type" , "key1" , "value1" , "{}" ) . unwrap ( ) ;
1556+ let record = wallet_service. get_record ( wallet_handle, "type" , "key1" , & _fetch_options ( true , true , true ) ) . unwrap ( ) ;
1557+ assert_eq ! ( "type" , record. get_type( ) . unwrap( ) ) ;
1558+ assert_eq ! ( "value1" , record. get_value( ) . unwrap( ) ) ;
1559+
1560+ wallet_service. close_wallet ( wallet_handle) . unwrap ( ) ;
1561+
1562+ let wallet_handle = wallet_service. open_wallet ( "test_wallet" , None , & _rekey_credentials ( ) ) . unwrap ( ) ;
1563+ let record = wallet_service. get_record ( wallet_handle, "type" , "key1" , & _fetch_options ( true , true , true ) ) . unwrap ( ) ;
1564+ assert_eq ! ( "type" , record. get_type( ) . unwrap( ) ) ;
1565+ assert_eq ! ( "value1" , record. get_value( ) . unwrap( ) ) ;
1566+ wallet_service. close_wallet ( wallet_handle) . unwrap ( ) ;
1567+
1568+ // Access failed for old key
1569+ let res = wallet_service. open_wallet ( "test_wallet" , None , & _credentials ( ) ) ;
1570+ assert_match ! ( Err ( WalletError :: AccessFailed ( _) ) , res) ;
1571+
1572+ // Works ok with new key when reopening
1573+ let wallet_handle = wallet_service. open_wallet ( "test_wallet" , None , & _credentials_for_new_key ( ) ) . unwrap ( ) ;
1574+ let record = wallet_service. get_record ( wallet_handle, "type" , "key1" , & _fetch_options ( true , true , true ) ) . unwrap ( ) ;
1575+ assert_eq ! ( "type" , record. get_type( ) . unwrap( ) ) ;
1576+ assert_eq ! ( "value1" , record. get_value( ) . unwrap( ) ) ;
1577+ }
15121578}
0 commit comments