From d1251df4cfd70c4df21bcb72007b723af2e95973 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Fri, 20 Dec 2024 18:30:49 +0100 Subject: [PATCH] Introduce Cip0134UriSet type --- .../src/cardano/cip509/mod.rs | 46 ++-- .../src/cardano/cip509/rbac/certs.rs | 1 + .../src/cardano/cip509/rbac/mod.rs | 81 +++--- .../src/cardano/cip509/types/tx_input_hash.rs | 6 +- .../src/cardano/cip509/utils/cip134/mod.rs | 7 + .../cip509/utils/{cip134.rs => cip134/uri.rs} | 5 +- .../cardano/cip509/utils/cip134/uri_set.rs | 243 ++++++++++++++++++ .../src/cardano/cip509/utils/mod.rs | 2 +- .../src/cardano/cip509/validation.rs | 160 +----------- .../src/cardano/cip509/x509_chunks.rs | 22 +- rust/rbac-registration/src/lib.rs | 3 +- .../src/registration/cardano/mod.rs | 4 +- 12 files changed, 352 insertions(+), 228 deletions(-) create mode 100644 rust/rbac-registration/src/cardano/cip509/utils/cip134/mod.rs rename rust/rbac-registration/src/cardano/cip509/utils/{cip134.rs => cip134/uri.rs} (98%) create mode 100644 rust/rbac-registration/src/cardano/cip509/utils/cip134/uri_set.rs diff --git a/rust/rbac-registration/src/cardano/cip509/mod.rs b/rust/rbac-registration/src/cardano/cip509/mod.rs index 421cf9852..1f29f1ec1 100644 --- a/rust/rbac-registration/src/cardano/cip509/mod.rs +++ b/rust/rbac-registration/src/cardano/cip509/mod.rs @@ -25,28 +25,43 @@ use validation::{ use x509_chunks::X509Chunks; use super::transaction::witness::TxWitness; -use crate::utils::{ - decode_helper::{decode_bytes, decode_helper, decode_map_len}, - general::{decode_utf8, decremented_index}, - hashing::{blake2b_128, blake2b_256}, +use crate::{ + cardano::cip509::rbac::Cip509RbacMetadata, + utils::{ + decode_helper::{decode_bytes, decode_helper, decode_map_len}, + general::{decode_utf8, decremented_index}, + hashing::{blake2b_128, blake2b_256}, + }, }; /// CIP509 label. pub const LABEL: u64 = 509; -/// CIP509. +/// A x509 metadata envelope. +/// +/// The envelope is required to prevent replayability attacks. See [this document] for +/// more details. +/// +/// [this document]: https://github.com/input-output-hk/catalyst-CIPs/blob/x509-envelope-metadata/CIP-XXXX/README.md #[derive(Debug, PartialEq, Clone, Default)] pub struct Cip509 { - /// `UUIDv4` Purpose . - pub purpose: Uuid, // (bytes .size 16) + /// A registration purpose (UUIDv4). + /// + /// The purpose is defined by the consuming dApp. + pub purpose: Uuid, /// Transaction inputs hash. - pub txn_inputs_hash: TxInputHash, // bytes .size 16 - /// Optional previous transaction ID. - pub prv_tx_id: Option>, // bytes .size 32 - /// x509 chunks. - pub x509_chunks: X509Chunks, // chunk_type => [ + x509_chunk ] + pub txn_inputs_hash: TxInputHash, + /// An optional BLAKE2b hash of the previous transaction. + /// + /// The hash must always be present except for the first registration transaction. + pub prv_tx_id: Option>, + /// Metadata. + /// + /// This field encoded in chunks. See [`X509Chunks`] for more details. + pub metadata: Cip509RbacMetadata, /// Validation signature. - pub validation_signature: Vec, // bytes size (1..64) + // TODO: FIXME: This probably should be a separate type and not just Vec. + pub validation_signature: Vec, } /// Validation value for CIP509 metadatum. @@ -132,9 +147,10 @@ impl Decode<'_, ()> for Cip509 { }, } } else { + // TODO: FIXME: Check that only one key (10, 11, 12 (+up to 17?)) is present?.. // Handle the x509 chunks 10 11 12 let x509_chunks = X509Chunks::decode(d, ctx)?; - cip509_metadatum.x509_chunks = x509_chunks; + cip509_metadatum.metadata = x509_chunks.into(); } } Ok(cip509_metadatum) @@ -179,7 +195,7 @@ impl Cip509 { let mut is_valid_stake_public_key = true; let mut is_valid_payment_key = true; let mut is_valid_signing_key = true; - if let Some(role_set) = &self.x509_chunks.0.role_set { + if let Some(role_set) = &self.metadata.role_set { // Validate only role 0 for role in role_set { if role.role_number == 0 { diff --git a/rust/rbac-registration/src/cardano/cip509/rbac/certs.rs b/rust/rbac-registration/src/cardano/cip509/rbac/certs.rs index de34cd392..f0abc2ee4 100644 --- a/rust/rbac-registration/src/cardano/cip509/rbac/certs.rs +++ b/rust/rbac-registration/src/cardano/cip509/rbac/certs.rs @@ -18,6 +18,7 @@ pub enum X509DerCert { /// Deleted indicates the key is deleted. Deleted, /// X.509 certificate. + // TODO: FIXME: Store `x509_cert::Certificate` instead of bytes?! X509Cert(Vec), } diff --git a/rust/rbac-registration/src/cardano/cip509/rbac/mod.rs b/rust/rbac-registration/src/cardano/cip509/rbac/mod.rs index 34675d80c..baa220493 100644 --- a/rust/rbac-registration/src/cardano/cip509/rbac/mod.rs +++ b/rust/rbac-registration/src/cardano/cip509/rbac/mod.rs @@ -16,19 +16,40 @@ use role_data::RoleData; use strum_macros::FromRepr; use super::types::cert_key_hash::CertKeyHash; -use crate::utils::decode_helper::{ - decode_any, decode_array_len, decode_bytes, decode_helper, decode_map_len, +use crate::{ + cardano::cip509::utils::Cip0134UriSet, + utils::decode_helper::{ + decode_any, decode_array_len, decode_bytes, decode_helper, decode_map_len, + }, }; /// Cip509 RBAC metadata. +/// +/// See [this document] for more details. +/// +/// [this document]: https://github.com/input-output-hk/catalyst-CIPs/tree/x509-role-registration-metadata/CIP-XXXX #[derive(Debug, PartialEq, Clone, Default)] +// TODO: FIXME: Discuss if we need options everywhere (`Option -> Vec`). pub struct Cip509RbacMetadata { + // TODO: FIXME: Parse X509DerCert?.. + // TODO: FIXME: Store only C509Cert (transcode X509DerCert to C509Cert?). + // TODO: FIXME: Check if we allow both lists to be present. + // TODO: FIXME: Better documentation for the certificate field (or fields!). /// Optional list of x509 certificates. pub x509_certs: Option>, /// Optional list of c509 certificates. /// The value can be either the c509 certificate or c509 metadatum reference. pub c509_certs: Option>, - /// Optional list of Public keys. + // TODO: FIXME: Better documentation for the URI set/list field. + /// This field isn't present in the encoded format and is populated by processing both + /// `x509_certs` and `c509_certs`. + pub fixme: Cip0134UriSet, + /// A list of public keys that can be used instead of storing full certificates. + /// + /// Check [this section] to understand the how certificates and the public keys list + /// are related. + /// + /// [this section]: https://github.com/input-output-hk/catalyst-CIPs/tree/x509-role-registration-metadata/CIP-XXXX#storing-certificates-and-public-key pub pub_keys: Option>, /// Optional list of revocation list. pub revocation_list: Option>, @@ -60,50 +81,11 @@ pub enum Cip509RbacMetadataInt { RoleSet = 100, } -impl Cip509RbacMetadata { - /// Create a new instance of `Cip509RbacMetadata`. - pub(crate) fn new() -> Self { - Self { - x509_certs: None, - c509_certs: None, - pub_keys: None, - revocation_list: None, - role_set: None, - purpose_key_data: HashMap::new(), - } - } - - /// Set the x509 certificates. - fn set_x509_certs(&mut self, x509_certs: Vec) { - self.x509_certs = Some(x509_certs); - } - - /// Set the c509 certificates. - fn set_c509_certs(&mut self, c509_certs: Vec) { - self.c509_certs = Some(c509_certs); - } - - /// Set the public keys. - fn set_pub_keys(&mut self, pub_keys: Vec) { - self.pub_keys = Some(pub_keys); - } - - /// Set the revocation list. - fn set_revocation_list(&mut self, revocation_list: Vec) { - self.revocation_list = Some(revocation_list); - } - - /// Set the role data set. - fn set_role_set(&mut self, role_set: Vec) { - self.role_set = Some(role_set); - } -} - impl Decode<'_, ()> for Cip509RbacMetadata { fn decode(d: &mut Decoder, ctx: &mut ()) -> Result { let map_len = decode_map_len(d, "Cip509RbacMetadata")?; - let mut x509_rbac_metadata = Cip509RbacMetadata::new(); + let mut x509_rbac_metadata = Cip509RbacMetadata::default(); for _ in 0..map_len { let key: u16 = decode_helper(d, "key in Cip509RbacMetadata", ctx)?; @@ -111,23 +93,23 @@ impl Decode<'_, ()> for Cip509RbacMetadata { match key { Cip509RbacMetadataInt::X509Certs => { let x509_certs = decode_array_rbac(d, "x509 certificate")?; - x509_rbac_metadata.set_x509_certs(x509_certs); + x509_rbac_metadata.x509_certs = Some(x509_certs); }, Cip509RbacMetadataInt::C509Certs => { let c509_certs = decode_array_rbac(d, "c509 certificate")?; - x509_rbac_metadata.set_c509_certs(c509_certs); + x509_rbac_metadata.c509_certs = Some(c509_certs); }, Cip509RbacMetadataInt::PubKeys => { let pub_keys = decode_array_rbac(d, "public keys")?; - x509_rbac_metadata.set_pub_keys(pub_keys); + x509_rbac_metadata.pub_keys = Some(pub_keys); }, Cip509RbacMetadataInt::RevocationList => { let revocation_list = decode_revocation_list(d)?; - x509_rbac_metadata.set_revocation_list(revocation_list); + x509_rbac_metadata.revocation_list = Some(revocation_list); }, Cip509RbacMetadataInt::RoleSet => { let role_set = decode_array_rbac(d, "role set")?; - x509_rbac_metadata.set_role_set(role_set); + x509_rbac_metadata.role_set = Some(role_set); }, } } else { @@ -139,6 +121,9 @@ impl Decode<'_, ()> for Cip509RbacMetadata { .insert(key, decode_any(d, "purpose key")?); } } + + // TODO: FIXME: + x509_rbac_metadata.fixme = Cip0134UriSet::new(); Ok(x509_rbac_metadata) } } diff --git a/rust/rbac-registration/src/cardano/cip509/types/tx_input_hash.rs b/rust/rbac-registration/src/cardano/cip509/types/tx_input_hash.rs index bcc0c0bc4..ec6faa945 100644 --- a/rust/rbac-registration/src/cardano/cip509/types/tx_input_hash.rs +++ b/rust/rbac-registration/src/cardano/cip509/types/tx_input_hash.rs @@ -1,6 +1,10 @@ //! Transaction input hash type -/// Transaction input hash representing in 16 bytes. +/// A 16-byte hash of the transaction inputs field. +/// +/// This type is described [here]. +/// +/// [here]: https://github.com/input-output-hk/catalyst-CIPs/blob/x509-envelope-metadata/CIP-XXXX/README.md#key-1-txn-inputs-hash #[derive(Debug, PartialEq, Clone, Default)] pub struct TxInputHash([u8; 16]); diff --git a/rust/rbac-registration/src/cardano/cip509/utils/cip134/mod.rs b/rust/rbac-registration/src/cardano/cip509/utils/cip134/mod.rs new file mode 100644 index 000000000..702b09faa --- /dev/null +++ b/rust/rbac-registration/src/cardano/cip509/utils/cip134/mod.rs @@ -0,0 +1,7 @@ +//! Utilities for [CIP-134] (Cardano URIs - Address Representation). +//! +//! [CIP-134]: https://github.com/cardano-foundation/CIPs/tree/master/CIP-0134 +pub use self::{uri::Cip0134Uri, uri_set::Cip0134UriSet}; + +mod uri; +mod uri_set; diff --git a/rust/rbac-registration/src/cardano/cip509/utils/cip134.rs b/rust/rbac-registration/src/cardano/cip509/utils/cip134/uri.rs similarity index 98% rename from rust/rbac-registration/src/cardano/cip509/utils/cip134.rs rename to rust/rbac-registration/src/cardano/cip509/utils/cip134/uri.rs index 6aa42f57c..2af2fc18c 100644 --- a/rust/rbac-registration/src/cardano/cip509/utils/cip134.rs +++ b/rust/rbac-registration/src/cardano/cip509/utils/cip134/uri.rs @@ -1,4 +1,4 @@ -//! Utility functions for CIP-0134 address. +//! An URI in the CIP-0134 format. // Ignore URIs that are used in tests and doc-examples. // cSpell:ignoreRegExp web\+cardano:.+ @@ -13,7 +13,8 @@ use pallas::ledger::addresses::Address; /// See the [proposal] for more details. /// /// [proposal]: https://github.com/cardano-foundation/CIPs/pull/888 -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] +#[allow(clippy::module_name_repetitions)] pub struct Cip0134Uri { /// A URI string. uri: String, diff --git a/rust/rbac-registration/src/cardano/cip509/utils/cip134/uri_set.rs b/rust/rbac-registration/src/cardano/cip509/utils/cip134/uri_set.rs new file mode 100644 index 000000000..4ad14fef8 --- /dev/null +++ b/rust/rbac-registration/src/cardano/cip509/utils/cip134/uri_set.rs @@ -0,0 +1,243 @@ +//! A set of [`Cip0134Uri`]. + +// TODO: FIXME: +#![allow(unused_imports)] +#![allow(dead_code)] + +use std::{collections::HashMap, sync::Arc}; + +use c509_certificate::{ + extensions::{alt_name::GeneralNamesOrText, extension::ExtensionValue}, + general_names::general_name::{GeneralNameTypeRegistry, GeneralNameValue}, + C509ExtensionType, +}; +use der_parser::der::parse_der_sequence; +use tracing::debug; +use x509_cert::der::{oid::db::rfc5912::ID_CE_SUBJECT_ALT_NAME, Decode}; + +use crate::{ + cardano::cip509::{ + rbac::{ + certs::{C509Cert, X509DerCert}, + Cip509RbacMetadata, + }, + utils::Cip0134Uri, + validation::URI, + Cip509, + }, + utils::general::decode_utf8, +}; + +/// A mapping from certificate index to +type UrisMap = HashMap; + +/// A set of [`Cip0134Uri`] contained in both x509 and c509 certificates stored in the +/// metadata part of [`Cip509`]. +/// +/// This structure uses [`Arc`] internally, so it is cheap to clone. +#[derive(Debug, Clone, Eq, PartialEq, Default)] +#[allow(clippy::module_name_repetitions)] +pub struct Cip0134UriSet(Arc); + +#[derive(Debug, Eq, PartialEq, Default)] +struct Cip0134UriSetInner { + /// Uris from x509 certificates. + c_uris: UrisMap, + /// Uris from c509 certificates. + x_uris: UrisMap, +} + +impl Cip0134UriSet { + pub fn new() -> Self { + todo!() + } + // TODO: FIXME: + // /// Creates a new `Cip0134UriList` instance from the given `Cip509`. + // #[must_use] + // pub fn new(cip509: &Cip509) -> Self { + // let metadata = &cip509.x509_chunks.0; + // let mut uris = process_x509_certificates(metadata); + // uris.extend(process_c509_certificates(metadata)); + // + // Self { uris: uris.into() } + // } + // + // /// Returns an iterator over the contained Cip0134 URIs. + // pub fn iter(&self) -> impl Iterator { + // self.uris.iter() + // } + // + // /// Returns a slice with all URIs in the list. + // #[must_use] + // pub fn as_slice(&self) -> &[Cip0134Uri] { + // &self.uris + // } +} + +// /// Iterates over X509 certificates and extracts CIP-0134 URIs. +// fn process_x509_certificates(metadata: &Cip509RbacMetadata) -> Vec { +// let mut result = Vec::new(); +// +// for cert in metadata.x509_certs.iter().flatten() { +// let X509DerCert::X509Cert(cert) = cert else { +// continue; +// }; +// let cert = match x509_cert::Certificate::from_der(cert) { +// Ok(cert) => cert, +// Err(e) => { +// debug!("Failed to decode x509 certificate DER: {e:?}"); +// continue; +// }, +// }; +// // Find the "subject alternative name" extension. +// let Some(extension) = cert +// .tbs_certificate +// .extensions +// .iter() +// .flatten() +// .find(|e| e.extn_id == ID_CE_SUBJECT_ALT_NAME) +// else { +// continue; +// }; +// let der = match parse_der_sequence(extension.extn_value.as_bytes()) { +// Ok((_, der)) => der, +// Err(e) => { +// debug!("Failed to parse DER sequence for Subject Alternative Name +// ({extension:?}): {e:?}"); continue; +// }, +// }; +// for data in der.ref_iter() { +// if data.header.raw_tag() != Some(&[URI]) { +// continue; +// } +// let content = match data.content.as_slice() { +// Ok(c) => c, +// Err(e) => { +// debug!("Unable to process content for {data:?}: {e:?}"); +// continue; +// }, +// }; +// let address = match decode_utf8(content) { +// Ok(a) => a, +// Err(e) => { +// debug!("Failed to decode content of {data:?}: {e:?}"); +// continue; +// }, +// }; +// match Cip0134Uri::parse(&address) { +// Ok(a) => result.push(a), +// Err(e) => { +// debug!("Failed to parse CIP-0134 address ({address}): {e:?}"); +// }, +// } +// } +// } +// +// result +// } +// +// /// Iterates over C509 certificates and extracts CIP-0134 URIs. +// fn process_c509_certificates(metadata: &Cip509RbacMetadata) -> Vec { +// let mut result = Vec::new(); +// +// for cert in metadata.c509_certs.iter().flatten() { +// let cert = match cert { +// C509Cert::C509Certificate(c) => c, +// C509Cert::C509CertInMetadatumReference(_) => { +// debug!("Ignoring unsupported metadatum reference"); +// continue; +// }, +// _ => continue, +// }; +// +// for extension in cert.tbs_cert().extensions().extensions() { +// if extension.registered_oid().c509_oid().oid() +// != &C509ExtensionType::SubjectAlternativeName.oid() +// { +// continue; +// } +// let ExtensionValue::AlternativeName(alt_name) = extension.value() else { +// debug!("Unexpected extension value type for {extension:?}"); +// continue; +// }; +// let GeneralNamesOrText::GeneralNames(gen_names) = alt_name.general_name() +// else { debug!("Unexpected general name type: {extension:?}"); +// continue; +// }; +// for name in gen_names.general_names() { +// if *name.gn_type() != +// GeneralNameTypeRegistry::UniformResourceIdentifier { continue; +// } +// let GeneralNameValue::Text(address) = name.gn_value() else { +// debug!("Unexpected general name value format: {name:?}"); +// continue; +// }; +// match Cip0134Uri::parse(address) { +// Ok(a) => result.push(a), +// Err(e) => { +// debug!("Failed to parse CIP-0134 address ({address}): {e:?}"); +// }, +// } +// } +// } +// } +// +// result +// } + +#[cfg(test)] +mod tests { + // TODO: FIXME: + // use minicbor::{Decode, Decoder}; + // use pallas::{ + // codec::utils::Nullable, + // ledger::{ + // addresses::{Address, Network}, + // traverse::{MultiEraBlock, MultiEraTx}, + // }, + // }; + // + // use super::*; + // use crate::cardano::transaction::raw_aux_data::RawAuxData; + // + // // This lint is disabled locally because unfortunately there is no + // // `allow-indexing-slicing-in-tests` option. Also it is impossible to use + // // `get(n).unwrap()` instead because Clippy will still complain + // (clippy::get-unwrap). #[allow(clippy::indexing_slicing)] + // #[test] + // fn list_new() { + // let block = + // hex::decode(include_str!("../../../../test_data/cardano/conway_1.block")). + // unwrap(); let block = MultiEraBlock::decode(&block).unwrap(); + // let tx = &block.txs()[3]; + // let cip509 = cip509(tx); + // + // let list = Cip0134UriList::new(&cip509); + // assert_eq!(list.as_slice().len(), 1); + // // cSpell:disable + // assert_eq!( + // list.as_slice()[0].uri(), + // "web+cardano://addr/ + // stake_test1urs8t0ssa3w9wh90ld5tprp3gurxd487rth2qlqk6ernjqcef4ugr" ); + // // cSpell:enable + // let Address::Stake(address) = list.as_slice()[0].address() else { + // panic!("Unexpected address type"); + // }; + // assert_eq!(Network::Testnet, address.network()); + // assert_eq!( + // "e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d6473903", + // address.payload().as_hash().to_string() + // ); + // } + // + // fn cip509(tx: &MultiEraTx) -> Cip509 { + // let Nullable::Some(data) = tx.as_conway().unwrap().clone().auxiliary_data else + // { panic!("Auxiliary data is missing"); + // }; + // let data = RawAuxData::new(data.raw_cbor()); + // let metadata = data.get_metadata(509).unwrap(); + // + // let mut decoder = Decoder::new(metadata.as_slice()); + // Cip509::decode(&mut decoder, &mut ()).unwrap() + // } +} diff --git a/rust/rbac-registration/src/cardano/cip509/utils/mod.rs b/rust/rbac-registration/src/cardano/cip509/utils/mod.rs index ab7c3954d..6cba2f3d6 100644 --- a/rust/rbac-registration/src/cardano/cip509/utils/mod.rs +++ b/rust/rbac-registration/src/cardano/cip509/utils/mod.rs @@ -1,6 +1,6 @@ //! Utility functions for CIP-509 pub mod cip19; -pub use cip134::Cip0134Uri; +pub use cip134::{Cip0134Uri, Cip0134UriSet}; mod cip134; diff --git a/rust/rbac-registration/src/cardano/cip509/validation.rs b/rust/rbac-registration/src/cardano/cip509/validation.rs index 205957f54..a2cbd8d3d 100644 --- a/rust/rbac-registration/src/cardano/cip509/validation.rs +++ b/rust/rbac-registration/src/cardano/cip509/validation.rs @@ -21,6 +21,9 @@ //! //! Note: This CIP509 is still under development and is subject to change. +// TODO: FIXME: +#![allow(unused_imports)] + use c509_certificate::{general_names::general_name::GeneralNameValue, C509ExtensionType}; use der_parser::der::parse_der_sequence; use pallas::{ @@ -110,159 +113,18 @@ pub(crate) fn validate_txn_inputs_hash( /// Validate the stake public key in the certificate with witness set in transaction. #[allow(clippy::too_many_lines)] pub(crate) fn validate_stake_public_key( - cip509: &Cip509, txn: &MultiEraTx, validation_report: &mut Vec, + _cip509: &Cip509, txn: &MultiEraTx, validation_report: &mut Vec, ) -> Option { let function_name = "Validate Stake Public Key"; - let mut pk_addrs = Vec::new(); - // CIP-0509 should only be in conway era - if let MultiEraTx::Conway(_) = txn { - // X509 certificate - if let Some(x509_certs) = &cip509.x509_chunks.0.x509_certs { - for x509_cert in x509_certs { - match x509_cert { - X509DerCert::X509Cert(cert) => { - // Attempt to decode the DER certificate - let der_cert = match x509_cert::Certificate::from_der(cert) { - Ok(cert) => cert, - Err(e) => { - validation_report.push(format!( - "{function_name}, Failed to decode x509 certificate DER: {e}" - )); - return None; - }, - }; - - // Find the Subject Alternative Name extension - let san_ext = - der_cert - .tbs_certificate - .extensions - .as_ref() - .and_then(|exts| { - exts.iter() - .find(|ext| ext.extn_id == ID_CE_SUBJECT_ALT_NAME) - }); - - // Subject Alternative Name extension if it exists - if let Some(san_ext) = san_ext { - match parse_der_sequence(san_ext.extn_value.as_bytes()) { - Ok((_, parsed_seq)) => { - for data in parsed_seq.ref_iter() { - // Check for context-specific primitive type with tag - // number - // 6 (raw_tag 134) - if data.header.raw_tag() == Some(&[URI]) { - match data.content.as_slice() { - Ok(content) => { - // Decode the UTF-8 string - let addr: String = match decode_utf8(content) { - Ok(addr) => addr, - Err(e) => { - validation_report.push(format!( - "{function_name}, Failed to decode UTF-8 string for context-specific primitive type with raw tag 134: {e}", - ), - ); - return None; - }, - }; - - // Extract the CIP19 hash and push into - // array - if let Ok(uri) = Cip0134Uri::parse(&addr) { - if let Address::Stake(a) = uri.address() { - pk_addrs.push( - a.payload().as_hash().to_vec(), - ); - } - } - }, - Err(e) => { - validation_report.push( - format!("{function_name}, Failed to process content for context-specific primitive type with raw tag 134: {e}")); - return None; - }, - } - } - } - }, - Err(e) => { - validation_report.push( - format!( - "{function_name}, Failed to parse DER sequence for Subject Alternative Name extension: {e}" - ) - ); - return None; - }, - } - } - }, - _ => continue, - } - } - } - // C509 Certificate - if let Some(c509_certs) = &cip509.x509_chunks.0.c509_certs { - for c509_cert in c509_certs { - match c509_cert { - C509Cert::C509CertInMetadatumReference(_) => { - validation_report.push(format!( - "{function_name}, C509 metadatum reference is currently not supported" - )); - }, - C509Cert::C509Certificate(c509) => { - for exts in c509.tbs_cert().extensions().extensions() { - if *exts.registered_oid().c509_oid().oid() - == C509ExtensionType::SubjectAlternativeName.oid() - { - match exts.value() { - c509_certificate::extensions::extension::ExtensionValue::AlternativeName(alt_name) => { - match alt_name.general_name() { - c509_certificate::extensions::alt_name::GeneralNamesOrText::GeneralNames(gn) => { - for name in gn.general_names() { - if name.gn_type() == &c509_certificate::general_names::general_name::GeneralNameTypeRegistry::UniformResourceIdentifier { - match name.gn_value() { - GeneralNameValue::Text(s) => { - if let Ok(uri) = Cip0134Uri::parse(s) { - if let Address::Stake(a) = uri.address() { - pk_addrs.push(a.payload().as_hash().to_vec()); - } - } - }, - _ => { - validation_report.push( - format!("{function_name}, Failed to get the value of subject alternative name"), - ); - } - } - } - } - }, - c509_certificate::extensions::alt_name::GeneralNamesOrText::Text(_) => { - validation_report.push( - format!("{function_name}, Failed to find C509 general names in subject alternative name"), - ); - } - } - }, - _ => { - validation_report.push( - format!("{function_name}, Failed to get C509 subject alternative name") - ); - } - } - } - } - }, - _ => continue, - } - } - } - } else { + if !matches!(txn, MultiEraTx::Conway(_)) { validation_report.push(format!("{function_name}, Unsupported transaction era")); return None; } + // TODO: FIXME: Replace pk_addrs. + let pk_addrs = Vec::new(); + // Create TxWitness // Note that TxWitness designs to work with multiple transactions let witnesses = match TxWitness::new(&[txn.clone()]) { @@ -597,7 +459,7 @@ mod tests { let mut decoder = Decoder::new(aux_data.as_slice()); let cip509 = Cip509::decode(&mut decoder, &mut ()).expect("Failed to decode Cip509"); - if let Some(role_set) = &cip509.x509_chunks.0.role_set { + if let Some(role_set) = &cip509.metadata.role_set { for role in role_set { if role.role_number == 0 { assert!(validate_payment_key(tx, role, &mut validation_report,).unwrap()); @@ -623,7 +485,7 @@ mod tests { let mut decoder = Decoder::new(aux_data.as_slice()); let cip509 = Cip509::decode(&mut decoder, &mut ()).expect("Failed to decode Cip509"); - if let Some(role_set) = &cip509.x509_chunks.0.role_set { + if let Some(role_set) = &cip509.metadata.role_set { for role in role_set { if role.role_number == 0 { assert!(validate_role_singing_key(role, &mut validation_report,)); @@ -650,7 +512,7 @@ mod tests { let mut decoder = Decoder::new(aux_data.as_slice()); let cip509 = Cip509::decode(&mut decoder, &mut ()).expect("Failed to decode Cip509"); - if let Some(role_set) = &cip509.x509_chunks.0.role_set { + if let Some(role_set) = &cip509.metadata.role_set { for role in role_set { if role.role_number == 0 { assert!(validate_payment_key(tx, role, &mut validation_report,).unwrap()); diff --git a/rust/rbac-registration/src/cardano/cip509/x509_chunks.rs b/rust/rbac-registration/src/cardano/cip509/x509_chunks.rs index 457faef6a..5e5182d69 100644 --- a/rust/rbac-registration/src/cardano/cip509/x509_chunks.rs +++ b/rust/rbac-registration/src/cardano/cip509/x509_chunks.rs @@ -21,15 +21,19 @@ pub enum CompressionAlgorithm { Zstd = 12, } -/// x509 chunks. -#[derive(Debug, PartialEq, Clone, Default)] -pub struct X509Chunks(pub Cip509RbacMetadata); - -#[allow(dead_code)] -impl X509Chunks { - /// Create new instance of `X509Chunks`. - fn new(chunk_data: Cip509RbacMetadata) -> Self { - Self(chunk_data) +/// A helper for decoding [`Cip509RbacMetadata`]. +/// +/// Due to encoding restrictions the [`Cip509`] metadata is encoded in chunks: +/// ```text +/// chunk_type => [ + x509_chunk ] +/// ``` +/// This helper is used to decode them into the actual structure. +#[derive(Debug, PartialEq, Clone)] +pub struct X509Chunks(Cip509RbacMetadata); + +impl From for Cip509RbacMetadata { + fn from(value: X509Chunks) -> Self { + value.0 } } diff --git a/rust/rbac-registration/src/lib.rs b/rust/rbac-registration/src/lib.rs index ab9cfd1e4..6e35f5165 100644 --- a/rust/rbac-registration/src/lib.rs +++ b/rust/rbac-registration/src/lib.rs @@ -2,4 +2,5 @@ pub mod cardano; pub mod registration; -pub(crate) mod utils; + +mod utils; diff --git a/rust/rbac-registration/src/registration/cardano/mod.rs b/rust/rbac-registration/src/registration/cardano/mod.rs index eeac8dd42..06a0362a7 100644 --- a/rust/rbac-registration/src/registration/cardano/mod.rs +++ b/rust/rbac-registration/src/registration/cardano/mod.rs @@ -198,7 +198,7 @@ impl RegistrationChainInner { // Add purpose to the list let purpose = vec![cip509.purpose]; - let registration = cip509.x509_chunks.0; + let registration = cip509.metadata; let point_tx_idx = PointTxIdx::new(point, tx_idx); let x509_cert_map = chain_root_x509_certs(registration.x509_certs, &point_tx_idx); @@ -269,7 +269,7 @@ impl RegistrationChainInner { new_inner.purpose.push(purpose); } - let registration = cip509.x509_chunks.0; + let registration = cip509.metadata; let point_tx_idx = PointTxIdx::new(point, tx_idx); update_x509_certs(&mut new_inner, registration.x509_certs, &point_tx_idx);