-
Notifications
You must be signed in to change notification settings - Fork 0
feat(rust/rbac-registration): Record each role data fields #244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
18211de
feat(rbac-registration): record each role data fields
bkioshn 7182c58
fix(rbac-registration): comment
bkioshn de7672f
fix(rbac-registration): syntax
bkioshn 2693290
Merge branch 'main' into feat/rbac-role-data-record
stevenj 72859a3
fix(rbac-registration): role data record
bkioshn 79b5cad
Merge branch 'main' into feat/rbac-role-data-record
bkioshn 7bb847a
fix(rbac-registration): remove key ref usize conversion
bkioshn b675c2a
fix(rbac-registration): move update rbac to its own file
bkioshn c513e94
fix(rbac-registration): add extract pk from cert or pk + rename
bkioshn 43e7a52
fix(rbac-registration): move all key extraction from cat-voice
bkioshn 48a1e05
fix(rbac-registration): add more function to get the actual pk from cert
bkioshn dc91e5a
Merge branch 'main' into feat/rbac-role-data-record
bkioshn 31e9e07
fix(rbac-registration): typo + format
bkioshn 83d6737
fix(rbac-registration): move cert_or_pk to its own file
bkioshn 1b69576
fix(rbac-registration): return ref
bkioshn d5a3e79
fix(rbac-registration): add structured error
bkioshn 3f098f3
fix(rbac-registration): change box to arc
bkioshn 0396289
Merge branch 'main' into feat/rbac-role-data-record
bkioshn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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
32 changes: 32 additions & 0 deletions
32
rust/rbac-registration/src/cardano/cip509/types/cert_or_pk.rs
This file contains hidden or 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,32 @@ | ||
//! C509 certificate, X509 certificate, or public key. | ||
|
||
use std::sync::Arc; | ||
|
||
use c509_certificate::c509::C509; | ||
use ed25519_dalek::VerifyingKey; | ||
use x509_cert::Certificate as X509; | ||
|
||
use crate::cardano::cip509::extract_key; | ||
|
||
/// Actual data of key local ref. Containing X509, C509 and public key. | ||
#[derive(Debug, Clone)] | ||
pub enum CertOrPk { | ||
/// X509 certificate, None if deleted. | ||
X509(Option<Arc<X509>>), | ||
/// C509 certificate, None if deleted. | ||
C509(Option<Arc<C509>>), | ||
/// Public key, None if deleted. | ||
PublicKey(Option<VerifyingKey>), | ||
} | ||
|
||
impl CertOrPk { | ||
/// Extract public key from the given certificate or public key. | ||
pub(crate) fn extract_pk(&self) -> Option<VerifyingKey> { | ||
match self { | ||
CertOrPk::X509(Some(x509)) => extract_key::x509_key(x509).ok(), | ||
CertOrPk::C509(Some(c509)) => extract_key::c509_key(c509).ok(), | ||
CertOrPk::PublicKey(pk) => *pk, | ||
_ => None, | ||
} | ||
} | ||
} |
This file contains hidden or 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,21 +1,25 @@ | ||
//! Types use in CIP-509 | ||
|
||
pub use cert_key_hash::CertKeyHash; | ||
pub use cert_or_pk::CertOrPk; | ||
pub use key_local_ref::{KeyLocalRef, LocalRefInt}; | ||
pub use payment_history::{Payment, PaymentHistory}; | ||
pub use point_data::PointData; | ||
pub use point_tx_idx::PointTxnIdx; | ||
pub use role_data::RoleData; | ||
pub use role_data_record::RoleDataRecord; | ||
pub use role_number::RoleNumber; | ||
pub use tx_input_hash::TxInputHash; | ||
pub use validation_signature::ValidationSignature; | ||
|
||
mod cert_key_hash; | ||
mod cert_or_pk; | ||
mod key_local_ref; | ||
mod payment_history; | ||
mod point_data; | ||
mod point_tx_idx; | ||
mod role_data; | ||
mod role_data_record; | ||
mod role_number; | ||
mod tx_input_hash; | ||
mod validation_signature; |
100 changes: 100 additions & 0 deletions
100
rust/rbac-registration/src/cardano/cip509/types/role_data_record.rs
This file contains hidden or 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,100 @@ | ||
//! Role data record where each role data fields are stored. | ||
|
||
use std::collections::HashMap; | ||
|
||
use pallas::ledger::addresses::ShelleyAddress; | ||
|
||
use super::{CertOrPk, PointData, PointTxnIdx}; | ||
|
||
/// Role data record where each field has it own record of its value and its associated | ||
/// point and transaction index. If a field has key rotation, then the vector index is | ||
/// used. Eg. Accessing key rotation 0 can be done by `signing_keys.first()` | ||
#[derive(Debug, Clone)] | ||
pub struct RoleDataRecord { | ||
/// List of signing key data and its associated point + tx index . | ||
/// The vector index is used to indicate the key rotation. | ||
signing_keys: Vec<PointData<CertOrPk>>, | ||
/// List of encryption key data and its associated point + tx index | ||
/// The vector index is used to indicate the key rotation. | ||
encryption_keys: Vec<PointData<CertOrPk>>, | ||
/// List of payment key and its associated point + tx index. | ||
payment_keys: Vec<PointData<ShelleyAddress>>, | ||
/// List of extended data and its associated point + tx index. | ||
extended_data: Vec<PointData<HashMap<u8, Vec<u8>>>>, | ||
} | ||
|
||
impl RoleDataRecord { | ||
/// Create a new empty role data record. | ||
pub(crate) fn new() -> Self { | ||
Self { | ||
signing_keys: Vec::new(), | ||
encryption_keys: Vec::new(), | ||
payment_keys: Vec::new(), | ||
extended_data: Vec::new(), | ||
} | ||
} | ||
|
||
/// Add a signing key data to the signing key list. The vector index is used to | ||
/// indicate the key rotation. | ||
pub(crate) fn add_signing_key(&mut self, data: CertOrPk, point_tx_idx: &PointTxnIdx) { | ||
self.signing_keys | ||
.push(PointData::new(point_tx_idx.clone(), data)); | ||
} | ||
|
||
/// Add an encryption key data to the encryption key list. The vector index is used to | ||
/// indicate the key rotation. | ||
pub(crate) fn add_encryption_key(&mut self, data: CertOrPk, point_tx_idx: &PointTxnIdx) { | ||
self.encryption_keys | ||
.push(PointData::new(point_tx_idx.clone(), data)); | ||
} | ||
|
||
/// Add a payment key to the payment key list. | ||
pub(crate) fn add_payment_key(&mut self, data: PointData<ShelleyAddress>) { | ||
self.payment_keys.push(data); | ||
} | ||
|
||
/// Add extended data to the extended data list. | ||
pub(crate) fn add_extended_data(&mut self, data: PointData<HashMap<u8, Vec<u8>>>) { | ||
self.extended_data.push(data); | ||
} | ||
|
||
/// Get the list of signing keys associated with this role. | ||
#[must_use] | ||
pub fn signing_keys(&self) -> &Vec<PointData<CertOrPk>> { | ||
&self.signing_keys | ||
} | ||
|
||
/// Get the list of encryption keys associated with this role. | ||
#[must_use] | ||
pub fn encryption_keys(&self) -> &Vec<PointData<CertOrPk>> { | ||
&self.encryption_keys | ||
} | ||
|
||
/// Get the list of payment keys associated with this role. | ||
#[must_use] | ||
pub fn payment_keys(&self) -> &Vec<PointData<ShelleyAddress>> { | ||
&self.payment_keys | ||
} | ||
|
||
/// Get the list of extended data associated with this role. | ||
#[must_use] | ||
pub fn extended_data(&self) -> &Vec<PointData<HashMap<u8, Vec<u8>>>> { | ||
&self.extended_data | ||
} | ||
|
||
/// Get the signing key data associated with this role and the given key rotation. | ||
/// The first signing key is at rotation 0, the second at rotation 1, and so on. | ||
/// Returns `None` if the given key rotation does not exist. | ||
#[must_use] | ||
pub fn signing_key_from_rotation(&self, rotation: usize) -> Option<&CertOrPk> { | ||
self.signing_keys.get(rotation).map(PointData::data) | ||
} | ||
|
||
/// Get the encryption key data associated with this role and the given key rotation. | ||
/// The first encryption key is at rotation 0, the second at rotation 1, and so on. | ||
/// Returns `None` if the given key rotation does not exist. | ||
#[must_use] | ||
pub fn encryption_key_from_rotation(&self, rotation: usize) -> Option<&CertOrPk> { | ||
self.encryption_keys.get(rotation).map(PointData::data) | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
rust/rbac-registration/src/cardano/cip509/utils/extract_key.rs
This file contains hidden or 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,94 @@ | ||
//! Functions for extracting public key from X509 and C509 certificates with additional | ||
//! verification. | ||
|
||
use anyhow::{anyhow, Context}; | ||
use c509_certificate::c509::C509; | ||
use ed25519_dalek::{VerifyingKey, PUBLIC_KEY_LENGTH}; | ||
use oid_registry::{Oid, OID_SIG_ED25519}; | ||
use thiserror::Error; | ||
use x509_cert::Certificate as X509Certificate; | ||
|
||
/// Error type for unsupported signature algorithms. | ||
#[derive(Error, Debug)] | ||
#[error("Unsupported signature algorithm: {oid}")] | ||
pub struct SignatureAlgoError { | ||
/// An OID of unsupported signature algorithm. | ||
oid: String, | ||
} | ||
|
||
/// Returns `VerifyingKey` from the given X509 certificate. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Returns an error if the signature algorithm is not supported and | ||
/// the public key cannot be extracted. | ||
pub fn x509_key(cert: &X509Certificate) -> anyhow::Result<VerifyingKey> { | ||
Mr-Leshiy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let oid: Oid = cert | ||
.tbs_certificate | ||
.subject_public_key_info | ||
.algorithm | ||
.oid | ||
.to_string() | ||
.parse() | ||
// `Context` cannot be used here because `OidParseError` doesn't implement `std::Error`. | ||
.map_err(|e| anyhow!("Invalid signature algorithm OID: {e:?}"))?; | ||
check_signature_algorithm(&oid)?; | ||
let extended_public_key = cert | ||
.tbs_certificate | ||
.subject_public_key_info | ||
.subject_public_key | ||
.as_bytes() | ||
.context("Invalid subject_public_key value (has unused bits)")?; | ||
verifying_key(extended_public_key).context("Unable to get verifying key from X509 certificate") | ||
} | ||
|
||
/// Returns `VerifyingKey` from the given C509 certificate. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Returns an error if the signature algorithm is not supported and | ||
/// the public key cannot be extracted. | ||
pub fn c509_key(cert: &C509) -> anyhow::Result<VerifyingKey> { | ||
let oid = cert | ||
.tbs_cert() | ||
.subject_public_key_algorithm() | ||
.algo_identifier() | ||
.oid(); | ||
check_signature_algorithm(oid)?; | ||
verifying_key(cert.tbs_cert().subject_public_key()) | ||
.context("Unable to get verifying key from C509 certificate") | ||
} | ||
|
||
/// Checks that the signature algorithm is supported. | ||
fn check_signature_algorithm(oid: &Oid) -> Result<(), SignatureAlgoError> { | ||
// Currently the only supported signature algorithm is ED25519. | ||
if *oid != OID_SIG_ED25519 { | ||
return Err(SignatureAlgoError { | ||
oid: oid.to_id_string(), | ||
}); | ||
} | ||
Ok(()) | ||
} | ||
|
||
// TODO: The very similar logic exists in the `rbac-registration` crate. It should be | ||
// moved somewhere and reused. See https://github.com/input-output-hk/catalyst-voices/issues/1952 | ||
bkioshn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Creates `VerifyingKey` from the given extended public key. | ||
fn verifying_key(extended_public_key: &[u8]) -> anyhow::Result<VerifyingKey> { | ||
/// An extender public key length in bytes. | ||
const EXTENDED_PUBLIC_KEY_LENGTH: usize = 64; | ||
|
||
if extended_public_key.len() != EXTENDED_PUBLIC_KEY_LENGTH { | ||
return Err(anyhow!( | ||
"Unexpected extended public key length in certificate: {}, expected {EXTENDED_PUBLIC_KEY_LENGTH}", | ||
extended_public_key.len() | ||
)); | ||
} | ||
// This should never fail because of the check above. | ||
let public_key = extended_public_key | ||
.get(0..PUBLIC_KEY_LENGTH) | ||
.context("Unable to get public key part")?; | ||
let bytes: &[u8; PUBLIC_KEY_LENGTH] = public_key | ||
.try_into() | ||
.context("Invalid public key length in X509 certificate")?; | ||
VerifyingKey::from_bytes(bytes).context("Invalid public key in X509 certificate") | ||
} |
This file contains hidden or 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,7 +1,7 @@ | ||
//! Utility functions for CIP-509 | ||
|
||
pub mod cip19; | ||
|
||
pub mod extract_key; | ||
pub use cip134_uri_set::Cip0134UriSet; | ||
|
||
mod cip134_uri_set; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.