Skip to content

Commit

Permalink
fix(rust/rbac-registration): Record CIP509 validation data (#95)
Browse files Browse the repository at this point in the history
* fix: validation data

Signed-off-by: bkioshn <[email protected]>

* chore: update version

Signed-off-by: bkioshn <[email protected]>

---------

Signed-off-by: bkioshn <[email protected]>
  • Loading branch information
bkioshn authored Dec 4, 2024
1 parent 149bf11 commit 47b5514
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 15 deletions.
2 changes: 1 addition & 1 deletion rust/rbac-registration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "rbac-registration"
description = "Role Based Access Control Registration"
keywords = ["cardano", "catalyst", "rbac registration"]
version = "0.0.1"
version = "0.0.2"
authors = [
"Arissara Chotivichit <[email protected]>"
]
Expand Down
45 changes: 38 additions & 7 deletions rust/rbac-registration/src/cardano/cip509/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,31 @@ pub struct Cip509 {
pub validation_signature: Vec<u8>, // bytes size (1..64)
}

/// Validation value for CIP509 metadatum.
#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Cip509Validation {
/// Boolean value for the validity of the transaction inputs hash.
pub valid_txn_inputs_hash: bool,
/// Boolean value for the validity of the auxiliary data.
pub valid_aux: bool,
/// Boolean value for the validity of the public key.
pub valid_public_key: bool,
/// Boolean value for the validity of the payment key.
pub valid_payment_key: bool,
/// Boolean value for the validity of the signing key.
pub signing_key: bool,
/// Additional data from the CIP509 validation..
pub additional_data: AdditionalData,
}

/// Additional data from the CIP509 validation.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct AdditionalData {
/// Bytes of precomputed auxiliary data.
pub precomputed_aux: Vec<u8>,
}

/// `UUIDv4` representing in 16 bytes.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct UuidV4([u8; 16]);
Expand Down Expand Up @@ -189,10 +214,13 @@ impl Cip509 {
/// # Parameters
/// * `txn` - Transaction data was attached to and to be validated/decoded against.
/// * `validation_report` - Validation report to store the validation result.
pub fn validate(&self, txn: &MultiEraTx, validation_report: &mut Vec<String>) -> bool {
pub fn validate(
&self, txn: &MultiEraTx, validation_report: &mut Vec<String>,
) -> Cip509Validation {
let tx_input_validate =
validate_txn_inputs_hash(self, txn, validation_report).unwrap_or(false);
let aux_validate = validate_aux(txn, validation_report).unwrap_or(false);
let (aux_validate, precomputed_aux) =
validate_aux(txn, validation_report).unwrap_or_default();
let mut stake_key_validate = true;
let mut payment_key_validate = true;
let mut signing_key = true;
Expand All @@ -209,10 +237,13 @@ impl Cip509 {
}
}
}
tx_input_validate
&& aux_validate
&& stake_key_validate
&& payment_key_validate
&& signing_key
Cip509Validation {
valid_txn_inputs_hash: tx_input_validate,
valid_aux: aux_validate,
valid_public_key: stake_key_validate,
valid_payment_key: payment_key_validate,
signing_key,
additional_data: AdditionalData { precomputed_aux },
}
}
}
18 changes: 14 additions & 4 deletions rust/rbac-registration/src/cardano/cip509/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use super::{
utils::cip19::{compare_key_hash, extract_cip19_hash, extract_key_hash},
Cip509, TxInputHash, TxWitness,
};
use crate::utils::general::zero_out_last_n_bytes;

/// Context-specific primitive type with tag number 6 (`raw_tag` 134) for
/// uniform resource identifier (URI) in the subject alternative name extension.
Expand Down Expand Up @@ -282,7 +283,10 @@ pub(crate) fn validate_stake_public_key(
// ------------------------ Validate Aux ------------------------

/// Validate the auxiliary data with the auxiliary data hash in the transaction body.
pub(crate) fn validate_aux(txn: &MultiEraTx, validation_report: &mut Vec<String>) -> Option<bool> {
/// Also return the pre-computed hash where the validation signature (99) set to
pub(crate) fn validate_aux(
txn: &MultiEraTx, validation_report: &mut Vec<String>,
) -> Option<(bool, Vec<u8>)> {
let function_name = "Validate Aux";

// CIP-0509 should only be in conway era
Expand Down Expand Up @@ -313,13 +317,19 @@ pub(crate) fn validate_aux(txn: &MultiEraTx, validation_report: &mut Vec<String>
}

/// Helper function for auxiliary data validation.
/// Also compute The pre-computed hash.
fn validate_aux_helper(
original_aux: &[u8], aux_data_hash: &Bytes, validation_report: &mut Vec<String>,
) -> Option<bool> {
) -> Option<(bool, Vec<u8>)> {
let mut vec_aux = original_aux.to_vec();

// Pre-computed aux with the last 64 bytes set to zero
zero_out_last_n_bytes(&mut vec_aux, 64);

// Compare the hash
match blake2b_256(original_aux) {
Ok(original_hash) => {
return Some(aux_data_hash.as_ref() == original_hash);
return Some((aux_data_hash.as_ref() == original_hash, vec_aux));
},
Err(e) => {
validation_report.push(format!("Cannot hash auxiliary data {e}"));
Expand Down Expand Up @@ -539,7 +549,7 @@ mod tests {
.expect("Failed to get transaction index");

validate_aux(tx, &mut validation_report);
assert!(validate_aux(tx, &mut validation_report).unwrap());
assert!(validate_aux(tx, &mut validation_report).unwrap().0);
}

#[test]
Expand Down
19 changes: 16 additions & 3 deletions rust/rbac-registration/src/registration/cardano/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
pub_key::{Ed25519PublicKey, SimplePublicKeyType},
CertKeyHash,
},
Cip509, UuidV4,
Cip509, Cip509Validation, UuidV4,
},
utils::general::decremented_index,
};
Expand Down Expand Up @@ -184,8 +184,10 @@ impl RegistrationChainInner {
}

let mut validation_report = Vec::new();
let validation_data = cip509.validate(txn, &mut validation_report);

// Do the CIP509 validation, ensuring the basic validation pass.
if !cip509.validate(txn, &mut validation_report) {
if !is_valid_cip509(&validation_data) {
// Log out the error if any
error!("CIP509 validation failed: {:?}", validation_report);
bail!("CIP509 validation failed, {:?}", validation_report);
Expand Down Expand Up @@ -240,8 +242,10 @@ impl RegistrationChainInner {
let mut new_inner = self.clone();

let mut validation_report = Vec::new();
let validation_data = cip509.validate(txn, &mut validation_report);

// Do the CIP509 validation, ensuring the basic validation pass.
if !cip509.validate(txn, &mut validation_report) {
if !is_valid_cip509(&validation_data) {
error!("CIP509 validation failed: {:?}", validation_report);
bail!("CIP509 validation failed, {:?}", validation_report);
}
Expand Down Expand Up @@ -286,6 +290,15 @@ impl RegistrationChainInner {
}
}

/// Check if the CIP509 is valid.
fn is_valid_cip509(validation_data: &Cip509Validation) -> bool {
validation_data.valid_aux
&& validation_data.valid_txn_inputs_hash
&& validation_data.valid_public_key
&& validation_data.valid_payment_key
&& validation_data.signing_key
}

/// Process x509 certificate for chain root.
fn chain_root_x509_certs(
x509_certs: Option<Vec<X509DerCert>>, point_tx_idx: &PointTxIdx,
Expand Down
7 changes: 7 additions & 0 deletions rust/rbac-registration/src/utils/general.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ pub(crate) fn decode_utf8(content: &[u8]) -> anyhow::Result<String> {
)
})
}

/// Zero out the last n bytes
pub(crate) fn zero_out_last_n_bytes(vec: &mut [u8], n: usize) {
if let Some(slice) = vec.get_mut(vec.len().saturating_sub(n)..) {
slice.fill(0);
}
}

0 comments on commit 47b5514

Please sign in to comment.