-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
author Arjen van Veen <[email protected]> 1701187280 +0100 committer Arjen van Veen <[email protected]> 1717744754 +0200 refactor for readability WIP clean up comments and duplicates clean up, add some comments cargo fmt clippy fix fmt assert on tests address pr comments refactor handle_response to return a validated_response, submit parsing and decryption errors under errors support creating a trust_anchor_registry from pem strings Fix x5chain encoding. X5Chain decoding fixes and version checking Improve reader validation code. - Also add a CLI tool for validating issuer certificates. Fix public key parsing Feat/reader auth cn (#79) * rebase onto feat/mdoc-auth * rebase and use mdoc-auth functions * wip experiment with cert building * small clean up * Fix inconsistency. (#78) * validated request improvements --------- Co-authored-by: Jacob <[email protected]> remove duplicate code clippy fix
- Loading branch information
1 parent
4e7fc9f
commit b1ec197
Showing
25 changed files
with
1,784 additions
and
1,256 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
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,84 @@ | ||
use std::{collections::BTreeMap, fs::File, io::Read, path::PathBuf}; | ||
|
||
use anyhow::{Context, Error, Ok}; | ||
use clap::Parser; | ||
use clap_stdin::MaybeStdin; | ||
use isomdl::presentation::{device::Document, Stringify}; | ||
|
||
mod x509; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(author, version, about, long_about = None)] | ||
struct Args { | ||
#[command(subcommand)] | ||
action: Action, | ||
} | ||
|
||
#[derive(Debug, clap::Subcommand)] | ||
enum Action { | ||
/// Print the namespaces and element identifiers used in an mDL. | ||
GetNamespaces { | ||
/// Base64 encoded mDL in the format used in the issuance module of this crate. | ||
mdl: MaybeStdin<String>, | ||
}, | ||
/// Validate a document signer cert against a possible root certificate. | ||
ValidateCerts { | ||
/// Validation rule set. | ||
rules: RuleSet, | ||
/// Path to PEM-encoded document signer cert. | ||
ds: PathBuf, | ||
/// Path to PEM-encoded IACA root cert. | ||
root: PathBuf, | ||
}, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, clap::ValueEnum)] | ||
enum RuleSet { | ||
Iaca, | ||
Aamva, | ||
NamesOnly, | ||
} | ||
|
||
fn main() -> Result<(), Error> { | ||
match Args::parse().action { | ||
Action::GetNamespaces { mdl } => print_namespaces(mdl.to_string()), | ||
Action::ValidateCerts { rules, ds, root } => validate_certs(rules, ds, root), | ||
} | ||
} | ||
|
||
fn print_namespaces(mdl: String) -> Result<(), Error> { | ||
let claims = Document::parse(mdl) | ||
.context("could not parse mdl")? | ||
.namespaces | ||
.into_inner() | ||
.into_iter() | ||
.map(|(ns, inner)| (ns, inner.into_inner().into_keys().collect())) | ||
.collect::<BTreeMap<String, Vec<String>>>(); | ||
println!("{}", serde_json::to_string_pretty(&claims)?); | ||
Ok(()) | ||
} | ||
|
||
fn validate_certs(rules: RuleSet, ds: PathBuf, root: PathBuf) -> Result<(), Error> { | ||
let mut ds_bytes = vec![]; | ||
File::open(ds)?.read_to_end(&mut ds_bytes)?; | ||
let mut root_bytes = vec![]; | ||
File::open(root)?.read_to_end(&mut root_bytes)?; | ||
let validation_errors = x509::validate(rules, &ds_bytes, &root_bytes)?; | ||
if validation_errors.is_empty() { | ||
println!("Validated!"); | ||
} else { | ||
println!( | ||
"Validation errors:\n{}", | ||
serde_json::to_string_pretty(&validation_errors)? | ||
) | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
#[test] | ||
fn print_namespaces() { | ||
super::print_namespaces(include_str!("../../test/stringified-mdl.txt").to_string()).unwrap() | ||
} | ||
} |
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,41 @@ | ||
use anyhow::anyhow; | ||
use isomdl::definitions::x509::{ | ||
error::Error as X509Error, | ||
trust_anchor::{RuleSetType, TrustAnchor, TrustAnchorRegistry, ValidationRuleSet}, | ||
x5chain::X509, | ||
X5Chain, | ||
}; | ||
|
||
use crate::RuleSet; | ||
|
||
pub fn validate( | ||
rules: RuleSet, | ||
signer: &[u8], | ||
root: &[u8], | ||
) -> Result<Vec<X509Error>, anyhow::Error> { | ||
let root_bytes = pem_rfc7468::decode_vec(root) | ||
.map_err(|e| anyhow!("unable to parse pem: {}", e))? | ||
.1; | ||
|
||
let ruleset = ValidationRuleSet { | ||
distinguished_names: vec!["2.5.4.6".to_string(), "2.5.4.8".to_string()], | ||
typ: match rules { | ||
RuleSet::Iaca => RuleSetType::IACA, | ||
RuleSet::Aamva => RuleSetType::AAMVA, | ||
RuleSet::NamesOnly => RuleSetType::NamesOnly, | ||
}, | ||
}; | ||
|
||
let trust_anchor = TrustAnchor::Custom(X509 { bytes: root_bytes }, ruleset); | ||
let trust_anchor_registry = TrustAnchorRegistry { | ||
certificates: vec![trust_anchor], | ||
}; | ||
let bytes = pem_rfc7468::decode_vec(signer) | ||
.map_err(|e| anyhow!("unable to parse pem: {}", e))? | ||
.1; | ||
let x5chain_cbor: serde_cbor::Value = serde_cbor::Value::Bytes(bytes); | ||
|
||
let x5chain = X5Chain::from_cbor(x5chain_cbor)?; | ||
|
||
Ok(x5chain.validate(Some(trust_anchor_registry))) | ||
} |
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
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
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
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,18 @@ | ||
use crate::{definitions::ValidationErrors, presentation::device::RequestedItems}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Serialize, Deserialize, Default)] | ||
pub struct ValidatedRequest { | ||
pub items_requests: RequestedItems, | ||
pub common_name: Option<String>, | ||
pub reader_authentication: Status, | ||
pub errors: ValidationErrors, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Default)] | ||
pub enum Status { | ||
#[default] | ||
Unchecked, | ||
Invalid, | ||
Valid, | ||
} |
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,23 @@ | ||
use serde::{Deserialize, Serialize}; | ||
use serde_json::Value; | ||
use std::collections::BTreeMap; | ||
|
||
#[derive(Serialize, Deserialize, Default)] | ||
pub struct ValidatedResponse { | ||
pub response: BTreeMap<String, Value>, | ||
pub decryption: Status, | ||
pub parsing: Status, | ||
pub issuer_authentication: Status, | ||
pub device_authentication: Status, | ||
pub errors: ValidationErrors, | ||
} | ||
|
||
pub type ValidationErrors = BTreeMap<String, serde_json::Value>; | ||
|
||
#[derive(Serialize, Deserialize, Default)] | ||
pub enum Status { | ||
#[default] | ||
Unchecked, | ||
Invalid, | ||
Valid, | ||
} |
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,63 @@ | ||
use crate::definitions::device_key::cose_key::Error as CoseError; | ||
use crate::definitions::helpers::non_empty_vec; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)] | ||
pub enum Error { | ||
#[error("Error occurred while validating x509 certificate: {0}")] | ||
ValidationError(String), | ||
#[error("Error occurred while decoding a x509 certificate: {0}")] | ||
DecodingError(String), | ||
#[error("Error decoding cbor")] | ||
CborDecodingError, | ||
#[error("Error decoding json")] | ||
JsonError, | ||
} | ||
|
||
impl From<serde_cbor::Error> for Error { | ||
fn from(_: serde_cbor::Error) -> Self { | ||
Error::CborDecodingError | ||
} | ||
} | ||
|
||
impl From<serde_json::Error> for Error { | ||
fn from(_: serde_json::Error) -> Self { | ||
Error::JsonError | ||
} | ||
} | ||
|
||
impl From<x509_cert::der::Error> for Error { | ||
fn from(value: x509_cert::der::Error) -> Self { | ||
Error::ValidationError(value.to_string()) | ||
} | ||
} | ||
|
||
impl From<p256::ecdsa::Error> for Error { | ||
fn from(value: p256::ecdsa::Error) -> Self { | ||
Error::ValidationError(value.to_string()) | ||
} | ||
} | ||
|
||
impl From<x509_cert::spki::Error> for Error { | ||
fn from(value: x509_cert::spki::Error) -> Self { | ||
Error::ValidationError(value.to_string()) | ||
} | ||
} | ||
|
||
impl From<CoseError> for Error { | ||
fn from(value: CoseError) -> Self { | ||
Error::ValidationError(value.to_string()) | ||
} | ||
} | ||
|
||
impl From<non_empty_vec::Error> for Error { | ||
fn from(value: non_empty_vec::Error) -> Self { | ||
Error::ValidationError(value.to_string()) | ||
} | ||
} | ||
|
||
impl From<asn1_rs::Error> for Error { | ||
fn from(value: asn1_rs::Error) -> Self { | ||
Error::ValidationError(value.to_string()) | ||
} | ||
} |
Oops, something went wrong.