-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0aeadb9
commit 503d464
Showing
6 changed files
with
214 additions
and
165 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
rust/rbac-registration/src/cardano/cip509/utils/cip134/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//! 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_list::Cip0134UriList}; | ||
|
||
mod uri; | ||
mod uri_list; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
rust/rbac-registration/src/cardano/cip509/utils/cip134/uri_list.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
//! A list of [`Cip0134Uri`]. | ||
use std::sync::Arc; | ||
|
||
use anyhow::{anyhow, Result}; | ||
use c509_certificate::{ | ||
extensions::{alt_name::GeneralNamesOrText, extension::ExtensionValue}, | ||
general_names::general_name::{GeneralNameTypeRegistry, GeneralNameValue}, | ||
C509ExtensionType, | ||
}; | ||
use der_parser::der::parse_der_sequence; | ||
use pallas::ledger::traverse::MultiEraTx; | ||
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 list of [`Cip0134Uri`]. | ||
/// | ||
/// This structure uses [`Arc`] internally, so it is cheap to clone. | ||
#[derive(Debug, Clone)] | ||
#[allow(clippy::module_name_repetitions)] | ||
pub struct Cip0134UriList { | ||
/// An internal list of URIs. | ||
uris: Arc<[Cip0134Uri]>, | ||
} | ||
|
||
impl Cip0134UriList { | ||
/// Creates a new `Cip0134UriList` instance from the given `Cip509`. | ||
/// | ||
/// # Errors | ||
/// - Unsupported transaction era. | ||
pub fn new(cip509: &Cip509, tx: &MultiEraTx) -> Result<Self> { | ||
if !matches!(tx, MultiEraTx::Conway(_)) { | ||
return Err(anyhow!("Unsupported transaction era ({})", tx.era())); | ||
} | ||
|
||
let metadata = &cip509.x509_chunks.0; | ||
let mut uris = process_x509_certificates(metadata); | ||
uris.extend(process_c509_certificates(metadata)); | ||
|
||
Ok(Self { uris: uris.into() }) | ||
} | ||
|
||
/// Returns an iterator over the contained Cip0134 URIs. | ||
pub fn iter(&self) -> impl Iterator<Item = &Cip0134Uri> { | ||
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<Cip0134Uri> { | ||
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<Cip0134Uri> { | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
//! Utility functions for CIP-509 | ||
pub mod cip19; | ||
pub use cip134::Cip0134Uri; | ||
pub use cip134::{Cip0134Uri, Cip0134UriList}; | ||
|
||
mod cip134; |
Oops, something went wrong.