Skip to content

Commit f9b2f04

Browse files
committed
Accept only a required authority. Redirection into stronger authorities is not accepted
1 parent d70d232 commit f9b2f04

33 files changed

+1006
-570
lines changed

libraries/chain/database.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -4400,7 +4400,8 @@ void database::validate_transaction(const std::shared_ptr<full_transaction_type>
44004400
const flat_set<public_key_type>& signature_keys = full_transaction->get_signature_keys();
44014401
const required_authorities_type& required_authorities = full_transaction->get_required_authorities();
44024402

4403-
hive::protocol::verify_authority(required_authorities,
4403+
hive::protocol::verify_authority(has_hardfork( HIVE_HARDFORK_1_28_STRICT_AUTHORITY_LEVEL ),
4404+
required_authorities,
44044405
signature_keys,
44054406
get_active,
44064407
get_owner,

libraries/plugins/apis/database_api/database_api.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,7 @@ DEFINE_API_IMPL( database_api_impl, get_potential_signatures )
17951795
DEFINE_API_IMPL( database_api_impl, verify_authority )
17961796
{
17971797
args.trx.verify_authority(
1798+
_db.has_hardfork( HIVE_HARDFORK_1_28_STRICT_AUTHORITY_LEVEL ),
17981799
_db.get_chain_id(),
17991800
[&]( string account_name ){ return authority( _db.get< chain::account_authority_object, chain::by_account >( account_name ).active ); },
18001801
[&]( string account_name ){ return authority( _db.get< chain::account_authority_object, chain::by_account >( account_name ).owner ); },
@@ -1827,6 +1828,7 @@ DEFINE_API_IMPL( database_api_impl, verify_account_authority )
18271828
}
18281829

18291830
bool ok = hive::protocol::has_authorization(
1831+
_db.has_hardfork( HIVE_HARDFORK_1_28_STRICT_AUTHORITY_LEVEL ),
18301832
required_authorities,
18311833
args.signers,
18321834
[&]( string account_name ) { return authority( _db.get< chain::account_authority_object, chain::by_account >( account_name ).active ); },
@@ -1856,6 +1858,7 @@ DEFINE_API_IMPL( database_api_impl, verify_signatures )
18561858
try
18571859
{
18581860
hive::protocol::verify_authority< verify_signatures_args >(
1861+
_db.has_hardfork( HIVE_HARDFORK_1_28_STRICT_AUTHORITY_LEVEL ),
18591862
{ args },
18601863
sig_keys,
18611864
[this]( const string& name ) { return authority( _db.get< chain::account_authority_object, chain::by_account >( name ).owner ); },

libraries/plugins/colony/colony_plugin.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ void colony_plugin_impl::start( uint32_t block_num )
626626
required_authorities_type required_authorities;
627627
required_authorities.required_active.insert( account.get_name() );
628628

629-
if( hive::protocol::has_authorization( required_authorities, common_keys, get_active, get_owner, get_posting, get_witness_key ) )
629+
if( hive::protocol::has_authorization( _db.has_hardfork( HIVE_HARDFORK_1_28_STRICT_AUTHORITY_LEVEL ), required_authorities, common_keys, get_active, get_owner, get_posting, get_witness_key ) )
630630
{
631631
if( i < _max_threads )
632632
threadI = _threads.emplace( _threads.end(), *this, (uint8_t)i );

libraries/protocol/hardfork.d/1_28.hf

+2
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,7 @@ long next_hf_time();
2525
#define HIVE_HARDFORK_1_28_GLOBAL_WITNESS_PROPS (HIVE_HARDFORK_1_28)
2626
// expiration time for a transaction is longer
2727
#define HIVE_HARDFORK_1_28_EXPIRATION_TIME (HIVE_HARDFORK_1_28)
28+
// accept only required authority. Redirection into stronger authorities is not accepted
29+
#define HIVE_HARDFORK_1_28_STRICT_AUTHORITY_LEVEL (HIVE_HARDFORK_1_28)
2830

2931
#endif

libraries/protocol/include/hive/protocol/sign_state.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct sign_state
2929
const authority_getter& a,
3030
const flat_set<public_key_type>& keys );
3131

32-
const authority_getter& get_active;
32+
const authority_getter& get_current_authority;
3333
const flat_set<public_key_type>& available_keys;
3434

3535
flat_map<public_key_type,bool> provided_signatures;

libraries/protocol/include/hive/protocol/transaction.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ namespace hive { namespace protocol {
7373
)const;
7474

7575
void verify_authority(
76+
bool strict_authority_level,
7677
const chain_id_type& chain_id,
7778
const authority_getter& get_active,
7879
const authority_getter& get_owner,
@@ -85,6 +86,7 @@ namespace hive { namespace protocol {
8586
)const;
8687

8788
set<public_key_type> minimize_required_signatures(
89+
bool strict_authority_level,
8890
const chain_id_type& chain_id,
8991
const flat_set<public_key_type>& available_keys,
9092
const authority_getter& get_active,

libraries/protocol/include/hive/protocol/transaction_util.hpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ required_authorities_type get_required_authorities(const vector<AuthContainerTyp
2626
return result;
2727
} FC_CAPTURE_AND_RETHROW((auth_containers)) }
2828

29-
void verify_authority(const required_authorities_type& required_authorities,
29+
void verify_authority(bool strict_authority_level,
30+
const required_authorities_type& required_authorities,
3031
const flat_set<public_key_type>& sigs,
3132
const authority_getter& get_active,
3233
const authority_getter& get_owner,
@@ -40,15 +41,17 @@ void verify_authority(const required_authorities_type& required_authorities,
4041
const flat_set<account_name_type>& owner_approvals = flat_set<account_name_type>(),
4142
const flat_set<account_name_type>& posting_approvals = flat_set<account_name_type>());
4243

43-
bool has_authorization( const required_authorities_type& required_authorities,
44+
bool has_authorization( bool strict_authority_level,
45+
const required_authorities_type& required_authorities,
4446
const flat_set<public_key_type>& sigs,
4547
const authority_getter& get_active,
4648
const authority_getter& get_owner,
4749
const authority_getter& get_posting,
4850
const witness_public_key_getter& get_witness_key );
4951

5052
template< typename AuthContainerType >
51-
void verify_authority(const vector<AuthContainerType>& auth_containers,
53+
void verify_authority(bool strict_authority_level,
54+
const vector<AuthContainerType>& auth_containers,
5255
const flat_set<public_key_type>& sigs,
5356
const authority_getter& get_active,
5457
const authority_getter& get_owner,
@@ -62,7 +65,8 @@ void verify_authority(const vector<AuthContainerType>& auth_containers,
6265
const flat_set<account_name_type>& owner_approvals = flat_set<account_name_type>(),
6366
const flat_set<account_name_type>& posting_approvals = flat_set<account_name_type>())
6467
{
65-
verify_authority(get_required_authorities(auth_containers),
68+
verify_authority(strict_authority_level,
69+
get_required_authorities(auth_containers),
6670
sigs,
6771
get_active,
6872
get_owner,

libraries/protocol/sign_state.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ bool sign_state::check_authority( const string& id )
2020
{
2121
if( approved_by.find(id) != approved_by.end() ) return true;
2222
uint32_t account_auth_count = 1;
23-
return check_authority_impl( get_active(id), 0, &account_auth_count );
23+
return check_authority_impl( get_current_authority(id), 0, &account_auth_count );
2424
}
2525

2626
bool sign_state::check_authority( const authority& auth, uint32_t depth, uint32_t account_auth_count )
@@ -62,7 +62,7 @@ bool sign_state::check_authority_impl( const authority& auth, uint32_t depth, ui
6262

6363
(*account_auth_count)++;
6464

65-
if( check_authority_impl( get_active( a.first ), depth + 1, account_auth_count ) )
65+
if( check_authority_impl( get_current_authority( a.first ), depth + 1, account_auth_count ) )
6666
{
6767
approved_by.insert( a.first );
6868
total_weight += a.second;
@@ -102,7 +102,7 @@ sign_state::sign_state(
102102
const flat_set<public_key_type>& sigs,
103103
const authority_getter& a,
104104
const flat_set<public_key_type>& keys
105-
) : get_active(a), available_keys(keys)
105+
) : get_current_authority(a), available_keys(keys)
106106
{
107107
for( const auto& key : sigs )
108108
provided_signatures[ key ] = false;

libraries/protocol/transaction.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ set<public_key_type> signed_transaction::get_required_signatures(
179179
}
180180

181181
set<public_key_type> signed_transaction::minimize_required_signatures(
182+
bool strict_authority_level,
182183
const chain_id_type& chain_id,
183184
const flat_set< public_key_type >& available_keys,
184185
const authority_getter& get_active,
@@ -199,6 +200,7 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
199200
try
200201
{
201202
hive::protocol::verify_authority(
203+
strict_authority_level,
202204
operations,
203205
result,
204206
get_active,
@@ -223,7 +225,8 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
223225
return set<public_key_type>( result.begin(), result.end() );
224226
}
225227

226-
void signed_transaction::verify_authority(const chain_id_type& chain_id,
228+
void signed_transaction::verify_authority(bool strict_authority_level,
229+
const chain_id_type& chain_id,
227230
const authority_getter& get_active,
228231
const authority_getter& get_owner,
229232
const authority_getter& get_posting,
@@ -233,7 +236,8 @@ void signed_transaction::verify_authority(const chain_id_type& chain_id,
233236
uint32_t max_membership,
234237
uint32_t max_account_auths) const
235238
{ try {
236-
hive::protocol::verify_authority(operations,
239+
hive::protocol::verify_authority(strict_authority_level,
240+
operations,
237241
get_signature_keys(chain_id, pack),
238242
get_active,
239243
get_owner,

libraries/protocol/transaction_util.cpp

+26-8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum class verify_authority_problem
1515

1616
template< typename PROBLEM_HANDLER, typename OTHER_AUTH_PROBLEM_HANDLER >
1717
void verify_authority_impl(
18+
bool strict_authority_level,
1819
const required_authorities_type& required_authorities,
1920
const flat_set<public_key_type>& sigs,
2021
const authority_getter& get_active,
@@ -73,8 +74,15 @@ FC_EXPAND_MACRO( \
7374
s.approved_by.insert( id );
7475
for( const auto& id : required_authorities.required_posting )
7576
{
76-
VERIFY_AUTHORITY_CHECK( s.check_authority( id ) || s.check_authority( get_active( id ) ) ||
77-
s.check_authority( get_owner( id ) ), verify_authority_problem::missing_posting, id );
77+
if( strict_authority_level )
78+
{
79+
VERIFY_AUTHORITY_CHECK( s.check_authority( id ), verify_authority_problem::missing_posting, id );
80+
}
81+
else
82+
{
83+
VERIFY_AUTHORITY_CHECK( s.check_authority( id ) || s.check_authority( get_active( id ) ) ||
84+
s.check_authority( get_owner( id ) ), verify_authority_problem::missing_posting, id );
85+
}
7886
}
7987
VERIFY_AUTHORITY_CHECK( !s.remove_unused_signatures(),
8088
verify_authority_problem::unused_signature, account_name_type() );
@@ -99,8 +107,16 @@ FC_EXPAND_MACRO( \
99107
// fetch all of the top level authorities
100108
for( const auto& id : required_authorities.required_active )
101109
{
102-
VERIFY_AUTHORITY_CHECK( s.check_authority( id ) || s.check_authority( get_owner( id ) ),
103-
verify_authority_problem::missing_active, id );
110+
if( strict_authority_level )
111+
{
112+
VERIFY_AUTHORITY_CHECK( s.check_authority( id ),
113+
verify_authority_problem::missing_active, id );
114+
}
115+
else
116+
{
117+
VERIFY_AUTHORITY_CHECK( s.check_authority( id ) || s.check_authority( get_owner( id ) ),
118+
verify_authority_problem::missing_active, id );
119+
}
104120
}
105121

106122
for( const auto& id : required_authorities.required_owner )
@@ -132,7 +148,8 @@ FC_EXPAND_MACRO( \
132148
#undef VERIFY_AUTHORITY_CHECK_OTHER_AUTH
133149
}
134150

135-
void verify_authority(const required_authorities_type& required_authorities,
151+
void verify_authority(bool strict_authority_level,
152+
const required_authorities_type& required_authorities,
136153
const flat_set<public_key_type>& sigs,
137154
const authority_getter& get_active,
138155
const authority_getter& get_owner,
@@ -146,7 +163,7 @@ void verify_authority(const required_authorities_type& required_authorities,
146163
const flat_set<account_name_type>& owner_approvals /* = flat_set<account_name_type>() */,
147164
const flat_set<account_name_type>& posting_approvals /* = flat_set<account_name_type>() */)
148165
{ try {
149-
verify_authority_impl( required_authorities, sigs,
166+
verify_authority_impl( strict_authority_level, required_authorities, sigs,
150167
get_active, get_owner, get_posting, get_witness_key,
151168
max_recursion_depth, max_membership, max_account_auths,
152169
active_approvals, owner_approvals, posting_approvals,
@@ -196,15 +213,16 @@ FC_EXPAND_MACRO( \
196213
#undef VERIFY_AUTHORITY_THROW
197214
} FC_CAPTURE_AND_RETHROW((sigs)) }
198215

199-
bool has_authorization( const required_authorities_type& required_authorities,
216+
bool has_authorization( bool strict_authority_level,
217+
const required_authorities_type& required_authorities,
200218
const flat_set<public_key_type>& sigs,
201219
const authority_getter& get_active,
202220
const authority_getter& get_owner,
203221
const authority_getter& get_posting,
204222
const witness_public_key_getter& get_witness_key )
205223
{
206224
bool result = true;
207-
verify_authority_impl( required_authorities, sigs,
225+
verify_authority_impl( strict_authority_level, required_authorities, sigs,
208226
get_active, get_owner, get_posting, get_witness_key,
209227
HIVE_MAX_SIG_CHECK_DEPTH, HIVE_MAX_AUTHORITY_MEMBERSHIP, HIVE_MAX_SIG_CHECK_ACCOUNTS,
210228
flat_set<account_name_type>(), flat_set<account_name_type>(), flat_set<account_name_type>(),

libraries/wallet/wallet.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,12 @@ class wallet_api_impl
562562
{
563563
const signed_transaction& signature_source = new_tx->get_transaction();
564564

565+
protocol::hardfork_version _result = _remote_wallet_bridge_api->get_hardfork_version({}, LOCK);
566+
567+
bool _strict_authority_level = _result.minor_v() >= 28;
568+
565569
auto minimal_signing_keys = signature_source.minimize_required_signatures(
570+
_strict_authority_level,
566571
_hive_chain_id,
567572
available_keys,
568573
[&]( const string& account_name ) { return collector.get_account( account_name ).active; },

tests/python/functional/authority/test_account_authority.py

+14-8
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def test_owner_account_authority(node: tt.InitNode, authority_level: str, alice:
7373
).account_auths, f"Account {bob.name} was not set as account_auths for the account {alice.name}."
7474

7575
if authority_level == "owner":
76-
assert node.api.database.verify_account_authority(
76+
assert not node.api.database.verify_account_authority(
7777
account=alice.name, signers=[tt.PublicKey(bob.name, secret="active")], level="active"
7878
).valid
7979

@@ -188,16 +188,22 @@ def test_signing_with_circular_account_authority(
188188
│ │
189189
● posting ● posting
190190
"""
191-
# bob as carols owner account authority set carols active authority to redirect to bob
191+
# bob as carol's owner account authority can't set carol's active authority to redirect to bob
192192
bob.wallet.api.use_authority("active", bob.name)
193-
bob.wallet.api.update_account_auth_account(carol.name, "active", bob.name, 1)
194-
assert (
195-
len(get_authority(node, carol.name, authority_level="active").account_auths) == 1
196-
), "Carol's active-account_auths is not set"
193+
with pytest.raises(tt.exceptions.CommunicationError):
194+
bob.wallet.api.update_account_auth_account(carol.name, "active", bob.name, 1)
197195

198-
# now bob can sign owner type operation (use active bob authority)
196+
# bob can't sign owner type operation (use active bob authority)
199197
bob.wallet.api.use_authority("active", bob.name)
200-
bob.wallet.api.sign_transaction(decline_voting_rights)
198+
with pytest.raises(tt.exceptions.CommunicationError):
199+
bob.wallet.api.sign_transaction(decline_voting_rights)
200+
201+
carol.wallet.api.import_key(tt.PrivateKey(account_name=carol.name, secret="owner"))
202+
assert len(carol.wallet.api.list_keys()) == 1, "Carol's wallet has an incorrect number of imported keys. Expected 1"
203+
carol.wallet.api.use_authority("owner", carol.name)
204+
# carol can't sign owner type operation (use owner carol authority)
205+
with pytest.raises(tt.exceptions.CommunicationError):
206+
carol.wallet.api.sign_transaction(decline_voting_rights)
201207

202208

203209
@run_for("testnet")

tests/python/functional/operation_tests/account_update_tests/test_account_update.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def test_update_account_active_authority(alice: UpdateAccount, authority_type: s
5252
"""
5353
alice.use_authority(authority_type)
5454
new_auth = alice.generate_new_authority()
55-
if authority_type == "posting":
55+
if authority_type == "posting" or authority_type == "owner":
5656
with pytest.raises(RequestError) as exception:
5757
alice.update_account(active=new_auth, use_account_update2=use_account_update2)
5858
alice.assert_if_rc_current_mana_was_unchanged()
@@ -78,7 +78,7 @@ def test_update_account_posting_authority(alice: UpdateAccount, authority_type:
7878
"""
7979
alice.use_authority(authority_type)
8080
new_auth = alice.generate_new_authority()
81-
if authority_type == "posting":
81+
if authority_type == "posting" or authority_type == "owner":
8282
with pytest.raises(RequestError) as exception:
8383
alice.update_account(posting=new_auth, use_account_update2=use_account_update2)
8484
alice.assert_if_rc_current_mana_was_unchanged()
@@ -104,7 +104,7 @@ def test_update_account_memo_key(alice: UpdateAccount, authority_type: str, use_
104104
"""
105105
alice.use_authority(authority_type)
106106
new_key = alice.generate_new_key()
107-
if authority_type == "posting":
107+
if authority_type == "posting" or authority_type == "owner":
108108
with pytest.raises(RequestError) as exception:
109109
alice.update_account(memo_key=new_key, use_account_update2=use_account_update2)
110110
alice.assert_if_rc_current_mana_was_unchanged()
@@ -130,7 +130,7 @@ def test_update_json_metadata(alice: UpdateAccount, authority_type: str, use_acc
130130
"""
131131
alice.use_authority(authority_type)
132132
new_json_meta = '{"foo": "bar"}'
133-
if authority_type == "posting":
133+
if authority_type == "posting" or authority_type == "owner":
134134
with pytest.raises(RequestError) as exception:
135135
alice.update_account(json_metadata=new_json_meta, use_account_update2=use_account_update2)
136136
alice.assert_if_rc_current_mana_was_unchanged()
@@ -153,9 +153,16 @@ def test_update_posting_json_metadata(alice: UpdateAccount, authority_type: str)
153153
"""
154154
alice.use_authority(authority_type)
155155
new_posting_json_meta = '{"foo": "bar"}'
156-
transaction = alice.update_account(posting_json_metadata=new_posting_json_meta, use_account_update2=True)
157-
alice.assert_if_rc_current_mana_was_reduced(transaction)
158-
alice.assert_account_details_were_changed(new_posting_json_meta=new_posting_json_meta)
156+
if authority_type == "active" or authority_type == "owner":
157+
with pytest.raises(RequestError) as exception:
158+
alice.update_account(posting_json_metadata=new_posting_json_meta, use_account_update2=True)
159+
alice.assert_if_rc_current_mana_was_unchanged()
160+
error_response = exception.value.error
161+
assert "Missing Posting Authority" in error_response
162+
else:
163+
transaction = alice.update_account(posting_json_metadata=new_posting_json_meta, use_account_update2=True)
164+
alice.assert_if_rc_current_mana_was_reduced(transaction)
165+
alice.assert_account_details_were_changed(new_posting_json_meta=new_posting_json_meta)
159166

160167

161168
@pytest.mark.testnet()

0 commit comments

Comments
 (0)