Skip to content

Commit

Permalink
Introduce Cip0134UriSet type
Browse files Browse the repository at this point in the history
  • Loading branch information
stanislav-tkach committed Dec 21, 2024
1 parent 433f3cb commit d1251df
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 228 deletions.
46 changes: 31 additions & 15 deletions rust/rbac-registration/src/cardano/cip509/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Hash<32>>, // 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<Hash<32>>,
/// Metadata.
///
/// This field encoded in chunks. See [`X509Chunks`] for more details.
pub metadata: Cip509RbacMetadata,
/// Validation signature.
pub validation_signature: Vec<u8>, // bytes size (1..64)
// TODO: FIXME: This probably should be a separate type and not just Vec.
pub validation_signature: Vec<u8>,
}

/// Validation value for CIP509 metadatum.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions rust/rbac-registration/src/cardano/cip509/rbac/certs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>),
}

Expand Down
81 changes: 33 additions & 48 deletions rust/rbac-registration/src/cardano/cip509/rbac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> -> 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<Vec<X509DerCert>>,
/// Optional list of c509 certificates.
/// The value can be either the c509 certificate or c509 metadatum reference.
pub c509_certs: Option<Vec<C509Cert>>,
/// 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<Vec<SimplePublicKeyType>>,
/// Optional list of revocation list.
pub revocation_list: Option<Vec<CertKeyHash>>,
Expand Down Expand Up @@ -60,74 +81,35 @@ 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<X509DerCert>) {
self.x509_certs = Some(x509_certs);
}

/// Set the c509 certificates.
fn set_c509_certs(&mut self, c509_certs: Vec<C509Cert>) {
self.c509_certs = Some(c509_certs);
}

/// Set the public keys.
fn set_pub_keys(&mut self, pub_keys: Vec<SimplePublicKeyType>) {
self.pub_keys = Some(pub_keys);
}

/// Set the revocation list.
fn set_revocation_list(&mut self, revocation_list: Vec<CertKeyHash>) {
self.revocation_list = Some(revocation_list);
}

/// Set the role data set.
fn set_role_set(&mut self, role_set: Vec<RoleData>) {
self.role_set = Some(role_set);
}
}

impl Decode<'_, ()> for Cip509RbacMetadata {
fn decode(d: &mut Decoder, ctx: &mut ()) -> Result<Self, decode::Error> {
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)?;
if let Some(key) = Cip509RbacMetadataInt::from_repr(key) {
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 {
Expand All @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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]);

Expand Down
7 changes: 7 additions & 0 deletions rust/rbac-registration/src/cardano/cip509/utils/cip134/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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:.+
Expand All @@ -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,
Expand Down
Loading

0 comments on commit d1251df

Please sign in to comment.