Skip to content

Commit de667b7

Browse files
role data as map
1 parent 2afd1ff commit de667b7

File tree

10 files changed

+300
-264
lines changed

10 files changed

+300
-264
lines changed

rust/cardano-blockchain-types/src/lib.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,6 @@
33
pub mod conversion;
44
pub mod hashes;
55

6-
mod auxdata;
7-
mod cip134_uri;
8-
mod fork;
9-
mod multi_era_block_data;
10-
mod network;
11-
mod point;
12-
mod slot;
13-
mod txn_index;
14-
mod txn_witness;
15-
166
pub use auxdata::{
177
aux_data::TransactionAuxData,
188
block::BlockAuxData,
@@ -29,3 +19,13 @@ pub use point::Point;
2919
pub use slot::Slot;
3020
pub use txn_index::TxnIndex;
3121
pub use txn_witness::{TxnWitness, VKeyHash};
22+
23+
mod auxdata;
24+
mod cip134_uri;
25+
mod fork;
26+
mod multi_era_block_data;
27+
mod network;
28+
mod point;
29+
mod slot;
30+
mod txn_index;
31+
mod txn_witness;

rust/rbac-registration/src/cardano/cip509/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,19 @@ use minicbor::{
1818
};
1919
use pallas::ledger::traverse::MultiEraTx;
2020
use strum_macros::FromRepr;
21-
use types::tx_input_hash::TxInputHash;
2221
use uuid::Uuid;
2322
use validation::{
2423
validate_aux, validate_payment_key, validate_role_singing_key, validate_stake_public_key,
2524
validate_txn_inputs_hash,
2625
};
27-
use x509_chunks::X509Chunks;
2826

2927
use super::transaction::witness::TxWitness;
3028
use crate::{
31-
cardano::cip509::{rbac::Cip509RbacMetadata, types::ValidationSignature},
29+
cardano::cip509::{
30+
rbac::Cip509RbacMetadata,
31+
types::{TxInputHash, ValidationSignature},
32+
x509_chunks::X509Chunks,
33+
},
3234
utils::{
3335
decode_helper::{
3436
decode_bytes, decode_helper, decode_map_len, report_duplicated_key, report_missing_keys,
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
use std::collections::HashMap;
2+
3+
use catalyst_types::problem_report::ProblemReport;
4+
use minicbor::{decode, Decode, Decoder};
5+
use strum_macros::FromRepr;
6+
7+
use crate::{
8+
cardano::cip509::{
9+
rbac::{
10+
role_data::RoleNumberAndData, C509Cert, RoleData, RoleNumber, SimplePublicKeyType,
11+
X509DerCert,
12+
},
13+
types::CertKeyHash,
14+
utils::Cip0134UriSet,
15+
},
16+
utils::decode_helper::{
17+
decode_any, decode_array_len, decode_bytes, decode_helper, decode_map_len,
18+
report_duplicated_key,
19+
},
20+
};
21+
22+
/// Cip509 RBAC metadata.
23+
///
24+
/// See [this document] for more details.
25+
///
26+
/// [this document]: https://github.com/input-output-hk/catalyst-CIPs/tree/x509-role-registration-metadata/CIP-XXXX
27+
#[derive(Debug, PartialEq, Clone)]
28+
pub struct Cip509RbacMetadata {
29+
/// A potentially empty list of x509 certificates.
30+
pub x509_certs: Vec<X509DerCert>,
31+
/// A potentially empty list of c509 certificates.
32+
pub c509_certs: Vec<C509Cert>,
33+
/// A set of URIs contained in both x509 and c509 certificates.
34+
///
35+
/// URIs from different certificate types are stored separately and certificate
36+
/// indexes are preserved too.
37+
///
38+
/// This field isn't present in the encoded format and is populated by processing both
39+
/// `x509_certs` and `c509_certs` fields.
40+
pub certificate_uris: Cip0134UriSet,
41+
/// A list of public keys that can be used instead of storing full certificates.
42+
///
43+
/// Check [this section] to understand the how certificates and the public keys list
44+
/// are related.
45+
///
46+
/// [this section]: https://github.com/input-output-hk/catalyst-CIPs/tree/x509-role-registration-metadata/CIP-XXXX#storing-certificates-and-public-key
47+
pub pub_keys: Vec<SimplePublicKeyType>,
48+
/// A potentially empty list of revoked certificates.
49+
pub revocation_list: Vec<CertKeyHash>,
50+
/// A potentially empty role data.
51+
pub role_data: HashMap<RoleNumber, RoleData>,
52+
/// Optional map of purpose key data.
53+
/// Empty map if no purpose key data is present.
54+
pub purpose_key_data: HashMap<u16, Vec<u8>>,
55+
}
56+
57+
/// The first valid purpose key.
58+
const FIRST_PURPOSE_KEY: u16 = 200;
59+
/// The last valid purpose key.
60+
const LAST_PURPOSE_KEY: u16 = 299;
61+
62+
/// Enum of CIP509 RBAC metadata with its associated unsigned integer value.
63+
#[derive(FromRepr, Debug, PartialEq, Copy, Clone)]
64+
#[repr(u16)]
65+
pub enum Cip509RbacMetadataInt {
66+
/// x509 certificates.
67+
X509Certs = 10,
68+
/// c509 certificates.
69+
C509Certs = 20,
70+
/// Public keys.
71+
PubKeys = 30,
72+
/// Revocation list.
73+
RevocationList = 40,
74+
/// Role data set.
75+
RoleSet = 100,
76+
}
77+
78+
impl Decode<'_, ProblemReport> for Cip509RbacMetadata {
79+
fn decode(d: &mut Decoder, report: &mut ProblemReport) -> Result<Self, decode::Error> {
80+
let context = "Cip509RbacMetadata";
81+
let map_len = decode_map_len(d, context)?;
82+
83+
let mut found_keys = Vec::new();
84+
85+
let mut x509_certs = Vec::new();
86+
let mut c509_certs = Vec::new();
87+
let mut pub_keys = Vec::new();
88+
let mut revocation_list = Vec::new();
89+
let mut role_data = HashMap::new();
90+
let mut purpose_key_data = HashMap::new();
91+
92+
for index in 0..map_len {
93+
let key: u16 = decode_helper(d, "key in Cip509RbacMetadata", &mut ())?;
94+
if let Some(key) = Cip509RbacMetadataInt::from_repr(key) {
95+
if report_duplicated_key(&found_keys, &key, index, context, report) {
96+
continue;
97+
}
98+
found_keys.push(key);
99+
100+
match key {
101+
Cip509RbacMetadataInt::X509Certs => {
102+
x509_certs =
103+
decode_array(d, "Cip509RbacMetadata x509 certificates", report);
104+
},
105+
Cip509RbacMetadataInt::C509Certs => {
106+
c509_certs = decode_array(d, "Cip509RbacMetadata c509 certificate", report);
107+
},
108+
Cip509RbacMetadataInt::PubKeys => {
109+
pub_keys = decode_array(d, "Cip509RbacMetadata public keys", report);
110+
},
111+
Cip509RbacMetadataInt::RevocationList => {
112+
revocation_list = decode_revocation_list(d, report);
113+
},
114+
Cip509RbacMetadataInt::RoleSet => {
115+
role_data = decode_array::<RoleNumberAndData>(
116+
d,
117+
"Cip509RbacMetadata role set",
118+
report,
119+
)
120+
.into_iter()
121+
.map(|v| (v.number, v.data))
122+
.collect();
123+
},
124+
}
125+
} else {
126+
if !(FIRST_PURPOSE_KEY..=LAST_PURPOSE_KEY).contains(&key) {
127+
report.other(&format!("Invalid purpose key set, should be with the range {FIRST_PURPOSE_KEY} - {LAST_PURPOSE_KEY}"), context);
128+
continue;
129+
}
130+
131+
match decode_any(d, "purpose key") {
132+
Ok(v) => {
133+
purpose_key_data.insert(key, v);
134+
},
135+
Err(e) => {
136+
report.other(&format!("Unable to decode purpose value: {e:?}"), context);
137+
},
138+
}
139+
}
140+
}
141+
142+
let certificate_uris = Cip0134UriSet::new(&x509_certs, &c509_certs, report);
143+
144+
Ok(Self {
145+
x509_certs,
146+
c509_certs,
147+
certificate_uris,
148+
pub_keys,
149+
revocation_list,
150+
role_data,
151+
purpose_key_data,
152+
})
153+
}
154+
}
155+
156+
/// Decodes an array of type T.
157+
fn decode_array<'b, T>(d: &mut Decoder<'b>, context: &str, report: &ProblemReport) -> Vec<T>
158+
where T: Decode<'b, ()> {
159+
let len = match decode_array_len(d, context) {
160+
Ok(v) => v,
161+
Err(e) => {
162+
report.other(&format!("Unable to decode array length: {e:?}"), context);
163+
return Vec::new();
164+
},
165+
};
166+
let len = match usize::try_from(len) {
167+
Ok(v) => v,
168+
Err(e) => {
169+
report.other(&format!("Invalid array length: {e:?}"), context);
170+
return Vec::new();
171+
},
172+
};
173+
174+
let mut result = Vec::with_capacity(len);
175+
for _ in 0..len {
176+
match T::decode(d, &mut ()) {
177+
Ok(v) => result.push(v),
178+
Err(e) => {
179+
report.other(&format!("Unable to decode array value: {e:?}"), context);
180+
},
181+
}
182+
}
183+
result
184+
}
185+
186+
/// Decode an array of revocation list.
187+
fn decode_revocation_list(d: &mut Decoder, report: &ProblemReport) -> Vec<CertKeyHash> {
188+
let context = "Cip509RbacMetadata revocation list";
189+
let len = match decode_array_len(d, context) {
190+
Ok(v) => v,
191+
Err(e) => {
192+
report.other(&format!("Unable to decode array length: {e:?}"), context);
193+
return Vec::new();
194+
},
195+
};
196+
let len = match usize::try_from(len) {
197+
Ok(v) => v,
198+
Err(e) => {
199+
report.other(&format!("Invalid array length: {e:?}"), context);
200+
return Vec::new();
201+
},
202+
};
203+
204+
let mut result = Vec::with_capacity(len);
205+
for _ in 0..len {
206+
let bytes = match decode_bytes(d, context) {
207+
Ok(v) => v,
208+
Err(e) => {
209+
report.other(
210+
&format!("Unable to decode certificate hash bytes: {e:?}"),
211+
context,
212+
);
213+
continue;
214+
},
215+
};
216+
match CertKeyHash::try_from(bytes) {
217+
Ok(v) => result.push(v),
218+
Err(e) => {
219+
report.other(
220+
&format!("Invalid revocation list certificate hash: {e:?}"),
221+
context,
222+
);
223+
},
224+
}
225+
}
226+
result
227+
}

0 commit comments

Comments
 (0)