Skip to content

Commit fc3b6c6

Browse files
committed
Merge branch 'eichhorl/check-signing-enabled' into 'master'
fix(ecdsa): FOLLOW-1007 Reject signing requests for disabled keys When retrieving new ecdsa signing requests from the state's subnet call context manager, we instantly reject requests for keys that don't have signing enabled on the current subnet and registry version. This means that when disabling signing with a key (that previously had singing enabled) at a registry version `v`, requests that were included in earlier blocks using a registry version `v' < v` are still going to be completed. See merge request dfinity-lab/public/ic!12535
2 parents 6da550e + 3482610 commit fc3b6c6

File tree

1 file changed

+109
-11
lines changed

1 file changed

+109
-11
lines changed

rs/consensus/src/ecdsa/payload_builder.rs

Lines changed: 109 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use ic_interfaces::{consensus_pool::ConsensusBlockChain, ecdsa::EcdsaPool};
1616
use ic_interfaces_registry::RegistryClient;
1717
use ic_interfaces_state_manager::{StateManager, StateManagerError};
1818
use ic_logger::{debug, error, info, warn, ReplicaLogger};
19+
use ic_registry_client_helpers::ecdsa_keys::EcdsaKeysRegistry;
1920
use ic_registry_client_helpers::subnet::SubnetRegistry;
2021
use ic_registry_subnet_features::EcdsaConfig;
2122
use ic_replicated_state::{metadata_state::subnet_call_context_manager::*, ReplicatedState};
@@ -207,7 +208,7 @@ pub fn make_bootstrap_summary(
207208
Ok(Some(summary_payload))
208209
}
209210

210-
/// Return EcdsaConfig if it is enabled for the given subnet.
211+
/// Return [EcdsaConfig] if it is enabled for the given subnet.
211212
pub(crate) fn get_ecdsa_config_if_enabled(
212213
subnet_id: SubnetId,
213214
registry_version: RegistryVersion,
@@ -236,6 +237,28 @@ pub(crate) fn get_ecdsa_config_if_enabled(
236237
Ok(None)
237238
}
238239

240+
/// Return ids of ECDSA keys of the given [EcdsaConfig] for which
241+
/// signing is enabled on the given subnet.
242+
pub(crate) fn get_enabled_signing_keys(
243+
subnet_id: SubnetId,
244+
registry_version: RegistryVersion,
245+
registry_client: &dyn RegistryClient,
246+
ecdsa_config: &EcdsaConfig,
247+
) -> Result<BTreeSet<EcdsaKeyId>, RegistryClientError> {
248+
let signing_subnets = registry_client
249+
.get_ecdsa_signing_subnets(registry_version)?
250+
.unwrap_or_default();
251+
Ok(ecdsa_config
252+
.key_ids
253+
.iter()
254+
.cloned()
255+
.filter(|key_id| match signing_subnets.get(key_id) {
256+
Some(subnets) => subnets.contains(&subnet_id),
257+
None => false,
258+
})
259+
.collect())
260+
}
261+
239262
/// Creates a threshold ECDSA summary payload.
240263
pub(crate) fn create_summary_payload(
241264
subnet_id: SubnetId,
@@ -644,16 +667,21 @@ pub(crate) fn create_data_payload_helper(
644667
// For next interval: context.registry_version from the new summary block
645668
let next_interval_registry_version = summary_block.context.registry_version;
646669

647-
let ecdsa_config = get_ecdsa_config_if_enabled(
670+
let Some(ecdsa_config) = get_ecdsa_config_if_enabled(
648671
subnet_id,
649672
curr_interval_registry_version,
650673
registry_client,
651674
&log,
652-
)?;
653-
if ecdsa_config.is_none() {
675+
)? else {
654676
return Ok(None);
655-
}
656-
let ecdsa_config = ecdsa_config.unwrap();
677+
};
678+
let enabled_signing_keys = get_enabled_signing_keys(
679+
subnet_id,
680+
curr_interval_registry_version,
681+
registry_client,
682+
&ecdsa_config,
683+
)?;
684+
657685
let mut ecdsa_payload = if let Some(prev_payload) = parent_block.payload.as_ref().as_ecdsa() {
658686
prev_payload.clone()
659687
} else {
@@ -678,6 +706,7 @@ pub(crate) fn create_data_payload_helper(
678706
height,
679707
context.time,
680708
&ecdsa_config,
709+
&enabled_signing_keys,
681710
next_interval_registry_version,
682711
&receivers,
683712
all_signing_requests,
@@ -696,6 +725,7 @@ pub(crate) fn create_data_payload_helper_2(
696725
height: Height,
697726
context_time: Time,
698727
ecdsa_config: &EcdsaConfig,
728+
enabled_signing_keys: &BTreeSet<EcdsaKeyId>,
699729
next_interval_registry_version: RegistryVersion,
700730
receivers: &[NodeId],
701731
all_signing_requests: &BTreeMap<CallbackId, SignWithEcdsaContext>,
@@ -721,7 +751,6 @@ pub(crate) fn create_data_payload_helper_2(
721751
ecdsa_payload.uid_generator.update_height(height)?;
722752
let current_key_transcript = ecdsa_payload.key_transcript.current.as_ref().cloned();
723753

724-
let valid_keys: BTreeSet<_> = ecdsa_config.key_ids.iter().cloned().collect();
725754
let request_expiry_time = ecdsa_config.signature_request_timeout_ns.and_then(|t| {
726755
let timeout = Duration::from_nanos(t);
727756
if context_time.as_nanos_since_unix_epoch() >= t {
@@ -736,7 +765,7 @@ pub(crate) fn create_data_payload_helper_2(
736765
request_expiry_time,
737766
ecdsa_payload,
738767
all_signing_requests,
739-
&valid_keys,
768+
enabled_signing_keys,
740769
ecdsa_payload_metrics,
741770
);
742771
update_ongoing_signatures(
@@ -981,7 +1010,10 @@ pub(crate) fn get_signing_requests<'a>(
9811010
refund: context.request.payment,
9821011
response_payload: ic_types::messages::Payload::Reject(RejectContext {
9831012
code: RejectCode::CanisterReject,
984-
message: format!("Invalid key_id in signature request: {:?}", context.key_id),
1013+
message: format!(
1014+
"Invalid or disabled key_id in signature request: {:?}",
1015+
context.key_id
1016+
),
9851017
}),
9861018
};
9871019
ecdsa_payload.signature_agreements.insert(
@@ -1752,7 +1784,11 @@ mod tests {
17521784
};
17531785
use ic_interfaces_registry::RegistryValue;
17541786
use ic_logger::replica_logger::no_op_logger;
1787+
use ic_protobuf::registry::crypto::v1::EcdsaSigningSubnetList;
17551788
use ic_protobuf::types::v1 as pb;
1789+
use ic_registry_client_fake::FakeRegistryClient;
1790+
use ic_registry_keys::make_ecdsa_signing_subnet_list_key;
1791+
use ic_registry_proto_data_provider::ProtoRegistryDataProvider;
17561792
use ic_registry_subnet_features::DEFAULT_ECDSA_MAX_QUEUE_SIZE;
17571793
use ic_test_artifact_pool::consensus_pool::TestConsensusPool;
17581794
use ic_test_utilities::consensus::fake::{Fake, FakeContentSigner};
@@ -1775,6 +1811,7 @@ mod tests {
17751811
idkg::IDkgTranscriptId, ThresholdEcdsaCombinedSignature,
17761812
};
17771813
use ic_types::crypto::{CryptoHash, CryptoHashOf};
1814+
use ic_types::subnet_id_into_protobuf;
17781815
use ic_types::{messages::CallbackId, Height, RegistryVersion};
17791816
use std::collections::BTreeSet;
17801817
use std::convert::TryInto;
@@ -1890,6 +1927,59 @@ mod tests {
18901927
block_proposal.content.as_ref().clone()
18911928
}
18921929

1930+
#[test]
1931+
fn test_get_enabled_signing_keys() {
1932+
let key_id1 = EcdsaKeyId::from_str("Secp256k1:some_key1").unwrap();
1933+
let key_id2 = EcdsaKeyId::from_str("Secp256k1:some_key2").unwrap();
1934+
let key_id3 = EcdsaKeyId::from_str("Secp256k1:some_key3").unwrap();
1935+
let ecdsa_config = EcdsaConfig {
1936+
key_ids: vec![key_id1.clone(), key_id2.clone()],
1937+
..EcdsaConfig::default()
1938+
};
1939+
let registry_data = Arc::new(ProtoRegistryDataProvider::new());
1940+
let registry = Arc::new(FakeRegistryClient::new(Arc::clone(&registry_data) as Arc<_>));
1941+
let subnet_id = subnet_test_id(1);
1942+
1943+
let add_key = |version, key_id, subnets| {
1944+
registry_data
1945+
.add(
1946+
&make_ecdsa_signing_subnet_list_key(key_id),
1947+
RegistryVersion::from(version),
1948+
Some(EcdsaSigningSubnetList { subnets }),
1949+
)
1950+
.expect("failed to add subnets to registry");
1951+
};
1952+
1953+
add_key(1, &key_id1, vec![subnet_id_into_protobuf(subnet_id)]);
1954+
add_key(2, &key_id2, vec![subnet_id_into_protobuf(subnet_id)]);
1955+
add_key(2, &key_id3, vec![subnet_id_into_protobuf(subnet_id)]);
1956+
add_key(3, &key_id1, vec![]);
1957+
registry.update_to_latest_version();
1958+
1959+
let test_cases = vec![
1960+
(0, Ok(BTreeSet::new())),
1961+
(1, Ok(BTreeSet::from_iter(vec![key_id1.clone()]))),
1962+
(2, Ok(BTreeSet::from_iter(vec![key_id1, key_id2.clone()]))),
1963+
(3, Ok(BTreeSet::from_iter(vec![key_id2]))),
1964+
(
1965+
4,
1966+
Err(RegistryClientError::VersionNotAvailable {
1967+
version: RegistryVersion::from(4),
1968+
}),
1969+
),
1970+
];
1971+
1972+
for (version, expected) in test_cases {
1973+
let result = get_enabled_signing_keys(
1974+
subnet_id,
1975+
RegistryVersion::from(version),
1976+
registry.as_ref(),
1977+
&ecdsa_config,
1978+
);
1979+
assert_eq!(result, expected);
1980+
}
1981+
}
1982+
18931983
#[test]
18941984
fn test_ecdsa_make_new_quadruples_if_needed() {
18951985
let subnet_id = subnet_test_id(1);
@@ -2869,6 +2959,7 @@ mod tests {
28692959
Height::from(5),
28702960
mock_time(),
28712961
&EcdsaConfig::default(),
2962+
&valid_keys,
28722963
RegistryVersion::from(9),
28732964
&[node_test_id(0)],
28742965
&sign_with_ecdsa_contexts,
@@ -2891,6 +2982,7 @@ mod tests {
28912982
Height::from(5),
28922983
mock_time(),
28932984
&EcdsaConfig::default(),
2985+
&valid_keys,
28942986
RegistryVersion::from(9),
28952987
&[node_test_id(0)],
28962988
&sign_with_ecdsa_contexts,
@@ -3865,8 +3957,9 @@ mod tests {
38653957
add_subnet_record(&registry_data_provider, 11, subnet_id, subnet_record);
38663958
registry.update_to_latest_version();
38673959
let registry_version = registry.get_latest_version();
3868-
3960+
let mut valid_keys = BTreeSet::new();
38693961
let key_id = EcdsaKeyId::from_str("Secp256k1:some_key").unwrap();
3962+
valid_keys.insert(key_id.clone());
38703963
let block_reader = TestEcdsaBlockReader::new();
38713964
let transcript_builder = TestEcdsaTranscriptBuilder::new();
38723965
let signature_builder = TestEcdsaSignatureBuilder::new();
@@ -3909,6 +4002,7 @@ mod tests {
39094002
Height::from(2),
39104003
mock_time(),
39114004
&ecdsa_config,
4005+
&valid_keys,
39124006
registry_version,
39134007
&node_ids,
39144008
&BTreeMap::default(),
@@ -3999,8 +4093,9 @@ mod tests {
39994093
add_subnet_record(&registry_data_provider, 511, subnet_id, subnet_record);
40004094
registry.update_to_latest_version();
40014095
let registry_version = registry.get_latest_version();
4002-
4096+
let mut valid_keys = BTreeSet::new();
40034097
let key_id = EcdsaKeyId::from_str("Secp256k1:some_key").unwrap();
4098+
valid_keys.insert(key_id.clone());
40044099
let mut block_reader = TestEcdsaBlockReader::new();
40054100
let transcript_builder = TestEcdsaTranscriptBuilder::new();
40064101
let signature_builder = TestEcdsaSignatureBuilder::new();
@@ -4062,6 +4157,7 @@ mod tests {
40624157
Height::from(2),
40634158
mock_time(),
40644159
&ecdsa_config,
4160+
&valid_keys,
40654161
registry_version,
40664162
&node_ids,
40674163
&BTreeMap::default(),
@@ -4089,6 +4185,7 @@ mod tests {
40894185
Height::from(3),
40904186
mock_time(),
40914187
&ecdsa_config,
4188+
&valid_keys,
40924189
registry_version,
40934190
&node_ids,
40944191
&BTreeMap::default(),
@@ -4114,6 +4211,7 @@ mod tests {
41144211
Height::from(3),
41154212
mock_time(),
41164213
&ecdsa_config,
4214+
&valid_keys,
41174215
registry_version,
41184216
&node_ids,
41194217
&BTreeMap::default(),

0 commit comments

Comments
 (0)