How do electronic passports work? (Part 2)

In the second part of this post I will try to give code examples for some basic functionality in eMRTDs. I will add code snippets for each of the sections. The code is mostly a port of my other project eMRTD_face_access from Python to Rust (emrtd crate). It came to life because I was interested in a rewrite of the project in Golang to take it away from Python. During the initial research of PSCS libraries in Golang, I found that there wasn’t a cross platform PCSC library that supports Windows, Linux and macOS. Then taking advantage of this, I decided to learn Rust and rewrite the project in Rust instead.

I also would like to mention that in this blog post, I won’t be implementing all the features of the Python program, nor all the features supported by ICAO Doc 9303. If you want a feature complete implementation, please look into JMRTD or others.

First of all, if you don’t have Rust set up, set it up by following the steps here. Then clone the emrtd repository and switch to the commit that is used in this blog post:

$ git clone https://github.com/Fethbita/emrtd.git
$ cd emrtd
$ git checkout d9e3064b11964f8ea7c755f52128f1b2a2eafbcd

Let’s take a look at cargo.toml first:

cargo.toml
[package]
name = "emrtd"
version = "0.0.1"
authors = ["Burak Can Kus"]
edition = "2021"
rust-version = "1.66.1"
description = "A library that can read an eMRTD and do security checks."
readme = "README.md"
repository = "https://github.com/Fethbita/emrtd"
license = "MIT OR Apache-2.0"
keywords = ["emrtd", "epassport", "eid", "electronic_id", "smartcard"]
categories = ["cryptography", "authentication", "command-line-utilities"]

[dependencies]
pcsc = "2.8.2"
openssl = { version = "0.10.64", features = ["vendored"] }
cipher = { version = "0.4.4", features = ["block-padding", "alloc"] }
des = "0.8.1"
aes = "0.8.4"
ecb = "0.1.2"
cbc = "0.1.2"
rasn = "0.14.0"
rasn-cms = "0.14.0"
rasn-pkix = "0.14.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"

[dev-dependencies]
hex-literal = "0.4.1"

Most of the things in this file are required or recommended to get published on crates.io. We try to use few non-Rust dependencies.

Connecting to a card

First thing we need to do is to connect a card to our card reader. For everything card related, I use the awesome pcsc crate. Let’s check the examples/read_emrtd.rs file as an example:

examples/read_emrtd.rs
  1use std::env;
  2
  3use emrtd::{
  4    bytes2hex, get_jpeg_from_ef_dg2, other_mrz, parse_master_list, passive_authentication,
  5    validate_dg, EmrtdComms, EmrtdError,
  6};
  7use tracing::{error, info};
  8
  9fn main() -> Result<(), EmrtdError> {
 10    tracing_subscriber::fmt()
 11        .with_max_level(tracing::Level::TRACE)
 12        .init();
 13
 14    // Establish a PC/SC context.
 15    let ctx = match pcsc::Context::establish(pcsc::Scope::User) {
 16        Ok(ctx) => ctx,
 17        Err(err) => {
 18            error!("Failed to establish context: {err}");
 19            std::process::exit(1);
 20        }
 21    };
 22
 23    // List available readers.
 24    let mut readers_buf = [0; 2048];
 25    let mut readers = match ctx.list_readers(&mut readers_buf) {
 26        Ok(readers) => readers,
 27        Err(err) => {
 28            error!("Failed to list readers: {err}");
 29            std::process::exit(1);
 30        }
 31    };
 32
 33    // Use the first reader.
 34    let reader = match readers.next() {
 35        Some(reader) => reader,
 36        None => {
 37            error!("No readers are connected.");
 38            std::process::exit(1);
 39        }
 40    };
 41    info!("Using reader: {reader:?}");
 42
 43    // Connect to the card.
 44    let card = match ctx.connect(reader, pcsc::ShareMode::Shared, pcsc::Protocols::ANY) {
 45        Ok(card) => card,
 46        Err(pcsc::Error::NoSmartcard) => {
 47            error!("A smartcard is not present in the reader.");
 48            std::process::exit(1);
 49        }
 50        Err(err) => {
 51            error!("Failed to connect to card: {err}");
 52            std::process::exit(1);
 53        }
 54    };
 55
 56    let mut sm_object = EmrtdComms::new(card);
 57
 58    // Get the card's ATR.
 59    info!("ATR from attribute: {}", bytes2hex(&sm_object.get_atr()?));
 60
 61    // Read EF.CardAccess
 62    // sm_object.select_ef(b"\x01\x1C", "EF.CardAccess", false)?;
 63    // let ef_cardacess = sm_object.read_data_from_ef(false)?;
 64    // info!("Data from the EF.CardAccess: {}", bytes2hex(&ef_cardacess));
 65
 66    // Read EF.DIR
 67    // sm_object.select_ef(b"\x2F\x00", "EF.DIR", false)?;
 68    // let ef_dir = sm_object.read_data_from_ef(false)?;
 69    // info!("Data from the EF.DIR: {}", bytes2hex(&ef_dir));
 70
 71    // Select eMRTD application
 72    sm_object.select_emrtd_application()?;
 73
 74    let doc_no = env::var("DOCNO").expect("Please set DOCNO environment variable");
 75    let birthdate = env::var("BIRTHDATE").expect("Please set BIRTHDATE environment variable");
 76    let expirydate = env::var("EXPIRYDATE").expect("Please set EXPIRYDATE environment variable");
 77
 78    let secret = other_mrz(&doc_no, &birthdate, &expirydate)?;
 79
 80    sm_object.establish_bac_session_keys(secret.as_bytes())?;
 81
 82    // Read EF.COM
 83    sm_object.select_ef(b"\x01\x1E", "EF.COM", true)?;
 84    let ef_com = sm_object.read_data_from_ef(true)?;
 85    info!("Data from the EF.COM: {}", bytes2hex(&ef_com));
 86
 87    // Read EF.SOD
 88    sm_object.select_ef(b"\x01\x1D", "EF.SOD", true)?;
 89    let ef_sod = sm_object.read_data_from_ef(true)?;
 90    info!("Data from the EF.SOD: {}", bytes2hex(&ef_sod));
 91
 92    let master_list = include_bytes!("../data/DE_ML_2024-04-10-10-54-13.ml");
 93
 94    let csca_cert_store = parse_master_list(master_list)?;
 95
 96    info!("Number of certificates parse from the Master List in the store {}", csca_cert_store.all_certificates().len());
 97
 98    let result = passive_authentication(&ef_sod, &csca_cert_store).unwrap();
 99    info!("{:?} {:?} {:?}", result.0.type_(), result.1, result.2);
100
101    // Read EF.DG1
102    sm_object.select_ef(b"\x01\x01", "EF.DG1", true)?;
103    let ef_dg1 = sm_object.read_data_from_ef(true)?;
104    info!("Data from the EF.DG1: {}", bytes2hex(&ef_dg1));
105    validate_dg(&ef_dg1, 1, result.0, &result.1)?;
106
107    // Read EF.DG2
108    sm_object.select_ef(b"\x01\x02", "EF.DG2", true)?;
109    let ef_dg2 = sm_object.read_data_from_ef(true)?;
110    info!("Data from the EF.DG2: {}", bytes2hex(&ef_dg2));
111    validate_dg(&ef_dg2, 2, result.0, &result.1)?;
112
113    let jpeg = get_jpeg_from_ef_dg2(&ef_dg2)?;
114    std::fs::write("face.jpg", jpeg).expect("Error writing file");
115
116    return Ok(());
117}

In the example we get a card handle we can use to send APDU packages to[1] and read environment variables DOCNO, BIRTHDATE and EXPIRYDATE to use during session key establishment. We establish the session keys using the establish_bac_session_keys function and then parse the Master List using the parse_master_list function. We then perform passive authentication using the passive_authentication function using the EF.SOD file.

Next, let’s look at the src/lib.rs file and go into a bit more detail about the functions there. The file begins with the definition of EmrtdError which is used for all errors that can occur in the library:

src/lib.rs#132
132#![forbid(unsafe_code)]
133
134extern crate alloc;
135use alloc::{borrow::ToOwned, collections::BTreeMap, format, string::String, vec, vec::Vec};
136use cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
137use core::{
138    fmt::{self, Debug, Write},
139    iter, mem,
140};
141use openssl::{
142    hash::{hash, MessageDigest},
143    memcmp::eq,
144    rand::rand_bytes,
145    sign::Verifier,
146    stack::Stack,
147    x509::{
148        store::{X509Store, X509StoreBuilder},
149        X509StoreContext, X509,
150    },
151};
152use pcsc::{Attribute::AtrString, Card};
153use rasn::{der, types::Oid};
154use rasn_cms::{CertificateChoices, RevocationInfoChoice};
155use tracing::{error, info, trace, warn};
156
157#[derive(Debug)]
158#[non_exhaustive]
159pub enum EmrtdError {
160    RecvApduError(u8, u8),
161    ParseMrzCharError(char),
162    ParseMrzFieldError(&'static str, String),
163    ParseAsn1DataError(usize, usize),
164    InvalidMacKeyError(usize, usize),
165    ParseDataError(String),
166    InvalidArgument(&'static str),
167    VerifyMacError(),
168    InvalidResponseError(),
169    OverflowSscError(),
170    InvalidOidError(),
171    ParseAsn1TagError(String, String),
172    InvalidFileStructure(&'static str),
173    VerifySignatureError(&'static str),
174    VerifyHashError(String),
175    PcscError(pcsc::Error),
176    BoringErrorStack(openssl::error::ErrorStack),
177    RasnEncodeError(rasn::error::EncodeError),
178    RasnDecodeError(rasn::error::DecodeError),
179    PadError(cipher::inout::PadError),
180    UnpadError(cipher::block_padding::UnpadError),
181}
182impl fmt::Display for EmrtdError {
183    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184        match *self {
185            Self::RecvApduError(ref sw1, ref sw2) => write!(
186                f,
187                "APDU command failed with status code: {sw1:02X} {sw2:02X}"
188            ),
189            Self::ParseMrzCharError(ref c) => {
190                write!(f, "MRZ can not contain the character: {c}")
191            }
192            Self::ParseMrzFieldError(mrz_field, ref value) => {
193                write!(f, "MRZ field {mrz_field} is invalid: {value}")
194            }
195            Self::ParseAsn1DataError(ref e_len, ref f_len) => write!(
196                f,
197                "ASN.1 data is incomplete, expected len: {e_len}, found len: {f_len}"
198            ),
199            Self::InvalidMacKeyError(ref e_len, ref f_len) => write!(
200                f,
201                "Invalid MAC key, expected len: {e_len}, found len: {f_len}"
202            ),
203            Self::ParseDataError(ref error) => write!(f, "Invalid data length: {error}"),
204            Self::InvalidArgument(error_msg) => write!(f, "Invalid argument: {error_msg}"),
205            Self::VerifyMacError() => {
206                write!(f, "Encrypted message MAC is not correct")
207            }
208            Self::InvalidResponseError() => {
209                write!(f, "Card response is invalid")
210            }
211            Self::OverflowSscError() => write!(f, "SSC overflew error"),
212            Self::InvalidOidError() => write!(f, "Invalid OID given"),
213            Self::ParseAsn1TagError(ref expected, ref found) => {
214                write!(f, "Invalid ASN.1 tag, expected: {expected}, found: {found}")
215            }
216            Self::InvalidFileStructure(error_msg) => {
217                write!(f, "Invalid EF structure: {error_msg}")
218            }
219            Self::VerifySignatureError(error_msg) => {
220                write!(f, "Signature verification failure: {error_msg}")
221            }
222            Self::VerifyHashError(ref error_msg) => {
223                write!(f, "Failure during comparison of hashes: {error_msg}")
224            }
225            Self::PcscError(ref e) => fmt::Display::fmt(&e, f),
226            Self::BoringErrorStack(ref e) => fmt::Display::fmt(&e, f),
227            Self::RasnEncodeError(ref e) => fmt::Display::fmt(&e, f),
228            Self::RasnDecodeError(ref e) => fmt::Display::fmt(&e, f),
229            Self::PadError(ref e) => fmt::Display::fmt(&e, f),
230            Self::UnpadError(ref e) => fmt::Display::fmt(&e, f),
231        }
232    }
233}
234// TODO, change to core::error soon, hopefully?
235impl std::error::Error for EmrtdError {}

I believe these errors are pretty self explanatory. Next, let’s look at the APDU struct:

src/lib.rs#APDU
2503/// An Application Protocol Data Unit (APDU) used in smart card communication.
2504#[derive(Debug, Clone)]
2505pub struct APDU {
2506    /// Class byte of the APDU
2507    cla: u8,
2508    /// Instruction byte of the APDU
2509    ins: u8,
2510    /// Parameter 1 byte of the APDU
2511    p1: u8,
2512    /// Parameter 2 byte of the APDU
2513    p2: u8,
2514    /// Length of the command data field (Lc) in the APDU
2515    lc: Option<Vec<u8>>,
2516    /// Command data field of the APDU
2517    cdata: Option<Vec<u8>>,
2518    /// Expected length of the response data field (Le) in the APDU
2519    le: Option<Vec<u8>>,
2520}
2521
2522impl APDU {
2523    /// Constructs a new APDU instance with the specified parameters.
2524    ///
2525    /// # Arguments
2526    ///
2527    /// * `cla` - The class byte of the APDU.
2528    /// * `ins` - The instruction byte of the APDU.
2529    /// * `p1` - The parameter 1 byte of the APDU.
2530    /// * `p2` - The parameter 2 byte of the APDU.
2531    /// * `lc` - Optional command data field length (Lc) of the APDU.
2532    /// * `cdata` - Optional command data field of the APDU.
2533    /// * `le` - Optional expected response data field length (Le) of the APDU.
2534    ///
2535    /// # Panics
2536    ///
2537    /// Panics if the lengths of `lc` and `le` violate ISO/IEC 7816-4 specifications.
2538    /// See the wiki article for more details:
2539    /// <https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit>
2540    ///
2541    /// # Example
2542    ///
2543    /// ```
2544    /// # use emrtd::EmrtdError;
2545    /// #
2546    /// # fn main() -> Result<(), EmrtdError> {
2547    /// use emrtd::APDU;
2548    /// let apdu = APDU::new(b'\x00', b'\x84', b'\x00', b'\x00', None, None, Some(vec![b'\x08']));
2549    /// #
2550    /// #     Ok(())
2551    /// # }
2552    /// ```
2553    pub fn new(
2554        cla: u8,
2555        ins: u8,
2556        p1: u8,
2557        p2: u8,
2558        lc: Option<Vec<u8>>,
2559        cdata: Option<Vec<u8>>,
2560        le: Option<Vec<u8>>,
2561    ) -> Self {
2562        match (lc.as_ref().map(Vec::len), le.as_ref().map(Vec::len)) {
2563            (None | Some(1 | 3), None)
2564            | (None | Some(1), Some(1))
2565            | (Some(3), Some(2))
2566            | (None, Some(3)) => { /* Valid */ }
2567            (_, _) => {
2568                panic!("lc and le length error");
2569            }
2570        }
2571
2572        Self {
2573            cla,
2574            ins,
2575            p1,
2576            p2,
2577            lc,
2578            cdata,
2579            le,
2580        }
2581    }
2582
2583    /// Retrieves the command header of the APDU.
2584    ///
2585    /// The command header consists of the class byte, instruction byte,
2586    /// parameter 1 byte, and parameter 2 byte of the APDU.
2587    ///
2588    /// # Returns
2589    ///
2590    /// The command header.
2591    ///
2592    /// # Examples
2593    ///
2594    /// ```
2595    /// # use emrtd::EmrtdError;
2596    /// #
2597    /// # fn main() -> Result<(), EmrtdError> {
2598    /// use emrtd::APDU;
2599    /// use hex_literal::hex;
2600    ///
2601    /// let apdu = APDU::new(b'\x00', b'\x84', b'\x00', b'\x00', None, None, Some(vec![b'\x08']));
2602    /// assert_eq!(apdu.get_command_header(), hex!("00840000"));
2603    /// #
2604    /// #     Ok(())
2605    /// # }
2606    /// ```
2607    #[must_use]
2608    pub fn get_command_header(&self) -> Vec<u8> {
2609        vec![self.cla, self.ins, self.p1, self.p2]
2610    }
2611}

We can use this struct to create new APDUs and internally use them to send commands to eMRTDs.

The usage of the struct is shown in the Doc comments of the implementation functions.

Before the next step, let’s look at a couple of utility functions and explain what they are:

src/lib.rs#bytes2hex
514/// Helper function that converts a byte slice into a hex string.
515///
516/// # Arguments
517///
518/// * `bytes` - Bytes to be converted to a hex string.
519///
520/// # Returns
521///
522/// A hex string representation of the input bytes.
523///
524/// # Example
525///
526/// ```
527/// # use emrtd::EmrtdError;
528/// #
529/// # fn main() -> Result<(), EmrtdError> {
530/// use emrtd::bytes2hex;
531/// let bytes = vec![0xDE, 0xAD, 0xBE, 0xEF];
532/// let hex_string = bytes2hex(&bytes);
533/// assert_eq!(hex_string, "DEADBEEF");
534/// #
535/// #     Ok(())
536/// # }
537/// ```
538#[must_use]
539pub fn bytes2hex(bytes: &[u8]) -> String {
540    bytes.iter().fold(String::new(), |mut acc, &byte| {
541        write!(&mut acc, "{byte:02X}").expect("Failed to write to string");
542        acc
543    })
544}
src/lib.rs#len2int
546/// Parses the ASN.1 length field.
547///
548/// ASN.1 length encoding can use a single byte for short lengths (up to 127) or multiple bytes
549/// for longer lengths.
550///
551/// # Arguments
552///
553/// * `data` - The ASN.1 data.
554/// * `tag_len` - Length of ASN.1 tag (T of TLV).
555///
556/// # Returns
557///
558/// Result containing a tuple with the start index and length field value, or an `EmrtdError`.
559///
560/// For example, if `tag_len` is 3 and the length field is a single byte with value 42,
561/// the returned value will be (4, 42).
562///
563/// If `tag_len` is 3 and the length field is 3 bytes long with value 2024,
564/// the returned value will be (6, 2024).
565///
566/// # Errors
567///
568/// * `EmrtdError` if the input is incomplete, i.e. if the data is too short to read the length value.
569fn len2int(data: &[u8], tag_len: usize) -> Result<(usize, usize), EmrtdError> {
570    if data.len() < tag_len + 1 {
571        error!(
572            "Error during len2int, `data.len()`: `{}` is less than `tag_len`: `{}`",
573            data.len(),
574            tag_len
575        );
576        return Err(EmrtdError::ParseAsn1DataError(tag_len + 1, data.len()));
577    }
578
579    if data[tag_len] & 0x80 == 0 {
580        Ok((tag_len + 1, data[tag_len] as usize))
581    } else {
582        let length_of_length = ((1 << 7) ^ data[tag_len]) as usize;
583
584        if data.len() < tag_len + 1 + length_of_length {
585            error!("Error during len2int, `data.len()`: `{}` is less than `tag_len + 1 + length_of_length`: `{}`", data.len(), tag_len + 1 + length_of_length);
586            return Err(EmrtdError::ParseAsn1DataError(
587                tag_len + 1 + length_of_length,
588                data.len(),
589            ));
590        }
591
592        let mut buf = [0_u8; mem::size_of::<usize>()];
593        buf[mem::size_of::<usize>() - length_of_length..]
594            .copy_from_slice(&data[tag_len + 1..tag_len + 1 + length_of_length]);
595
596        Ok((tag_len + 1 + length_of_length, usize::from_be_bytes(buf)))
597    }
598}
src/lib.rs#int2asn1len
600/// Encodes the length field in ASN.1 format.
601///
602/// If the length is less than 128, a single octet is used to represent the length.
603/// Otherwise, the long form is used, where the first octet specifies the number of
604/// octets used for the length, followed by the length encoded in big-endian order.
605///
606/// # Arguments
607///
608/// * `length` - The length to be encoded.
609///
610/// # Returns
611///
612/// The ASN.1 encoded length.
613///
614/// # Panics
615/// Should not panic.
616///
617/// # Examples
618///
619/// ```
620/// # use emrtd::EmrtdError;
621/// #
622/// # fn main() -> Result<(), EmrtdError> {
623/// use emrtd::int2asn1len;
624/// use hex_literal::hex;
625///
626/// let result = int2asn1len(0);
627/// assert_eq!(result, hex!("00").to_vec());
628///
629/// let result = int2asn1len(42);
630/// assert_eq!(result, hex!("2A").to_vec());
631///
632/// let result = int2asn1len(127);
633/// assert_eq!(result, hex!("7F").to_vec());
634///
635/// let result = int2asn1len(2024);
636/// assert_eq!(result, hex!("8207E8").to_vec());
637///
638/// let result = int2asn1len(65536);
639/// assert_eq!(result, hex!("83010000").to_vec());
640///
641/// let result = int2asn1len(usize::MAX);
642/// assert_eq!(result, hex!("88FFFFFFFFFFFFFFFF").to_vec());
643/// #
644/// #     Ok(())
645/// # }
646/// ```
647#[must_use]
648pub fn int2asn1len(length: usize) -> Vec<u8> {
649    if length < 128 {
650        vec![u8::try_from(length).expect("`length` is less than 128")]
651    } else {
652        let mut length_bytes: Vec<u8> = Vec::new();
653        let mut len = length;
654
655        let mut octet_count: u8 = 0;
656        while len > 0 {
657            octet_count += 1;
658            len >>= 8;
659        }
660        length_bytes.push(0x80 | octet_count);
661        for i in (0..octet_count).rev() {
662            let masked_bits = (length >> (8 * i)) & 0xFF;
663            length_bytes
664                .push(u8::try_from(masked_bits).expect("Bits are masked, must fit in a u8"));
665        }
666        length_bytes
667    }
668}
src/lib.rs#generate_key_seed
670/// Generates a key seed from the given secret.
671///
672/// Calculates the SHA-1 of `secret` and returns the result.
673///
674/// Calculation is explained at ICAO Doc 9303-11 Section 4.3.2:
675/// <https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf>
676///
677/// # Arguments
678///
679/// * `secret` - The secret from which to generate the key seed.
680///
681/// # Returns
682///
683/// The generated key seed if successful.
684///
685/// # Errors
686///
687/// `EmrtdError` if 'SHA1' fails.
688fn generate_key_seed(secret: &[u8]) -> Result<Vec<u8>, EmrtdError> {
689    let hash_bytes = hash(MessageDigest::sha1(), secret).map_err(EmrtdError::BoringErrorStack)?;
690    Ok(hash_bytes.to_vec())
691}
src/lib.rs#compute_key
892/// Computes a key based on the given key seed, key type, and encryption algorithm.
893///
894/// For calculation examples see ICAO Doc 9303-11 Appendix D.1:
895/// <https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf>
896///
897/// # Arguments
898///
899/// * `key_seed` - The key seed.
900/// * `key_type` - The type of the key (Encryption or Mac) to be created.
901/// * `alg` - The encryption algorithm to be used (DES3, AES128, AES192, or AES256).
902///
903/// # Returns
904///
905/// Result containing the computed 3DES or AES key if successful.
906///
907/// # Errors
908///
909/// `EmrtdError` key computation fails.
910fn compute_key(
911    key_seed: &[u8],
912    key_type: &KeyType,
913    alg: &EncryptionAlgorithm,
914) -> Result<Vec<u8>, EmrtdError> {
915    let c: &[u8] = match *key_type {
916        KeyType::Encryption => b"\x00\x00\x00\x01",
917        KeyType::Mac => b"\x00\x00\x00\x02",
918    };
919
920    let mut d = key_seed.to_vec();
921    d.extend_from_slice(c);
922
923    match alg {
924        EncryptionAlgorithm::DES3 => {
925            let hash_bytes =
926                hash(MessageDigest::sha1(), &d).map_err(EmrtdError::BoringErrorStack)?;
927            let key_1_2 = des3_adjust_parity_bits(hash_bytes.iter().copied().take(16).collect());
928            match *key_type {
929                KeyType::Encryption => Ok([&key_1_2[..], &key_1_2[..8]].concat()),
930                KeyType::Mac => Ok(key_1_2),
931            }
932        }
933        EncryptionAlgorithm::AES128 => {
934            let hash_bytes =
935                hash(MessageDigest::sha1(), &d).map_err(EmrtdError::BoringErrorStack)?;
936            Ok(hash_bytes.iter().copied().take(16).collect())
937        }
938        EncryptionAlgorithm::AES192 => {
939            let hash_bytes =
940                hash(MessageDigest::sha256(), &d).map_err(EmrtdError::BoringErrorStack)?;
941            Ok(hash_bytes.iter().copied().take(24).collect())
942        }
943        EncryptionAlgorithm::AES256 => {
944            let hash_bytes =
945                hash(MessageDigest::sha256(), &d).map_err(EmrtdError::BoringErrorStack)?;
946            Ok(hash_bytes.to_vec())
947        }
948    }
949}
src/lib.rs#compute_mac
 951/// Computes a MAC of data using the given key and MAC algorithm.
 952///
 953/// # Arguments
 954///
 955/// * `key` - The MAC key.
 956/// * `data` - The data to calculate the MAC of.
 957/// * `alg` - The MAC algorithm to be used (DES or AES-CMAC).
 958///
 959/// # Returns
 960///
 961/// Result containing the computed MAC or an `EmrtdError`.
 962///
 963/// # Errors
 964///
 965/// * `EmrtdError` if `key` or `data` length is wrong or cipher operation fails.
 966fn compute_mac(key: &[u8], data: &[u8], alg: &MacAlgorithm) -> Result<Vec<u8>, EmrtdError> {
 967    match *alg {
 968        MacAlgorithm::DES => {
 969            if key.len() != 16 {
 970                error!("Can not compute MAC, MAC key is invalid.");
 971                return Err(EmrtdError::InvalidMacKeyError(16, key.len()));
 972            }
 973
 974            if data.len() % 8 != 0 {
 975                error!("Can not compute MAC, data length is invalid.");
 976                return Err(EmrtdError::ParseDataError(format!(
 977                    "MAC calculation should be a multiple of 8, but found {}",
 978                    key.len()
 979                )));
 980            }
 981
 982            let key1 = &key[..8];
 983            let key2 = &key[8..];
 984
 985            let mut h = encrypt_ecb::<ecb::Encryptor<des::Des>>(key1, &data[..8])?;
 986
 987            for i in 1..(data.len() / 8) {
 988                h = encrypt_ecb::<ecb::Encryptor<des::Des>>(
 989                    key1,
 990                    &xor_slices(&h, &data[8 * i..8 * (i + 1)])?,
 991                )?;
 992            }
 993
 994            let mac_x = encrypt_ecb::<ecb::Encryptor<des::Des>>(
 995                key1,
 996                &decrypt_ecb::<ecb::Decryptor<des::Des>>(key2, &h)?,
 997            )?;
 998
 999            Ok(mac_x)
1000        }
1001        MacAlgorithm::AESCMAC => {
1002            unimplemented!("AES-CMAC MAC calculation is not yet implemented");
1003        }
1004    }
1005}
src/lib.rs#xor_slices
1007/// XORs two byte slices and returns the result.
1008///
1009/// # Arguments
1010///
1011/// * `a` - First input.
1012/// * `b` - Second input.
1013///
1014/// # Returns
1015///
1016/// Result containing the `XORed` result or an `EmrtdError`.
1017///
1018/// # Errors
1019///
1020/// * `EmrtdError` if input `a` and `b` have different lengths.
1021fn xor_slices(a: &[u8], b: &[u8]) -> Result<Vec<u8>, EmrtdError> {
1022    if a.len() == b.len() {
1023        let result: Vec<u8> = a.iter().zip(b.iter()).map(|(&x, &y)| x ^ y).collect();
1024        return Ok(result);
1025    }
1026    error!(
1027        "XORed slices must have the same length, found {}, {}",
1028        a.len(),
1029        b.len()
1030    );
1031    Err(EmrtdError::ParseDataError(format!(
1032        "XORed slices must have the same length, found {}, {}",
1033        a.len(),
1034        b.len()
1035    )))
1036}
src/lib.rs#padding_method_2
1038/// Pads the input data using padding method 2.
1039///
1040/// <https://en.wikipedia.org/wiki/ISO/IEC_9797-1#Padding_method_2>
1041///
1042/// # Arguments
1043///
1044/// * `data` - Data to be padded.
1045/// * `pad_to` - Length to pad to.
1046///
1047/// # Returns
1048///
1049/// Padded data or an `EmrtdError` if `pad_to` is 0.
1050///
1051/// # Errors
1052///
1053/// * `EmrtdError` if `pad_to` is 0.
1054fn padding_method_2(data: &[u8], pad_to: usize) -> Result<Vec<u8>, EmrtdError> {
1055    if pad_to == 0 {
1056        error!("pad_to must be greater than 0, found {}", pad_to);
1057        return Err(EmrtdError::InvalidArgument("pad_to must be greater than 0"));
1058    }
1059
1060    let mut data = data.to_vec();
1061    data.push(0x80);
1062    if data.len() % pad_to != 0 {
1063        let padding_len = pad_to - (data.len() % pad_to);
1064        data.extend(iter::repeat(0).take(padding_len));
1065    }
1066    Ok(data)
1067}
src/lib.rs#remove_padding
1069/// Removes the padding added by padding method 2 from the input data.
1070///
1071/// <https://en.wikipedia.org/wiki/ISO/IEC_9797-1#Padding_method_2>
1072///
1073/// # Arguments
1074///
1075/// * `data` - The padded data.
1076///
1077/// # Returns
1078///
1079/// If the padding exists, data with the padding removed, otherwise original data.
1080fn remove_padding(data: &[u8]) -> &[u8] {
1081    for (i, &b) in data.iter().rev().enumerate() {
1082        if b == 0x80 {
1083            return &data[..data.len() - 1 - i];
1084        }
1085    }
1086    data
1087}
src/lib.rs#des3_adjust_parity_bits
1089/// Adjusts the parity bits of a 3DES key.
1090///
1091/// # Arguments
1092///
1093/// * `key` - The 3DES key.
1094///
1095/// # Returns
1096///
1097/// 3DES key with adjusted parity bits.
1098fn des3_adjust_parity_bits(mut key: Vec<u8>) -> Vec<u8> {
1099    for byte in &mut key {
1100        let mut bitmask = 1;
1101        let mut b = *byte;
1102        for _ in 0..8 {
1103            bitmask ^= b & 0x1;
1104            b >>= 1;
1105        }
1106        *byte ^= bitmask;
1107    }
1108    key
1109}
src/lib.rs#calculate_check_digit
386/// Calculates the check digit for the given data using a specific algorithm.
387/// Calculation is explained at ICAO Doc 9303-3 Section 4.9:
388/// <https://www.icao.int/publications/Documents/9303_p3_cons_en.pdf>
389///
390/// # Arguments
391///
392/// * `data` - Data for which the check digit needs to be calculated.
393///
394/// # Returns
395///
396/// Result containing the calculated check digit or an `EmrtdError`.
397///
398/// # Errors
399///
400/// * `EmrtdError` if an invalid character is given.
401fn calculate_check_digit(data: &str) -> Result<char, EmrtdError> {
402    #[rustfmt::skip]
403    let values: BTreeMap<char, u32> = [
404        ('0', 0), ('1', 1), ('2', 2), ('3', 3), ('4', 4), ('5', 5), ('6', 6), ('7', 7),
405        ('8', 8), ('9', 9), ('<', 0), ('A', 10), ('B', 11), ('C', 12), ('D', 13), ('E', 14),
406        ('F', 15), ('G', 16), ('H', 17), ('I', 18), ('J', 19), ('K', 20), ('L', 21), ('M', 22),
407        ('N', 23), ('O', 24), ('P', 25), ('Q', 26), ('R', 27), ('S', 28), ('T', 29), ('U', 30),
408        ('V', 31), ('W', 32), ('X', 33), ('Y', 34), ('Z', 35),
409    ]
410    .iter()
411    .copied()
412    .collect();
413
414    let weights = [7, 3, 1];
415    let mut total = 0;
416
417    for (counter, value) in data.chars().enumerate() {
418        if let Some(weighted_value) = values.get(&value).copied() {
419            total += weights[counter % 3] * weighted_value;
420        } else {
421            error!("Can not calculate check digit for invalid character: `{value}`");
422            return Err(EmrtdError::ParseMrzCharError(value));
423        }
424    }
425
426    let check_digit =
427        char::from_digit(total % 10, 10).expect("usize % 10 can not be greater than 10");
428    Ok(check_digit)
429}
src/lib.rs#other_mrz
431/// Manually calculates the MRZ (Machine Readable Zone) string for BAC (Basic Access Control).
432///
433/// This function takes document number, birthdate, and expiry date as input, and calculates
434/// the MRZ string by appending check digits to each corresponding input.
435///
436/// # Arguments
437///
438/// * `doc_no` - Document number for MRZ calculation.
439/// * `birthdate` - Birthdate for MRZ calculation.
440/// * `expirydate` - Expiry date for MRZ calculation.
441///
442/// # Returns
443///
444/// Result containing a formatted MRZ string suitable for use in BAC (Basic Access Control) or an `EmrtdError`.
445///
446/// # Errors
447///
448/// * `EmrtdError` if MRZ field length is invalid or contains invalid characters
449///
450/// # Example
451///
452/// ```
453/// # use emrtd::EmrtdError;
454/// #
455/// # fn main() -> Result<(), EmrtdError> {
456/// use emrtd::other_mrz;
457/// let result = other_mrz("L898902C3", "740812", "120415")?;
458/// assert_eq!(result, String::from("L898902C3674081221204159"));
459/// #
460/// #     Ok(())
461/// # }
462/// ```
463pub fn other_mrz(doc_no: &str, birthdate: &str, expirydate: &str) -> Result<String, EmrtdError> {
464    // Document number can be up to 9 characters on TD3 sized eMRTDs (https://www.icao.int/publications/Documents/9303_p4_cons_en.pdf Appendix B)
465    // Document number can be up to 22 characters on TD1 sized eMRTDs (https://www.icao.int/publications/Documents/9303_p5_cons_en.pdf 4.2.2)
466    // Document number can be up to 14 characters on TD2 sized eMRTDs (https://www.icao.int/publications/Documents/9303_p6_cons_en.pdf 4.2.2.2)
467    if doc_no.len() > 22
468        || doc_no
469            .chars()
470            .any(|c| !"0123456789<ABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c))
471    {
472        error!("Error during other_mrz, document number length must be less than 23 and should not contain illegal characters, received {doc_no}");
473        return Err(EmrtdError::ParseMrzFieldError(
474            "Document number",
475            doc_no.to_owned(),
476        ));
477    }
478    if birthdate.len() != 6
479        || birthdate
480            .chars()
481            .any(|c| !"0123456789<ABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c))
482    {
483        error!("Error during other_mrz, birth date length must be 6 and should not contain illegal characters, received {birthdate}");
484        return Err(EmrtdError::ParseMrzFieldError(
485            "Birth date",
486            birthdate.to_owned(),
487        ));
488    }
489    if expirydate.len() != 6
490        || expirydate
491            .chars()
492            .any(|c| !"0123456789<ABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(c))
493    {
494        error!("Error during other_mrz, expiry date length must be 6 and should not contain illegal characters, received {expirydate}");
495        return Err(EmrtdError::ParseMrzFieldError(
496            "Expiry date",
497            expirydate.to_owned(),
498        ));
499    }
500
501    let formatted_mrz = format!(
502        "{:<9}{}{}{}{}{}",
503        doc_no,
504        calculate_check_digit(doc_no)?,
505        birthdate,
506        calculate_check_digit(birthdate)?,
507        expirydate,
508        calculate_check_digit(expirydate)?
509    );
510
511    Ok(formatted_mrz)
512}
src/lib.rs#oid2digestalg
1111/// Convert an OID (Object Identifier) byte array to its corresponding digest algorithm name.
1112///
1113/// # Arguments
1114///
1115/// * `oid` - OID.
1116///
1117/// # Returns
1118///
1119/// The name of the digest algorithm if the OID is recognized, else an `EmrtdError`.
1120///
1121/// # Errors
1122///
1123/// * `EmrtdError` if an unsupported OID is given.
1124fn oid2digestalg(oid: &rasn::types::ObjectIdentifier) -> Result<MessageDigest, EmrtdError> {
1125    let digest_alg_oid_dict: [(&Oid, MessageDigest); 6] = [
1126        (
1127            Oid::const_new(&[2, 16, 840, 1, 101, 3, 4, 2, 4]),
1128            MessageDigest::sha224(),
1129        ),
1130        (
1131            Oid::const_new(&[2, 16, 840, 1, 101, 3, 4, 2, 3]),
1132            MessageDigest::sha512(),
1133        ),
1134        (
1135            Oid::const_new(&[2, 16, 840, 1, 101, 3, 4, 2, 2]),
1136            MessageDigest::sha384(),
1137        ),
1138        (
1139            Oid::const_new(&[2, 16, 840, 1, 101, 3, 4, 2, 1]),
1140            MessageDigest::sha256(),
1141        ),
1142        (Oid::const_new(&[1, 3, 14, 3, 2, 26]), MessageDigest::sha1()),
1143        (
1144            Oid::const_new(&[1, 2, 840, 113549, 2, 5]),
1145            MessageDigest::md5(),
1146        ),
1147    ];
1148    for (digest_oid, digest) in digest_alg_oid_dict {
1149        if oid.eq(digest_oid) {
1150            return Ok(digest);
1151        }
1152    }
1153    error!("Invalid OID while finding a digest algorithm");
1154    Err(EmrtdError::InvalidOidError())
1155}
src/lib.rs#validate_asn1_tag
1157/// Validate the ASN.1 tag of the provided data. Multi-byte tags are supported.
1158///
1159/// # Arguments
1160///
1161/// * `data` - The data to validate.
1162/// * `tag` - The expected ASN.1 tag.
1163///
1164/// # Returns
1165///
1166/// Nothing if the tag is valid, or an `EmrtdError` if validation fails.
1167///
1168/// # Errors
1169///
1170/// * `EmrtdError` if the data is incomplete or the tags don't match.
1171fn validate_asn1_tag(data: &[u8], tag: &[u8]) -> Result<(), EmrtdError> {
1172    match data.get(..tag.len()) {
1173        Some(d) => {
1174            if !d.starts_with(tag) {
1175                error!(
1176                    "Error while validating ASN1 tag, expected: {}, found {}",
1177                    bytes2hex(tag),
1178                    bytes2hex(d)
1179                );
1180                Err(EmrtdError::ParseAsn1TagError(bytes2hex(tag), bytes2hex(d)))
1181            } else {
1182                Ok(())
1183            }
1184        }
1185        None => {
1186            error!("Error while validating ASN1 tag, `data.len()`: `{}` is less than `tag.len()`: `{}`", data.len(), tag.len());
1187            Err(EmrtdError::ParseAsn1DataError(tag.len(), data.len()))
1188        }
1189    }
1190}
src/lib.rs#get_asn1_child
1192/// Retrieve the ASN.1 child from the provided data.
1193///
1194/// # Arguments
1195///
1196/// * `data` - The data containing the ASN.1 structure.
1197/// * `tag_len` - The length of the tag.
1198///
1199/// # Returns
1200///
1201/// A `Result` containing the child element and the remaining data,
1202/// or an `EmrtdError` if extraction fails.
1203///
1204/// # Errors
1205///
1206/// * `EmrtdError` if the data is incomplete.
1207fn get_asn1_child(data: &[u8], tag_len: usize) -> Result<(&[u8], &[u8]), EmrtdError> {
1208    if data.len() < tag_len {
1209        error!(
1210            "Error during get_asn1_child, `data.len()`: `{}` is less than `tag_len`: `{}`",
1211            data.len(),
1212            tag_len
1213        );
1214        return Err(EmrtdError::ParseAsn1DataError(tag_len, data.len()));
1215    }
1216
1217    let (tl, v) = len2int(data, tag_len)?;
1218    if data.len() < tl + v {
1219        error!(
1220            "Error during get_asn1_child, `data.len()`: `{}` is less than `tl + v`: `{}`",
1221            data.len(),
1222            tl + v
1223        );
1224        return Err(EmrtdError::ParseAsn1DataError(tl + v, data.len()));
1225    }
1226    Ok((&data[tl..tl + v], &data[tl + v..]))
1227}

Next we have 4 utility functions that are necessary to use in BAC. They are basic DES and 3DES encryption/decryption functions, wrapped for easier use. The reason we use this instead of openssl is because openssl does not support DES. Instead, we use the native Rust implementation of block ciphers.

src/lib.rs#encrypt(_ecb),decrypt(_ecb)
693/// Encrypts data using the specified block cipher and mode.
694///
695/// # Arguments
696///
697/// * `key` - The encryption key.
698/// * `iv` - An optional initialization vector.
699/// * `data` - The data to be encrypted.
700///
701/// # Returns
702///
703/// Encrypted data if successful.
704///
705/// # Errors
706///
707/// `EmrtdError` if encryption fails.
708fn encrypt<CM>(key: &[u8], iv: Option<&[u8]>, data: &[u8]) -> Result<Vec<u8>, EmrtdError>
709where
710    CM: BlockEncryptMut + KeyIvInit,
711{
712    if key.len() != CM::key_size() {
713        error!(
714            "Wrong key size for cipher encryption, expected {}, found {}",
715            CM::key_size(),
716            key.len()
717        );
718        return Err(EmrtdError::InvalidArgument(
719            "Wrong key size for cipher encryption",
720        ));
721    }
722    if let Some(iv) = iv {
723        if iv.len() != CM::iv_size() {
724            error!(
725                "Wrong IV size for cipher encryption, expected {}, found {}",
726                CM::iv_size(),
727                iv.len()
728            );
729            return Err(EmrtdError::InvalidArgument(
730                "Wrong IV size for cipher encryption",
731            ));
732        }
733    }
734    if data.len() % CM::block_size() != 0 {
735        error!(
736            "Wrong data size for cipher encryption, expected {}, found {}",
737            CM::block_size(),
738            data.len()
739        );
740        return Err(EmrtdError::InvalidArgument(
741            "Wrong data size for cipher encryption",
742        ));
743    }
744
745    Ok(CM::new(key.into(), iv.unwrap_or_default().into())
746        .encrypt_padded_vec_mut::<cipher::block_padding::NoPadding>(data))
747}
748
749/// Encrypts data using the specified block cipher in Electronic Codebook (ECB) mode.
750///
751/// # Arguments
752///
753/// * `key` - The encryption key.
754/// * `data` - The data to be encrypted.
755///
756/// # Returns
757///
758/// Encrypted data if successful.
759///
760/// # Errors
761///
762/// `EmrtdError` if encryption fails.
763fn encrypt_ecb<CM>(key: &[u8], data: &[u8]) -> Result<Vec<u8>, EmrtdError>
764where
765    CM: BlockEncryptMut + KeyInit,
766{
767    if key.len() != CM::key_size() {
768        error!(
769            "Wrong key size for cipher encryption, expected {}, found {}",
770            CM::key_size(),
771            key.len()
772        );
773        return Err(EmrtdError::InvalidArgument(
774            "Wrong key size for cipher encryption",
775        ));
776    }
777    if data.len() % CM::block_size() != 0 {
778        error!(
779            "Wrong data size for cipher encryption, expected {}, found {}",
780            CM::block_size(),
781            data.len()
782        );
783        return Err(EmrtdError::InvalidArgument(
784            "Wrong data size for cipher encryption",
785        ));
786    }
787
788    Ok(CM::new(key.into()).encrypt_padded_vec_mut::<cipher::block_padding::NoPadding>(data))
789}
790
791/// Decrypts data using the specified block cipher and mode.
792///
793/// # Arguments
794///
795/// * `key` - The decryption key.
796/// * `iv` - An optional initialization vector.
797/// * `data` - The data to be decrypted.
798///
799/// # Returns
800///
801/// Decrypted data if successful.
802///
803/// # Errors
804///
805/// `EmrtdError` if decryption fails.
806fn decrypt<CM>(key: &[u8], iv: Option<&[u8]>, data: &[u8]) -> Result<Vec<u8>, EmrtdError>
807where
808    CM: BlockDecryptMut + KeyIvInit,
809{
810    if key.len() != CM::key_size() {
811        error!(
812            "Wrong key size for cipher decryption, expected {}, found {}",
813            CM::key_size(),
814            key.len()
815        );
816        return Err(EmrtdError::InvalidArgument(
817            "Wrong key size for cipher decryption",
818        ));
819    }
820    if let Some(iv) = iv {
821        if iv.len() != CM::iv_size() {
822            error!(
823                "Wrong IV size for cipher decryption, expected {}, found {}",
824                CM::iv_size(),
825                iv.len()
826            );
827            return Err(EmrtdError::InvalidArgument(
828                "Wrong IV size for cipher decryption",
829            ));
830        }
831    }
832    if data.len() % CM::block_size() != 0 {
833        error!(
834            "Wrong data size for cipher decryption, expected {}, found {}",
835            CM::block_size(),
836            data.len()
837        );
838        return Err(EmrtdError::InvalidArgument(
839            "Wrong data size for cipher decryption",
840        ));
841    }
842
843    CM::new(key.into(), iv.unwrap_or_default().into())
844        .decrypt_padded_vec_mut::<cipher::block_padding::NoPadding>(data)
845        .map_err(EmrtdError::UnpadError)
846}
847
848/// Decrypts data using the specified block cipher in Electronic Codebook (ECB) mode.
849///
850/// # Arguments
851///
852/// * `key` - The decryption key.
853/// * `data` - The data to be decrypted.
854///
855/// # Returns
856///
857/// Decrypted data if successful.
858///
859/// # Errors
860///
861/// `EmrtdError` if decryption fails.
862fn decrypt_ecb<CM>(key: &[u8], data: &[u8]) -> Result<Vec<u8>, EmrtdError>
863where
864    CM: BlockDecryptMut + KeyInit,
865{
866    if key.len() != CM::key_size() {
867        error!(
868            "Wrong key size for cipher decryption, expected {}, found {}",
869            CM::key_size(),
870            key.len()
871        );
872        return Err(EmrtdError::InvalidArgument(
873            "Wrong key size for cipher decryption",
874        ));
875    }
876    if data.len() % CM::block_size() != 0 {
877        error!(
878            "Wrong data size for cipher decryption, expected {}, found {}",
879            CM::block_size(),
880            data.len()
881        );
882        return Err(EmrtdError::InvalidArgument(
883            "Wrong data size for cipher decryption, expected {}, found {}",
884        ));
885    }
886
887    CM::new(key.into())
888        .decrypt_padded_vec_mut::<cipher::block_padding::NoPadding>(data)
889        .map_err(EmrtdError::UnpadError)
890}

Now that we have the necessary utility functions, let’s look at another struct to let us communicate with the eMRTD and do the low level operations that are necessary.

src/lib.rs#EmrtdComms
2613pub struct EmrtdComms {
2614    /// The card interface used for communication with the eMRTD.
2615    card: Card,
2616    /// The encryption algorithm used for securing communication with the eMRTD.
2617    enc_alg: Option<EncryptionAlgorithm>,
2618    /// The MAC (Message Authentication Code) algorithm used for data integrity verification.
2619    mac_alg: Option<MacAlgorithm>,
2620    /// The padding length used for encryption, data will be padded to multiple of `pad_len`.
2621    pad_len: usize,
2622    /// The session key used for encryption.
2623    ks_enc: Option<Vec<u8>>,
2624    /// The session key used for MAC generation.
2625    ks_mac: Option<Vec<u8>>,
2626    /// The Secure Session Counter (SSC).
2627    ssc: Option<Vec<u8>>,
2628}

The implementation of the EmrtdComms is the main code that is used in our project. I will quickly mention each of the functions and what they are used for and I hope that the implementation is clear enough to understand the details. I also provided links in the Doc comments where possible, if you would like to go and see it in ICAO Doc 9303 or relevant RFCs.

src/lib.rs#EmrtdComms
2630impl EmrtdComms {
2631    /// Constructs a new `EmrtdComms` instance with the smart card interface.
2632    ///
2633    /// # Arguments
2634    ///
2635    /// * `card` - The PC/SC smart card interface.
2636    ///
2637    /// # Returns
2638    ///
2639    /// A new `EmrtdComms` instance.
2640    #[must_use]
2641    pub fn new(card: Card) -> Self {
2642        Self {
2643            card,
2644            enc_alg: None,
2645            mac_alg: None,
2646            pad_len: 0,
2647            ks_enc: None,
2648            ks_mac: None,
2649            ssc: None,
2650        }
2651    }
2652
2653    // Other functions here ...
src/lib.rs#get_atr
2653    /// Retrieves the Answer to Reset (ATR) from the smart card.
2654    ///
2655    /// # Returns
2656    ///
2657    /// ATR or an `EmrtdError`.
2658    ///
2659    /// # Errors
2660    ///
2661    /// * `EmrtdError` wrapping `PscsError` in case of failure.
2662    pub fn get_atr(&mut self) -> Result<Vec<u8>, EmrtdError> {
2663        match self.card.get_attribute_owned(AtrString) {
2664            Ok(atr) => Ok(atr),
2665            Err(err) => Err(EmrtdError::PcscError(err)),
2666        }
2667    }
src/lib.rs#send
2669    /// Sends an APDU (Application Protocol Data Unit) to the smart card and receives the response.
2670    /// If `secure` is `false`, the APDU is sent in plaintext.
2671    /// If `secure` is `true`, the function checks that the secure channel is established previously,
2672    /// such as using `establish_bac_session_keys` function.
2673    /// For more details and examples, see ICAO Doc 9303-11 Section 9.8 and Appendix D.4
2674    /// <https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf>
2675    ///
2676    /// # Arguments
2677    ///
2678    /// * `apdu` - The APDU to be sent.
2679    /// * `secure` - A flag indicating whether to send the APDU securely.
2680    ///
2681    /// # Returns
2682    ///
2683    /// The response data and status bytes if the operation succeeds else an `EmrtdError`.
2684    ///
2685    /// # Errors
2686    ///
2687    /// * `EmrtdError` in case of failure during sending or receiving an APDU.
2688    pub fn send(&mut self, apdu: &APDU, secure: bool) -> Result<(Vec<u8>, [u8; 2]), EmrtdError> {
2689        // Sending APDU in plaintext
2690        if !secure {
2691            let mut apdu_bytes = vec![];
2692            apdu_bytes.extend(&apdu.get_command_header());
2693            apdu_bytes.extend(&apdu.lc.clone().unwrap_or_default());
2694            apdu_bytes.extend(&apdu.cdata.clone().unwrap_or_default());
2695            apdu_bytes.extend(&apdu.le.clone().unwrap_or_default());
2696
2697            trace!("Sending APDU: {}", bytes2hex(&apdu_bytes));
2698            let mut response_buffer = [0; pcsc::MAX_BUFFER_SIZE];
2699
2700            return match self.card.transmit(&apdu_bytes, &mut response_buffer) {
2701                Ok(response) => {
2702                    if response.len() < 2 {
2703                        error!(
2704                            "Card response length should be greater than or equal to 2, found {}",
2705                            response.len()
2706                        );
2707                        return Err(EmrtdError::InvalidResponseError());
2708                    }
2709
2710                    let status_bytes: [u8; 2] =
2711                        [response[response.len() - 2], response[response.len() - 1]];
2712
2713                    let data = response[..response.len() - 2].to_vec();
2714
2715                    trace!(
2716                        "APDU response ({:02X}{:02X}): {}",
2717                        status_bytes[0],
2718                        status_bytes[1],
2719                        bytes2hex(&data)
2720                    );
2721
2722                    Ok((data, status_bytes))
2723                }
2724                Err(err) => Err(EmrtdError::PcscError(err)),
2725            };
2726        }
2727
2728        self.increment_ssc()?;
2729
2730        let Some(ref ssc) = self.ssc else {
2731            error!("SSC is not set but trying to send securely");
2732            return Err(EmrtdError::InvalidArgument(
2733                "SSC is not set but trying to send securely",
2734            ));
2735        };
2736        let Some(ref enc_alg) = self.enc_alg else {
2737            error!("Enc algorithm is not set but trying to send securely");
2738            return Err(EmrtdError::InvalidArgument(
2739                "Enc algorithm is not set but trying to send securely",
2740            ));
2741        };
2742        let Some(ref mac_alg) = self.mac_alg else {
2743            error!("MAC algorithm is not set but trying to send securely");
2744            return Err(EmrtdError::InvalidArgument(
2745                "MAC algorithm is not set but trying to send securely",
2746            ));
2747        };
2748        let Some(ref ks_enc) = self.ks_enc else {
2749            error!("Session key ks_enc is not set but trying to send securely");
2750            return Err(EmrtdError::InvalidArgument(
2751                "Session key ks_enc is not set but trying to send securely",
2752            ));
2753        };
2754        let Some(ref ks_mac) = self.ks_mac else {
2755            error!("Session key ks_mac is not set but trying to send securely");
2756            return Err(EmrtdError::InvalidArgument(
2757                "Session key ks_mac is not set but trying to send securely",
2758            ));
2759        };
2760        if self.pad_len == 0 {
2761            error!("Padding length is 0 but trying to send securely");
2762            return Err(EmrtdError::InvalidArgument(
2763                "Padding length is 0 but trying to send securely",
2764            ));
2765        }
2766        let pad_len = self.pad_len;
2767        let mut apdu = apdu.clone();
2768
2769        apdu.cla |= 0x0C;
2770
2771        let mut payload = Vec::new();
2772        if let Some(cdata) = &apdu.cdata {
2773            let data = &padding_method_2(cdata, pad_len)?;
2774            let encrypted_data = match enc_alg {
2775                EncryptionAlgorithm::DES3 => {
2776                    encrypt::<cbc::Encryptor<des::TdesEde3>>(ks_enc, Some(&[0; 8]), data)?
2777                }
2778                EncryptionAlgorithm::AES128 => {
2779                    let ssc_enc = encrypt_ecb::<ecb::Encryptor<aes::Aes128>>(ks_enc, ssc)?;
2780                    encrypt::<cbc::Encryptor<aes::Aes128>>(ks_enc, Some(&ssc_enc), data)?
2781                }
2782                EncryptionAlgorithm::AES192 => {
2783                    let ssc_enc = encrypt_ecb::<ecb::Encryptor<aes::Aes192>>(ks_enc, ssc)?;
2784                    encrypt::<cbc::Encryptor<aes::Aes192>>(ks_enc, Some(&ssc_enc), data)?
2785                }
2786                EncryptionAlgorithm::AES256 => {
2787                    let ssc_enc = encrypt_ecb::<ecb::Encryptor<aes::Aes256>>(ks_enc, ssc)?;
2788                    encrypt::<cbc::Encryptor<aes::Aes256>>(ks_enc, Some(&ssc_enc), data)?
2789                }
2790            };
2791
2792            if apdu.ins % 2 == 0 {
2793                // For a command with even INS, any command data is encrypted
2794                // and encapsulated in a Tag 87 with padding indicator (01).
2795                let do87 = [
2796                    b"\x87",
2797                    (&*int2asn1len([&b"\x01"[..], &encrypted_data].concat().len())),
2798                    &[&b"\x01"[..], &encrypted_data].concat(),
2799                ]
2800                .concat();
2801                payload.extend_from_slice(&do87);
2802            } else {
2803                // For a command with odd INS, any command data is encrypted
2804                // and encapsulated in a Tag 85 without padding indicator.
2805                let do85 = [
2806                    b"\x85",
2807                    (&*int2asn1len(encrypted_data.len())),
2808                    &encrypted_data,
2809                ]
2810                .concat();
2811                payload.extend_from_slice(&do85);
2812            }
2813        }
2814
2815        if let Some(le) = &apdu.le {
2816            // Commands with response (Le field not empty)
2817            // have a protected Le-field (Tag 97) in the command data.
2818            let do97 = [b"\x97", (&*int2asn1len(le.len())), le].concat();
2819            payload.extend_from_slice(&do97);
2820        }
2821
2822        let padded_header = padding_method_2(&apdu.get_command_header(), pad_len)?;
2823        let n = padding_method_2(&[&ssc, (&*padded_header), &payload].concat(), pad_len)?;
2824        let cc = compute_mac(ks_mac, &n, mac_alg)?;
2825
2826        let do8e = [b"\x8E", (&*int2asn1len(cc.len())), &cc].concat();
2827        payload.extend_from_slice(&do8e);
2828
2829        let protected_apdu = [
2830            apdu.get_command_header(),
2831            [payload.len() as u8].to_vec(),
2832            payload,
2833            b"\x00".to_vec(),
2834        ]
2835        .concat();
2836
2837        trace!("Sending Protected APDU: {}", bytes2hex(&protected_apdu));
2838        let mut response_buffer = [0; pcsc::MAX_BUFFER_SIZE];
2839
2840        match self.card.transmit(&protected_apdu, &mut response_buffer) {
2841            Ok(response) => {
2842                if response.len() < 2 {
2843                    error!(
2844                        "Card response length should be greater than or equal to 2, found {}",
2845                        response.len()
2846                    );
2847                    return Err(EmrtdError::InvalidResponseError());
2848                }
2849
2850                let status_bytes: [u8; 2] =
2851                    [response[response.len() - 2], response[response.len() - 1]];
2852
2853                let data = self.process_secure_rapdu(&response[..response.len() - 2])?;
2854
2855                trace!(
2856                    "APDU response ({:02X}{:02X}): {}",
2857                    status_bytes[0],
2858                    status_bytes[1],
2859                    bytes2hex(&data)
2860                );
2861
2862                Ok((data, status_bytes))
2863            }
2864            Err(err) => Err(EmrtdError::PcscError(err)),
2865        }
2866    }
src/lib.rs#process_secure_rapdu
2868    /// Processes a secured Application Protocol Data Unit response received from the smart card.
2869    ///
2870    /// # Arguments
2871    ///
2872    /// * `rapdu` - A slice containing the Secure `R_APDU` to be processed.
2873    ///
2874    /// # Returns
2875    ///
2876    /// Decrypted data or an `EmrtdError`.
2877    ///
2878    /// # Errors
2879    ///
2880    /// * `EmrtdError` in case of failure during processing of received APDU.
2881    fn process_secure_rapdu(&mut self, rapdu: &[u8]) -> Result<Vec<u8>, EmrtdError> {
2882        self.increment_ssc()?;
2883
2884        let Some(ref ssc) = self.ssc else {
2885            error!("SSC is not set but trying to process R_APDU");
2886            return Err(EmrtdError::InvalidArgument(
2887                "SSC is not set but trying to process R_APDU",
2888            ));
2889        };
2890        let Some(ref enc_alg) = self.enc_alg else {
2891            error!("Enc algorithm is not set but trying to process R_APDU");
2892            return Err(EmrtdError::InvalidArgument(
2893                "Enc algorithm is not set but trying to process R_APDU",
2894            ));
2895        };
2896        let Some(ref mac_alg) = self.mac_alg else {
2897            error!("MAC algorithm is not set but trying to process R_APDU");
2898            return Err(EmrtdError::InvalidArgument(
2899                "MAC algorithm is not set but trying to process R_APDU",
2900            ));
2901        };
2902        let Some(ref ks_enc) = self.ks_enc else {
2903            error!("Session key ks_enc is not set but trying to process R_APDU");
2904            return Err(EmrtdError::InvalidArgument(
2905                "Session key ks_enc is not set but trying to process R_APDU",
2906            ));
2907        };
2908        let Some(ref ks_mac) = self.ks_mac else {
2909            error!("Session key ks_mac is not set but trying to process R_APDU");
2910            return Err(EmrtdError::InvalidArgument(
2911                "Session key ks_mac is not set but trying to process R_APDU",
2912            ));
2913        };
2914        if self.pad_len == 0 {
2915            error!("Padding length is 0 but trying to process R_APDU");
2916            return Err(EmrtdError::InvalidArgument(
2917                "Padding length is 0 but trying to process R_APDU",
2918            ));
2919        }
2920        let pad_len = self.pad_len;
2921
2922        let mut encrypted_data = Vec::new();
2923        let mut decrypted_data = Vec::new();
2924        let mut do85: Option<&[u8]> = None;
2925        let mut do87: Option<&[u8]> = None;
2926        let mut do99: Option<&[u8]> = None;
2927        let mut do8e: Option<&[u8]> = None;
2928
2929        trace!("R_APDU: {}", bytes2hex(rapdu));
2930
2931        let mut rapdu = rapdu;
2932        loop {
2933            let (tl_len, value_len) = len2int(rapdu, 1)?;
2934            match rapdu[0] {
2935                b'\x85' => {
2936                    encrypted_data = rapdu[tl_len..tl_len + value_len].to_vec();
2937                    do85 = Some(&rapdu[..tl_len + value_len]);
2938                }
2939                b'\x87' => {
2940                    encrypted_data = rapdu[tl_len..tl_len + value_len].to_vec();
2941                    do87 = Some(&rapdu[..tl_len + value_len]);
2942                }
2943                b'\x99' => do99 = Some(&rapdu[..tl_len + value_len]),
2944                b'\x8e' => {
2945                    do8e = Some(&rapdu[tl_len..tl_len + value_len]);
2946                }
2947                _ => {
2948                    error!("Tag not supported in encrypted R_APDU");
2949                    return Err(EmrtdError::ParseDataError(format!(
2950                        "Tag {:02X} not supported in encrypted R_APDU",
2951                        rapdu[0]
2952                    )));
2953                }
2954            }
2955            rapdu = &rapdu[tl_len + value_len..];
2956            if rapdu.is_empty() {
2957                break;
2958            }
2959        }
2960
2961        let k = padding_method_2(
2962            &[
2963                &ssc,
2964                do85.unwrap_or_default(),
2965                do87.unwrap_or_default(),
2966                do99.unwrap_or_default(),
2967            ]
2968            .concat(),
2969            pad_len,
2970        )?;
2971        let cc = compute_mac(ks_mac, &k, mac_alg)?;
2972        if !eq(&cc, do8e.unwrap_or_default()) {
2973            error!("MAC verification failed");
2974            return Err(EmrtdError::VerifyMacError());
2975        }
2976
2977        if !encrypted_data.is_empty() {
2978            // If INS is even, remove the padding indicator (01)
2979            if do87.is_some() {
2980                encrypted_data = encrypted_data[1..].to_vec();
2981            }
2982            // Decrypt
2983            let decrypted_padded_data = match enc_alg {
2984                EncryptionAlgorithm::DES3 => decrypt::<cbc::Decryptor<des::TdesEde3>>(
2985                    ks_enc,
2986                    Some(&[0; 8]),
2987                    &encrypted_data,
2988                )?,
2989                EncryptionAlgorithm::AES128 => {
2990                    let ssc_enc = encrypt_ecb::<ecb::Encryptor<aes::Aes128>>(ks_enc, ssc)?;
2991                    decrypt::<cbc::Decryptor<aes::Aes128>>(ks_enc, Some(&ssc_enc), &encrypted_data)?
2992                }
2993                EncryptionAlgorithm::AES192 => {
2994                    let ssc_enc = encrypt_ecb::<ecb::Encryptor<aes::Aes192>>(ks_enc, ssc)?;
2995                    decrypt::<cbc::Decryptor<aes::Aes192>>(ks_enc, Some(&ssc_enc), &encrypted_data)?
2996                }
2997                EncryptionAlgorithm::AES256 => {
2998                    let ssc_enc = encrypt_ecb::<ecb::Encryptor<aes::Aes256>>(ks_enc, ssc)?;
2999                    decrypt::<cbc::Decryptor<aes::Aes256>>(ks_enc, Some(&ssc_enc), &encrypted_data)?
3000                }
3001            };
3002            // Remove padding
3003            decrypted_data = remove_padding(&decrypted_padded_data).to_vec();
3004        }
3005        Ok(decrypted_data)
3006    }
src/lib.rs#select_emrtd_application
3008    /// Selects the eMRTD application on the card.
3009    ///
3010    /// This function sends a command to select the eMRTD application using AID `A0000002471001`.
3011    ///
3012    /// # Returns
3013    ///
3014    /// Nothing if the selection is successful.
3015    ///
3016    /// # Errors
3017    ///
3018    /// `EmrtdError` in case of failure during sending the APDU.
3019    pub fn select_emrtd_application(&mut self) -> Result<(), EmrtdError> {
3020        // Select eMRTD application
3021        let aid = b"\xA0\x00\x00\x02\x47\x10\x01";
3022        info!(
3023            "Selecting eMRTD Application `International AID`: {}...",
3024            bytes2hex(aid)
3025        );
3026        let apdu = APDU::new(
3027            b'\x00',
3028            b'\xA4',
3029            b'\x04',
3030            b'\x0C',
3031            Some(int2asn1len(aid.len())),
3032            Some(aid.to_vec()),
3033            None,
3034        );
3035        match self.send(&apdu, false) {
3036            Ok((_, status)) => match status {
3037                [0x90, 0x00] => Ok(()),
3038                [sw1, sw2] => {
3039                    error!("Received invalid SW during Select eMRTD Application command: {sw1:02X} {sw2:02X}");
3040                    Err(EmrtdError::RecvApduError(sw1, sw2))
3041                }
3042            },
3043            Err(err) => {
3044                error!("Error while selecting eMRTD Application.");
3045                Err(err)
3046            }
3047        }
3048    }
src/lib.rs#select_ef
3050    /// Selects a specific Elementary File (EF) on the smart card by sending a "Select File" APDU.
3051    ///
3052    /// # Arguments
3053    ///
3054    /// * `fid` - Array representing the File Identifier (FID) of the EF to select.
3055    /// * `fname` - The name of the file being selected (used for logging purposes).
3056    ///
3057    /// # Returns
3058    ///
3059    /// Nothing if successful, else an `EmrtdError`.
3060    ///
3061    /// # Errors
3062    ///
3063    /// * `EmrtdError` in case of failure during sending the APDU.
3064    pub fn select_ef(
3065        &mut self,
3066        fid: &[u8; 2],
3067        fname: &str,
3068        secure: bool,
3069    ) -> Result<(), EmrtdError> {
3070        // Send "Select File" APDU
3071        trace!("Selecting File {fname}: {}...", bytes2hex(fid));
3072        let apdu = APDU::new(
3073            b'\x00',
3074            b'\xA4',
3075            b'\x02',
3076            b'\x0C',
3077            Some(int2asn1len(fid.len())),
3078            Some(fid.to_vec()),
3079            None,
3080        );
3081        match self.send(&apdu, secure) {
3082            Ok((_, status)) => match status {
3083                [0x90, 0x00] => Ok(()),
3084                [sw1, sw2] => {
3085                    error!("Received invalid SW during Select EF command: {sw1:02X} {sw2:02X}");
3086                    Err(EmrtdError::RecvApduError(sw1, sw2))
3087                }
3088            },
3089            Err(err) => {
3090                error!("Error while selecting an EF.");
3091                Err(err)
3092            }
3093        }
3094    }
src/lib.rs#read_data_from_ef
3096    /// Reads data from an EF (Elementary File) in an eMRTD (electronic Machine Readable Travel Document).
3097    ///
3098    /// This function sends APDU (Application Protocol Data Unit) commands to read the data from the EF.
3099    /// It starts by reading the first four bytes of the file, then determines the total length of the file.
3100    /// Afterward, it reads the rest of the bytes in chunks until it reaches the end of the file.
3101    /// `select_ef` function must be called before calling this function.
3102    ///
3103    /// # Returns
3104    ///
3105    /// The data read from the EF if successful, else an `EmrtdError`.
3106    ///
3107    /// # Errors
3108    ///
3109    /// * `EmrtdError` in case of failure.
3110    pub fn read_data_from_ef(&mut self, secure: bool) -> Result<Vec<u8>, EmrtdError> {
3111        // Read Binary of first four bytes
3112        let apdu = APDU::new(
3113            b'\x00',
3114            b'\xB0',
3115            b'\x00',
3116            b'\x00',
3117            None,
3118            None,
3119            Some(vec![b'\x04']),
3120        );
3121        // Send "Read Binary" APDU for the first 4 bytes
3122        trace!("Reading first 4 bytes from EF...");
3123        let mut data = match self.send(&apdu, secure) {
3124            Ok((data, status)) => match status {
3125                [0x90, 0x00] => data,
3126                [sw1, sw2] => {
3127                    error!("Received invalid SW during reading first 4 bytes of EF: {sw1:02X} {sw2:02X}");
3128                    return Err(EmrtdError::RecvApduError(sw1, sw2));
3129                }
3130            },
3131            Err(err) => {
3132                error!("Error while reading 4 bytes from EF.");
3133                return Err(err);
3134            }
3135        };
3136
3137        if data.len() != 4 {
3138            error!(
3139                "Card response length should be equal to the requested amount 4, found {}",
3140                data.len()
3141            );
3142            return Err(EmrtdError::InvalidResponseError());
3143        }
3144
3145        let data_len;
3146        {
3147            let (tl, v) = len2int(&data, 1)?;
3148            data_len = tl + v;
3149        };
3150
3151        let mut offset = 4;
3152
3153        // Read the rest of the bytes
3154        trace!("Reading {data_len} bytes from EF...");
3155        while offset < data_len {
3156            let le = if data_len - offset < 0xFA {
3157                [((data_len - offset) & 0xFF) as u8]
3158            } else {
3159                [0x00]
3160            };
3161
3162            // Send "Read Binary" APDU for the next chunk
3163            let offset_bytes = [(offset >> 8) as u8, (offset & 0xFF) as u8];
3164            let read_apdu = APDU::new(
3165                b'\x00',
3166                b'\xB0',
3167                offset_bytes[0],
3168                offset_bytes[1],
3169                None,
3170                None,
3171                Some(vec![le[0]]),
3172            );
3173            trace!("Reading next {} bytes from EF...", data_len - offset);
3174            let data_read = match self.send(&read_apdu, secure) {
3175                Ok((data, status)) => match status {
3176                    [0x90, 0x00] => data,
3177                    [sw1, sw2] => {
3178                        error!("Received invalid SW during reading bytes {} of EF: {sw1:02X} {sw2:02X}", data_len - offset);
3179                        return Err(EmrtdError::RecvApduError(sw1, sw2));
3180                    }
3181                },
3182                Err(err) => {
3183                    error!("Error while reading bytes from EF.");
3184                    return Err(err);
3185                }
3186            };
3187
3188            if data_read.is_empty() {
3189                error!("Requested bytes while reading EF but received 0 bytes.");
3190                return Err(EmrtdError::InvalidResponseError());
3191            }
3192
3193            // Append the new data to the result
3194            data.extend_from_slice(&data_read);
3195            offset += data_read.len();
3196        }
3197
3198        if offset != data_len {
3199            error!(
3200                "Error while parsing EF data from the card, expected {offset}, found {data_len}."
3201            );
3202            return Err(EmrtdError::InvalidResponseError());
3203        }
3204
3205        Ok(data)
3206    }
src/lib.rs#establish_bac_session_keys
3208    /// Establishes session keys for Basic Access Control (BAC) protocol.
3209    ///
3210    /// For more details and examples, see ICAO Doc 9303-11 Section 4.3 and Appendix D.3
3211    /// <https://www.icao.int/publications/Documents/9303_p11_cons_en.pdf>
3212    ///
3213    /// # Arguments
3214    ///
3215    /// * `secret` - The secret key used for BAC (from MRZ, generate it using `other_mrz` function.
3216    ///
3217    /// # Returns
3218    ///
3219    /// * Nothing if successful, else an `EmrtdError`.
3220    ///
3221    /// # Errors
3222    ///
3223    /// * `EmrtdError` in case of failure during BAC session key establishment.
3224    pub fn establish_bac_session_keys(&mut self, secret: &[u8]) -> Result<(), EmrtdError> {
3225        let ba_key_seed = &generate_key_seed(secret)?[..16];
3226
3227        // Calculate the basic access keys (ba_key_enc and ba_key_mac)
3228        trace!("Computing basic access keys...");
3229        let ba_key_enc = &compute_key(
3230            ba_key_seed,
3231            &KeyType::Encryption,
3232            &EncryptionAlgorithm::DES3,
3233        )?;
3234        let ba_key_mac = &compute_key(ba_key_seed, &KeyType::Mac, &EncryptionAlgorithm::DES3)?;
3235
3236        // AUTHENTICATION AND ESTABLISHMENT OF SESSION KEYS
3237        trace!("Establishing session keys...");
3238        let apdu = APDU::new(
3239            b'\x00',
3240            b'\x84',
3241            b'\x00',
3242            b'\x00',
3243            None,
3244            None,
3245            Some(vec![b'\x08']),
3246        );
3247        let rnd_ic = match self.send(&apdu, false) {
3248            Ok((rnd_ic, status)) => match status {
3249                [0x90, 0x00] => rnd_ic,
3250                [sw1, sw2] => {
3251                    error!("Received invalid SW during establishing BAC session keys: {sw1:02X} {sw2:02X}");
3252                    return Err(EmrtdError::RecvApduError(sw1, sw2));
3253                }
3254            },
3255            Err(err) => {
3256                error!("Error while establishing BAC session keys.");
3257                return Err(err);
3258            }
3259        };
3260
3261        let mut rnd_ifd: [u8; 8] = [0; 8];
3262        rand_bytes(&mut rnd_ifd).map_err(EmrtdError::BoringErrorStack)?;
3263        let mut k_ifd: [u8; 16] = [0; 16];
3264        rand_bytes(&mut k_ifd).map_err(EmrtdError::BoringErrorStack)?;
3265
3266        let e_ifd = encrypt::<cbc::Encryptor<des::TdesEde3>>(
3267            ba_key_enc,
3268            Some(&[0; 8]),
3269            &[&rnd_ifd[..], (&*rnd_ic), &k_ifd[..]].concat(),
3270        )?;
3271
3272        let m_ifd = compute_mac(
3273            &ba_key_mac.clone(),
3274            &padding_method_2(&e_ifd, 8)?,
3275            &MacAlgorithm::DES,
3276        )?;
3277        let cmd_data = [&e_ifd, (&*m_ifd)].concat();
3278
3279        let apdu = APDU::new(
3280            b'\x00',
3281            b'\x82',
3282            b'\x00',
3283            b'\x00',
3284            Some(int2asn1len(cmd_data.len())),
3285            Some(cmd_data),
3286            Some(vec![b'\x28']),
3287        );
3288        let resp_data_enc = match self.send(&apdu, false) {
3289            Ok((resp_data_enc, status)) => match status {
3290                [0x90, 0x00] => resp_data_enc,
3291                [sw1, sw2] => {
3292                    error!("Received invalid SW during establishing BAC session keys: {sw1:02X} {sw2:02X}");
3293                    return Err(EmrtdError::RecvApduError(sw1, sw2));
3294                }
3295            },
3296            Err(err) => {
3297                error!("Error while establishing BAC session keys.");
3298                return Err(err);
3299            }
3300        };
3301
3302        let m_ic = compute_mac(
3303            &ba_key_mac.clone(),
3304            &padding_method_2(&resp_data_enc[..resp_data_enc.len() - 8], 8)?,
3305            &MacAlgorithm::DES,
3306        )?;
3307        if !eq(&m_ic, &resp_data_enc[resp_data_enc.len() - 8..]) {
3308            error!("MAC verification failed");
3309            return Err(EmrtdError::VerifyMacError());
3310        }
3311
3312        let resp_data = decrypt::<cbc::Decryptor<des::TdesEde3>>(
3313            ba_key_enc,
3314            Some(&[0; 8]),
3315            &resp_data_enc[..resp_data_enc.len() - 8],
3316        )?;
3317
3318        if !eq(&resp_data[..8], &rnd_ic[..]) {
3319            error!("Error while establishing BAC session keys.");
3320            return Err(EmrtdError::InvalidResponseError());
3321        }
3322
3323        if !eq(&resp_data[8..16], &rnd_ifd[..]) {
3324            error!("Error while establishing BAC session keys.");
3325            return Err(EmrtdError::InvalidResponseError());
3326        }
3327
3328        let k_ic: &[u8] = &resp_data[16..32];
3329
3330        let ses_key_seed = xor_slices(&k_ifd, k_ic)?;
3331
3332        let ks_enc = compute_key(
3333            &ses_key_seed,
3334            &KeyType::Encryption,
3335            &EncryptionAlgorithm::DES3,
3336        )?;
3337        let ks_mac = compute_key(&ses_key_seed, &KeyType::Mac, &EncryptionAlgorithm::DES3)?;
3338
3339        let ssc = [&rnd_ic[4..], &rnd_ifd[4..]].concat();
3340
3341        self.enc_alg = Some(EncryptionAlgorithm::DES3);
3342        self.mac_alg = Some(MacAlgorithm::DES);
3343        self.pad_len = 8;
3344        self.ks_enc = Some(ks_enc);
3345        self.ks_mac = Some(ks_mac);
3346        self.ssc = Some(ssc);
3347
3348        Ok(())
3349    }
src/lib.rs#increment_ssc
3351    /// Increment the Secure Session Counter (SSC).
3352    ///
3353    /// # Returns
3354    ///
3355    /// Nothing if successful, else an `EmrtdError` if the SSC is not set or overflows.
3356    ///
3357    /// # Errors
3358    ///
3359    /// * `EmrtdError` if SSC is invalid or overflows.
3360    fn increment_ssc(&mut self) -> Result<(), EmrtdError> {
3361        if let Some(ref mut ssc) = self.ssc {
3362            if ssc.len() == 8 {
3363                let int_val = u64::from_be_bytes(ssc.as_slice().try_into().unwrap());
3364                let incremented_val = int_val
3365                    .checked_add(1)
3366                    .ok_or(EmrtdError::OverflowSscError())?;
3367                *ssc = incremented_val.to_be_bytes().to_vec();
3368                Ok(())
3369            } else if ssc.len() == 16 {
3370                let int_val = u128::from_be_bytes(ssc.as_slice().try_into().unwrap());
3371                let incremented_val = int_val
3372                    .checked_add(1)
3373                    .ok_or(EmrtdError::OverflowSscError())?;
3374                *ssc = incremented_val.to_be_bytes().to_vec();
3375                Ok(())
3376            } else {
3377                unimplemented!("Only 8 and 16 byte SSC is supported");
3378            }
3379        } else {
3380            error!("SSC is not set but trying to increment");
3381            Err(EmrtdError::InvalidArgument(
3382                "SSC is not set but trying to increment",
3383            ))
3384        }
3385    }

All this above lets us read files from eMRTDs. Next, we need functions that will help us decode the information in these files and do higher level validations, such as Passive, Active, or Chip Authentication.

src/lib.rs#parse_master_list
1229/// Parses the master list data and constructs an `X509Store`.
1230///
1231/// # Arguments
1232///
1233/// * `master_list` - The master list data to be parsed as a byte slice.
1234///
1235/// # Returns
1236///
1237/// * `X509Store` containing the parsed CSCA certificates if successful.
1238///
1239/// # Errors
1240///
1241/// `EmrtdError` if parsing fails.
1242///
1243/// # Panics
1244///
1245/// Might panic under different circumstances.
1246///
1247/// # Examples
1248///
1249/// ```
1250/// # use emrtd::EmrtdError;
1251/// #
1252/// # fn main() -> Result<(), EmrtdError> {
1253/// use emrtd::parse_master_list;
1254/// use tracing::{info, error};
1255///
1256/// let master_list_bytes = &[/* EF.SOD Data */];
1257///
1258/// match parse_master_list(master_list_bytes) {
1259///     Ok(cert_store) => {
1260///         info!("Master list successfully parsed, number of certificates in the store {}", cert_store.all_certificates().len());
1261///     },
1262///     Err(err) => error!("Master list parsing failed: {:?}", err),
1263/// }
1264/// #
1265/// #     Ok(())
1266/// # }
1267/// ```
1268pub fn parse_master_list(master_list: &[u8]) -> Result<X509Store, EmrtdError> {
1269    // We expect a Master List as specified in
1270    // ICAO Doc 9303-12 Section 9
1271    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1272
1273    // RFC 5652 Section 12.1, Cryptographic Message Syntax
1274    // <https://datatracker.ietf.org/doc/html/rfc5652#section-12.1>
1275    //
1276    // ContentInfo ::= SEQUENCE {
1277    //   contentType ContentType,
1278    //   content [0] EXPLICIT ANY DEFINED BY contentType }
1279    //
1280    // ContentType ::= OBJECT IDENTIFIER
1281    let content_info =
1282        der::decode::<rasn_cms::ContentInfo>(master_list).map_err(EmrtdError::RasnDecodeError)?;
1283
1284    // RFC 5652 Section 5.1, SignedData Type
1285    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.1>
1286    // Verify the id-signedData OID
1287    if content_info
1288        .content_type
1289        .ne(Oid::const_new(&[1, 2, 840, 113549, 1, 7, 2]))
1290    {
1291        error!("Master List ContentInfo contentType OID must be id-signedData");
1292        return Err(EmrtdError::InvalidFileStructure(
1293            "Master List ContentInfo contentType OID must be id-signedData",
1294        ));
1295    }
1296
1297    // RFC 5652 Section 12.1, Cryptographic Message Syntax
1298    // <https://datatracker.ietf.org/doc/html/rfc5652#section-12.1>
1299    //
1300    // SignedData ::= SEQUENCE {
1301    //   version CMSVersion,
1302    //   digestAlgorithms DigestAlgorithmIdentifiers,
1303    //   encapContentInfo EncapsulatedContentInfo,
1304    //   certificates [0] IMPLICIT CertificateSet OPTIONAL,
1305    //   crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
1306    //   signerInfos SignerInfos }
1307    let signed_data = der::decode::<rasn_cms::SignedData>(content_info.content.as_bytes())
1308        .map_err(EmrtdError::RasnDecodeError)?;
1309
1310    // RFC 5652 Sections 12.1 and 10.2.5
1311    // <https://datatracker.ietf.org/doc/html/rfc5652>
1312    // First item in the SignedData Sequence is version
1313    // ICAO Doc 9303-12 Section 9
1314    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1315    // For Master Lists it is always set to Value 3
1316    if signed_data.version.ne(&rasn::types::Integer::from(3)) {
1317        error!("Master List SignedData version must be V3");
1318        return Err(EmrtdError::InvalidFileStructure(
1319            "Master List SignedData version must be V3",
1320        ));
1321    }
1322
1323    // RFC 5652 Section 12.1, Cryptographic Message Syntax
1324    // <https://datatracker.ietf.org/doc/html/rfc5652#section-12.1>
1325    // Second item in the SignedData Sequence is digestAlgorithms
1326    //
1327    // It is mandatory by ICAO Doc 9303-12 Section 9
1328    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1329    if signed_data.digest_algorithms.is_empty() {
1330        error!("Master List SignedData digestAlgorithms can not be empty");
1331        return Err(EmrtdError::InvalidFileStructure(
1332            "Master List SignedData digestAlgorithms can not be empty",
1333        ));
1334    }
1335
1336    // RFC 5652 Section 12.1, Cryptographic Message Syntax
1337    // <https://datatracker.ietf.org/doc/html/rfc5652#section-12.1>
1338    // Third item in the SignedData Sequence is encapContentInfo
1339    // It contains CscaMasterList
1340    //
1341    // ICAO Doc 9303-12 Section 9
1342    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1343    // CscaMasterList {joint-iso-itu-t(2) international-organization(23) icao(136) mrtd(1) security(1) masterlist(2)}
1344    if signed_data
1345        .encap_content_info
1346        .content_type
1347        .ne(Oid::const_new(&[2, 23, 136, 1, 1, 2]))
1348    {
1349        error!("Master List SignedData encapContentInfo OID must be id-icao-cscaMasterList");
1350        return Err(EmrtdError::InvalidFileStructure(
1351            "Master List SignedData encapContentInfo OID must be id-icao-cscaMasterList",
1352        ));
1353    }
1354
1355    // It is mandatory by ICAO Doc 9303-12 Section 9
1356    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1357    let Some(csca_master_list_bytes) = signed_data.encap_content_info.content else {
1358        error!("Master List SignedData must contain eContent CscaMasterList");
1359        return Err(EmrtdError::InvalidFileStructure(
1360            "Master List SignedData must contain eContent CscaMasterList",
1361        ));
1362    };
1363
1364    // RFC 5652 Section 12.1, Cryptographic Message Syntax
1365    // <https://datatracker.ietf.org/doc/html/rfc5652#section-12.1>
1366    // Fourth item in the SignedData Sequence is certificates
1367    //
1368    // It is mandatory by ICAO Doc 9303-12 Section 9
1369    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1370    //
1371    // > The Master List Signer certificate MUST be included and the
1372    // > CSCA certificate, which can be used to verify the signature in the
1373    // > signerInfos field SHOULD be included.
1374    let master_list_signer = {
1375        let mut possible_master_list_signer = None;
1376        let mut possible_csca_cert = None;
1377        for cert in signed_data.certificates.iter().flatten() {
1378            if let CertificateChoices::Certificate(c) = cert {
1379                match &c.tbs_certificate.extensions {
1380                    Some(exts) => {
1381                        if exts.is_empty() {
1382                            error!("Certificate Extensions must exist certificates in Master List");
1383                            return Err(EmrtdError::InvalidFileStructure(
1384                                "Certificate Extensions must exist certificates in Master List",
1385                            ));
1386                        }
1387                        if possible_master_list_signer.is_none() {
1388                            for ext in exts.iter() {
1389                                // It is mandatory by ICAO Doc 9303-12 Section 7.1.1.3
1390                                // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1391                                //
1392                                // > The Object Identifier (OID) that must be included in the extendedKeyUsage
1393                                // extension for Master List Signer certificates is 2.23.136.1.1.3.
1394                                if ext.extn_id.eq(Oid::const_new(&[2, 5, 29, 37]))
1395                                    && ext.extn_value.len() == 10
1396                                    && eq(
1397                                        &ext.extn_value,
1398                                        b"\x30\x08\x06\x06\x67\x81\x08\x01\x01\x03",
1399                                    )
1400                                {
1401                                    let master_list_signer_bytes =
1402                                        der::encode(&c).map_err(EmrtdError::RasnEncodeError)?;
1403                                    let master_list_signer =
1404                                        X509::from_der(&master_list_signer_bytes)
1405                                            .map_err(EmrtdError::BoringErrorStack)?;
1406                                    possible_master_list_signer = Some(master_list_signer);
1407                                    break;
1408                                // It is mandatory by ICAO Doc 9303-12 Table 6
1409                                // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1410                                //
1411                                // > Basic constraints cA is mandatory for CSCA certificates
1412                                // > PathLenConstraint must always be '0'
1413                                } else if ext.extn_id.eq(Oid::const_new(&[2, 5, 29, 19]))
1414                                    && ext.extn_value.len() == 8
1415                                    && eq(&ext.extn_value, b"\x30\x06\x01\x01\xFF\x02\x01\x00")
1416                                {
1417                                    let csca_cert_bytes =
1418                                        der::encode(&c).map_err(EmrtdError::RasnEncodeError)?;
1419                                    let csca_cert = X509::from_der(&csca_cert_bytes)
1420                                        .map_err(EmrtdError::BoringErrorStack)?;
1421                                    possible_csca_cert = Some(csca_cert);
1422                                    break;
1423                                }
1424                            }
1425                        }
1426                    }
1427                    None => {
1428                        error!("Certificate Extensions must exist certificates in Master List");
1429                        return Err(EmrtdError::InvalidFileStructure(
1430                            "Certificate Extensions must exist certificates in Master List",
1431                        ));
1432                    }
1433                }
1434            }
1435        }
1436        // Make sure we got a possible certificate
1437        match possible_master_list_signer {
1438            Some(c) => {
1439                // And verify that the Master List Signer was issued by CSCA certificate if it exists
1440                match possible_csca_cert {
1441                    Some(csca_cert) => {
1442                        let chain = Stack::new().map_err(EmrtdError::BoringErrorStack)?;
1443                        let mut store_bldr =
1444                            X509StoreBuilder::new().map_err(EmrtdError::BoringErrorStack)?;
1445                        store_bldr
1446                            .add_cert(csca_cert)
1447                            .map_err(EmrtdError::BoringErrorStack)?;
1448                        let store = store_bldr.build();
1449
1450                        let mut context =
1451                            X509StoreContext::new().map_err(EmrtdError::BoringErrorStack)?;
1452                        let master_list_verification = context
1453                            .init(&store, &c, &chain, |c| {
1454                                let verification = c.verify_cert()?;
1455                                if verification {
1456                                    Ok((verification, ""))
1457                                } else {
1458                                    Ok((verification, c.error().error_string()))
1459                                }
1460                            })
1461                            .map_err(EmrtdError::BoringErrorStack)?;
1462                        if !master_list_verification.0 {
1463                            warn!("Error while verifying Master List Signer Certificate signature: {}", master_list_verification.1);
1464                        }
1465                        info!(
1466                            "Master List Signer Certificate signature verification result: {}",
1467                            master_list_verification.0
1468                        );
1469                    }
1470                    None => {
1471                        warn!("Master List Signer Certificate signature is not verified, no CSCA certificate found in signed_data.certificates");
1472                    }
1473                }
1474                c
1475            }
1476            None => unimplemented!("Master List must include a Master List Signer"),
1477        }
1478    };
1479
1480    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1481    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1482    // Fifth item in the SignedData Sequence is crls
1483    //
1484    // It should **not** be present ICAO Doc 9303-10 Section 4.6.2.2
1485    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1486    if signed_data.crls.is_some() {
1487        error!("Master List must not contain a CRL");
1488        return Err(EmrtdError::InvalidFileStructure(
1489            "Master List must not contain a CRL",
1490        ));
1491    }
1492
1493    // RFC 5652 Section 12.1, Cryptographic Message Syntax
1494    // <https://datatracker.ietf.org/doc/html/rfc5652#section-12.1>
1495    // Last item in the SignedData Sequence is signerInfos
1496    //
1497    // It is recommended to provide only 1 SignerInfo by
1498    // ICAO Doc 9303-12 Section 9
1499    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1500    if signed_data.signer_infos.is_empty() {
1501        error!("Master List must include at least one SignerInfo");
1502        return Err(EmrtdError::InvalidFileStructure(
1503            "Master List must include at least one SignerInfo",
1504        ));
1505    }
1506    // Only one signer_info is supported
1507    if signed_data.signer_infos.len() > 1 {
1508        unimplemented!("Master Lists that include more than one SignerInfo are not supported")
1509    }
1510
1511    let signer_info = signed_data
1512        .signer_infos
1513        .first()
1514        .expect("len of SignerInfos is 1");
1515
1516    // RFC 5652 Section 5.3
1517    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.3>
1518    // > version is the syntax version number.  If the SignerIdentifier is
1519    // > the CHOICE issuerAndSerialNumber, then the version MUST be 1.  If
1520    // > the SignerIdentifier is subjectKeyIdentifier, then the version
1521    // > MUST be 3.
1522    //
1523    // It is recommended to provide subjectKeyIdentifier (v3) instead of issuerandSerialNumber (v1)
1524    // by ICAO Doc 9303-12 Section 9
1525    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1526    match signer_info.sid {
1527        rasn_cms::SignerIdentifier::IssuerAndSerialNumber(_) => {
1528            // Recommended
1529            if signer_info.version.ne(&rasn::types::Integer::from(1)) {
1530                error!("Master List SignedData signerInfo IssuerAndSerialNumber is provided but version is not 1");
1531                return Err(EmrtdError::InvalidFileStructure("Master List SignedData signerInfo IssuerAndSerialNumber is provided but version is not 1"));
1532            }
1533        }
1534        rasn_cms::SignerIdentifier::SubjectKeyIdentifier(_) => {
1535            if signer_info.version.ne(&rasn::types::Integer::from(3)) {
1536                error!("Master List SignedData signerInfo SubjectKeyIdentifier is provided but version is not 3");
1537                return Err(EmrtdError::InvalidFileStructure("Master List SignedData signerInfo SubjectKeyIdentifier is provided but version is not 3"));
1538            }
1539        }
1540    };
1541
1542    // RFC 5652 Section 5.3
1543    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.3>
1544    // > The message digest algorithm SHOULD be among those
1545    // > listed in the digestAlgorithms field of the associated SignerData.
1546    // > Implementations MAY fail to validate signatures that use a digest
1547    // > algorithm that is not included in the SignedData digestAlgorithms
1548    // > set.
1549    if !signed_data
1550        .digest_algorithms
1551        .contains(&signer_info.digest_algorithm)
1552    {
1553        error!("Master List SignedData signerInfo DigestAlgorithm must be included in SignedData digestAlgorithms set");
1554        return Err(EmrtdError::InvalidFileStructure(
1555            "Master List SignedData signerInfo DigestAlgorithm must be included in SignedData digestAlgorithms set",
1556        ));
1557    }
1558    // Ignore digest_algorithm parameters
1559    let digest_algorithm = oid2digestalg(&signer_info.digest_algorithm.algorithm)?;
1560
1561    // RFC 5652 Section 5.3
1562    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.3>
1563    //
1564    // > signedAttrs is a collection of attributes that are signed.  The
1565    // > field is optional, but it MUST be present if the content type of
1566    // > the EncapsulatedContentInfo value being signed is not id-data.
1567    //
1568    // EncapsulatedContentInfo
1569    // by ICAO Doc 9303-12 Section 9
1570    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1571    // is `(OID joint-iso-itu-t(2) international-organization(23) icao(136) mrtd(1) security(1) masterlist(2))`
1572    // So this field is mandatory
1573    let signed_attrs = match &signer_info.signed_attrs {
1574        None => {
1575            error!("Master List SignedData signerInfo signed_attrs can't be empty");
1576            return Err(EmrtdError::InvalidFileStructure(
1577                "Master List SignedData signerInfo signed_attrs can't be empty",
1578            ));
1579        }
1580        Some(signed_attrs) => signed_attrs,
1581    };
1582
1583    // RFC 5652 Section 5.3
1584    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.3>
1585    //
1586    // > If the field is present, it MUST
1587    // > contain, at a minimum, the following two attributes:
1588    // >
1589    // >   * A content-type attribute [...]
1590    // >   * A message-digest attribute [...]
1591    //
1592    // RFC 5652 Section 11.1
1593    // <https://datatracker.ietf.org/doc/html/rfc5652#section-11.1>
1594    //
1595    // > The following object identifier identifies the content-type
1596    // > attribute:
1597    // >
1598    // >    id-contentType OBJECT IDENTIFIER ::= { iso(1) member-body(2)
1599    // >        us(840) rsadsi(113549) pkcs(1) pkcs9(9) 3 }
1600    // >
1601    // > Content-type attribute values have ASN.1 type ContentType:
1602    // >
1603    // >    ContentType ::= OBJECT IDENTIFIER
1604    //
1605    // RFC 5652 Section 11.2
1606    // <https://datatracker.ietf.org/doc/html/rfc5652#section-11.2>
1607    //
1608    // > The following object identifier identifies the message-digest
1609    // > attribute:
1610    // >
1611    // >    id-messageDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
1612    // >        us(840) rsadsi(113549) pkcs(1) pkcs9(9) 4 }
1613    // >
1614    // > Message-digest attribute values have ASN.1 type MessageDigest:
1615    // >
1616    // >    MessageDigest ::= OCTET STRING
1617    //
1618    // ICAO Doc 9303-12 Section 9
1619    // <https://www.icao.int/publications/Documents/9303_p12_cons_en.pdf>
1620    // also makes signing time mandatory
1621    // > signedAttrs MUST include signing time (see [PKCS #9]).
1622    // But we skip verifying that.
1623    let mut content_type = None;
1624    let mut message_digest = None;
1625
1626    for signed_attr in signed_attrs {
1627        if signed_attr
1628            .r#type
1629            .eq(Oid::const_new(&[1, 2, 840, 113549, 1, 9, 3]))
1630        {
1631            // ContentType
1632            if signed_attr.values.len() != 1 {
1633                error!("Master List SignedData signerInfo signed_attrs contentType attribute values must have a single item");
1634                return Err(EmrtdError::InvalidFileStructure("Master List SignedData signerInfo signed_attrs contentType attribute values must have a single item"));
1635            }
1636            let temp = signed_attr
1637                .values
1638                .first()
1639                .expect("There is only one item")
1640                .as_bytes();
1641            content_type = Some(
1642                der::decode::<rasn::types::ObjectIdentifier>(temp)
1643                    .map_err(EmrtdError::RasnDecodeError)?,
1644            );
1645        } else if signed_attr
1646            .r#type
1647            .eq(Oid::const_new(&[1, 2, 840, 113549, 1, 9, 4]))
1648        {
1649            // MessageDigest
1650            if signed_attr.values.len() != 1 {
1651                error!("Master List SignedData signerInfo signed_attrs messageDigest attribute values must have a single item");
1652                return Err(EmrtdError::InvalidFileStructure("Master List SignedData signerInfo signed_attrs messageDigest attribute values must have a single item"));
1653            }
1654            let temp = signed_attr
1655                .values
1656                .first()
1657                .expect("There is only one item")
1658                .as_bytes();
1659            message_digest = Some(
1660                der::decode::<rasn::types::OctetString>(temp)
1661                    .map_err(EmrtdError::RasnDecodeError)?,
1662            );
1663        }
1664    }
1665
1666    let (Some(content_type), Some(message_digest)) = (content_type, message_digest) else {
1667        error!("Master List SignedData signerInfo signed_attrs contentType or messageDigest values do not exist");
1668        return Err(EmrtdError::InvalidFileStructure("Master List SignedData signerInfo signed_attrs contentType or messageDigest values do not exist"));
1669    };
1670
1671    // RFC 5652 Section 5.3
1672    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.3>
1673    //
1674    // > A content-type attribute having as its value the content type
1675    // > of the EncapsulatedContentInfo value being signed.
1676    //
1677    // contentType inside signedAttrs must be id-icao-cscaMasterList
1678    if content_type.ne(Oid::const_new(&[2, 23, 136, 1, 1, 2])) {
1679        error!("Master List SignedData signerInfo signed_attrs contentType must be id-icao-cscaMasterList");
1680        return Err(EmrtdError::InvalidFileStructure("Master List SignedData signerInfo signed_attrs contentType must be id-icao-cscaMasterList",));
1681    }
1682
1683    // RFC 5652 Section 5.4
1684    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.4>
1685    //
1686    // Message Digest Calculation Process as specified in RFC 5652
1687    let csca_master_list_hash =
1688        hash(digest_algorithm, &csca_master_list_bytes).map_err(EmrtdError::BoringErrorStack)?;
1689
1690    if csca_master_list_hash.ne(&message_digest) {
1691        error!("Digest of cscaMasterList does not match with the digest in SignedAttributes");
1692        return Err(EmrtdError::InvalidFileStructure(
1693            "Digest of cscaMasterList does not match with the digest in SignedAttributes",
1694        ));
1695    }
1696    info!("Digest of cscaMasterList matches with the digest in SignedAttributes");
1697
1698    // Ignore unsignedAttrs
1699    _ = signer_info.unsigned_attrs;
1700
1701    // RFC 5652 Section 5.4
1702    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.4>
1703    //
1704    // > [...] A separate encoding of the signedAttrs field is performed for message digest calculation.
1705    // > The IMPLICIT [0] tag in the signedAttrs is not used for the DER
1706    // > encoding, rather an EXPLICIT SET OF tag is used.  That is, the DER
1707    // > encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0]
1708    // > tag, MUST be included in the message digest calculation along with
1709    // > the length and content octets of the SignedAttributes value.
1710    let mut signed_attrs_bytes = der::encode(&signed_attrs).map_err(EmrtdError::RasnEncodeError)?;
1711    signed_attrs_bytes[0] = b'\x31';
1712
1713    // Signature Verification
1714    // Follows RFC 5652 Section 5.6 Signature Verification Process
1715    // <https://datatracker.ietf.org/doc/html/rfc5652#section-5.6>
1716    let _signature_algorithm = &signer_info.signature_algorithm;
1717    let signature = &signer_info.signature;
1718    info!("{:?}", master_list_signer);
1719    let pub_key = master_list_signer
1720        .public_key()
1721        .map_err(EmrtdError::BoringErrorStack)?;
1722    let mut verifier =
1723        Verifier::new(digest_algorithm, &pub_key).map_err(EmrtdError::BoringErrorStack)?;
1724    verifier
1725        .update(&signed_attrs_bytes)
1726        .map_err(EmrtdError::BoringErrorStack)?;
1727    let sig_verified = verifier
1728        .verify(signature)
1729        .map_err(EmrtdError::BoringErrorStack)?;
1730    info!("Signature verification: {sig_verified}");
1731
1732    if !sig_verified {
1733        error!("Signature verification failure during Master List parsing");
1734        return Err(EmrtdError::VerifySignatureError(
1735            "Signature verification failure during Master List parsing",
1736        ));
1737    }
1738
1739    // Parse the eContent
1740    let csca_master_list = der::decode::<csca_master_list::CscaMasterList>(&csca_master_list_bytes)
1741        .map_err(EmrtdError::RasnDecodeError)?;
1742
1743    if csca_master_list.version.ne(&rasn::types::Integer::from(0)) {
1744        error!("MasterList CscaMasterListVersion must be V0");
1745        return Err(EmrtdError::InvalidFileStructure(
1746            "MasterList CscaMasterListVersion must be V0",
1747        ));
1748    }
1749
1750    // Create a store that can be used to verify DSC certificate during passive authentication
1751    let mut store_bldr = X509StoreBuilder::new().map_err(EmrtdError::BoringErrorStack)?;
1752
1753    for csca_cert in csca_master_list.cert_list {
1754        match der::encode(&csca_cert).map_err(EmrtdError::RasnEncodeError) {
1755            Ok(c) => {
1756                let x509cert = X509::from_der(&c).map_err(EmrtdError::BoringErrorStack)?;
1757                store_bldr
1758                    .add_cert(x509cert)
1759                    .map_err(EmrtdError::BoringErrorStack)?;
1760            }
1761            Err(e) => return Err(e),
1762        }
1763    }
1764
1765    let store = store_bldr.build();
1766
1767    Ok(store)
1768}
src/lib.rs#passive_authentication
1770/// Perform passive authentication on the EF.SOD (Security Object Data) of an eMRTD (electronic Machine Readable Travel Document).
1771///
1772/// This function follows the specifications outlined in ICAO Doc 9303-10 Section 4.6.2 and RFC 3369.
1773/// It verifies the integrity and authenticity of the EF.SOD by validating its structure, signature, and other relevant attributes.
1774///
1775/// # Arguments
1776///
1777/// * `ef_sod` - The EF.SOD (Security Object Data) read from an eMRTD.
1778///
1779/// # Returns
1780///
1781/// A `Result` containing a tuple with the following elements if the passive authentication was successful:
1782/// * `MessageDigest` - The message digest algorithm used for hashing the data groups (EF.DG1..16).
1783/// * `Vec<DataGroupHash>` - A vector containing hashes of the data groups as specified in the `LDSSecurityObject`.
1784/// * `X509` - Document Signer Certificate (DSC) used for signing the EF.SOD.
1785///
1786/// If passive authentication fails due to any reason such as invalid structure, mismatched hashes, or signature verification failure,
1787/// an `EmrtdError` is returned indicating the specific failure reason.
1788///
1789/// # Errors
1790///
1791/// Returns an `EmrtdError` if passive authentication fails.
1792///
1793/// # Panics
1794///
1795/// Might panic under different circumstances.
1796///
1797/// # Examples
1798///
1799/// ```
1800/// # use emrtd::EmrtdError;
1801/// #
1802/// # fn main() -> Result<(), EmrtdError> {
1803/// use emrtd::passive_authentication;
1804/// use openssl::x509::store::X509StoreBuilder;
1805/// use tracing::{info, error};
1806///
1807/// let store = X509StoreBuilder::new().map_err(EmrtdError::BoringErrorStack)?.build();
1808///
1809/// let ef_sod_data = &[/* EF.SOD Data */];
1810/// match passive_authentication(ef_sod_data, &store) {
1811///     Ok((digest_algorithm, dg_hashes, dsc)) => {
1812///         info!("Passive authentication successful!");
1813///         info!("Message Digest Algorithm (openssl NID): {:?}", digest_algorithm.type_());
1814///         info!("Data Group Hashes: {:?}", dg_hashes);
1815///         info!("Document Signer Certificate: {:?}", dsc);
1816///     }
1817///     Err(err) => error!("Passive authentication failed: {:?}", err),
1818/// }
1819/// #
1820/// #     Ok(())
1821/// # }
1822/// ```
1823///
1824/// # TODOs
1825///
1826/// * Instead of returning error immediately after an error, collect all errors and return at the end
1827/// of the function, i.e. in case of signature verification failure, maybe the user can still get the DG hashes
1828pub fn passive_authentication(
1829    ef_sod: &[u8],
1830    cert_store: &X509Store,
1831) -> Result<(MessageDigest, Vec<lds_security_object::DataGroupHash>, X509), EmrtdError> {
1832    // ICAO Doc 9303-10 Section 4.6.2
1833    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1834    // Strip Document Security Object Tag 0x77
1835    validate_asn1_tag(ef_sod, b"\x77")?;
1836    let (ef_sod_rem, empty) = get_asn1_child(ef_sod, 1)?;
1837    if !empty.is_empty() {
1838        error!("EF.SOD file tag is wrong, must be '0x77'");
1839        return Err(EmrtdError::InvalidFileStructure(
1840            "EF.SOD file tag is wrong, must be '0x77'",
1841        ));
1842    }
1843
1844    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1845    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1846    //
1847    // ContentInfo ::= SEQUENCE {
1848    //   contentType ContentType,
1849    //   content [0] EXPLICIT ANY DEFINED BY contentType }
1850    //
1851    // ContentType ::= OBJECT IDENTIFIER
1852    let content_info =
1853        der::decode::<rasn_cms::ContentInfo>(ef_sod_rem).map_err(EmrtdError::RasnDecodeError)?;
1854
1855    // RFC 3369 Section 5.1, SignedData Type
1856    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.1>
1857    // Verify the id-signedData OID
1858    if content_info
1859        .content_type
1860        .ne(Oid::const_new(&[1, 2, 840, 113549, 1, 7, 2]))
1861    {
1862        error!("EF.SOD ContentInfo contentType OID must be id-signedData");
1863        return Err(EmrtdError::InvalidFileStructure(
1864            "EF.SOD ContentInfo contentType OID must be id-signedData",
1865        ));
1866    }
1867
1868    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1869    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1870    //
1871    // SignedData ::= SEQUENCE {
1872    //   version CMSVersion,
1873    //   digestAlgorithms DigestAlgorithmIdentifiers,
1874    //   encapContentInfo EncapsulatedContentInfo,
1875    //   certificates [0] IMPLICIT CertificateSet OPTIONAL,
1876    //   crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
1877    //   signerInfos SignerInfos }
1878    let signed_data = der::decode::<rasn_cms::SignedData>(content_info.content.as_bytes())
1879        .map_err(EmrtdError::RasnDecodeError)?;
1880
1881    // RFC 3369 Sections 12.1 and 10.2.5
1882    // <https://datatracker.ietf.org/doc/html/rfc3369>
1883    // First item in the SignedData Sequence is version
1884    // ICAO Doc 9303-10 Section 4.6.2.2
1885    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1886    // For eMRTDs it is always set to Value 3
1887    if signed_data.version.ne(&rasn::types::Integer::from(3)) {
1888        error!("EF.SOD SignedData version must be V3");
1889        return Err(EmrtdError::InvalidFileStructure(
1890            "EF.SOD SignedData version must be V3",
1891        ));
1892    }
1893
1894    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1895    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1896    // Second item in the SignedData Sequence is digestAlgorithms
1897    //
1898    // It is mandatory by ICAO Doc 9303-10 Section 4.6.2.2
1899    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1900    if signed_data.digest_algorithms.is_empty() {
1901        error!("EF.SOD SignedData digestAlgorithms can not be empty");
1902        return Err(EmrtdError::InvalidFileStructure(
1903            "EF.SOD SignedData digestAlgorithms can not be empty",
1904        ));
1905    }
1906
1907    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1908    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1909    // Third item in the SignedData Sequence is encapContentInfo
1910    // It contains LDSSecurityObject
1911    //
1912    // ICAO Doc 9303-10 Section 4.6.2.3 and Appendix D.2
1913    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1914    // LDSSecurityObjectV0 {joint-iso-itu-t (2) international(23) icao(136) mrtd(1) security(1) ldsSecurityObject(1)}
1915    // LDSSecurityObjectV1 {joint-iso-itu-t (2) international(23) icao(136) mrtd(1) security(1) ldsSecurityObject(1)}
1916    if signed_data
1917        .encap_content_info
1918        .content_type
1919        .ne(Oid::const_new(&[2, 23, 136, 1, 1, 1]))
1920    {
1921        error!("EF.SOD SignedData encapContentInfo OID must be id-icao-mrtd-security-ldsSecurityObject");
1922        return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData encapContentInfo OID must be id-icao-mrtd-security-ldsSecurityObject"));
1923    }
1924
1925    // It is mandatory by ICAO Doc 9303-10 Section 4.6.2.2
1926    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1927    let Some(lds_security_object_bytes) = signed_data.encap_content_info.content else {
1928        error!("EF.SOD SignedData must contain eContent LDSSecurityObject");
1929        return Err(EmrtdError::InvalidFileStructure(
1930            "EF.SOD SignedData must contain eContent LDSSecurityObject",
1931        ));
1932    };
1933
1934    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1935    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1936    // Fourth item in the SignedData Sequence is certificates
1937    //
1938    // It is mandatory by ICAO Doc 9303-10 Section 4.6.2.2 for LDS v1
1939    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1940    //
1941    // > States are REQUIRED to include the Document Signer Certificate (CDS) which can
1942    // > be used to verify the signature in the signerInfos field.
1943    //
1944    // But it is optional for LDS v0 ICAO Doc 9303-10 Appendix D.1
1945    let dsc = {
1946        let mut possible_dsc = None;
1947        for cert in signed_data.certificates.iter().flatten() {
1948            if let CertificateChoices::Certificate(c) = cert {
1949                let dsc_bytes = der::encode(&c).map_err(EmrtdError::RasnEncodeError)?;
1950                let dsc = X509::from_der(&dsc_bytes).map_err(EmrtdError::BoringErrorStack)?;
1951                possible_dsc = Some(dsc);
1952                break;
1953            }
1954        }
1955        // Make sure we got a possible certificate
1956        match possible_dsc {
1957            Some(c) => {
1958                let chain = Stack::new().map_err(EmrtdError::BoringErrorStack)?;
1959                let mut context = X509StoreContext::new().map_err(EmrtdError::BoringErrorStack)?;
1960                let dsc_verification = context.init(cert_store, &c, &chain, |c| {
1961                    let verification = c.verify_cert()?;
1962                    if verification {
1963                        Ok((verification, ""))
1964                    } else {
1965                        Ok((verification, c.error().error_string()))
1966                    }
1967                }).map_err(EmrtdError::BoringErrorStack)?;
1968                if !dsc_verification.0 {
1969                    error!("Error while verifying Document Signer Certificate signature: {}", dsc_verification.1);
1970                    return Err(EmrtdError::InvalidFileStructure("DSC certificate verification using CSCA store failed"));
1971                }
1972                info!("Document Signer Certificate signature verification result: {}", dsc_verification.0);
1973                c
1974            },
1975            None => unimplemented!("Documents that do not include a Document Signer Certificate are not yet supported, or the included certificate is not supported")
1976        }
1977    };
1978
1979    // RFC 3369 Section 12.1, Cryptographic Message Syntax
1980    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
1981    // Fifth item in the SignedData Sequence is crls
1982    //
1983    // It is recommended **not** to use by ICAO Doc 9303-10 Section 4.6.2.2
1984    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
1985    let crl_bytes = {
1986        let mut possible_crl = None;
1987        for crl in signed_data.crls.iter().flatten() {
1988            if let RevocationInfoChoice::Crl(c) = crl {
1989                possible_crl = Some(c);
1990                break;
1991            }
1992        }
1993        match possible_crl {
1994            Some(c) => {
1995                // Try to encode it
1996                match der::encode(&c).map_err(EmrtdError::RasnEncodeError) {
1997                    Ok(c) => Some(c),
1998                    Err(e) => return Err(e),
1999                }
2000            }
2001            None => None,
2002        }
2003    };
2004
2005    if let Some(_crl) = crl_bytes {
2006        // We just ignore it
2007    }
2008
2009    // RFC 3369 Section 12.1, Cryptographic Message Syntax
2010    // <https://datatracker.ietf.org/doc/html/rfc3369#section-12.1>
2011    // Last item in the SignedData Sequence is signerInfos
2012    //
2013    // It is recommended to provide only 1 SignerInfo by
2014    // ICAO Doc 9303-10 Section 4.6.2.2
2015    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
2016    if signed_data.signer_infos.is_empty() {
2017        error!("EF.SOD SignedData signerInfos can't be empty");
2018        return Err(EmrtdError::InvalidFileStructure(
2019            "EF.SOD SignedData signerInfos can't be empty",
2020        ));
2021    }
2022
2023    // Only one signer_info is supported
2024    if signed_data.signer_infos.len() > 1 {
2025        unimplemented!("EF.SOD that include more than one SignerInfo are not supported")
2026    }
2027
2028    let signer_info = signed_data
2029        .signer_infos
2030        .first()
2031        .expect("len of SignerInfos is 1");
2032
2033    // RFC 3369 Section 5.3
2034    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.3>
2035    // > version is the syntax version number.  If the SignerIdentifier is
2036    // > the CHOICE issuerAndSerialNumber, then the version MUST be 1.  If
2037    // > the SignerIdentifier is subjectKeyIdentifier, then the version
2038    // > MUST be 3.
2039    //
2040    // It is recommended to provide issuerandSerialNumber (v1) instead of subjectKeyIdentifier (v3)
2041    // by ICAO Doc 9303-10 Section 4.6.2.2
2042    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
2043    match signer_info.sid {
2044        rasn_cms::SignerIdentifier::IssuerAndSerialNumber(_) => {
2045            if signer_info.version.ne(&rasn::types::Integer::from(1)) {
2046                error!("EF.SOD SignedData signerInfo IssuerAndSerialNumber is provided but version is not 1");
2047                return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData signerInfo IssuerAndSerialNumber is provided but version is not 1"));
2048            }
2049        }
2050        rasn_cms::SignerIdentifier::SubjectKeyIdentifier(_) => {
2051            if signer_info.version.ne(&rasn::types::Integer::from(3)) {
2052                error!("EF.SOD SignedData signerInfo SubjectKeyIdentifier is provided but version is not 3");
2053                return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData signerInfo SubjectKeyIdentifier is provided but version is not 3"));
2054            }
2055        }
2056    };
2057
2058    // RFC 3369 Section 5.3
2059    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.3>
2060    // > The message digest algorithm SHOULD be among those
2061    // > listed in the digestAlgorithms field of the associated SignerData.
2062    // > Implementations MAY fail to validate signatures that use a digest
2063    // > algorithm that is not included in the SignedData digestAlgorithms
2064    // > set.
2065    if !signed_data
2066        .digest_algorithms
2067        .contains(&signer_info.digest_algorithm)
2068    {
2069        error!("EF.SOD SignedData signerInfo DigestAlgorithm must be included in SignedData digestAlgorithms set");
2070        return Err(EmrtdError::InvalidFileStructure(
2071            "EF.SOD SignedData signerInfo DigestAlgorithm must be included in SignedData digestAlgorithms set",
2072        ));
2073    }
2074    // Ignore digest_algorithm parameters
2075    let digest_algorithm = oid2digestalg(&signer_info.digest_algorithm.algorithm)?;
2076
2077    // RFC 3369 Section 5.3
2078    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.3>
2079    //
2080    // > signedAttrs is a collection of attributes that are signed.  The
2081    // > field is optional, but it MUST be present if the content type of
2082    // > the EncapsulatedContentInfo value being signed is not id-data.
2083    //
2084    // EncapsulatedContentInfo
2085    // by ICAO Doc 9303-10 Section 4.6.2.2
2086    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
2087    // is `(OID joint-iso-itu-t (2) international(23) icao(136) mrtd(1) security(1) ldsSecurityObject(1))`
2088    // So this field is mandatory
2089    let signed_attrs = match &signer_info.signed_attrs {
2090        None => {
2091            error!("EF.SOD SignedData signerInfo signed_attrs can't be empty");
2092            return Err(EmrtdError::InvalidFileStructure(
2093                "EF.SOD SignedData signerInfo signed_attrs can't be empty",
2094            ));
2095        }
2096        Some(signed_attrs) => signed_attrs,
2097    };
2098
2099    // RFC 3369 Section 5.3
2100    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.3>
2101    //
2102    // > If the field is present, it MUST
2103    // > contain, at a minimum, the following two attributes:
2104    // >
2105    // >   * A content-type attribute [...]
2106    // >   * A message-digest attribute [...]
2107    //
2108    // RFC 3369 Section 11.1
2109    // <https://datatracker.ietf.org/doc/html/rfc3369#section-11.1>
2110    //
2111    // > The following object identifier identifies the content-type
2112    // > attribute:
2113    // >
2114    // >    id-contentType OBJECT IDENTIFIER ::= { iso(1) member-body(2)
2115    // >        us(840) rsadsi(113549) pkcs(1) pkcs9(9) 3 }
2116    // >
2117    // > Content-type attribute values have ASN.1 type ContentType:
2118    // >
2119    // >    ContentType ::= OBJECT IDENTIFIER
2120    //
2121    // RFC 3369 Section 11.2
2122    // <https://datatracker.ietf.org/doc/html/rfc3369#section-11.2>
2123    //
2124    // > The following object identifier identifies the message-digest
2125    // > attribute:
2126    // >
2127    // >    id-messageDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2)
2128    // >        us(840) rsadsi(113549) pkcs(1) pkcs9(9) 4 }
2129    // >
2130    // > Message-digest attribute values have ASN.1 type MessageDigest:
2131    // >
2132    // >    MessageDigest ::= OCTET STRING
2133    let mut content_type = None;
2134    let mut message_digest = None;
2135
2136    for signed_attr in signed_attrs {
2137        if signed_attr
2138            .r#type
2139            .eq(Oid::const_new(&[1, 2, 840, 113549, 1, 9, 3]))
2140        {
2141            // ContentType
2142            if signed_attr.values.len() != 1 {
2143                error!("EF.SOD SignedData signerInfo signed_attrs contentType attribute values must have a single item");
2144                return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData signerInfo signed_attrs contentType attribute values must have a single item"));
2145            }
2146            let temp = signed_attr
2147                .values
2148                .first()
2149                .expect("There is only one item")
2150                .as_bytes();
2151            content_type = Some(
2152                der::decode::<rasn::types::ObjectIdentifier>(temp)
2153                    .map_err(EmrtdError::RasnDecodeError)?,
2154            );
2155        } else if signed_attr
2156            .r#type
2157            .eq(Oid::const_new(&[1, 2, 840, 113549, 1, 9, 4]))
2158        {
2159            // MessageDigest
2160            if signed_attr.values.len() != 1 {
2161                error!("EF.SOD SignedData signerInfo signed_attrs messageDigest attribute values must have a single item");
2162                return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData signerInfo signed_attrs messageDigest attribute values must have a single item"));
2163            }
2164            let temp = signed_attr
2165                .values
2166                .first()
2167                .expect("There is only one item")
2168                .as_bytes();
2169            message_digest = Some(
2170                der::decode::<rasn::types::OctetString>(temp)
2171                    .map_err(EmrtdError::RasnDecodeError)?,
2172            );
2173        }
2174    }
2175
2176    let (Some(content_type), Some(message_digest)) = (content_type, message_digest) else {
2177        error!("EF.SOD SignedData signerInfo signed_attrs contentType or messageDigest values do not exist");
2178        return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData signerInfo signed_attrs contentType or messageDigest values do not exist"));
2179    };
2180
2181    // RFC 3369 Section 5.3
2182    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.3>
2183    //
2184    // > A content-type attribute having as its value the content type
2185    // > of the EncapsulatedContentInfo value being signed.
2186    //
2187    // contentType inside signedAttrs must be id-icao-mrtd-security-ldsSecurityObject
2188    if content_type.ne(Oid::const_new(&[2, 23, 136, 1, 1, 1])) {
2189        error!("EF.SOD SignedData signerInfo signed_attrs contentType must be id-icao-mrtd-security-ldsSecurityObject");
2190        return Err(EmrtdError::InvalidFileStructure("EF.SOD SignedData signerInfo signed_attrs contentType must be id-icao-mrtd-security-ldsSecurityObject",));
2191    }
2192
2193    // RFC 3369 Section 5.4
2194    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.4>
2195    //
2196    // Message Digest Calculation Process as specified in RFC 3369
2197    let lds_security_object_hash =
2198        hash(digest_algorithm, &lds_security_object_bytes).map_err(EmrtdError::BoringErrorStack)?;
2199
2200    if lds_security_object_hash.ne(&message_digest) {
2201        error!("Digest of LDSSecurityObject does not match with the digest in SignedAttributes");
2202        return Err(EmrtdError::InvalidFileStructure(
2203            "Digest of LDSSecurityObject does not match with the digest in SignedAttributes",
2204        ));
2205    }
2206    info!("Digest of LDSSecurityObject matches with the digest in SignedAttributes");
2207
2208    // Ignore unsignedAttrs
2209    _ = signer_info.unsigned_attrs;
2210
2211    // RFC 3369 Section 5.4
2212    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.4>
2213    //
2214    // > [...] A separate encoding of the signedAttrs field is performed for message digest calculation.
2215    // > The IMPLICIT [0] tag in the signedAttrs is not used for the DER
2216    // > encoding, rather an EXPLICIT SET OF tag is used.  That is, the DER
2217    // > encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0]
2218    // > tag, MUST be included in the message digest calculation along with
2219    // > the length and content octets of the SignedAttributes value.
2220    let mut signed_attrs_bytes = der::encode(&signed_attrs).map_err(EmrtdError::RasnEncodeError)?;
2221    signed_attrs_bytes[0] = b'\x31';
2222
2223    // Signature Verification
2224    // Follows RFC 3369 Section 5.6 Signature Verification Process
2225    // <https://datatracker.ietf.org/doc/html/rfc3369#section-5.6>
2226    let _signature_algorithm = &signer_info.signature_algorithm;
2227    let signature = &signer_info.signature;
2228    let pub_key = dsc.public_key().map_err(EmrtdError::BoringErrorStack)?;
2229    let mut verifier =
2230        Verifier::new(digest_algorithm, &pub_key).map_err(EmrtdError::BoringErrorStack)?;
2231    verifier
2232        .update(&signed_attrs_bytes)
2233        .map_err(EmrtdError::BoringErrorStack)?;
2234    let sig_verified = verifier
2235        .verify(signature)
2236        .map_err(EmrtdError::BoringErrorStack)?;
2237    info!("Signature verification: {sig_verified}");
2238
2239    if !sig_verified {
2240        error!("Signature verification failure during EF.SOD parsing");
2241        return Err(EmrtdError::VerifySignatureError(
2242            "Signature verification failure during EF.SOD parsing",
2243        ));
2244    }
2245
2246    // Parse the eContent
2247    let lds_security_object =
2248        der::decode::<lds_security_object::LDSSecurityObject>(&lds_security_object_bytes)
2249            .map_err(EmrtdError::RasnDecodeError)?;
2250    // LDSSecurityObject has two versions, it is defined by ICAO Doc 9303-10
2251    if lds_security_object
2252        .version
2253        .eq(&rasn::types::Integer::from(0))
2254    {
2255        if lds_security_object.lds_version_info.is_some() {
2256            error!("EF.SOD LDSSecurityObjectVersion is V0, but ldsVersionInfo is present");
2257            return Err(EmrtdError::InvalidFileStructure(
2258                "EF.SOD LDSSecurityObjectVersion is V0, but ldsVersionInfo is present",
2259            ));
2260        }
2261        info!("LDSSecurityObjectVersion is V0");
2262    } else if lds_security_object
2263        .version
2264        .eq(&rasn::types::Integer::from(1))
2265    {
2266        if lds_security_object.lds_version_info.is_none() {
2267            error!("EF.SOD LDSSecurityObjectVersion is V1, but ldsVersionInfo is not present");
2268            return Err(EmrtdError::InvalidFileStructure(
2269                "EF.SOD LDSSecurityObjectVersion is V1, but ldsVersionInfo is not present",
2270            ));
2271        }
2272        info!("LDSSecurityObjectVersion is V1");
2273    }
2274    // Skip Algorithm parameters
2275    let file_digest_algorithm = oid2digestalg(&lds_security_object.hash_algorithm.algorithm)?;
2276    if lds_security_object.data_group_hash_values.len() < 2
2277        || lds_security_object.data_group_hash_values.len() > 16
2278    {
2279        error!("EF.SOD LDSSecurityObject DataGroupHash values are invalid");
2280        return Err(EmrtdError::InvalidFileStructure(
2281            "EF.SOD LDSSecurityObject DataGroupHash values are invalid",
2282        ));
2283    }
2284    for data_group_hash in &lds_security_object.data_group_hash_values {
2285        if data_group_hash
2286            .data_group_number
2287            .gt(&rasn::types::Integer::from(16))
2288        {
2289            error!("EF.SOD LDSSecurityObject invalid DataGroupHash number");
2290            return Err(EmrtdError::InvalidFileStructure(
2291                "EF.SOD LDSSecurityObject invalid DataGroupHash number",
2292            ));
2293        }
2294    }
2295    let dg_hashes = lds_security_object.data_group_hash_values;
2296
2297    Ok((file_digest_algorithm, dg_hashes, dsc))
2298}
src/lib.rs#get_jpeg_from_ef_dg2
2300/// Extracts the JPEG image from the EF.DG2.
2301///
2302/// This function follows the specifications outlined in ICAO Doc 9303-10 Section 4.7.2 for the structure of EF.DG2 files.
2303/// For details, refer to: [ICAO Doc 9303-10 Section 4.7.2](https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf)
2304///
2305/// # Arguments
2306///
2307/// * `ef_dg2` - EF.DG2 contents.
2308///
2309/// # Returns
2310///
2311/// Extracted JPEG image data if successful, else `EmrtdError`.
2312///
2313/// # Errors
2314///
2315/// `EmrtdError` if the EF.DG2 file structure is invalid or if errors occur during parsing.
2316///
2317/// # Examples
2318///
2319/// ```
2320/// # use emrtd::EmrtdError;
2321/// #
2322/// # fn main() -> Result<(), EmrtdError> {
2323/// use emrtd::get_jpeg_from_ef_dg2;
2324/// use tracing::{info, error};
2325///
2326/// let ef_dg2 = &[/* EF.DG2 Data */];
2327///
2328/// let jpeg = match get_jpeg_from_ef_dg2(ef_dg2) {
2329///     Ok(jpeg) => {
2330///         info!("JPEG successfully extracted.")
2331///     },
2332///     Err(e) => error!("Error during JPEG extraction from EF.DG2: {}", e)
2333/// };
2334/// #
2335/// #     Ok(())
2336/// # }
2337/// ```
2338pub fn get_jpeg_from_ef_dg2(ef_dg2: &[u8]) -> Result<&[u8], EmrtdError> {
2339    // ICAO Doc 9303-10 Section 4.7.2
2340    // <https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf>
2341    // Strip EF.DG2 Tag 0x75
2342    validate_asn1_tag(ef_dg2, b"\x75")?;
2343    let (ef_dg2_rem, empty) = get_asn1_child(ef_dg2, 1)?;
2344    if !empty.is_empty() {
2345        error!("EF.DG2 file tag is wrong, must be '0x75'");
2346        return Err(EmrtdError::InvalidFileStructure(
2347            "EF.DG2 file tag is wrong, must be '0x75'",
2348        ));
2349    }
2350    // Strip Biometric Information Template Group Template Tag 0x7F61
2351    validate_asn1_tag(ef_dg2_rem, b"\x7F\x61")?;
2352    let (ef_dg2_rem, empty) = get_asn1_child(ef_dg2_rem, 2)?;
2353    if !empty.is_empty() {
2354        error!("EF.DG2 Biometric Information Template Group Template Tag must be '0x7F61'");
2355        return Err(EmrtdError::InvalidFileStructure(
2356            "EF.DG2 Biometric Information Template Group Template Tag must be '0x7F61'",
2357        ));
2358    }
2359    // Find number of biometric templates
2360    validate_asn1_tag(ef_dg2_rem, b"\x02")?;
2361    let (number_of_face_images, ef_dg2_rem) = get_asn1_child(ef_dg2_rem, 1)?;
2362    if number_of_face_images.len() != 1 || number_of_face_images[0] < 1 {
2363        error!("EF.DG2 file invalid structure, must contain at least one face image");
2364        return Err(EmrtdError::InvalidFileStructure(
2365            "EF.DG2 file invalid structure, must contain at least one face image",
2366        ));
2367    }
2368    // We only get the first face image
2369    validate_asn1_tag(ef_dg2_rem, b"\x7F\x60")?;
2370    let (first_instance, _other_instances) = get_asn1_child(ef_dg2_rem, 2)?;
2371    // Skip the Biometric Header Template (BHT) parsing
2372    validate_asn1_tag(first_instance, b"\xA1")?;
2373    let (_bht, biometric_data) = get_asn1_child(first_instance, 1)?;
2374    if biometric_data.is_empty() {
2375        error!("EF.DG2 first biometric image must not be empty");
2376        return Err(EmrtdError::InvalidFileStructure(
2377            "EF.DG2 first biometric image must not be empty",
2378        ));
2379    }
2380    // Strip the image tag '5F2E' or '7F2E'
2381    match validate_asn1_tag(biometric_data, b"\x5F\x2E") {
2382        Ok(()) => {}
2383        Err(EmrtdError::ParseAsn1TagError(_, _)) => validate_asn1_tag(biometric_data, b"\x7F\x2E")?,
2384        Err(e) => return Err(e),
2385    }
2386    let (biometric_data, _) = get_asn1_child(biometric_data, 2)?;
2387    if biometric_data.len() < 46 {
2388        error!("EF.DG2 invalid biometric image structure");
2389        return Err(EmrtdError::InvalidFileStructure(
2390            "EF.DG2 invalid biometric image structure",
2391        ));
2392    }
2393    // Face Image Data Standard for e-Governance Applications in India
2394    // https://egovstandards.gov.in/sites/default/files/Face_Image_Data_Standard_Ver1.0.pdf
2395    // Section 6.3
2396    // Ideally we would get these values looking at ISO 19794-5:2005
2397    //
2398    // Strip the Facial Record Header (14 bytes)
2399    validate_asn1_tag(biometric_data, b"\x46\x41\x43\x00\x30\x31\x30\x00")?;
2400    let biometric_data = &biometric_data[14..];
2401    // Strip Facial Information (20 bytes)
2402    let biometric_data = &biometric_data[20..];
2403    // Strip Image Information (12 bytes)
2404    let biometric_data = &biometric_data[12..];
2405
2406    Ok(biometric_data)
2407}
src/lib.rs#validate_dg
2409/// Validates the integrity of a Data Group (DG) in an eMRTD.
2410///
2411/// # Arguments
2412///
2413/// * `dg` - Data Group contents.
2414/// * `dg_number` - The number of the Data Group to validate, ranging from 1 to 16.
2415/// * `message_digest` - The cryptographic hash function used to compute the hash of the Data Group in EF.SOD.
2416/// * `verified_hashes` - A slice of `DataGroupHash` objects representing the pre-verified hashes of Data Groups.
2417///
2418/// # Returns
2419///
2420/// * `Ok(())` if the validation succeeds, indicating that the Data Group is valid.
2421/// * `Err(EmrtdError)` if the validation fails, containing details about the failure.
2422///
2423/// # Errors
2424///
2425/// `EmrtdError` in case of failure during verification.
2426///
2427/// # Panics
2428///
2429/// Might panic under different circumstances.
2430///
2431/// # Examples
2432///
2433/// ```
2434/// # use emrtd::EmrtdError;
2435/// #
2436/// # fn main() -> Result<(), EmrtdError> {
2437/// use emrtd::{passive_authentication, validate_dg};
2438/// use openssl::x509::store::X509StoreBuilder;
2439/// use tracing::{info, error};
2440///
2441/// let store = X509StoreBuilder::new().map_err(EmrtdError::BoringErrorStack)?.build();
2442///
2443/// let ef_sod_data = &[/* EF.SOD Data */];
2444/// let ef_dg1 = &[/* EF.DG1 Data */];
2445/// match passive_authentication(ef_sod_data, &store) {
2446///     Ok((digest_algorithm, verified_dg_hashes, dsc)) => {
2447///         match validate_dg(ef_dg1, 1, digest_algorithm, &verified_dg_hashes) {
2448///             Ok(()) => {
2449///                 info!("EF.DG1 successfully verified")
2450///             }
2451///             Err(err) => error!("Passive authentication failed: {:?}", err),
2452///         }
2453///     }
2454///     Err(err) => {
2455///         error!("Passive authentication failed: {:?}", err)
2456///     }
2457/// }
2458/// #
2459/// #     Ok(())
2460/// # }
2461/// ```
2462pub fn validate_dg(
2463    dg: &[u8],
2464    dg_number: i32,
2465    message_digest: MessageDigest,
2466    verified_hashes: &[lds_security_object::DataGroupHash],
2467) -> Result<(), EmrtdError> {
2468    if !(1..=16).contains(&dg_number) {
2469        error!("Invalid Data Group number: {}", dg_number);
2470        return Err(EmrtdError::InvalidArgument("Invalid Data Group number"));
2471    }
2472
2473    let hash_bytes = hash(message_digest, dg).map_err(EmrtdError::BoringErrorStack)?;
2474    let mut verified_hash = None;
2475    for dg_hash in verified_hashes {
2476        if dg_hash
2477            .data_group_number
2478            .eq(&rasn::types::Integer::from(dg_number))
2479        {
2480            verified_hash = Some(&dg_hash.data_group_hash_value);
2481        }
2482    }
2483    match verified_hash {
2484        Some(verified_hash) => {
2485            if !eq(verified_hash, &hash_bytes) {
2486                error!("Potentially cloned document, hashes do not match");
2487                return Err(EmrtdError::VerifyHashError(
2488                    "Potentially cloned document, hashes do not match".to_owned(),
2489                ));
2490            }
2491        }
2492        None => {
2493            error!("Potentially cloned document, EF.DG{dg_number} file hash is not found inside verified hashes");
2494            return Err(EmrtdError::VerifyHashError(format!(
2495                "EF.DG{dg_number} file hash is not found inside verified hashes"
2496            )));
2497        }
2498    }
2499
2500    Ok(())
2501}

With all that, we are done. The library is still missing crucial features, especially PACE. There has been many ID cards issued since January 2018 that do not support BAC, and only support PACE. Active Authentication and Chip Authentication are also not supported yet. I plan to include them sometime in the future. Many of the eMRTDs also have quirks, this implementation does not care for any of those[3]. More tests must be written, testing using ICAO test vectors is also something to consider[4].

But I have some remarks about Rust to add here:


Footnotes:

[1]: ^ Smart card application protocol data unit

[2]: ^ https://en.wikipedia.org/wiki/Answer_to_reset

[3]: ^ For a well written post about eMRTD data quirks, see https://wf.lavatech.top/aves-tech-notes/emrtd-data-quirks

[4]: ^ For a great resource collecting all the test specifications, see https://blog.protocolbench.org/test-specifications/