Expand description
A library that can read an eMRTD.
A library that can read an eMRTD (Electronic Machine Readable Travel Document).
The emrtd
crate provides a simple API that can be used to communicate with
eMRTDs and read the data that resides within them. With the help of openssl
,
it can perform Passive Authentication.
NOTE: Please note that this crate is provided ‘as is’ and is not considered production-ready. Use at your own risk.
Currently Active Authentication (AA), Chip Authentication (CA), PACE or EAC are not supported.
Enable the passive_auth
feature for Passive Authentication (PA), but note
that it depends on openssl
crate.
§Quick Start
use emrtd::{bytes2hex, get_jpeg_from_ef_dg2, other_mrz, EmrtdComms, EmrtdError};
use tracing::{error, info};
#[cfg(feature = "passive_auth")]
use emrtd::{parse_master_list, passive_authentication, validate_dg};
fn main() -> Result<(), EmrtdError> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
.init();
let doc_no = "DOCUMENT NUMBER";
let birthdate = "BIRTH DATE IN YYMMDD";
let expirydate = "EXPIRY DATE IN YYMMDD";
// Establish a PC/SC context.
let ctx = match pcsc::Context::establish(pcsc::Scope::User) {
Ok(ctx) => ctx,
Err(err) => {
error!("Failed to establish context: {err}");
return Ok(());
}
};
// List available readers.
let mut readers_buf = [0; 2048];
let mut readers = match ctx.list_readers(&mut readers_buf) {
Ok(readers) => readers,
Err(err) => {
error!("Failed to list readers: {err}");
return Ok(());
}
};
// Use the first reader.
let reader = match readers.next() {
Some(reader) => reader,
None => {
error!("No readers are connected.");
return Ok(());
}
};
info!("Using reader: {reader:?}");
// Connect to the card.
let card = match ctx.connect(reader, pcsc::ShareMode::Shared, pcsc::Protocols::ANY) {
Ok(card) => card,
Err(pcsc::Error::NoSmartcard) => {
error!("A smartcard is not present in the reader.");
return Ok(());
}
Err(err) => {
error!("Failed to connect to card: {err}");
return Ok(());
}
};
let mut sm_object = EmrtdComms::new(card);
// Get the card's ATR.
info!("ATR from attribute: {}", bytes2hex(&sm_object.get_atr()?));
// Read EF.CardAccess
sm_object.select_ef(b"\x01\x1C", "EF.CardAccess", false)?;
let ef_cardacess = sm_object.read_data_from_ef(false)?;
info!("Data from the EF.CardAccess: {}", bytes2hex(&ef_cardacess));
// Read EF.DIR
// let ef_dir = sm_object.read_data_from_ef(b"\x2F\x00", "EF.DIR");
// info!("Data from the EF.DIR: {}", bytes2hex(&ef_dir));
// Select eMRTD application
sm_object.select_emrtd_application()?;
let secret = match other_mrz(&doc_no, &birthdate, &expirydate) {
Ok(secret) => secret,
Err(EmrtdError) => {
error!("Invalid MRZ string.");
return Ok(());
}
};
sm_object.establish_bac_session_keys(secret.as_bytes())?;
// Read EF.COM
sm_object.select_ef(b"\x01\x1E", "EF.COM", true)?;
let ef_com = sm_object.read_data_from_ef(true)?;
info!("Data from the EF.COM: {}", bytes2hex(&ef_com));
// Read EF.SOD
sm_object.select_ef(b"\x01\x1D", "EF.SOD", true)?;
let ef_sod = sm_object.read_data_from_ef(true)?;
info!("Data from the EF.SOD: {}", bytes2hex(&ef_sod));
#[cfg(feature = "passive_auth")]
{
let master_list = include_bytes!("../data/DE_ML_2024-04-10-10-54-13.ml");
let csca_cert_store = parse_master_list(master_list)?;
let result = passive_authentication(&ef_sod, &csca_cert_store).unwrap();
info!("{:?} {:?} {:?}", result.0.type_(), result.1, result.2);
}
// Read EF.DG1
sm_object.select_ef(b"\x01\x01", "EF.DG1", true)?;
let ef_dg1 = sm_object.read_data_from_ef(true)?;
info!("Data from the EF.DG1: {}", bytes2hex(&ef_dg1));
#[cfg(feature = "passive_auth")]
validate_dg(&ef_dg1, 1, result.0, &result.1)?;
// Read EF.DG2
sm_object.select_ef(b"\x01\x02", "EF.DG2", true)?;
let ef_dg2 = sm_object.read_data_from_ef(true)?;
info!("Data from the EF.DG2: {}", bytes2hex(&ef_dg2));
#[cfg(feature = "passive_auth")]
validate_dg(&ef_dg2, 2, result.0, &result.1)?;
let jpeg = get_jpeg_from_ef_dg2(&ef_dg2)?;
std::fs::write("face.jpg", jpeg).expect("Error writing file");
return Ok(());
}
Structs§
- An Application Protocol Data Unit (APDU) used in smart card communication.
Enums§
Functions§
- Helper function that converts a byte slice into a hex string.
- Extracts the JPEG image from the EF.DG2.
- Encodes the length field in ASN.1 format.
- Manually calculates the MRZ (Machine Readable Zone) string for BAC (Basic Access Control).