-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathcommon.rs
127 lines (112 loc) · 4.93 KB
/
common.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#![allow(dead_code)]
use anyhow::{anyhow, Context, Result};
use isomdl::cbor;
use isomdl::definitions::device_engagement::{CentralClientMode, DeviceRetrievalMethods};
use isomdl::definitions::device_request::{DataElements, DocType, Namespaces};
use isomdl::definitions::helpers::NonEmptyMap;
use isomdl::definitions::x509::trust_anchor::TrustAnchorRegistry;
use isomdl::definitions::{self, BleOptions, DeviceRetrievalMethod};
use isomdl::presentation::device::{Document, Documents, RequestedItems, SessionManagerEngaged};
use isomdl::presentation::{
authentication::RequestAuthenticationOutcome, device, reader, Stringify,
};
use signature::Signer;
use uuid::Uuid;
pub const DOC_TYPE: &str = "org.iso.18013.5.1.mDL";
pub const NAMESPACE: &str = "org.iso.18013.5.1";
pub const AGE_OVER_21_ELEMENT: &str = "age_over_21";
pub struct Device {}
impl Device {
/// Parse the mDL encoded string into a [Documents] object.
pub fn parse_mdl() -> Result<NonEmptyMap<DocType, Document>> {
let mdl_encoded = include_str!("data/stringified-mdl.txt");
let mdl = Document::parse(mdl_encoded.to_string()).context("could not parse mDL")?;
let docs = Documents::new(DOC_TYPE.to_string(), mdl);
Ok(docs)
}
/// Creates a QR code containing `DeviceEngagement` data, which includes its public key.
pub fn initialise_session() -> Result<(SessionManagerEngaged, String)> {
// Parse the mDL
let docs = Device::parse_mdl()?;
let drms = DeviceRetrievalMethods::new(DeviceRetrievalMethod::BLE(BleOptions {
peripheral_server_mode: None,
central_client_mode: Some(CentralClientMode {
uuid: Uuid::new_v4(),
}),
}));
let session = device::SessionManagerInit::initialise(docs, Some(drms), None)
.context("failed to initialize device")?;
session
.qr_engagement()
.context("could not generate qr engagement")
}
/// Establishes the reader session from the given QR code and create request for needed elements.
pub fn establish_reader_session(qr: String) -> Result<(reader::SessionManager, Vec<u8>)> {
let requested_elements = Namespaces::new(
NAMESPACE.into(),
DataElements::new(AGE_OVER_21_ELEMENT.to_string(), false),
);
let trust_anchors = TrustAnchorRegistry::default();
let (reader_sm, session_request, _ble_ident) =
reader::SessionManager::establish_session(qr, requested_elements, trust_anchors)
.context("failed to establish reader session")?;
Ok((reader_sm, session_request))
}
/// The Device handles the request from the reader and advances the state.
pub fn handle_request(
state: SessionManagerEngaged,
request: Vec<u8>,
trusted_verifiers: TrustAnchorRegistry,
) -> Result<(device::SessionManager, RequestAuthenticationOutcome)> {
let (session_manager, validated_request) = {
let session_establishment: definitions::SessionEstablishment =
cbor::from_slice(&request).context("could not deserialize request")?;
state
.process_session_establishment(session_establishment, trusted_verifiers)
.context("could not process process session establishment")?
};
if session_manager.get_next_signature_payload().is_some() {
anyhow::bail!("there were errors processing request");
}
Ok((session_manager, validated_request))
}
/// Prepare response with required elements.
pub fn create_response(
mut session_manager: device::SessionManager,
requested_items: &RequestedItems,
key: &p256::ecdsa::SigningKey,
) -> Result<Vec<u8>> {
let permitted_items = [(
DOC_TYPE.to_string(),
[(NAMESPACE.to_string(), vec![AGE_OVER_21_ELEMENT.to_string()])]
.into_iter()
.collect(),
)]
.into_iter()
.collect();
session_manager.prepare_response(requested_items, permitted_items);
let (_, sign_payload) = session_manager.get_next_signature_payload().unwrap();
let signature: p256::ecdsa::Signature = key.sign(sign_payload);
session_manager
.submit_next_signature(signature.to_vec())
.context("failed to submit signature")?;
session_manager
.retrieve_response()
.ok_or(anyhow!("cannot prepare response"))
}
pub fn create_signing_key() -> Result<p256::ecdsa::SigningKey> {
Ok(p256::SecretKey::from_sec1_pem(include_str!("data/sec1.pem"))?.into())
}
}
pub struct Reader {}
impl Reader {
/// Reader Processing mDL data.
pub fn reader_handle_device_response(
reader_sm: &mut reader::SessionManager,
response: Vec<u8>,
) -> Result<()> {
let validated = reader_sm.handle_response(&response);
println!("Validated Response: {validated:?}");
Ok(())
}
}