Skip to content

Commit 59e6b99

Browse files
author
vlad
committed
Fixed contract/admin proof validation for migrated contracts
1 parent 961c225 commit 59e6b99

File tree

3 files changed

+96
-58
lines changed

3 files changed

+96
-58
lines changed

cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use enclave_utils::{Keychain, KEY_MANAGER};
12
use serde::{Deserialize, Serialize};
23

34
#[cfg(feature = "random")]
@@ -19,7 +20,8 @@ use crate::cosmwasm_config::ContractOperation;
1920
use crate::contract_validation::verify_block_info;
2021

2122
use crate::contract_validation::{
22-
generate_admin_proof, generate_contract_key_proof, ReplyParams, ValidatedMessage,
23+
generate_admin_proof, generate_contract_key_proof, validate_admin_proof, ReplyParams,
24+
ValidatedMessage,
2325
};
2426
use crate::external::results::{
2527
HandleSuccess, InitSuccess, MigrateSuccess, QuerySuccess, UpdateAdminSuccess,
@@ -240,7 +242,11 @@ pub fn init(
240242

241243
// todo: can move the key to somewhere in the output message if we want
242244

243-
let admin_proof = generate_admin_proof(&canonical_admin_address.0 .0, &og_contract_key);
245+
let admin_proof = generate_admin_proof(
246+
&Keychain::generate_admin_proof_secret(KEY_MANAGER.get_consensus_seed().unwrap().last()),
247+
&canonical_admin_address.0 .0,
248+
&og_contract_key,
249+
);
244250

245251
Ok(InitSuccess {
246252
output,
@@ -328,12 +334,13 @@ pub fn migrate(
328334
) {
329335
debug!("Found hardcoded admin for migrate");
330336
} else {
331-
let sender_admin_proof =
332-
generate_admin_proof(&canonical_sender_address.0 .0, &og_contract_key);
333-
334-
if admin_proof != sender_admin_proof {
337+
if let Err(e) = validate_admin_proof(
338+
&canonical_sender_address.0 .0,
339+
&og_contract_key,
340+
admin_proof,
341+
) {
335342
error!("Failed to validate sender as current admin for migrate");
336-
return Err(EnclaveError::ValidationFailure);
343+
return Err(e);
337344
}
338345
debug!("Validated migrate proof successfully");
339346
}
@@ -442,6 +449,9 @@ pub fn migrate(
442449
// todo: can move the key to somewhere in the output message if we want
443450

444451
let new_contract_key_proof = generate_contract_key_proof(
452+
&Keychain::generate_contract_key_proof_secret(
453+
KEY_MANAGER.get_consensus_seed().unwrap().last(),
454+
),
445455
&canonical_contract_address.0 .0,
446456
&contract_code.hash(),
447457
&og_contract_key,
@@ -495,12 +505,15 @@ pub fn update_admin(
495505

496506
let og_contract_key = base_env.get_og_contract_key()?;
497507

498-
let sender_admin_proof = generate_admin_proof(&canonical_sender_address.0 .0, &og_contract_key);
499-
500-
if sender_admin_proof != current_admin_proof {
508+
if let Err(e) = validate_admin_proof(
509+
&canonical_sender_address.0 .0,
510+
&og_contract_key,
511+
current_admin_proof,
512+
) {
501513
error!("Failed to validate sender as current admin for update_admin");
502-
return Err(EnclaveError::ValidationFailure);
514+
return Err(e);
503515
}
516+
504517
debug!("Validated update_admin proof successfully");
505518

506519
let parsed_sig_info: SigInfo = extract_sig_info(sig_info)?;
@@ -522,7 +535,11 @@ pub fn update_admin(
522535
Some(&canonical_new_admin_address),
523536
)?;
524537

525-
let new_admin_proof = generate_admin_proof(&canonical_new_admin_address.0 .0, &og_contract_key);
538+
let new_admin_proof = generate_admin_proof(
539+
&Keychain::generate_admin_proof_secret(KEY_MANAGER.get_consensus_seed().unwrap().last()),
540+
&canonical_new_admin_address.0 .0,
541+
&og_contract_key,
542+
);
526543

527544
debug!("update_admin success: {:?}", new_admin_proof);
528545

cosmwasm/enclaves/shared/contract-engine/src/contract_validation.rs

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use enclave_cosmos_types::types::{
1313
use enclave_crypto::traits::VerifyingKey;
1414
use enclave_crypto::{sha_256, AESKey, Hmac, Kdf, HASH_SIZE};
1515
use enclave_ffi_types::EnclaveError;
16-
use enclave_utils::KEY_MANAGER;
16+
use enclave_utils::{Keychain, KEY_MANAGER};
1717
use protobuf::Message;
1818

1919
use crate::hardcoded_admins::is_code_hash_allowed;
@@ -308,19 +308,13 @@ pub fn validate_contract_key(
308308

309309
let sent_contract_key_proof = base_env.get_current_contract_key_proof()?;
310310

311-
let contract_key_proof = generate_contract_key_proof(
311+
validate_contract_key_proof(
312312
&canonical_contract_address.0 .0,
313313
&contract_code.hash(),
314314
&og_contract_key,
315-
&current_contract_key, // this is already validated
316-
);
317-
318-
if sent_contract_key_proof != contract_key_proof {
319-
error!("Failed to validate contract key proof for a migrated contract");
320-
return Err(EnclaveError::ValidationFailure);
321-
}
322-
323-
Ok(())
315+
&current_contract_key,
316+
&sent_contract_key_proof,
317+
)
324318
} else {
325319
trace!("Contract still has original code, validating contract_key");
326320

@@ -335,17 +329,42 @@ pub fn validate_contract_key(
335329
}
336330
}
337331

338-
pub fn generate_admin_proof(admin: &[u8], contract_key: &[u8]) -> [u8; enclave_crypto::HASH_SIZE] {
332+
pub fn generate_admin_proof(
333+
proof_secret: &AESKey,
334+
admin: &[u8],
335+
contract_key: &[u8],
336+
) -> [u8; enclave_crypto::HASH_SIZE] {
339337
let mut data_to_sign = vec![];
340338
data_to_sign.extend_from_slice(admin);
341339
data_to_sign.extend_from_slice(contract_key);
342340

343-
let admin_proof_secret = KEY_MANAGER.get_admin_proof_secret().unwrap();
341+
proof_secret.sign_sha_256(data_to_sign.as_slice())
342+
}
343+
344+
pub fn validate_admin_proof(
345+
admin: &[u8],
346+
contract_key: &[u8],
347+
proof: &[u8],
348+
) -> Result<(), EnclaveError> {
349+
let seeds = KEY_MANAGER.get_consensus_seed().unwrap();
350+
for i_seed in 1..seeds.arr.len() {
351+
let expected_proof = generate_admin_proof(
352+
&Keychain::generate_admin_proof_secret(&seeds.arr[i_seed]),
353+
admin,
354+
contract_key,
355+
);
356+
357+
if proof == &expected_proof {
358+
return Ok(());
359+
}
360+
}
344361

345-
admin_proof_secret.sign_sha_256(data_to_sign.as_slice())
362+
error!("Failed to validate admin key proof for a migrated contract");
363+
Err(EnclaveError::ValidationFailure)
346364
}
347365

348366
pub fn generate_contract_key_proof(
367+
proof_secret: &AESKey,
349368
contract_address: &[u8],
350369
code_hash: &[u8],
351370
og_contract_key: &[u8],
@@ -357,9 +376,33 @@ pub fn generate_contract_key_proof(
357376
data_to_sign.extend_from_slice(og_contract_key);
358377
data_to_sign.extend_from_slice(new_contract_key);
359378

360-
let contract_key_proof_secret = KEY_MANAGER.get_contract_key_proof_secret().unwrap();
379+
proof_secret.sign_sha_256(data_to_sign.as_slice())
380+
}
381+
382+
pub fn validate_contract_key_proof(
383+
contract_address: &[u8],
384+
code_hash: &[u8],
385+
og_contract_key: &[u8],
386+
new_contract_key: &[u8],
387+
proof: &[u8; enclave_crypto::HASH_SIZE],
388+
) -> Result<(), EnclaveError> {
389+
let seeds = KEY_MANAGER.get_consensus_seed().unwrap();
390+
for i_seed in 1..seeds.arr.len() {
391+
let expected_proof = generate_contract_key_proof(
392+
&Keychain::generate_contract_key_proof_secret(&seeds.arr[i_seed]),
393+
contract_address,
394+
code_hash,
395+
og_contract_key,
396+
new_contract_key,
397+
);
398+
399+
if proof == &expected_proof {
400+
return Ok(());
401+
}
402+
}
361403

362-
contract_key_proof_secret.sign_sha_256(data_to_sign.as_slice())
404+
error!("Failed to validate contract key proof for a migrated contract");
405+
Err(EnclaveError::ValidationFailure)
363406
}
364407

365408
pub struct ValidatedMessage {

cosmwasm/enclaves/shared/utils/src/key_manager.rs

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ pub struct Keychain {
7070
pub random_encryption_key: Option<AESKey>,
7171
pub initial_randomness_seed: Option<AESKey>,
7272
registration_key: Option<KeyPair>,
73-
admin_proof_secret: Option<AESKey>,
74-
contract_key_proof_secret: Option<AESKey>,
7573
pub extra_data: SgxMutex<KeychainMutableData>,
7674
}
7775

@@ -283,8 +281,6 @@ impl Keychain {
283281
initial_randomness_seed: None,
284282
//#[cfg(feature = "random")]
285283
random_encryption_key: None,
286-
admin_proof_secret: None,
287-
contract_key_proof_secret: None,
288284
extra_data: SgxMutex::new(KeychainMutableData {
289285
height: 0,
290286
validator_set_serialized: Vec::new(),
@@ -433,20 +429,6 @@ impl Keychain {
433429
})
434430
}
435431

436-
pub fn get_admin_proof_secret(&self) -> Result<AESKey, CryptoError> {
437-
self.admin_proof_secret.ok_or_else(|| {
438-
error!("Error accessing admin_proof_secret (does not exist, or was not initialized)");
439-
CryptoError::ParsingError
440-
})
441-
}
442-
443-
pub fn get_contract_key_proof_secret(&self) -> Result<AESKey, CryptoError> {
444-
self.contract_key_proof_secret.ok_or_else(|| {
445-
error!("Error accessing contract_key_proof_secret (does not exist, or was not initialized)");
446-
CryptoError::ParsingError
447-
})
448-
}
449-
450432
pub fn delete_consensus_seed(&mut self) {
451433
self.consensus_seed.arr.clear();
452434
}
@@ -471,6 +453,14 @@ impl Keychain {
471453
seed.derive_key_from_this(&RANDOMNESS_ENCRYPTION_KEY_SECRET_DERIVE_ORDER.to_be_bytes())
472454
}
473455

456+
pub fn generate_contract_key_proof_secret(seed: &Seed) -> AESKey {
457+
seed.derive_key_from_this(&CONTRACT_KEY_PROOF_SECRET_DERIVE_ORDER.to_be_bytes())
458+
}
459+
460+
pub fn generate_admin_proof_secret(seed: &Seed) -> AESKey {
461+
seed.derive_key_from_this(&ADMIN_PROOF_SECRET_DERIVE_ORDER.to_be_bytes())
462+
}
463+
474464
pub fn generate_consensus_master_keys(&mut self) -> Result<(), EnclaveError> {
475465
if !self.is_consensus_seed_set() {
476466
trace!("Seed not initialized, skipping derivation of enclave keys");
@@ -512,18 +502,6 @@ impl Keychain {
512502
Some(Self::generate_randomness_seed(self.consensus_seed.last()));
513503
}
514504

515-
self.admin_proof_secret = Some(
516-
self.consensus_seed
517-
.last()
518-
.derive_key_from_this(&ADMIN_PROOF_SECRET_DERIVE_ORDER.to_be_bytes()),
519-
);
520-
521-
self.contract_key_proof_secret = Some(
522-
self.consensus_seed
523-
.last()
524-
.derive_key_from_this(&CONTRACT_KEY_PROOF_SECRET_DERIVE_ORDER.to_be_bytes()),
525-
);
526-
527505
Ok(())
528506
}
529507
}

0 commit comments

Comments
 (0)